In this tutorial, we discuss a modified version of Uri Wilensky’s “GIS General Examples” model, which is bundled with NetLogo in the “Code Examples” section of the Models Library. This tutorial example requires a copy of the data folder associated with that model (which can be found in the “Models” folder of the NetLogo installation directory). In particular, this tutorial example imports country shape data and (slightly old) country population data, so as to be able to compute population densities, like so:

The data behind this includes the following table:

CNTRY_NAME

POP_CNTRY

SQKM

…

Afghanistan

17250390

641358.44

…

Albania

3416945

28798

…

Algeria

27459230

2323510.25

…

…

…

…

…

As well as colouring countries by population density, we will be able to construct representative models of the world population, where each NetLogo agent represents 10 million people in the real world, and these agents are located in the appropriate country on a world map. For example, Australia’s population of roughly 20 million people is represented by 2 agents, while Canada’s population of roughly 30 million people is represented by 3 agents. India and China are a little more crowded:

Constructing agent populations in this way allows agents to have country-dependent behaviour. The same approach, with different GIS datasets, allows models of individual countries, states, or cities, with populations determined by GIS data on, for example, counties or suburbs.

The NetLogo code

Loading the GIS data is much like Uri Wilensky’s “GIS General Examples” model (specific details will be given later), while the following procedure sets up the population density data in the patches:

Here the calls to gis:apply-coverage copy values from the GIS country dataset to the named patch variables. The ask which follows calculates the population density of each patch, and colours it appropriately.

How should we create the agents? The simplest answer is to use those calculated population densities, combined with the fact that the average patch has an area of 510,000,000 / N square kilometres, where N is the number of patches (ignoring the substantial distortion due to the map projection). To take India as an example, the population density is 283.7 people per square kilometre, which works out to 13,671,000 people per patch, which will be represented by 1.3671 agents (this is in fact a slight overestimate, since the sum total of India’s patches have a slightly greater area than the country itself). We can effectively create 1.3671 agents per patch by always creating one agent, and creating an additional one with probability 0.3671. The sprout-<breeds> primitive is used to create the agents:

Results

This code gives a different result each time, with between 540 and 640 agents created. The black line on the histogram below shows the average value of 584, while the dotted line shows the actual world population (some years ago) of 5.695 billion (corresponding to 570 agents). Notice that over-estimating the number of agents per grid square has given a population which is too large. This is in spite of the fact that populations of countries occupying zero grid squares don’t get counted at all. Examples of such small countries include Singapore (population 2.8 million), Rwanda (7.9 million), and Burundi (6.0 million). The other difficulty is that, because of the substantial distortion due to the map projection, there are not enough agents in countries near the equator (like Brazil), and too many in countries near the poles (like Russia). The dashed blue line shows the result of a better (and deterministic) method, which we discuss next.

A better way

For the deterministic alternative, we also use the NetLogo tables extension, which provides tables of key-value mappings (with put, get, and has-key?). We use two tables: patches-to-go, which maps a country name to a number of patches, and people-to-go, which maps a country name to a number of agents. The second of these tables is created using a loop over GIS attributes (3):

This sets up the people-to-go table to hold the number of agents that must be created for each country (the question marks refer to the “vector feature” objects that the loop is iterating over). The number of patches for each country, on the other hand, is trickier. It is tempting to use multiple calls to count patches with ..., but that would be slow. The following alternative iterates once over all patches, adding one to the appropriate table entry in patches-to-go each time (and also accumulating the total desired-people to create, excluding countries with zero patches):

The actual creation process looks at the ratio of the people-to-go and patches-to-go table entries, creating agents when this ratio becomes large enough. As the dashed blue line on the histogram above indicates, the number of agents created (558) is less than the 570 expected from the total world population. This is because of the exclusion of countries with zero patches, as well as the impact of rounding. Making the patches smaller alleviates this problem (with patches of a tenth the area, 563 agents are created), but slows down execution.

Some basics

Finally, the following setup code loads the GIS data, much as in Uri Wilensky’s “GIS General Examples” model. As with many NetLogo features, there is considerable sophistication “under the hood,” making the GIS data import relatively easy. However, the gis:load-dataset procedure will not, unfortunately, load all SHP files.

One point to note is the use of the gis:set-world-envelope-ds primitive to fit the GIS data to the NetLogo world grid. The “DS” version of this primitive is necessary because having max-pxcor twice the size of max-pycor does not give the world the exact 2:1 aspect ratio which the dataset uses.

Going further

Since each agent contains a country name, we can extend this tutorial example with country-specific economic data or population-growth data, and so simulate evolution of the state of the planet using country-specific behaviour. For anyone wishing to experiment with doing so, the full NetLogo code for this tutorial can be downloaded from Modeling Commons. As an example, we can use NetLogo file-read operations to read in this list of countries and median ages into another table (data adapted from Wikipedia). The following additional code in agent-setup will then assign a moderately realistic age to each agent (assuming ages very roughly follow a uniform distribution, and ignoring the differences between mean and median):

