Posted in September 2014

Creating custom colour schemes in PyQGIS

In my last post I explored some of the new colour related features available in QGIS 2.6. At the end of that post I hinted at the possibility of creating QGIS colour schemes using python. Let’s take a look…

We’ll start with something nice and easy – a colour scheme which contains a predefined set of colours (e.g., standard company colours). This is done by subclassing QgsColorScheme and implementing the required methods ‘schemeName‘, ‘fetchColors‘ and ‘clone‘. It’s all fairly self explanatory – most of the important stuff happens in fetchColors, which returns a list of QColor/string pairs. Here’s a sample:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class QgsCgaLightColorScheme(QgsColorScheme):
    def __init__(self, parent=None): 
    def schemeName(self):
        return "CGA Colors!"
    def fetchColors(self,context='', basecolor=QColor()):
        return [[QColor('#555555'),'Gray'],
                    [QColor('#5555FF'),'Light Blue'],
                    [QColor('#55FF55'),'Light Green'],
                    [QColor('#55FFFF'),'Light Cyan'],
                    [QColor('#FF5555'),'Light Red'],
                    [QColor('#FF55FF'),'Light Magenta'],
    def flags(self):
        return QgsColorScheme.ShowInAllContexts
    def clone(self):
        return QgsCgaLightColorScheme()

cgaScheme = QgsCgaLightColorScheme()

This scheme will now appear in all colour buttons and colour picker dialogs:

CGA colours… what your map was missing!

If you only wanted the scheme to appear in the colour picker dialog, you’d modify the flags method to return QgsColorScheme.ShowInColorDialog instead.

QgsColorSchemes can also utilise a “base colour” when generating their colour list. Here’s a sample colour scheme which generates slightly randomised variations on the base colour. The magic again happens in the fetchColors method, which copies the hue of the base colour and generates random saturation and value components for the returned colours.

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import random

class QgsRandomColorScheme(QgsColorScheme):
    def __init__(self, parent=None): 

    def schemeName(self):
        return "Random colors!"

    def fetchColors(self, context='', basecolor=QColor() ):
        noColors = random.randrange(30)
        minVal = 130;
        maxVal = 255;
        colorList = []
        for i in range(noColors):
            if basecolor.isValid():
                h = basecolor.hue()
                #generate random hue
                h = random.randrange(360);

            s = random.randrange(100,255)
            v = random.randrange(100,255)

            colorList.append( [ QColor.fromHsv( h, s, v), "random color! " + str(i) ] )

        return colorList

    def flags(self):
        return QgsColorScheme.ShowInAllContexts

    def clone(self):
        return QgsRandomColorScheme()

randomScheme = QgsRandomColorScheme()

Here’s the random colour scheme in action… note how the colours are all based loosely around the current red base colour.

Randomised colours

You may also have noticed the context argument for fetchColors. This can be used to tweak the returned colour list depending on the context of the colour picker. Possible values include ‘composer‘, ‘symbology‘, ‘gui‘ or ‘labelling‘.

One final fun example… here’s a colour scheme which grabs its colours using the Colour Lovers API to fetch a random popular palette from the site:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from xml.etree import ElementTree
import urllib2
import random

class colorLoversScheme(QgsColorScheme):

    def __init__(self, parent=None): 
        xmlurl = ''

        headers = { 'User-Agent' : 'Mozilla/5.0' }
        req = urllib2.Request(xmlurl, None, headers)
        doc = ElementTree.parse(urllib2.urlopen(req)).getroot()

        palettes = doc.findall('palette')
        palette = random.choice(palettes)

        title = palette.find('title').text
        username = palette.find('userName').text
        attrString = title + ' by ' + username
        colors = ['#'+c.text for c in palette.find('colors').findall('hex')]

        self.color_list = [[QColor(c), attrString] for c in colors]

    def schemeName(self):
        return "Color lovers popular palette"

    def fetchColors(self, context='', basecolor=QColor()):
        return self.color_list

    def flags(self):
        return QgsColorScheme.ShowInAllContexts

    def clone(self):
        return colorLoversScheme()

loversScheme = colorLoversScheme()      
QgsColorSchemeRegistry.instance().addColorScheme( loversScheme )

Clicking a colour button will now give us some daily colour scheme inspiration…

Grabbing a palette from the Colours Lovers site

Grabbing a palette from the Colours Lovers site

Ok, now it’s over to all you PyQGIS plugin developers – time to go wild!

Tagged , , , ,

What’s new in QGIS 2.6 – Tons of colour improvements!

With one month left before the release of QGIS 2.6, it’s time to dive into some of the new features it will bring… starting with colours.

Working with colours is a huge part of cartography. In QGIS 2.4 I made a few changes to improve interaction with colours. These included the ability to copy and paste colours by right clicking on a colour button, and dragging-and-dropping colours between buttons. However, this was just the beginning of the awesomeness awaiting colours in QGIS 2.6… so let’s dive in!

Part 1 – New colour picker dialog

While sometimes it’s best to stick with an operating system’s native dialog boxes, colour pickers are one exception to this. That’s because most native colours pickers are woefully inadequate, and are missing a bunch of features which make working with colours much easier. So, in QGIS 2.6, we’ve taken the step of rolling out our very own colour picker:

New QGIS colour picker

Before starting work on this, I conducted a review of a number of existing colour picker implementations to find out what works and what doesn’t. Then, I shamelessly modelled this new dialog off the best bits of all of these! (GIMP users will find the new dialog especially familiar – that’s no coincidence, it’s a testament to how well crafted GIMP’s colour picker is.)

The new QGIS colour picker features:

  • Colour sliders and spin boxes for Hue, Saturation, Value, Red, Green and Blue colour components
  • An opacity slider (no more guessing what level of transparency “189” corresponds to!)
  • A text entry box which accepts hex colours, colour names and CSS rgb(#,#,#) type colours. (The drop down arrow you can see on this box in the screenshot above allows you to specify the display format for colours, with options like #RRGGBB and #RRGGBBAA)
  • A grid of colour swatches for storing custom colours
  • A visual preview of the new colour compared to the previous colour
  • Support for dragging and dropping colours into and out of the dialog
  • A colour wheel and triangle method for tweaking colours (by the way, all these colour widgets are reusable, so you can easily dump them into your PyQGIS plugins)
    Colour wheel widget
  • A colour palettes tab. This tab supports adding and removing colours from a palette, creating new palettes and importing and exporting colours from a GPL palette file. (We’ll explore colour palettes in more detail later in this post.)
    Colour palettes
  • A colour sampler! This tab allows you to sample a colour from under the mouse pointer. Just click the “Sample color” button, and then click anywhere on the screen (or press the space bar if you’re sampling outside of the QGIS window). You even get the choice of averaging the colour sample over a range of pixels. (Note that support for sampling is operating system dependant, and currently it is not available under OSX.)
    Built in colour sampler! Woohoo!

Part 2 – New colour button menus

Just like the new colour dialog is heavily based off other colour dialog implementations, this new feature is inspired by Microsoft’s excellent colour buttons in their recent Office versions (I make no claim to originality here!). Now, all QGIS colour buttons come with a handy drop down menu which allows you to quickly choose from some frequently used colour shortcuts. You’ve got the previously available options of copying and pasting colours from 2.4, plus handy swatches for recently used colours and for other standard colours.


Handy colour menu for buttons

Part 3 – Colour palettes

You may have noticed in the above screenshot the “Standard colors” swatches, and wondered what these were all about.  Well, QGIS 2.6 has extensive support for color palettes. There’s a few different “built-in” color palettes:

  • The “Standard colors” palette. This palette can be modified through the Options → Colors tab. You can add, remove, edit, and rename colours, as well as import color schemes from a GPL palette file. These standard colours apply to your QGIS installation, so they’ll be available regardless of what project you’re currently working on.

    Customising the standard colours

    Customising the standard QGIS colours

  • The “Project colors” palette. This can be accessed via the Project Properties → Default styles tab. This palette is saved inside the .qgs project file, so it’s handy for setting up a project-specific colour scheme.
  • The “Recent colors” palette. This simply shows colours you’ve recently used within QGIS.

You can easily create new colour palettes directly from the colour picker dialog. Behind the scenes, these palettes are saved into your .qgis/palettes folder as standard GPL palette files, which makes it nice and easy to modify them in other apps or transfer them between installations. It’s also possible to just dump a stack of quality palettes directly into this folder and they’ll be available from within QGIS.

Perhaps the best bit about colour schemes in QGIS is that they can be created using PyQGIS plugins, which opens up tons of creative possibilities… More on this in a future blog post!

So there we go. Tons of improvements for working with colours are heading your way in QGIS 2.6, which is due out on the 24th October.

(Before we end, let’s take a quick look at what the competition offers over in MapInfo land. Yeah… no thanks. You might want to invest some development time there Pitney Bowes!)

Tagged , , , ,