Ever since I added expression based labels, including the new expression builder UI, something that I always wanted to add is the ability to define custom user defined functions in Python (or C++) and use them in an expression. The expression engine is used for labels, rulebased rendering, layer actions, field calculator, and atlas composer tags. Thanks to the all the awesome work on the expression engine by Martin all this cool stuff is now possible.

Today I pushed a commit into master that adds the ability to define a function in Python (or C++), register it in the expression engine, then use it anywhere expressions are used.

The good stuff

Lets take a use case from Ujaval Gandhi and his example of counting vertices for each feature.

First we need to import the new qgsfunction decorator function from qgis.utils. The qgsfunction decorator will take a normal Python function, wrap it up in the class used to define a function, and register it in the engine.

@qgsfunction(0, "Python") means we are defining a new vertices function that takes 0 args and lives in the “python” group in the expression builder UI. Any custom function must take (values, feature, parent) as python args. values is a list of QVariants passed into the function, feature is the current QgsFeature, and parent is expression engine node (you use this to raise errors).

Pretty simple. Get the geometry from the feature, check if it’s a polygon, if it is then count the number of vertices and return that number.

Now that we have that all done we can save it into a file in our .qgis/python folder, lets call it userfunctions.py (note you don’t have to save it here, anywhere that QGIS can find it will do. Anywhere on PATH)

Lets open QGIS and run import userfunctions.py:

Importing functions from userfunctions.py

Now open the label properties for the layer:

The new function shown in the expression builder

Nice! Notice also that the function doc string is used as the function help. How cool is that. You can also see the $ sign in front of the function, this is because any functions that take no args are considered special and use the $ sign as a convention, this is all automatic when the function is registered.

And the result is:

The label using the new function

You can even use it in the rule based rendering:

Rule rendering using new function

Enjoy!

Notes

You must unregister a function once you are finished with it using QgsExpression.unregisterFunction(name). This mainly applies to plugins where the user might unload your plugin and the code is no longer available. In the above example we could import userfunctions and never unregister because we plan on using it for the whole session.

Note: The following post only applies to QGIS 1.7. QGIS 1.7.1 (upcoming patch) will not have this issue as the default behavior has changed.

One thing I noticed when running QGIS 1.7 was my rasters were really slow to open and sometimes froze QGIS. I thought maybe it was some bad plugin that I had installed, nope; maybe opening the raster of the network drive was causing it to be slow, nope. I tried a bunch of stuff, still nothing. After a while a few other people posted to the mailing list saying they were having the same issue, turns out the solution was very simple.

In QGIS contrast enhancement for rasters is turned on by default, so each time a raster is opened QGIS had to calculate the stats (max and min for example) for the raster and then scale the contrast. For a large raster this is pretty heavy and this was the cause of all those problems.

So what’s the solution?

Turns out QGIS will remember the contrast setting for all rasters if you want it to.

To fix the slow opening raster problem:

Open a small raster (just any old picture will do)

Double click the layer in the layer list

Change Contrast Enhancement to No Stretch

Change Contrast Enhancement to No Stretch

Hit the little Save icon next to the drop down box

Open your big raster.

That setting will now be remembered for each raster that is opened and improve the loading time.

One trend that come up a lot in the poll I recently ran (results will be out soon, just writing a summary blog post) is “Needs more powerful edit tools“. And I agree.

Coming from a MapInfo background nothing much changes when you move to QGIS, MapInfo had the simple Add Point, Add Region, Add Line kind of tools and then you need to use plugins to do anything a bit more advanced (MapCAD). QGIS has the start of a kind of MapCAD thing happening although not as complete.

Why not just let people write plugins?

However I think in order to make QGIS a more attractive package to a lot of people it needs to get some built in semi-advanced to advanced editing tools; getting back to those poll results of “Needs more powerful edit tools”.

I thought to myself “What would I like QGIS to be able to do when it came to editing?” although I came up with a small set my editing needs are only relatively small. I then thought the best way to find out what people need is to just create a blank canvas for people to throw their ideas around on and then go from there.

Why not just create a ticket?

My idea is to get a larger idea of what people need and want rather than just one-off tickets. Although the ideas will be at the edit tool idea level it will be easier to see how they should all fit together if they are all in one place and editable by other people. You can then start asking questions like: Do we really need that UI there? Can we merge these tools? How should the output be handled?

