2

I'm trying to write a python function that takes a BGSREF attribute from a BGS geology shapefile and uses it to colour up the geology polygons of a shapefile.

I posted my non-code working as a part answer to Data-defined Styles in QGIS as it shows the maths behind taking a BGSREF code and converting it to RGB values, but I would like to know what needs to be corrected to have the full solution.

Using Nathan's QGIS Blog post on User defined expression functions for QGIS as a basis I created my code like:

from qgis.utils import qgsfunction
from qgis.core import QGis

aColourAdjust = [0,7,14,21,31,42,54,67,80,100]

@qgsfunction(1, "Python")
def BGSrefToQGIScolorRGB(values, feature, parent):
    """
       Converts BGSref colour (attribution) to RGB values.
       Output as integers in the range 0 - 255, in the style:
       color_rgb(rrr,ggg,bbb) or color_rgba(rrr,ggg,bbb,aaa)
    """
    # set some variables
    #rgbValue = "color_rgb(255,255,255)"
    rgbValue = "255,255,255"
    #rgbValue = "<255>,<255>,<255>"
    isTransparent = 'False'

    bgsref2Convert = values[0]

    # Test the length of the input value and pad with zeros if applicable.
    if len(str(bgsref2Convert)) == 1:
        bgsref2Convert = "00" + str(bgsref2Convert)
    elif len(str(bgsref2Convert)) == 2:
        bgsref2Convert = "0" + str(bgsref2Convert)
    elif len(str(bgsref2Convert)) == 3:
        pass
    else:
        isTransparent = 'True'

    #Now we can calculate the RGB values...
    if isTransparent:
        #rgbValue = "color_rgba(255,255,255,255)"
        rgbValue = "255,255,255,255"
        #rgbValue = ""<255>,<255>,<255>,<255>"
    else:
        yellow = aColourAdjust[int(bgsref2Convert[:1])]
        cyan = aColourAdjust[int(bgsref2Convert[-1:])]
        magenta = aColourAdjust[int(bgsref2Convert[1:2])]

        # 100.0 is deliberate to get a floating point result, otherwise the result of division will always be zero.
        red = 255-((cyan/100.0)*255)
        green = 255-((magenta/100.0)*255)
        blue = 255-((yellow/100.0)*255)

        #Now just need to find the expected QGIS format for the colour output...

        #rgbValue = "color_rgb(" + str(int(red)) + "," + str(int(green)) + "," + str(int(blue)) + ")"
        rgbValue = str(int(red)) + "," + str(int(green)) + "," + str(int(blue))
        #rgbValue = "<" + str(int(red)) + ">,<" + str(int(green)) + ">,<" + str(int(blue)) + ">"
    return rgbValue

I start QGIS (2.2.0), open the Python Console, import my function, and it shows in the expression string builder.

For my chosen layer style properties, I choose Single Symbol, data defined properties, Expression and create an expression like: BGSrefToQGIScolorRGB( "BGSREF" ) and apply this, but I never seem to get any colours in the map.

The help tip tells me the colour format is: '<red>,<green>,<blue>,<alpha>' but what does this actually mean?

I've tried outputting the results as the following strings (255 here indicates number format not the literal output):

* <255><255><255><255>
* <255><255><255>
* 255,255,255
* color_rgb(255,255,255)

Nothing seems to work for me.

What format is expected?

1

You need to set the color of QgsSymbol with .setColor(). setColor() needs a QColor. QColors can be set with three integers for red, green, and blue with values between 0 to 255.

So if you had a symbol "symbol" this would set the color:

symbol.setColor(QColor(red, green, blue))

Edit: You can also set alpha too (QColor(red, green, blue, alpha)), but the default for that is 0.

  • Thanks for your quick response. Can you clarify though, do I need to change my python function so that it calls 'symbol.setColor(QColor(red, green, blue))' or is it the expression that I build that needs to use the rgb value that is returned by my function? – nmtoken Mar 10 '14 at 17:19
  • SetColor acts on your symbol. So do it after you initialize the symbol. For example: self.symbol = QgsFillSymbolV2() self.symbol.setColor(QColor(red, green, blue)) – midfield99 Mar 10 '14 at 18:09
  • But I'm not initializing a symbol, or trying to write some standalone pygis that might do this. I trying to write a function that converts an attribute to a colour as part of an expression. The expression builder help tells me that it is expecting a <red>,<green>,<blue>,<alpha> colour as input, and it's this that I'm trying to do via the function (the output of my function). I may be completely misunderstanding the expression builder here, but I was expecting the expression builder would take the function, apply it to each attribute in the table and symbolize the layer accordingly. – nmtoken Mar 10 '14 at 18:18
  • Ah, I misunderstood that. I thought you were initializing the symbol. I'm not completely sure how you would use python to change the color with an expression builder. ` '<red>,<green>,<blue>,<alpha>' ' just means it expects something like this: 'color_rgb($Value1, $Value2, $Value3)' . 'color_rgb(255,255,255)' should be a valid command in the expression builder though. It works for me. – midfield99 Mar 10 '14 at 18:43
  • It doesn't answer your python problem, but could you get the rgb values computed in excel or open office? .dbf files are spreadsheets, so you could add three columns for red, green and blue values, and then use the expression builder to set the color to 'color_rgb($Field1, $Field2, $Field3)'. Just replace the Fields with the appropriate columns. – midfield99 Mar 10 '14 at 18:47
1

The result of the expression should produce a string like:

255,51,117

or optionally (with an alpha channel value) a string like:

255,255,255,255

  • With judicious debugging, I realise that I had errors in the python syntax such that the test of isTransparent in the above code ALWAYS evaluates to true, so the conversion never takes place. I have posted the full corrected code to gis.stackexchange.com/questions/60450/…. – nmtoken Mar 12 '14 at 12:20

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.