QGIS Planet

QGIS training (3 days) and Birdwatching/Field data collection (2 days) in South Portugal, January 2015

Faunalia and Imagine-Science are pleased to announce a QGIS training (3 days) course during a week that will include 2 days of field activities related to birdwatching and field data collection. Where: Portugal/Algarve, specifically “Ria de Alvor -Mexilhoeira Grande” near Portimão. When: 26 to 30 January 2015.   For more informations about QGIS training program, […]
Learn More

Slides FOSS4G 2014

Slides from our presentations at FOSS4G 2014 in Portland/Oregon: From Nottingham to PDX: QGIS 2014 roundup State of QGIS Server Easy ETL with OGR Pirmin Kalberer (@implgeo)
Learn More

Share and manage your Data with QGIS Cloud and WFS-T

A lot of people are using QGIS Cloud as a service with ready to use QGIS webclient. It’s very easy to publish data and share maps in this way. But QGIS Cloud has more power under the hood. A not so obvious feature of QGIS Cloud is the option to share your data via Web Feature Service (WFS) and manage them via Web Feature Service Transactional (WFS-T). “The basic Web Feature Service allows querying and retrieval of features.
Learn More

Sourcepole at FOSS4G 2014 in Portland

In one week, the 2014 FOSS4G Conference will start in Portland/Oregon. Sourcepole supports this major event as a bronze sponsor. Our conference contributions: Workshop presented by Horst Düster (@moazagotl) Tuesday afternoon: QGIS Plugin Development with PyQt4 and PyQGIS Presentations by Pirmin Kalberer ((@implgeo)) Thursday, Session 2, Track 7, 13:00 - 13:25: State of QGIS Server Thursday, Session 2, Track 7, 13:30 - 13:55: From Nottingham to PDX: QGIS 2014 roundup Thursday, Session 3, Track 6, 16:25 - 13:25: Easy ETL with OGR Meet Pirmin and Horst at Sourcepole’s exhibition booth and have a look at our latest products.
Learn More

QGIS Layer Tree API (Part 2)

In part 1 we covered how to access the project’s layer tree and read its data. Now let’s focus on building and manipulating layer trees. We’ll also look at how to receive updates about changes within a layer tree.

Starting with an empty project, first we will get access to the layer tree and create some memory layers for testing:

root = QgsProject.instance().layerTreeRoot()

layer1 = QgsVectorLayer("Point", "Layer 1", "memory")
layer2 = QgsVectorLayer("Polygon", "Layer 2", "memory")

Adding Nodes

Now let’s add some layers to the project’s layer tree. There are two ways of doing that:

  1. Explicit addition. This is done with the addLayer() or insertLayer() call of the QgsLayerTreeGroup class. The former appends to the group node, while the latter allows you to specify the index at which the layer should be added.

    # step 1: add the layer to the registry, False indicates not to add to the layer tree
    QgsMapLayerRegistry.instance().addMapLayer(layer1, False)
    # step 2: append layer to the root group node
    node_layer1 = root.addLayer(layer1)
    
  2. Implicit addition. The project’s layer tree is connected to the layer registry and listens for the addition and removal of layers. When a layer is added to the registry, it will be automatically added to the layer tree. It is therefore enough to simply add a layer to the map layer registry (leaving the second argument of addMapLayer() with its default value of True):

    QgsMapLayerRegistry.instance().addMapLayer(layer1)
    

    This behaviour is facilitated by the QgsLayerTreeRegistryBridge class. By default it inserts layers at the first position of the root node. The insertion point for new layers can be changed - within the QGIS application the insertion point is updated whenever the current selection in the layer tree view changes.

Groups can be added using the addGroup() or insertGroup() calls of the QgsLayerTreeGroup class:

node_group1 = root.insertGroup(0, "Group 1")
# add another sub-group to group1
node_subgroup1 = node_group1.addGroup("Sub-group 1")

There are also the general addChildNode(), insertChildNode() and insertChildNodes() calls that allow the addition of existing nodes:

QgsMapLayerRegistry.instance().addMapLayer(layer2, False)

node_layer2 = QgsLayerTreeLayer(layer2)
root.insertChildNode(0, node_layer2)

node_group2 = QgsLayerTreeGroup("Group 2")
root.addChildNode(node_group2)

Nodes that are being added must not have any parent yet (i.e. being part of some layer tree). On the other hand, the nodes that get inserted may already have children, so it is possible to create a whole sub-tree and then add it in one operation to the project’s layer tree.

Removing Nodes

