Archive

GIS

20141108_175726_0A few weeks ago, I had the pleasure to give an interview about open source GIS for the American magazine XYHT. We talked about the open source development model and the motivation behind contributing to open source projects. You can read the full interview in the November issue.

XYHT is available as a classic print magazine as well as for free online and focuses on “positioning and measurement” topics:

http://www.xyht.com

This experiment is motivated by a discussion I had with Dr. Claus Rinner about introducing students to GIS concepts using Conway’s Game of Life. Conway’s Game of Life is a popular example to demonstrate cellular automata. Based on an input grid of “alive” and “dead” cells, new cell values are computed on each iteration based on four simple rules for the cell and its 8 neighbors:

  1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
  2. Any live cell with two or three live neighbours lives on to the next generation.
  3. Any live cell with more than three live neighbours dies, as if by overcrowding.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

(Source: Wikipedia – Conway’s Game of Life)

Based on these simple rules, effects like the following “glider gun” can be achieved:

Gospers glider gun.gif
Gospers glider gun” by KieffOwn work. Licensed under CC BY-SA 3.0 via Wikimedia Commons.

There are some Game of Life implementations for GIS out there, e.g. scripts for ArcGIS or a module for SAGA. Both of these examples are raster-based. Since I couldn’t find any examples of raster manipulation like this in pyQGIS, I decided to instead implement a vector version: a Processing script which receives an input grid of cells and outputs the next iteration based on the rules of Game of Life. In the following screencast, you can see the Processing script being called repeatedly by a script from the Python console:

So far, it’s a quick and dirty first implementation. To make it more smooth, I’m considering adding spatial indexing and using memory layers instead of having Processing create a bunch of Shapefiles.

It would also be interesting to see a raster version done in PyQGIS. Please leave a comment if you have any ideas how this could be achieved.

Did you miss FOSS4G 2014? Don’t despair: the talks have been recorded and are available on Vimeo. I suggest to start with the following video of Pirmin’s talk wrapping up the developments since last year:

From Nottingham to PDX: QGIS 2014 roundup — Pirmin Kalberer, Sourcepole AG from FOSS4G on Vimeo.

Other talks include:

For the full list see https://vimeo.com/search/sort:plays/format:detail?q=qgis+foss4g

And of course – last but not least – watch Gary Sherman’s Sol Katz Award acceptance speech if you haven’t seen it yet. Congratulations Gary!

Gary Sherman’s Sol Katz Award acceptance from Gateway Geomatics on Vimeo.

Today’s post is inspired by a recent thread on the QGIS user mailing list titled “exporting text to Illustrator?”. The issue was that with the introduction of the new labeling system, all labels were exported as paths when creating an SVG. Unnoticed by almost everyone (and huge thanks to Alex Mandel for pointing out!) an option has been added to 2.4 by Larry Shaffer which allows exporting labels as texts again.

To export labels as text, open the Automatic Placement Settings (button in the upper right corner of the label dialog) and uncheck the Draw text as outlines option.

Screenshot 2014-09-20 21.03.26

Note that we are also cautioned that

For now the developers recommend you only toggle this option right
before exporting
and that you recheck it after.

Alex even recorded a video showcasing the functionality:

When mapping flows or other values which relate to a certain direction, styling these layers gets interesting. I faced the same challenge when mapping direction-dependent error values. Neighboring cell pairs were connected by two lines, one in each direction, with an associated error value. This is what I came up with:

srtm_errors_1200px

Each line is drawn with an offset to the right. The size of the offset depends on the width of the line which in turn depends on the size of the error. You can see the data-defined style properties here:

directed_error_style

To indicate the direction, I added a marker line with one > marker at the center. This marker line also got assigned the same offset to match the colored line bellow. I’m quite happy with how these turned out and would love to hear about your approaches to this issue.

srtm_errors_detail

These figures are part of a recent publication with my AIT colleagues: A. Graser, J. Asamer, M. Dragaschnig: “How to Reduce Range Anxiety? The Impact of Digital Elevation Model Quality on Energy Estimates for Electric Vehicles” (2014).

Update 2017: Please follow the instructions on the OSGeo4W website: https://trac.osgeo.org/osgeo4w/wiki/ExternalPythonPackages


Update 2015: I now recommend this workflow based on Nathan’s post on installing Python setup tools:

  1. Download ez_setup.py
  2. Run python ez_setup.py in your OSGeo4W shell
  3. Run easy_install pysal in your OSGeo4W shell

Original post:

Today’s post is a summary of how to install PySAL on Windows for OSGeo4W Python.

The most important resource was https://trac.osgeo.org/osgeo4w/wiki/ExternalPythonPackages

In the OSGeo4W Shell run:

C:\Users\anita_000\Desktop>curl http://python-distribute.org/distribute_setup.py | python

Update: Note that python-distribute.org has gone down since I posted this. See http://www.gossamer-threads.com/lists/python/python/1158958 for more info.

Then download https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py to the Desktop and run:

C:\Users\anita_000\Desktop>python get-pip.py

When pip is ready, install PySAL:

C:\Users\anita_000\Desktop>pip install pysal

Test the installation:

C:\Users\anita_000\Desktop>python
Python 2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)] on win 32
Type "help", "copyright", "credits" or "license" for more information.
>>> import pysal

The point table of the Spatialite database created from OSM north-eastern Austria contains more than 500,000 points. This post shows how the style works which – when applied to the point layer – wil make sure that only towns and (when zoomed in) villages will be marked and labeled.

Screenshot 2014-07-12 12.30.21

In the attribute table, we can see that there are two tags which provide context for populated places: the place and the population tag. The place tag has it’s own column created by ogr2ogr when converting from OSM to Spatialite. The population tag on the other hand is listed in the other_tags column.

Screenshot 2014-07-12 13.00.15

for example

"opengeodb:lat"=>"47.5000237","opengeodb:lon"=>"16.0334769","population"=>"623"

Overview maps would be much too crowded if we simply labeled all cities and towns. Therefore, it is necessary to filter towns based on their population and only label the bigger ones. I used limits of 5,000 and 10,000 inhabitants depending on the scale.

Screenshot 2014-07-12 12.56.33

At the core of these rules is an expression which extracts the population value from the other_tags attribute: The strpos() function is used to locate the text "population"=>" within the string attribute value. The population value is then extracted using the left() function to get the characters between "population"=>" and the next occurrence of ". This value can ten be cast to integer using toint() and then compared to the population limit:

5000 < toint( 
   left (
      substr(
         "other_tags",
         strpos("other_tags" ,'"population"=>"')+16,
         8
      ),
      strpos(
         substr(
            "other_tags",
            strpos("other_tags" ,'"population"=>"')+16,
            8
         ),
        '"'
      )
   )
) 

There is also one additional detail concerning label placement in this style: When zoomed in closer than 1:400,000 the labels are placed on top of the points but when zoomed out further, the labels are put right of the point symbol. This is controlled using a scale-based expression in the label placement:

Screenshot 2014-07-12 13.32.47

As usual, you can find the style on Github: https://github.com/anitagraser/QGIS-resources/blob/master/qgis2/osm_spatialite/osm_spatialite_tonerlite_point.qml

In my opinion, Stamen’s Toner-lite map is one of the best background maps to use together with colorful overlays. The only downsides of using it in QGIS are that the OpenLayers plugin can not provide the tiles at print resolution and that the projection is limited to Web Mercator. That’s why I’ve started to recreate the style for OSM Spatialite databases:

toner-lite

So far, there are styles for lines and polygons and they work quite well for the scale range between 1:1 and 1:250000. As always, you can download the styles from QGIS-resources on Github.

Using OSM data in QGIS is a hot topic but so far, no best practices for downloading, preprocessing and styling the data have been established. There are many potential solutions with all their advantages and disadvantages. To give you a place to start, I thought I’d share a workflow which works for me to create maps like the following one from nothing but OSM:

osm_google_100k

Getting the data

Raw OSM files can be quite huge. That’s why it’s definitely preferable to download the compressed binary .pbf format instead of the XML .osm format.

As a download source, I’d recommend Geofabrik. The area in the example used in this post is part of the region Pays de la Loire, France.

Preparing the data for QGIS

In the preprocessing step, we will extract our area of interest and convert the .pbf into a spatialite database which can be used directly in QGIS.

This can be done in one step using ogr2ogr:

C:\Users\anita_000\Geodata\OSM_Noirmoutier>ogr2ogr -f "SQLite" -dsco SPATIALITE=YES -spat 2.59 46.58 -1.44 47.07 noirmoutier.db noirmoutier.pbf

where the -spat option controls the area of interest to be extracted.

When I first published this post, I suggested a two step approach. You can find it here for future reference:

For the first step: extracting the area of interest, we need Osmosis. (For Windows, you can get osmosis from openstreetmap.org. Unpack to use. Requires Java.)

When you have Osmosis ready, we can extract the area of interest to the .osm format:

C:\Users\anita_000\Geodata\OSM_Noirmoutier>..\bin\osmosis.bat --read-pbf pays-de-la-loire-latest.osm.pbf --bounding-box left=-2.59 bottom=46.58 right=-1.44 top=47.07 --write-xml noirmoutier.osm

While QGIS can also load .osm files, I found that performance and access to attributes is much improved if the .osm file is converted to spatialite. Luckily, that’s easy using ogr2ogr:

C:\Users\anita_000\Geodata\OSM_Noirmoutier>ogr2ogr -f "SQLite" -dsco SPATIALITE=YES noirmoutier.db noirmoutier.osm

Finishing preprocessing in QGIS

In QGIS, we’ll want to load the points, lines, and multipolygons using Add SpatiaLite Layer:

Screenshot 2014-05-31 11.39.40