There are also complexities associated with building models satisfying multiple constraints (e.g. combining the kind of spatial constraints discussed here with various demographic profiles). For information on that, I refer readers to the agent-based modelling literature (e.g. this book).

Readers can also experiment with loading other GIS datasets (although the GIS extension will not load all SHP files). For example, here is the result of loading Statistical Local Areas from the Australian Bureau of Statistics:

19 thoughts on “The NetLogo GIS extension: a tutorial”

Thank you for your information. i am trying to make evacuation model by using Letlogo. Before seeing your article, I just used ‘import-pcolor’. And I realize that it must need GIS data to make better agent-based model.

I am working on an evacuation model for a building. I used shape file and vectordataset for setting up the environment. What is your suggestion for generating the environment?
Also, I got a problem with the gis:apply coverage primitive. It gives a runtime error. “Extension exception: not a vectordataset ”
Do you know any solution for this?
I can send you both shap file and the netlogo code, if you need.

I have lat/long data to map the lower 48 states of the U.S. Plus lat/long for selected cities. However, I wanted to add Congressional Districts or maybe zip code areas to the map, so I am trying the GIS extension to Netlogo. The maps look much better. However, when I try to put the cities on the vector map, they are off. Not sure how to coordinate the two. The Netlogo world sets 0,0 in the lower left corner, and I convert the city lat/long to Netlogo coordinates. Also do this for the non-GIS version of the maps, and that looks okay. But when I use the GIS map, it’s not fitting into the Netlogo world so that the lat/long data matches. Any way to fix this? These cities are not going to be in a GIS database – or at least many of them won’t. Thanks for any advice you have.

Well, first, there’s an option when you right-click edit on the Netlogo world to set the origin 0,0 (I usually have it in the centre).

Second, the Netlogo coordinates specify patch centres. If you have the origin in the lower left, x actually runs from -0.5 to max-pxcor + 0.5, and y runs from -0.5 to max-pycor + 0.5 (although only the range 0 to max-pxcor and 0 to max-pycor are legal turtle positions). You need to do the conversion correctly.

Third, there may still be a bug in the Netlogo GIS extension. I notice that the patches and lines in my example don’t 100% line up. You might need to do some experimentation with the coordinates of geographic features and then compensate for the error. I must confess that I’ve never done anything requiring that level of accuracy.

I think your second comment may help – trial-and-error resulted in “correction factors” very close to the min latitude and longitude that is subtraced from each city’s location. These are within 0.5 of the actual boundary lat/long points. Will have to look at this when I’m more awake.

The CONUS map looks pretty good, though. Cities seem to be where they should be – i.e., not yet under water and in the expected states! Need to check this out for individual states, though.

Tony,
Some more progress, but more questions. I imported the data files I use in Netlogo into QGIS. The cities lined up really nicely. Then I created a shapefile and went back to Netlogo. I can now create a U.S. map with the cities and have a button that turns the cities on and off. So then I added the cities as agents using the same data file that QGIS used. And they are all a little off. And it’s not consistently to one direction – some to the right, some up to the right, some down, etc. So is there a way to create or link an agent to a point from the GIS city? I am just getting into the GIS extension, so I am not familiar with all the options. Or is it possible to retrieve the patch from the GIS city points? That might work, too. Thanks for your help.

It’s hard to know what’s wrong without seeing your code. It could still be the kind of coordinate mismatch I described before (especially if the errors go the same way in similar parts of the map). Whatever it is, you could probably reduce the problem by editing the world (right-click and edit) to have more and smaller patches.

I don’t understand your other questions, precisely, You can certainly use the ordinary patch-here to identify the patch that an agent is on and setxy to reset an agent’s position.

Turns out that I can import the cities file into QGIS and create a shapefile. Then back in Netlogo the cities and background maps can be merged. The code example in the Models library that you mention in the tutorial shows how to do that and create agents. So all is well! Thanks for your help.

Hello,
I’m trying to include 5 rasters in my model, all the rasters are from the same region, but when I apply more than 1 occurs the following extension error.
Extension exception: Dimensions (width=334991 height=334992) are too large
error while observer running GIS:APPLY-RASTER
called by procedure DISPLAY-CLASES-IN-PATCHES
called by Button ‘display-clases-in-patches’
What can I do? I think is something related with
gis:set-world-envelope (gis:envelope-union-of (gis:envelope-of apt-dataset) (gis:envelope-of clases-dataset))
Is something wrong?

You should probably contact the NetLogo people themselves, but I’m guessing your rasters are just much to large (if the dimensions are really width=334991 height=334992). Alternatively, if the rasters are from different areas, NetLogo is being forced to build such a large raster internally to hold the five pieces.

Can you combine them all the rasters into one using GIS software before loading them into NetLogo? It sounds like you may need to downsample the rasters to fit your patch grid as well.