6

I'm having problems using a Python function in the expression editor to style a polygon fill in QGIS.

I'm trying to use a random colour scheme. However, I need to do this over a series of different maps from different points in history.

I need the colour for "Norway" to be the same across all maps, likewise the colour should be the same for "Germany". I don't care what the colour is for each country, just that it is consistent between layers.

To do this, I have a Python function which uses the MD5 hash of the column value.

This function works, it looks up an attribute by name and returns an "r,g,b,a" string based on the first 4 bytes of the MD5 hash:-

"""
Define new functions using @qgsfunction. feature and parent must always be the
last args. Use args=-1 to pass a list of values as arguments
"""

from qgis.core import *
from qgis.gui import *
import hashlib

@qgsfunction(args='auto', group='Custom')
def hashcolor(values, feature, parent):
    v = feature.attribute(values)
    if not v:
        v = "Null"
    h = hashlib.md5()
    h.update(v)
    hd = h.hexdigest()
    r = int(hd[0:2],16)
    g = int(hd[2:4],16)
    b = int(hd[4:6],16)
    return "{0},{1},{2},255".format(r,g,b)

So for example,

hashcolour('CNTRY') will always return 213,185,41,255 if the CNTRY field contains "Norway"

I then use this expression as the fill colour for my polygons.

enter image description here

However, I could only get this to work if certain criteria are met:-

  • I have labelling turned on for that layer and
  • I have used "CNTRY" somewhere in the label's expression

I don't want labels, and I can't just use the empty string, so I had to use this hack on the label expression to get it to work:-

regexp_replace("CNTRY", '.*','')

Can anyone explain why I need to use labels in this way to get a python-expression defined colour to work? Is this a bug, or a side-effect of how the expression editor is supposed to work? It seems odd that labelling should be needed to allow polygon styling...

(Setup : Ubuntu Trusty 32-bit, QGIS 2.12.3-Lyon)

3

I can confirm your issue also on Fedora 23 QGIS 2.10.1. Looking at you function you pass the name of the field to the function where you lookup the value. The function engine then does this for every record in the table. You can parse the value directly using " and not ' if you simplify the function to:

from qgis.core import *
from qgis.gui import *

import hashlib

@qgsfunction(args='auto', group='Custom')
def hashcolor(values, feature, parent):
    h = hashlib.md5()
    h.update(values)
    hd = h.hexdigest()
    r = int(hd[0:2],16)
    g = int(hd[2:4],16)
    b = int(hd[4:6],16)
    return "{0},{1},{2},255".format(r,g,b)

Then pass in the columnname like:

hashcolor( "CNTRY" )

This will work without the strange label stunt.

Instead of a hashcolor generator you could also just use the normal classify color style on CNTRY and save the style for future use in other maps where the style can be loaded.

  • that works, thank you! I went for this approach (rather than saving style files) as there are 20 layers and very few countries appear in more than two or three layers.. although I suppose I could have combined the layer shapefiles, applied the categorisation to the combined layer and saved the style file from there. – Steven Kay Feb 22 '16 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.