When we load the spatialite tables, there are a lot of features and some issues:

  • There is no land polygon. Instead, there are “coastline” line features.
  • Most river polygons are missing. Instead there are “riverbank” line features.

Screenshot 2014-05-31 11.59.58

Luckily, creating the missing river polygons is not a big deal:

  1. First, we need to select all the lines where waterway=riverbank.
    Screenshot 2014-05-31 13.14.00
  2. Then, we can use the Polygonize tool from the processing toolbox to automatically create polygons from the areas enclosed by the selected riverbank lines. (Note that Processing by default operates only on the selected features but this setting can be changed in the Processing settings.)
    Screenshot 2014-05-31 13.40.16

Creating the land polygon (or sea polygon if you prefer that for some reason) is a little more involved since most of the time the coastline will not be closed for the simple reason that we are often cutting a piece of land out of the main continent. Therefore, before we can use the Polygonize tools, we have to close the area. To do that, I suggest to first select the coastline using "other_tags" LIKE '%"natural"=>"coastline"%' and create a new layer from this selection (save selection as …) and edit it (don’t forget to enable snapping!) to add lines to close the area. Then polygonize.

Screenshot 2014-05-31 14.38.48

Styling the data

Now that all preprocessing is done, we can focus on the styling.

You can get the styles used in the map from my Github QGIS-resources repository:

  • osm_spatialite_googlemaps_multipolygon.qml … rule-based renderer incl. rules for: water, natural, residential areas and airports
  • osm_spatialite_googlemaps_lines.qml … rule-based renderer incl. rules for roads, rails, and rivers, as well as rules for labels
  • osm_spatialite_googlemaps_roadshields.qml … special label style for road shields
  • osm_spatialite_googlemaps_places.qml … label style for populated places such as cities and towns

qgis_osm_google_100k

This post shows how to quickly and easily create a small QGIS plugin for counting the number of features within a vector layer.

To get started, you will need QGIS and Qt Designer (to design the user interface) installed. If you are on Windows, I suggest WinPython which provides Qt Designer and Spyder (a Python IDE).

The great thing about creating plugins for QGIS: There is a plugin for that! It’s called Plugin Builder. And while you are at it, also install Plugin Reloader. Reloader is very useful for plugin developers because it lets you quickly reload your plugin without having to restart QGIS every time you make changes to the code.

installPluginBuilder

Plugin Builder will create all the files we need for our plugin. Just start it and select a name for your plugin class (one word in CamelCase), as well as a name for the plugin itself and the plugin menu entry (can be multiple words). Once you press Ok, you’re asked to select a folder to store the plugin. You can save directly to the QGIS plugin folder ~\.qgis2\python\plugins.

pluginBuilder

Next, open the newly created folder (in my case ~\.qgis2\python\plugins\BuilderTest). Amongst other files, it contains the user interface file ui_buildertest.ui. Our plugin will count the number of features in a vector layer. Therefore, it needs a combobox which allows the user to select a layer. Open the .ui file in Qt Designer and add a combobox to the dialog. Change the object name of the combobox to layerCombo. We’ll later use this name in the plugin code to add items to the combobox. Save the dialog and close Qt Designer.

qtDesigner

Now, we need to compile the .ui and the resources.qrc file to turn the dialog and the icon into usable Python code. This is done on the command line. On Windows, I suggest using the OSGeo4W Shell. Navigate to the plugin folder and run:

pyuic4 -o ui_buildertest.py ui_buildertest.ui
pyrcc4 -o resources_rc.py resources.qrc

Note: Using the latest version of Plugin Builder, you only need to compile resources.qrc because the .ui is now loaded dynamically. Furthermore, you should use the following command to compile the resources:

pyrcc4 -o resources.py resources.qrc 

If you enable and run the plugin now, you will already see the dialog but the combobox will be empty. To populate the combobox, we need to write a few lines of code in buildertest.py. First, we’ll fetch all loaded layers and add all vector layers to the combobox. Then, we’ll add code to compute and display the number of features in the selected layer. To achieve this, we expand the run() method:

def run(self):        
    # show the dialog
    self.dlg.show()

    layers = QgsMapLayerRegistry.instance().mapLayers().values()
    for layer in layers:
        if layer.type() == QgsMapLayer.VectorLayer:
            self.dlg.layerCombo.addItem( layer.name(), layer ) 
         
    # Run the dialog event loop
    result = self.dlg.exec_()
    # See if OK was pressed
    if result == 1:
        # do something useful 
        index = self.dlg.layerCombo.currentIndex()
        layer = self.dlg.layerCombo.itemData(index)
        QMessageBox.information(self.iface.mainWindow(),"hello world","%s has %d features." %(layer.name(),layer.featureCount()))

When you are done with the code, you can use Plugin Reloader to load the new version. When you start the plugin now, the combobox will be populated with the names of the vector layers in your current project. And on pressing Ok, the plugin will compute and display the number of features.

builderTEst

builderTestResult

For more information on PyQGIS and more code samples I warmly recommend the PyQGIS Cookbook. Have fun!