The overall goal is to have a tight, thought out, group of edit tools rather then someone creating a plugin over here for one thing and some else creating something else over there.

So how do we get this going?

Well I have created a Google Document that anyone can edit and view in order to start brainstorming ideas. The link can be found here.

I have already created an example of two ideas that I would like to see.

So go ahead, throw some ideas up. I’m interested to see where this can head.

Why use Google Docs and not the QGIS wiki?

Mainly because Google Docs makes it very easy to do frictionless editing of a document together. No need for user names or passwords or overwriting someone else’s changes (Google Docs is all real time).

I have just whipped up a small user poll for QGIS users. The poll is just to give me (and indirectly the team) some idea of people’s opinions about QGIS and what it could do better. The poll is only short (9 questions) and one of the main things is “What could QGIS do better?”.

All the answers are anonymous so feel free to say what you like about anything. In the end if something isn’t working the way you think it should, write it down. It’s not going to hurt anyone’s feelings :)

If you are a partial QGIS users who mostly uses MapInfo or ESRI stuff I would also like to get your opinion.

Another cool open source project that I have become a part of (as a QGIS packager and tester) is the OSGeo-Live project. The OSGeo-Live project is a live DVD/USB/Virtual Machine built on xUbuntu(striped down Ubuntu linux) that has a lot of cool open source geo spatial programs all set up and ready to use.

The OSGeo-Live project contains:

Browser clients

A small sample of crisis management software

All the popular database engines (PostGIS, SpaitalLite etc)

Pretty much all the open source desktop GIS apps (QGIS, uDig etc)

Open Source GPS navigation apps and globes.

A collection of handy spatial tools

A ready to go web services ready to try in your browser or desktop GIS.

I am, as a heavy QGIS user and a guy-who-tries-to-write-features-and-patches-for-the-code, very happy with this release. I know a lot of people have put a lot of hard work and free time into working on features and bug fixes that keep making this free GIS system even better.

The QGIS team has shifted their source control system to using GIT, which I am very happy about as a lot of the guys on the #qgis IRC channel will know :). The bug tracer has also been moved tohttp://hub.qgis.org/projects/quantum-gis.

Since the release of QGIS 1.6 there have been 1199 commits (using git to count: git log –pretty=oneline upstream/release-1_6_0..upstream/release-1_7_0 | wc -l). Not a bad effort if I may so myself.

If you are still reading this, I really hope it’s because you are waiting for QGIS 1.7 to install.

Turns out the last blog post I did on this subject contained a few errors, mainly that QGIS wouldn’t render the layer when you opened it.

The answer is so obvious it’s almost embarrassing :)

In order to open and display a SQL Server 2008 layer in QGIS correctly, via OGR, you must have a geometry_columns table in your database with the name, geometry type and srid of the layer. That’s it! Oh look, it was even right in front of me in the OGR code for the mssqlspatial driver.

So the process to open a MS SQL 2008 spatial layer in OGR is as follows.

There are two main tables which tell OGR how to read a layers projection:

geometry_columns

spatial_ref_sys

geometry_columns contains the table name and the key for the table spatial_ref_sys which contains the projection string. The projection string is the info that QGIS needs in order to correctly render a layer.

The easiest way to get the correct tables is to let OGR handle it for you via ogr2ogr, then just adding any other tables you may have already in your database to the geometry_columns table.

So to get ogr2ogr to create the right tables for you it’s as simple as running the following command from inside the OSGeo4W shell, changing the connection string part of course:

Uploading even just one table this way will create both tables and fill in the needed info.
The geometry_columns table:

f_table_catalog

f_table_schema

f_table_name

f_geometry_column

geodb

dbo

rivers

ogr_geometry

coord_dimension

srid

geometry_type

2

32768

POLYGON

The spatial_ref_sys table:

srid

auth_name

auth_srid

srtext

proj4text

32768

NULL

NULL

PROJCS[“UTM_Zone_56_Southern_Hemisph….

+proj=utm +zone=56 +south +ellps=GRS80 +units=m +no_defs

So if you have already existing tables in your MS SQL 2008 database that were loaded, via say MapInfo’s EasyLoader, you would just upload one table via ogr2ogr to create the two tables needed by QGIS(using OGR) and then add the other tables to the geometry_columns table. If they are all in the same projection than you are in luck as you will only need to upload one in order to get the right strings in the spatial_ref_sys table, if not just upload a small sample for each projection.

If you see a value in Layer SRS WKT: then chances are it’s set right and QGIS should be able to render it, however if you see: Layer SRS WKT:(unknown) Than chances are QGIS will not render it correctly.

Hopefully this help people use MS SQL 2008 Spatial with QGIS, a important step I think in the world of using QGIS on Windows (especially when you don’t have the freedom to run PostGIS:) ).