The removal of nodes from a layer tree is always done from the parent group node. For example, nodes displayed as top-level items need to be removed from the root node. There are several ways of removing them. The most general form is to use the removeChildren() method that takes two arguments: the index of the first child node to be removed and how many child nodes to remove. Removal of a group node will also remove all of its children.

There are several convenience methods for removal:

root.removeChildNode(node_group2)

root.removeLayer(layer1)

There is one more way to remove layers from the project’s layer tree:

QgsMapLayerRegistry.instance().addMapLayer(layer1)

The project’s layer tree is notified when any map layers are being removed from the map layer registry and the layer nodes representing affected layers will be automatically removed from the layer tree. This is handled by the QgsLayerTreeRegistryBridge class mentioned earlier.

Moving Nodes

When managing the layer tree, it is often necessary to move some nodes to a different position - within the same parent node or to a different parent node (group). Moving a node is done in three steps: 1. clone the existing node, 2. add the cloned node to the desired place in layer tree, 3. remove the original node. The following code assumes that the existing node we move is a child of the root node:

cloned_group1 = node_group1.clone()
root.insertChildNode(0, cloned_group1)
root.removeChildNode(node_group1)

Modifying Nodes

There are a number of operations one can do with nodes:

  1. Rename. Both group and layer nodes can be renamed. For layer nodes this will modify the name directly inside the map layers.

    node_group1.setName("Group X")
    node_layer2.setLayerName("Layer X")
    
  2. Change visibility. This is actually a check state (checked or unchecked, for group nodes also partially checked) that is associated with the node and normally related to the visibility of layers and groups in the map canvas. In the GUI, the layer tree view is capable of showing a check box for changing the state.

    print node_group1.isVisible()
    node_group1.setVisible(Qt.Checked)
    node_layer2.setVisible(Qt.Unchecked)
    
  3. Change expanded state. The boolean expanded/collapsed state refers to how the node should be shown in layer tree view in the GUI - whether its children should be shown or hidden.

    print node_group1.isExpanded()
    node_group1.setExpanded(False)
    
  4. Change custom properties. Each node may have some associated custom properties. The properties are key-value pairs, keys being strings, values being of variant type (QVariant). They can be used by other components of QGIS or plugins to store additional data. Custom properties are preserved when a layer tree is saved and loaded.

    Use the customProperties() call to get a list of keys of custom properties, then the customProperty() method for getting the value of a particular key. To modify properties, there is a setCustomProperty() method which sets a key-value pair and a removeCustomProperty() method to remove a pair.

    node_group1.setCustomProperty("test_key", "test_value")
    print node_group1.customProperties()
    print node_group1.customProperty("test_key")
    node_group1.removeCustomProperty("test_key")
    print node_group1.customProperties()
    

Signals from Nodes

There are various signals emitted by nodes which may be used by client code to follow changes to the layer tree. Signals from children are automatically propagated to their parent node, so it is enough to connect to the root node to listen for changes from any level of the tree.

Modification of the Layer Tree Structure

The addition of new nodes always emits a pair of signals - before and after the actual addition. Signals pass information about which node is the parent node and the range of child indices:

  • willAddChildren(node, indexFrom, indexTo)
  • addedChildren(node, indexFrom, indexTo)

In order to access the newly added nodes, it is necessary to use the addedChildren signal.

The following code sample illustrates how to connect to signals emitted from the layer tree. When the last line is executed, two lines from the newly defined methods should be printed to the console:

def onWillAddChildren(node, indexFrom, indexTo):
  print "WILL ADD", node, indexFrom, indexTo
def onAddedChildren(node, indexFrom, indexTo):
  print "ADDED", node, indexFrom, indexTo

root.willAddChildren.connect(onWillAddChildren)
root.addedChildren.connect(onAddedChildren)

g = root.addGroup("My Group")

Removal of nodes is handled in a very similar manner to the addition - there is also a pair of signals:

  • willRemoveChildren(node, indexFrom, indexTo)
  • removedChildren(node, indexFrom, indexTo)

This time in order to access nodes being removed it is necessary to connect to the willRemoveChildren signal.

Modification of Tree Nodes

There are a few more signals that allow monitoring of internal changes to nodes:

  • a node is checked or unchecked: visibilityChanged(node, state)
  • a node’s custom property is defined or removed: customPropertyChanged(node, key)
  • a node gets expanded or collapsed: expandedChanged(node, expanded)

Summary

We have covered how to make changes to a layer tree structure and how to listen for changes possibly made by other pieces of code. In a future post we look at GUI components for displaying and modifying the layer tree and the connection between map canvas and layer tree.

