Blog post authored by Richard Wen and Claus Rinner
A great way to demonstrate the manipulation of geospatial raster data is Conway’s Game of Life [1]. The “game” starts with a grid (“board”) of binary cells, which represent either alive (populated) or dead (empty) states. Each cell interacts with its eight adjacent neighbours to determine its next state. At each iteration of the game clock, the following rules are applied [1]:
- A live cell with less than two or more than three live neighbours dies (under-population, overcrowding).
- A live cell with two or three live neighbours continues to live.
- A dead cell with three live neighbours becomes alive (reproduction).
The free and open-source Geographic Information System (GIS) software package QGIS [2] offers support for scripting with the Python programming language (pyQGIS module), which enables the use of powerful libraries such as NumPy and GDAL for dealing with raster data. Numerical Python (NumPy) [3] is a package developed for Python that is geared towards scientific computation with support for multi-dimensional arrays and matrices. The Geospatial Data Abstraction Library (GDAL) [4] is a library for translating raster and vector geospatial data formats available as a binding for Python.
Using NumPy, GDAL, and pyQGIS, we implemented the Game of Life, where NumPy manipulates the arrays, GDAL handles reading and writing of the raster data, and pyQGIS visualizes the rasters and their relative changes. The source code was written by Master of Spatial Analysis student Richard Wen with input from Dr. Claus Rinner and is available at https://github.com/rwenite/QGIS_RasterArray. The project was inspired by Anita Graser’s visit to Ryerson’s Lab for Geocomputation in October 2014, during which Anita developed a vector-based version of the Game of Life in QGIS (see http://anitagraser.com/2014/11/16/more-experiments-with-game-of-life/).
Our implementation takes an object-oriented approach, in which an object of a Game of Life class is instantiated and the gaming board is updated with the cycle() method using the QGIS python console. The core function is the manipulation of individual raster cells based on a coded algorithm – in this case, the rules defined by the Game of Life.
Let’s start by initializing and cycling a gaming board using default parameters:
# Instantiate a starting board x = GameofLife()
# Cycle the board twice x.cycle(2)
The gaming board may be initialized with a random raster, a filled raster, a custom raster, or from a pre-defined raster file:
# The default is a random raster, we can set the width and height as well x = GameofLife(width=3,height=5) # Cycle the board x.cycle()
# Fill a cells object with 1s y = Cells(inRaster=1) # Create a raster with the filled cells object in the directory y.toRaster("path\\to\\filledraster\\file.tif") # Instantiate a starting board with the filled raster x = GameofLife(raster="path\\to\\filledraster\\file.tif") # Cycle the board x.cycle()
# Generate a raster from a list of tuples y=Cells(inRaster=[ (0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0), (0,0,1,0,0,1,0,0), (0,0,0,0,0,0,0,0), (0,0,1,0,0,1,0,0), (0,0,0,1,1,0,0,0), (0,0,0,0,0,0,0,0), (0,0,0,0,0,0,0,0)]) # Create a raster with the custom cells object in the directory y.toRaster("path\\to\\customraster\\file.tif") # Instantiate a starting board with the custom raster x = GameofLife(raster="path\\to\\customraster\\file.tif")
# Instantiate a starting board with a raster x = GameofLife(raster="path\\to\\raster\\file.tif")
Date source: City of Toronto Open Data [5]
Some other interesting features include changing animation speed, jumping cycles, and applying customized layer styles:
# Adjust delay to 3 seconds x.speed=3 # Cycle 10 times normally x.cycle(10) # Cycle 5 times and display every 2nd cycle x.cycle(5,2) # Set the style to the defined qml file x.style = “path\\to\\qml\\style\\file.qml”
This post focuses on the functionality of the program, while its inner workings can be grasped from comments in the Python source code posted at https://github.com/rwenite/QGIS_RasterArray. The code was written and tested for QGIS 2.6; feedback on any issues is most welcome. The use of a NumPy array to iterate through the grid cells was found in an answer by user “gene” on GIS StackExchange [6]. Reading and processing raster data does have its challenges. When dealing with large grids, reading raster data in blocks rather than as a whole is advisable, because there may not be enough RAM to store an entire file at once [7].
The aim of implementing the Game of Life with Python and QGIS is to demonstrate some fundamental concepts of raster data analysis and cellular automata modeling, both of which have important applications in Geography and GIS. Existing QGIS functionality and scripts for raster processing seem to focus more on low-level input/output operations than higher-level analysis functions. For example, we did not find advanced local and focal raster operations in QGIS’ raster calculator. Thus, we envision that the RasterArray code could serve as a basis for expanding raster analysis in QGIS. The code will also be used in a yet-to-be-written lab assignment in GEO641 “GIS and Decision Support” in Ryerson’s BA in Geographic Analysis program.
References:
[1] Wikipedia, Conway’s Game of Life
http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
[2] QGIS
http://www2.qgis.org/en/site/
[3] NumPy, Numerical Python
http://www.numpy.org/
[4] GDAL, Geospatial Data Abstraction Library
http://trac.osgeo.org/gdal/wiki/GdalOgrInPython
[5] Toronto Open Data, Regional Municipal Boundary
http://www.toronto.ca/open
[6] How to do loops on raster cells with python console in QGIS?
http://gis.stackexchange.com/questions/107996/how-to-do-loops-on-raster-cells-with-python-console-in-qgis
[7] Chris Garrard, Utah State University, Reading Raster Data with GDAL
http://www.gis.usu.edu/~chrisg/python/2008/os5_slides.pdf