I might even do a video tutorial when I get some free time after my exams and my wedding.

If you’re using MapInfo think of thematics + queries but on steroids. Rule based rendering allows you to you set, well, rules on what gets rendered and how. The rules are based on a simple SQL style query language that’s built into QGIS.

Take for example the above screen shot. The screen shot is from a current project I am doing in QGIS to clean up our current stormwater/drainage layer. The layer is a in a bit of a mess at the moment so I needed a way to visualize what I have cleaned up and what I haven’t, so enter QGIS rule based styling.

For example: A pipe that has an upstream and downstream invert and is part of the trunk (main) network is then considered valid (for this situation anyway), so I created the following rule:

We also have little connecting pipes that I don’t want to include in valid trunk as they are only used to connect pits to pipes and are just cosmetic, I have excluded them by adding “Description !=’Drainage Imaginary Pipe’” to the above filter.

Next I wanted to show invalid trunk network pipes (ones without an up or downstream invert), so we just invert the last condition and swap the last AND for a OR:

Finally I want to show pipe direction on all pipes but not the connecting pipes, again as they are just cosmetic:

Description != 'Drainage Imaginary Pipe'

You will also note in the screenshot above that I have a max zoom scales set on the last three rules, this is because when I zoom out all that info becomes overwhelming at that scale and distracts from showing the invalid parts of the main trunk line.

So after all that, the results:

Map rendered using rules

and if I zoom out pass 5,000:

Map rendered when zoomed out pass 5,000

I think you can see how this rule based rendering could be very powerful, in fact I have about four different rule sets I use with the drainage layer to show different things to different people.

I forked the QGIS repo on GitHub a little while ago although one thing that bothered me was that it gave me copies of all the branches that the main QGIS git repo had. This is understandable as it’s the way it works however I don’t really need all these branches in my forked copy of the repo as I don’t care about them. I only care the ones I am working on, and I don’t want to see a big list of branches in my git fork that have nothing to do with me.

So the next question was how do I delete all the branches on the remote repo at GitHub. Well you would normally do:

git push origin :branch_name

although doing that by hand for each branch is, well, a pain in the butt! After a chat with a guy (strk) on the #qgis IRC channel who is more skilled at bash then me (I’m still a Linux noob) he came up with this:

So if you have not already guessed from my increasing post about QGIS. I really like it as a GIS system but with all systems it comes with its shortcomings. (Nothing that can’t be fixed of course)

Here is my little wishlist of a few things I would love to see in QGIS.

Multipule map canvases. (ArcGIS, MapInfo)

I was thinking more like ArcGIS data frames vs something like what MapInfo has (multiple windows). I think the multi window system can add confusion for people new to GIS, plus I hate having to window manage.

SQL like interface. (MapInfo)

This is something that I really like from MapInfo. It adds a lot of power to the application being able to spatially join two tables that don’t share a command link column and get back a new layer. Adding this to QGIS could be a pretty big task, although a very rewarding one IMO.

Now there is some credit in saying “well you can just import your data into PostGIS and use that”, however that is not always a option and I think having a layer above that can query any open layer would be very very powerful.

These are just two of the main things that I would like to see, I’ll update the post if I can think of anymore.

Of course being open source I can write the features myself but C++ is still a bit over my head at the moment.

I would love to see what other peoples thoughts, or mini wishlists, are. So if you are willing, drop a comment and let me know.

EDIT: If you are having trouble opening MS SQL 2008 in QGIS I will have a blog post coming explaining how to correct it. Or you can read the comments between TheGeoist and I below which will have the answer.

Replacing {serverName} with your server name, if installed on your local machine you can use localhost; {databaseName} with the name of the database with the tables;{tableName} with the table to open; {yourLayerNameHere} with the name you would like the layer to have in the map legend.

After that you should see your MS SQL Spatial table displayed in QGIS, with editing support.

At the moment there is no nice interface in QGIS to open MS SQL tables like there is for PostGIS, although that might be a good plugin project for someone to work on.