You may also like...

Mergin Maps, a field data collection app based on QGIS. Mergin Maps makes field work easy with its simple interface and cloud-based sync. Available on Android, iOS and Windows. Screenshots of the Mergin Maps mobile app for Field Data Collection
Get it on Google Play Get it on Apple store
Learn More

Multiple map grids in the QGIS print composer

In printed maps, having several coordinate grids over one map is a very usefull feature. For instance using a meter system as output CRS, it is nice to display a latitude / longitude grid as well. Until now, the QGIS print composer allowed only one coordinate grid per composer map and it was restricted to the map output CRS. Having that multigrid / multiCRS feature in QGIS Enterprise since 13.04 already, I’ve recently found the time to port it into the QGIS developer version.
Learn More

QGIS Layer Tree API (Part 1)

This blog post will be about the QGIS component responsible for showing the list of layers. In the QGIS project we typically call this component the “legend widget”. People used to other GIS software may also use other names such as “table of contents (ToC)”.

Layers in the legend widget can be organised into groups. This grouping allows easier manipulation of layers. For example it is possible to toggle the visibility of all layers at once. In addition to layers, groups can also contain other groups, effectively creating a hierarchy of groups and layers. From now on, we will refer to this hierarchy as the layer tree.

The legend widget might look like this:

QGIS Legend Widget

Until QGIS 2.4, there has been only limited support for interacting with the legend widget using the QGIS API. There is a QgsLegendInterface class (which can be obtained with iface.legendInterface()) available for plugins. The legend interface has emerged in an ad-hoc way, leading to various issues when used in plugins. It is also worth noting that third-party applications based on QGIS have no access to the legend interface.

Layer Tree API

The layer tree API has been introduced in QGIS 2.4 to overcome these existing problems and add even more flexibility to the way the layer tree can be queried or modified.

The layer tree is a classical tree structure built of nodes. There are currently two types of nodes: group nodes and layer nodes. Group nodes can contain other (child) nodes, while layer nodes are ‘leaves’ of the tree, without any child nodes. The layer tree for the legend widget shown in the picture above looks like this:

Layer Tree Structure

The green nodes are group nodes (QgsLayerTreeGroup class) and the yellow nodes are layer nodes (QgsLayerTreeLayer class).

The legend widget also displays items using symbols, making it look like a real legend. The symbology is not part of the layer tree and will be discussed in an upcoming post.

To start working with the layer tree, we first need a reference to its root node. The project’s layer tree can be accessed easily:

root = QgsProject.instance().layerTreeRoot()

The root node is a group node - its children are shown as top-level items in the legend widget.

print root
print root.children()

This returns a list of the children of a node. The list includes only direct children - children of sub-groups need to be queried directly from those sub-groups.

Now let’s try to access the first child node in the tree and do a little bit of introspection:

child0 = root.children()[0]
print child0
print type(child0)
print isinstance(child0, QgsLayerTreeLayer)
print child0.parent()

With the children() and parent() methods it is possible to traverse the layer tree. A node is the root node of a tree if it has no parent:

print root.parent()

The following example shows how to list top-level items of the layer tree. For group nodes it will print the group name, for layer nodes it will print the layer name and ID.

for child in root.children():
  if isinstance(child, QgsLayerTreeGroup):
    print "- group: " + child.name()
  elif isinstance(child, QgsLayerTreeLayer):
    print "- layer: " child.layerName() + "  ID: " + child.layerId()

In order to traverse the full layer tree, it would be necessary to recursively call the same code for sub-groups.

There are some helper routines for common tasks like finding nodes representing layers in the tree. These take into account all descendants, not just top-level nodes.

ids = root.findLayerIds()
print ids
print root.findLayers()
print root.findLayer(ids[0])

It is assumed that a single layer is represented in a layer tree only once. There may however be temporary situations when a layer is represented by more than one node, for example when moving nodes (a new node is created before the old one is removed shortly after).

Similarly it is possible to search for group nodes by name:

print root.findGroup("POI")

Group names are not necessarily unique - if there are multiple groups with the same name, the first encountered during tree traversal will be returned.

Summary

In this blog post we have shown how to query the project’s layer tree. Upcoming blog entries will focus on modifying the layer tree and interacting with other parts of QGIS.

You may also like...

Mergin Maps, a field data collection app based on QGIS. Mergin Maps makes field work easy with its simple interface and cloud-based sync. Available on Android, iOS and Windows. Screenshots of the Mergin Maps mobile app for Field Data Collection
Get it on Google Play Get it on Apple store
Learn More

