Wednesday, March 10, 2010

Importing Raster Files in NetLogo without the GIS Extension

I've been working mainly on abstract ABM, and I really don't need all that bells and whistles, and besides I've had some problems when trying to handle the relation between the real coordinate system and NetLogo own system. What I want is to use a GIS (GRASS in my case) to create artificial landscape with some given statistical or geostatistical proprieties that I can import in NetLogo. There is only one problem for this: NetLogo identifies the integer coordinates at its centroid and not on the bottom-left corner. This means that a world with max-pxcor and max-pycor set to 1 have actually four cells, with the coordinate of their centroids at 0,0; 0,1; 1,1; and 1,0. Thus in reality the absolute extent of the world is -0.5 to +1.5, with the actual cell size maintained to 1. Now if you create a map in GRASS with cellsize 1 and extent max x and max y at 1 you will have only 1 cell.   


So here's my solution:
0)Set up a GRASS region with 0,0 origin on the bottom-left.


1)Create a raster model in GRASS and import in R as a SpatialGridDataFrame (via maptools or spgrass6; you can of course also create a model in R directly)


2)Export as text file using the following code (where "data" is the SpatialGridDataFrame):


#Extrapolate the coordinates of the cell centroid

x<-coordinates(data)
#Shift the coordinate by half the cell size
x<-x-(data@grid@cellsize[1]/2)
#convert matrix to data.frame
x<-as.data.frame(x)
#export the data value (data@data) as the third column of the data.frame
x[,3]<-data@data
#write the output into a text file with tab separator, without putting any column name
write.table(x,"data.txt",sep="\t",col.names=FALSE,row.names=FALSE)



If you look at the .txt you'll see something like this:

0    49    120
1    49    110 
...

3)Read the text file in NetLogo. The procedure is adapted from what Railsback and Grimm have written in their forthcoming book on ABM which is simply GREAT and I advise to everybody.


to import-rast [filename]
file-open filename
  while [not file-at-end?]
  [
    let next-X file-read
    let next-Y file-read
    let next-Z file-read
     
    ask patch next-X next-Y [set mapValue next-Z ]
  ]
    
file-close

end

so I use this in my setup procedure putting something like:

import-rast "mapA.txt"

with mapValue being a numerical property of the patch which I am interested in. Be sure also to set the NetLogo world with origins at the bottom-left, and use as maxpxcor and maxpycor the maxX and maxY of your Raster minus the cellsize (e.g. for a 50 x 50 Raster map with cellsize 1, maxpxcor and maxpycor should be 49). Oddly, if your world is to small, there will be no error message but just a portion of the raster model presented in NetLogo.
Again this workflow is fine as long as your model is abstract. You can of course use this for real world raster data, but you need to shift the entire data so that you have your origin on your bottom-left, or you can use the GIS-Extension.

1 comment:

  1. Does it matter if you have an odd number when you do this:
    x<-x-(data@grid@cellsize[1]/2)

    ReplyDelete