The QGIS Ireland user group posted a method of adding the ArcGIS Online global raster basemap to QGIS to use as an alternative to the openLayers plugin:
Scottish QGIS User Group
Stirling, 19th March 2014
It was a long time coming but the wait was worth it. Forty two excited QGIS users and open-source GIS enthusiasts arrived at the Stirling Management Centre on a brilliantly sunny March day. People had traveled from all over the UK to make the day happen: Charley Glynn from OS in Southampton, Pete Wells, Martin Dobias and Saber Razmjooei from Brighton as well as others from Aberdeen, Inverness, Dundee, Edinburgh, Glasgow, Cumbria and most places inbetween. The event was supported by thinkWhere, based in Stirling, and Neil Benny and Heikki Vesanto provided suitably geeky geo entertainment.
First up was Neil Benny (thinkWhere) who provided us with an overview of QGIS through the years to the current top features available in version 2.2 “Valmiera”. The questions on everyone’s minds were answered when he presented a series of slides outlining the benefits of using open source software, highlighting the savings and investments and the importance of investing in training. His top 10 feature comparison of proprietary v open source desktop GIS provoked much discussion.
After a coffee break I presented a short talk on how Angus Council is moving to a mixed hybrid GIS environment to take advantage of the flexibility of the open source licence and the variety of tools available to deliver results. Available here http://vimeo.com/89959143
Martin Dobias of Lutra Consulting and core QGIS developer revealed some of the performance enhancements available in the development version of QGIS. The multi-threaded multi-core rendering impressed everyone and will prove a huge draw card to seasoned GIS’ers used to single threaded applications.
Saber Razmjooei (Lutra) filled in an open slot talking about the autoTrace plugin they developed for a group of Local Authorities across the UK. Modeled on the MapInfo trace tool it forms a key part of a lot of Council workflows and is a good example of how future plugin development work can deliver savings.
Pete Wells (Lutra) delivered a very comprehensive overview of Python and QGIS and how they interact at different levels through the python bindings. There was a lot of interest in this and this was reflected in the feedback forms we collected where Python, plugins, hands-on workshops and tutorials feature high on the list of wants.
Charley Glynn (OS) unveiled some fantastic cartography using the OS vector products of MasterMap, VectorMap Local and District. He also revealed the work OS has been doing to make corporate styles available to the public and the Ordnance Survey’s bias towards open source software. Again the feedback forms revealed a desire to get hands on with QGIS to create good looking custom cartography. The next Scottish user group meeting will definitely be having some hands-on workshops.
Heikki Vesanto (thinkWhere) bravely ventured into live demos of how to connect to just about any spatial data format available. Local files, local databases, WMS feeds, WFS feeds, text files, CSV and URLs with images and custom map templates using the Atlas generator. An excellent overview of just how flexible QGIS is when it comes to consuming data and converting data to almost every format supported by OGR and GDAL.
Thanks must go to the generosity of thinkWhere in supporting a feature filled programme of presentations and keeping us topped up with coffee. As a result the first Scottish QGIS user group meeting was a success and there is definitely a desire for more events like this.
Slides and videos of the presentations will be available here shortly.
There are two things I have coded, re-coded and re-re-coded through all my plugins: the management of the settings and the management of combo boxes associated to layers and their fields.
I have decided to write two generic python modules to solve these tasks to avoid reinventing the wheel every time.
The first one is called QGIS setting manager.
This module allows you to:
- manage different types of settings (bool, string, color, integer, double, stringlist)
- read and write settings in QGIS application or in the QGIS project
- automatically set widgets from corresponding setting
- automatically write settings from widgets of a dialog
This means that the class of a dialog dedicated to editing the plugins settings can be reduced to just a few lines.
You just have to name widgets according to settings and the module automatically detect the widgets, sets/reads the value from the widget and read/write the settings accordingly.
A setting class would look like this
from qgissettingmanager import * class MySettings(SettingManager): def __init__(self): SettingManager.__init__(self, myPluginName) self.addSetting("myVariable", "bool", "global", True)
reading and write settings are performed by doing
self.settings = MySettings() self.settings.setValue("myVariable", False) myVariable = self.settings.value("myVariable")
and a dialog looks like this
class MyDialog(QDialog, Ui_myDialog, SettingDialog): def __init__(self): QDialog.__init__(self) self.setupUi(self) self.settings = MySettings() SettingDialog.__init__(self, self.settings)
The second module is called QGIS combo manager. This module autmatically manages combo box widgets for layers, fields of vector layers and bands of raster layers.
You can associate a field combo to a layer combo: as soon as the layer has been modified, the fields are updated to the current layer.
Associating a combo box to layers and another one to its fields would look like this:
from qgiscombomanager import * self.layerComboManager = VectorLayerCombo(self.layerComboWidget) self.myFieldComboManager = FieldCombo(self.myFieldComboManager, self.layerComboManager)
A very awaited feature is now available in the master version of QGIS: identifying features in the map!
You can define the class of the map tool as follows:
from PyQt4.QtCore import * from PyQt4.QtGui import * from qgis.core import * from qgis.gui import * class IdentifyGeometry(QgsMapToolIdentify): def __init__(self, canvas): self.canvas = canvas QgsMapToolIdentify.__init__(self, canvas) def canvasReleaseEvent(self, mouseEvent): results = self.identify(mouseEvent.x(),mouseEvent.y(), self.TopDownStopAtFirst, self.VectorLayer) if len(results) > 0: self.emit( SIGNAL( "geomIdentified" ), results.mLayer, results.mFeature)
This class will try to identify a feature of any visible vector layer and returning the first found feature (using layer order). Then, it will emit the signal with the layer and the feature identified.
To customize this, you can use the identify method with different arguments:
- type of layer
- type of identification (current layer, top-down, top-down stop at first or the QGIS setting)
- list of layers
There is two ways of calling the identify methods:
- identify (x, y, layerList=, IdentifyMode mode=self.DefaultQgsSetting)
- identify (x, y, identifyMode, layerType=AllLayers)
Identify mode and layer types are defined here. Mainly the options can be:
- Identify mode: self.DefaultQgsSetting, self.ActiveLayer, self.TopDownStopAtFirst, self.TopDownAll
- Layer type: self.AllLayers, self.VectorLayer, self.RasterLayer
Both methods return a structure IdentifyResult defined in the API. Mainly, it contains:
- the feature (mFeature) if the identified layer is a vector layer
- the corresponding layer (mLayer)
- the derived attributes (mDerivedAttributes): the raster value for raster layers
In your plugin main code, you can define a toolbox button to enable your map tool:
class myPlugin(): def initGui(self): self.mapToolAction = QAction(QIcon(":/plugins/myPlugin/icons/myIcon.png"), "My Plugin", self.iface.mainWindow()) self.mapToolAction.setCheckable(True) QObject.connect(self.mapToolAction, SIGNAL("triggered()"), self.mapToolInit) self.iface.addToolBarIcon(self.mapToolAction) self.iface.addPluginToMenu("&My Plugin", self.mapToolAction) def mapToolInit(self): canvas = self.iface.mapCanvas() if self.mapToolAction.isChecked() is False: canvas.unsetMapTool(self.mapTool) return self.mapToolAction.setChecked( True ) self.mapTool = IdentifyGeometry(canvas) QObject.connect(self.mapTool , SIGNAL("geomIdentified") , self.doSometing ) canvas.setMapTool(self.mapTool) QObject.connect( canvas, SIGNAL( "mapToolSet(QgsMapTool *)" ), self.mapToolChanged)</em> def doSomething(self, layer, feature): # do something
If you want your plugin to be back compatible with version before 1.9, you can select the features at the clicked point using a given tolerance and using the current layer:
try: from qgis.gui import QgsMapToolIdentify except: from qgis.gui import QgsMapTool as QgsMapToolIdentify class IdentifyGeometry(QgsMapToolIdentify): def __init__(self, canvas): self.canvas = canvas QgsMapToolIdentify.__init__(self, canvas) def canvasReleaseEvent(self, mouseEvent): try: results = self.identify(mouseEvent.x(),mouseEvent.y(), self.TopDownStopAtFirst, self.VectorLayer) if len(results) > 0: self.emit( SIGNAL( "geomIdentified" ), results.mLayer, results.mFeature) except: # qgis <1.9 point = self.toMapCoordinates( mouseEvent.pos() ) layer = self.canvas.currentLayer() if layer == None: return if layer.type() != QgsMapLayer.VectorLayer: return point = self.canvas.mapRenderer().mapToLayerCoordinates(layer, point) pixTolerance = 6 mapTolerance = pixTolerance * self.canvas.mapUnitsPerPixel() rect = QgsRectangle(point.x()-mapTolerance,point.y()-mapTolerance,point.x()+mapTolerance,point.y()+mapTolerance) provider = layer.dataProvider() provider.select(, rect, True, True) subset =  f = QgsFeature() while (provider.nextFeature(f)): subset.append(f) if len(subset) == 0: return if len(subset) > 1: idx = QgsSpatialIndex() for f in subset: idx.insertFeature(f) nearest = idx.nearestNeighbor( point, 1 ) layer.featureAtId(nearest,f, True, False) self.emit( SIGNAL( "geomIdentified" ), layer, f)
Note, that this last code (for version <1.9) does not consider scale dependent visibility and can therefore return a feature which is not visible in the map!
Following up on my last post, Running Scripts in the Python Console, I created a plugin to simplify running scripts:
The Script Runner plugin allows you to add your scripts to a list so they are readily available. You can then run them to automate QGIS tasks and have full access to the PyQGIS API. In addition, you can view information about the classes, methods, and functions in your module as well as browse the source:
In order for your script to work with ScriptRunner it has to implement a single function as an entry point. Here is some additional information from the Help tab of the plugin:
In order for Script Runner to execute your script you must define a run_script function that accepts a single argument. This is the standard entry point used by Script Runner. A reference to the qgis.utils.iface object will be passed to your run_script function. You don’t have to use the iface object in your script but your run_script function must accept it as an argument.
Here is an example of a simple run_script function:
def run_script(iface): ldr = Loader(iface) ldr.load_shapefiles('/vmap0_shapefiles')
In this example, the run_script creates an instance (ldr) of a class named Loader that is defined in the same source file. It then calls a method in the Loader class named load_shapefiles to do something useful—in this case, load all the shapefiles in a specified directory.
Alternatively, you could choose not to use classes and just do everything within the run_script function, including having it call functions in the same script or others you might import. The important thing is to be sure you have defined a run_script function. If not, Script Runner won’t load your script.
Working with Scripts
To run a script, you must add it to Script Runner using the Add Script tool on the toolbar. This will add it to a list in the left panel. This list of scripts is persisted between uses of QGIS. You can remove a script using the Remove Script tool. This just removes it from the list; it does nothing to the script file on disk.
Once you have a script loaded, you can click the Script Info tool to populate the Info and Source tabs in the panel on the right. The Info tab contains the docstring from your module and then a list of the classes, methods, and functions found in the script. Having a proper docstring at the head of your script will help you determine the puprose of script.
You can view the source of the script on the Source tab. This allows you to quickly confirm that you are using the right script and it does what you think it will.
Installing the Plugin
To install the plugin:
- Open the Python plugin installer: Plugins->Fetch Python Plugins
- Check to see if you have the new Official repository in your list of plugins by clicking on Repositories tab. The URL is http://plugins.qgis.org/plugins/plugins.xml.
- If you have it, skip to step 5. If the new repository isn’t in the list, add it by clicking the Add button. Give it a name and insert the URL http://plugins.qgis.org/plugins/plugins.xml
- Click on the Plugins tab
- Enter scriptrunner in the Filter box
- Select the ScriptRunner plugin and click Install
ScriptRunner adds an entry to the Plugins menu as well as a tool on the Plugins toolbar: . Click it and you are off and running.
This week we look at the OpenLayers plugin for QGIS. This plugin allows you to add a number of image services to your map canvas:
- Aerial with labels
Installing the Plugin
The OpenLayers plugin is installed like all other Python plugins. From the the Plugins menu in QGIS, choose Fetch Python Plugins. This brings up the plugin installer. To find the plugin, enter openlayers in the Filter box, then select OpenLayers Plugin from the list. Once it’s highlighted, click the Install plugin button. This will download the plugin from the repository, install it, and load it into QGIS.
Using the Plugin
The OpenLayers Plugin uses your view extent to fetch the data from the service you choose. For this reason you should load at least one of your own layers first. Since each of the services are expecting a request in latitude/longitude your layer either has to be geographic or you must enable on the fly projection.
To add one of the services you have two choices; you can pick the service from the Plugins->OpenLayers plugin menu or you can use the OpenLayers Overview. The Overview opens a new panel that allows you to choose a service from a drop-down list. Click the Enable map checkbox to enable the drop-down list and preview the service you want to add. If you are happy with what you see, you can add it to the map by clicking the Add map button.
In the screenshot below we have enabled the Overview panel, added the world boundaries layer1, zoomed to an area of interest, and added the Google terrain (physical) data:
You can add as many services as you want, previewing them using the OpenLayers Overview panel.
This week we take a look at a how to plot a terrain profile using the Profile plugin. The plugin can be used with any raster format supported by QGIS. You can can display profiles from up to three rasters at once, allowing you to compare the results. To illustrate, we’ll create a simple profile using a DEM of a 1:63,360 quadrangle in Alaska.
Installing the Plugin
The Profile plugin is installed like all other Python plugins. From the the Plugins menu in QGIS, choose Fetch Python Plugins. This brings up the plugin installer. To find the plugin, enter profile in the Filter box, then select Profile from the list. Once it’s highlighted, click the Install plugin button. This will download the plugin from the repository, install it, and load it into QGIS.1
Using the Plugin
Here we have loaded the DEM as well as a raster (DRG) of the topography for the same quadrangle and zoomed in a bit to an area of interest:
The yellow line has been added to indicate where we will take the profile. While the Profile plugin allows you to interactively select the profile line it doesn’t display the line on the map.
To create a profile, first make sure the raster you want to profile is selected in the layer list, then activate the plugin from the Plugins toolbar by clicking on it. The cursor becomes a cross that you use to create the profile line: click at the start point, move to the end and click again. Once you have created the profile line, the plugin pops up the result:
The profile is taken from the northeast towards the southwest, based on where we clicked first. You can change the exaggeration of the profile by using the slider on the left. The X axis shows the distance along the profile line in map units and the Y axis shows the cell values from the raster—in this case, elevation in meters.
You can save the result as a PDF or SVG using the buttons at the bottom of the dialog.
The Statistics tab displays some information for the raster layer and the profile line:
If we had additional rasters loaded, we could use the Setup tab to add them to the profile analysis. This would display the results using the colors specified for each layer and we could compare them on the Profile tab.
This is just one of several QGIS plugins that deal with profiles. You can check out the rest of them using the Python Plugin installer.
1 The Profile plugin requires the Python module for QWT5. If you don’t have this installed, a warning will be displayed during the installation process.
This week we highlight the Points to Paths plugin, a handy way to convert a series of points into line features. This plugin lets you “connect the dots” based on an common attribute and a sequence field. The attribute field determines which points should be grouped together into a line. The sequence field determines the order in which the points will connected. The output from this plugin is a shapefile.
Let’s take a look at some example data. Here we have some fictional wildlife tracking data for two moose. The tracking data is in shapefile format, but you can use any vector format supported by QGIS. The tracking data is symbolized by our two animals: Moose1 and Moose2:
The moose_tracks layer has an animal tracking id field (animal_tid) and a sequence field (id). This is all we need to convert the individual observations into a line feature that represents the animals path.
Installing the Plugin
The Points to Paths plugin is installed like all other Python plugins. From the the Plugins menu in QGIS, choose Fetch Python Plugins. This brings up the plugin installer. To find the plugin, enter points to in the Filter box, then select Points to Paths from the list. Once it’s highlighted, click the Install plugin button. This will download the plugin from the repository, install it, and load it into QGIS.
Using the Plugin
Let’s convert the tracking data to paths. To get started, choose Plugins->Points to Paths from the menu or click on the Points to Paths tool on the Plugin toolbar. This brings up the PointsToPaths dialog box where we specify the paramaters needed to create the paths. Below is the completed dialog for our moose tracks:
The first drop-down box contains a list of the vector layers loaded in QGIS—in our case we have just one: moose_tracks. For the group field drop-down we chose the field that contains the tracking identifier for each animal. This determines which points will be selected and grouped to form an individual line. The point order field drop-down specifies the field that contains the ordering for the observations. In this case, the id field is incremented with each observation and can be used to construct the paths. We don’t have a date/time field in this data, but your observations may be sequenced in this way. The Python date format field allows you to specify a format string so the plugin can determine how to sequence your points based on date/time.
The last thing we need to specify is the output shapefile. You can do this by typing in the full path to a new shapefile or by using the Browse button.
With these options set, clicking the OK button will create the new shapefile containing the paths created from our point observations. Once the shapefile is created, the plugin gives you the option to add the new shapefile directly to QGIS.
The result of our simple example are shown below:
We symbolized the individual tracks using the Categorized renderer on the Style tab of the vector properties dialog. You can see we now have a track for each animal. The attribute table created by the plugin contains the following fields:
- group – the name of the animal taken from the field we chose as the group field
- begin – the value of the first point order field used to create the path
- end – the value of the last point order field used to create the path
In our data, group contains the animal name, begin the value of the lowest id field for animal, and end contains the greatest id value. In a more typical data set, begin and end would contain the start and end date/time values for the observation. Labeling the observation points with our sequence field or date/time values would allow us to determine the direction of movement.
If you have point data that represent a movement of an object, this plugin is a great way to convert it into a path that can be used for visualization, analysis, or map composition.
QGIS has a lot of plugins, including over 180 that have been contributed by users. If you aren’t using plugins, you are missing out on a lot that QGIS has to offer. I’m starting what I hope to be a regular feature: Plugin of the Week. This week we’ll take a look at Time Manager.
- Wildlife tracking
- Storm centers
- QGIS users
Expanding on our last post about QGIS Users Around the World, we’ll use Time Manager to watch access to the QGIS Python plugin repository through time. If you refer to the previous post, you’ll see that all the IP addresses contacting the repository were extracted from the web server log and geocoded to get the approximate geographic coordinates. To use Time Manager all we need is the time for each access to the repository.
A important part (for our purpose) of the web server log entry looks like this:
184.108.40.206 - - [23/Oct/2011:21:17:54 +0000] "GET /repo/contributed HTTP/1.1" 200 256
Time Manager supports date/time in the following formats:
- YYYY-MM-DD HH:MM:SS
- YYYY-MM-DD HH:MM
As you can see, this doesn’t work with the format in the web server log.
The geocoding process created a file containing IP address, country, city (where available), latitude and longitude. This file is used to create a Python dictionary to look up locations by IP address. Using this file and a bit of Python, the web server log entries were converted into a CSV file containing:
220.127.116.11,2011-10-23 21:13:53,United States,61.2149,-149.258
18.104.22.168,2011-10-23 21:14:22,United States,61.2149,-149.258
22.214.171.124,2011-10-23 21:17:54,United States,61.2149,-149.258
126.96.36.199,2011-10-23 21:18:04,United States,61.2149,-149.258
The CSV file was first converted to a shapefile using the QGIS Delimited Text plugin. Performance with Time Manager was somewhat slow using a shapefile containing 134,171 locations. The shapefile was imported into a SpatiaLite database (you can do this using ogr2ogr or the SpatiaLite GUI).
Using Time Manager
To display the progression of access to the repository (and thus users of QGIS), we first have to have the Time Manager plugin installed. Once installed, we enable it using the Plugin Manger.
As you can see from the screenshot above, Time Manager installs a new panel in QGIS that sits below the map canvas. You can set a number of options by clicking Settings; the most important being the layer to use in the visualization. For the QGIS users, we use the time_manager_req layer that was created from the web server logs. With the location and date/time data in the proper format, you can click the “Play” button to start the display. For each time interval, the plugin selects the appropriate entries and displays a frame for the duration specified in the settings.
You can use the time slider to move around or move the time interval forward or backward using the buttons on each end of the slider.
A really nice feature is the ability to export to video. At present this saves a PNG file and world file for each time interval. You can then use another software package to combine these to create a video animation of the time sequence. Once solution is to use mencoder:
mencoder "mf://*.PNG" -mf fps=10 -o output.avi -ovc lavc -lavcopts vcodec=mpeg4
Putting all this together gives us the following visualization of QGIS user activity from October 23 through December 19, 2011:
You can see the “wave” of activity progress from east to west as the daylight hours come and go.
If you have spatial data with a date or time component, the Time Manager plugin provides a convenient way to visualize the temporal relationships.
One of the difficult things to track in the open source world is the number of people who actually use your software. In the proprietary commercial world you have licenses, invoices, and so forth. In the case of QGIS, we can track the total number of downloads from qgis.org, but this doesn’t represent the total installed base. It is impossible to accurately determine the actual number of people using QGIS, but we can get an approximation of the number and where they are in the world.
The analysis was done using the log files from the QGIS contributed repository:
- The IP address of each entry that retrieved the plugin list from the server represents one or more users—these IPs were collected into a unique list
- Using a Python script, each IP address in the log was geocoded to get the approximate latitude and longitude of the user
- The IP address, country, latitude, and longitude were written to a CSV file
- The CSV file was converted to a Spatialite layer to create the map of users
The map represents 35,603 unique IP addresses of users that accessed the repository between October 23, 2011 and December 17, 2011.
The geocoding process varies in precision—some IPs are located to the city level while others only return a general location for the country.
Some assumptions and observations:
- Most (maybe all) users make use of Python plugins and therefore access the contributed repository at some point
- Country-level points (blue) on the map represent more than one user
- Some points represent organizations that use a single IP for all users accessing the Internet. These points will represent more than one user
- Some users may access the repository from more than one IP address
So how many people use QGIS? At the very minimum, 35,000. We know that the downloads of just the Windows version exceeded 100,000. Given that there are 7,183 IP addresses that are generalized to a country location, we can safely assume that the number of actual users is much higher than that.
Considering the number of points that represent an organization and those that represent a country location, I think we can safely assume that the number of QGIS users easily exceeds 100,000 worldwide.
The Plugin Builder allows you to quickly create a skeleton Python plugin by generating all that boring boilerplate that every plugin requires.
Here is a short video showing how to create, compile, and install a new plugin.