Getting started with QGIS

QGIS is a Free and Open Source Software, developed by a growing community of individuals and organisations.

Installation

You can download the latest version of QGIS from here. On that page, you can find the appropriate QGIS installation package for your operating system.

If you are a MS Windows user, you have 2 options: the standalone installer or the OSGeo4W installer, each of which has its own strengths:

  • OSGeo4W Installer Strengths
    • Access to the "master" (development) version of QGIS which means you can make use of the latest (yesterday's) cutting-edge features
    • Access to QGIS-Server (which allows you to publish your maps through a Web Mapping Service)
  • Standalone Installer Strengths
    • Simplest method of installation

Starting QGIS

Once you finish installing QGIS, you can find its icon on your desktop and/or Start menu. Launch QGIS and wait for the application to start. If you're a MS Windows user, QGIS might take some time to start up for the first time but subsequent loads will be much faster.

QGIS Start page

Arranging tool-bars

QGIS features a number of tool-bars. You can move them around by clicking and dragging the vertical or horizontal dotted bars separating the tool-bars (for example, the bar to the left of the help tool's icon in the image above).

Setting the Coordinate Reference System (CRS)

It is recommended to set the Coordinate Reference System (CRS) for your project before adding any data. CRS or SRS is a coordinate-based local, regional or global system used to locate geographical entities. Many CRSs are available and each is suited to a particular area of the globe. There is a comprehensive list of CRS codes available here. In this example, we will set the CRS to match the British National Grid coordinate reference system. The easiest way to search for a specific CRS is using its unique EPSG code. The EPSG code for British National Grid is 27700.

To set the CRS for your projects in QGIS, from the main menu, select Settings > Options. A new window will appear. Select CRS tab.

QGIS Options

CRS list

In the Search section, set Authority to "EPSG" and Search for to "ID". Type 27700 into the search box and click Find. Highlight the correct row in Coordinate Reference System section and click OK.

Adding data

GIS data is usually in either raster or vector format. QGIS supports a large number of GIS data formats through the GDAL/OGR library and other plugins. In the example below we will download and add some OS OpenData™ raster and vector datasets into QGIS.

Raster

Ordnance Survey released a number of OS OpenData raster datasets to the public under a very permissive license. You can download the data from here.

For this particular example, follow this link and browse to OS Street View®. Select SX from the map. Move towards the bottom of the page and click next. Fill in the required information and click continue. You should receive an email with a link to download osstvw_sx.zip (note: it is a 383.9 MB file - you can order a DVD instead if you have a slow internet connection). Once the download has finished, unzip the file. You should now have a new folder called OS Street View SX which contains 2 subfolders and a readme file.

Browse to Street View SX > data > georeferencing files > tfw. Select all the TFW files and move them to the Street View SX > data > sx folder. The TFW files contain georeferencing information describing the location of each TIF file.

In QGIS, from the main menu, select Layer > Add Raster Layer... and browse to the Street View SX > data > sx folder. Select sx99nw.tif, sx99ne.tif, sx99sw.tif and sx99se.tif. Click Open. You should now be able to see the raster tiles in the QGIS canvas and the Layers panel at the left side of the screen.

Raster files do not always contain CRS information. We can easily organise the layers and assign the correct CRS (EPSG:27700) with the help of groups. Create a new group by right-clicking on the blank space (not on the sx99 layers) in the Layers panel and selecting Add group. Set the name of the group to OS Street View. Next, move the sx99 layers into the new group by selecting them all and dragging them into the OS Street View group. Once all the sx99 layers are inside the OS Street View group, right-click on the group and select Set group CRS. A new dialog, similar to that seen in the Setting the CRS chapter will appear. Assign the British National Grid CRS (EPSG:27700) and click OK.

QGIS raster

Vector

Next, we'll bring some vector data into QGIS. Go to the OS OpenData Supply page and browse to OS VectorMap™ District (there are two OS VectorMap datasets on this page, for this example, ensure you select the vector version and not the raster version) and select SX from the map. Scroll to the bottom of the page and click next. Fill in the required information and click continue. Download vmdvec_sx.zip from the link you'll receive by email. Extract the contents of the ZIP file.

In QGIS, from the main menu, select Layer > Add Vector Layer... and browse to the OS VectorMap District (Vector) SX > data > SX. Select SX_Airport.shp, SX_RailwayTrack.shp and SX_Road.shp. Click Open. Click Open again.

To change the style of a vector layer, right-click on the layer in the Layers panel and select Properties. In the Style tab of the Layer Properties dialog, you can define exactly how the layer should look.

QGIS vector

Other Data

Internet based mapping can also be brought into QGIS, for example, a plugin exists that allows OpenStreetMap, Google, Bing and Yahoo maps to be added to QGIS.

Web map services (WMS) are another source of mapping data. In the next we'll add a WMS layer provided by British Geological Survey to our map. Please read the BGS WMS Terms of use. Another example of WMS is Ordnance Survey's OS OnDemand service. If you have OS OnDemand license, you can follow the instructions on Ordnance Survey's website (sorry, link no longer works) to add other useful WMS layers.

To add the BGS WMS, select Layer > Add WMS Layer... from the main menu. The Add Layer(s) from a Server dialog will appear. Click New.

wms add

Set the name to BGS and set the URL to the following:

http://maps.bgs.ac.uk/ArcGIS/services/BGS_Detailed_Geology/MapServer/WMS...

Click OK, and in the Add Layer(s) from a Server dialog, click Connect.

wms add layer

Select all the layers and click Add. Close the Add Layer(s) from a Server dialog. The BGS layer should become visible as you zoom-in to a scale of 1:50000 or closer. Alternatively, you can manually set the Scale in the status bar to 1:50000 and the BGS layer will appear.

wms BGS

Plugins

QGIS is written in a manner that makes it possible for anyone it extend its functionality through the use of plugins. As a result, there are many plugins available to the user, making QGIS highly modular and flexible.

Core plugins

Core plugins are plugins that are shipped with QGIS and can be optionally enabled through the QGIS Plugin Manager.  To access the QGIS Plugin Manager, from the main menu, Select Plugins > Manage Plugins...

qgis core plugins

Select the All tab and type OpenLayers Plugin into the Filter box. Select the plugin and click Install plugin. You should now be able to add OpenStreetMap, Google, Bing and Yahoo maps to your canvas using the Web > OpenLayers plugin menu.

qgis and OpenLayers

Further information

For further help using QGIS, you can always check the manual, user or developer mailing lists or QGIS forum.

If you'd like to master QGIS as quickly as possible, why not attend one of our training courses.

Troubleshooting

Installing OpenLayers Plugin

To install OpenLayers plugin, from the main menu, click Plugins > Manage and Install Plugins.... A new window will appear.

You should be able to search and install the OpenLayers plugin within your list.

Windows Installation

Although you can have different version of QGIS installed under Windows, it's recommended to uninstall old versions before attempting to install new versions.

On rare occasions, some anti-virus software has been known to remove the qgis.exe and python.exe files from the installation folder. If you're having problems running the QGIS shortcut, please ensure those 2 files exist in the installation folder.

If QGIS cannot find your Python folder, you may need to set the PYTHONPATH environment variable to your QGIS folder (\QGIS\apps\python).

Access to internet

To be able to access WMS, WFS and 3rd party plugins, you'll need to have internet access. In the event that you're behind a proxy server, you can enter the proxy server details in Settings > Options > Network:

qgis proxy

You may also like...

Mergin Maps, a field data collection app based on QGIS. Mergin Maps makes field work easy with its simple interface and cloud-based sync. Available on Android, iOS and Windows. Screenshots of the Mergin Maps mobile app for Field Data Collection
Get it on Google Play Get it on Apple store
Learn More

„Geo For All“ - neue Technologien für eine Welt im Wandel

GEOSummit 2014, Bern „Geo for all“ ist nicht nur das Motto der weltumspannenden ICA-OSGeo Lab Initiative zur Förderung der GIS-Ausbildung an Hochschulen, sondern steht allgemein für den immer breiteren Zugang zu professionellen GIS-Werkzeugen. Im Kartenbereich haben Produkte wie TileMill oder D3.js, sowie Dienste wie CartoDB, GeoCommons, usw. den Anwenderkreis weit über das klassische GIS-Fachbebiet hinaus erweitert. Im Vortrag werden einige herausragende Beispiele vorgestellt und deren Relevanz für die Fachwelt erläutert.
Learn More

Why QGIS Class Names Start with Qgs

If you’re a developer, or have looked at the QGIS source code, you’ve likely noticed that most C++ classes in the project start with Qgs. Back before the dark ages of QGIS, Trolltech (now Digia) allowed you to reserve name prefixes for classes that used the Qt framework. Shortly afterwards, I reserved the gs prefix for my use, resulting in class names that start with Qgs. You might think this is based on some mangling of words like QGIS or perhaps GIS, but it was purely egocentric:
Learn More