Posts by Nathan

I work for a local council in Australia in GIS/Asset management. QGIS developer and Python (not the snake) lover.

UI theme support now core in QGIS


I enjoy using the dark UI theme for QGIS so much I figured why not make it a core feature. In the next version of QGIS if you head to the options screen you can now find a UI Theme option.

Options | General_037

The default dark theme is called Night Mapping for all those late night mapping jobs that you do, or if you just like dark UI themes.

QGIS b789fab_029

Selection_031

Selection_034

Something you will notice with this theme is the custom icons for the layer visibility. Pretty nifty! Here is how it is done

Creating new themes

To create a new theme simply make a new folder in .qgis2\themes\ with the name of the theme you want and create a style.qss file inside there. Check out the default themes for an example

Follow the Qt style sheet guides to see what can be styled.

Something I have added on top of the normal style sheets is variable support. Variables can be declared in a variables.qss file in the theme folder.

Here is an example of some variables:

@background: #323232
@text: #aaa
@selection: #507098
@menuback: #444
@highlight: #ffaa00

Now in style.qss we can do this:

QWidget
{
color: @text;
background-color: @background;
}

Great for not having to repeat your self or quick updating in a single place. When the theme is applied via the Options dialog or via the API it will replace the variables in style.qss using variables.qss. The result file is called style.qss.auto

Needs some tweaks

The default dark theme is a collection of stuff I have found around the net and stuff I have added myself. It’s far from prefect and I would love help to make it the best dark theme for QGIS. If you have another theme you think would make a good default one open a pull request on GitHub

Enjoy

Mixing a bit of Excel into QGIS – conditional formatted table cells


I was using Excel the other day and used the conditional formatting rules to style some cells based on a condition. If you have never seen or used them they look like this:

They are pretty handy for a quick idea on the state of your data.  Looking at QGIS I thought to myself “Wait!? Why not do that in QGIS too. That would be pretty neat”.  And with that here it is, finally!. Conditional formatting rules for QGIS attribute table.

cells

icons

You can control the font style, color, background color, even custom icons based on QGIS symbols. The buttons at the top give you access to quick styles which you can tweak more with the other options.

The conditions are just normal QGIS expressions. Use the special variable @value to refer to the current cell value. As they are normal QGIS expressions you can reference the other fields in the expressions.

(Click the GIF for a better view)

table

So go nuts. I would love to hear any feedback if you use it. Try it out in the next nightly dev build.

QGIS UI themes plugin


Scrap that idea. Seems there is already a  plugin to do this called Load QSS.  I’m not going to duplicate effort. Use that one and we can all make it better.

Want to have a dark theme, or even your own custom theme, for QGIS?  No worries. The UI Theme plugin has your back. Grab it from the plugin installer.  

Change the theme using Plugins -> UI Themes -> Theme It!

theme

Just select a theme and the interface will change styles.  Here is the dark theme called “Much Dark. Such Goth” :)

dark

I will let you try the “Oh my eyes” theme.

Themes can be added by creating a {name}.css file in plugin folder themes folder and edited __init__.pyfile to list the theme.  I’m working on this to make it better but I wrote this in about half an hour so it’s not all there yet.

The active themes is saved in the settings and restored on QGIS load.

If you make a cool theme feel free to make a pull request or ticket so it can be added to the plugin for others to use.  There is heaps that can be done with the Qt stylesheets so go nuts and make something cool.

Note: It’s a work in progress and things might not always look right.

Hat racks; or appreciating people for what they do.


The biggest thing with open source work is that it can be pretty thankless. There is a lot more that goes into a open source project then just some lines of code, there is events, documentation, API documentation, PR material, more documentation, websites, build setups, etc. It’s quite easy to just look at a project on GitHub, check out the graphs and see the top contributors and never think about it again. Because the code is all that matters right?

githubn

All hail Jürgen and Nyall!

Getting back to the point.  There is a lot of stuff that goes into an open source project that can go unnoticed and under appreciated.  Stuff that isn’t code is hard to track.  Do you know who maintains the QGIS website? What about who translates the UI? What about who ran the last dev meetings? These projects are non code related but are normally things that go unnoticed or under appreciated simply because it’s not a fancy chart in GitHub.  Making people feel welcome and appreciated in a project normally leads to a higher retention rate and a better overall feel for the project.  I remember when I was first thanked for the work I added to QGIS and how it made me feel, still here doing the same thing so it must have worked pretty well.

At PyCon AU 2015  Katie McLaughlin gave a talk about welcoming contributions to a project and being generally being nice to people. Not just being nice but actively thanking people for what they do and how it makes you feel. People generally put a lot of time into the projects they involve themselves in knowing you are appreciated makes you feel good.

Katie got the idea for the project from the talk and post titled A Place to Hang Your Hat by Leslie Hawthorn.  It seems like a silly title but read it and it will all make sense.

Her sub text makes the perfect summary:

On getting many good things done. And no one knows you’re doing any of it.

I’m not going to copy the post here but I will steal her tl;dr part:

  • If someone has volunteered to help your project, take the time to write a 2-3 sentence summary of what they did to help.
  • You can send it to them, along with a thank you note, or offer to post it on their LinkedIn profile. (Remember, users can approve recommendations before they’re added to their profile.)
  • Let’s spend some time celebrating our successes and all of our contributions! Let folks know you’re celebrating that success using #LABHR as a hashtag.
  • #LABHR stands for Let’s All Build a Hat Rack. For why its an awesome acronym, you have to read the post.

And here is the example post she makes:

Sample Recommendation

Deb Nicholson, Board Member, Open Hatch
While not strictly related to her work as an OpenHatch board members, Deb has given me invaluable counsel on fundraising for various non-profits I’ve been affiliated with. She’s also trained numerous community members on how to perform in-person advocacy for free and open source software projects, and software patent reform. As part of that training, she’s also convened numerous meetings and round tables to help people get things done in the open source world. She performs all this work with grace and patience for our sometimes difficult personalities. She’s brilliant and utterly unflappable. Cannot recommend her work highly enough.

So go ahead. Write something nice about someone and what they have done. Send it to them, blog about it, put it in Twitter, LinkedIn, etc.

Accessing composer item properties via custom expressions in QGIS


So here is a neat trick. Lets say you wanted to access the scale of a composer map to make it part of a label. The scale bar can already be set to numeric to show the number value but what if it needs to be part of an existing label with other text. Not to fear, expression functions are here.

  • Create a new composer. Add the map frame and a label.
  • Set the item ID of the map frame to something you can remember, lets just use themap
  • Select the label and add some text
  • Click Insert Expression

Now for the cool part

  • Select Function Editor
  • Click New File. Give the file a new name and hit save. I called it composer functions.

In the code editor paste this code:

from qgis.utils import iface
from qgis.core import *
from qgis.gui import *

@qgsfunction(args="auto", group='Composer')
def composeritemattr(composername, mapname, attrname, feature, parent):
    composers = iface.activeComposers()
    # Find the composer with the given name
    comp = [composer.composition() for composer in composers 
                if composer.composerWindow().windowTitle() == composername][0]
    # Find the item
    item = comp.getComposerItemById(mapname)
    # Get the attr by name and call 
    return getattr(item, attrname)()
  • Click Run Script

run

Now in your label use this text:

Scale: [% composeritemattr('Composer 1', 'themap', 'scale')%]

Update the Composer 1 to match your composer name, and the themap to match your item ID.

and like magic here is the scale from the map item in a label:

2015-05-21 22_00_09-Composer 1

Check the expression error section if the label doesn’t render

error

PSA: Please use new style Qt signals and slots not the old style


Don’t do this:

self.connect(self.widget, 
             SIGNAL("valueChanged(int)"), 
             self.valuechanged)

It’s the old way, the crappy way. It’s prone to error and typing mistakes. And who really wants to be typing strings as functions and arg names in it. Gross.

Do this:

self.widget.valueChanged.connect(self.valuechanged)
self.widget.valueChanged[str].connect(self.valuechanged)

Much nicer. Cleaner. Looks and feels like Python not some mash up between C++ and Python. The int argument is the default so it will use that. If you to pick the signal type you can use [type].

Don’t do this:

self.emit(SIGNAL("changed()", value1, value2))

Do this

class MyType(QObject):
   changed = pyqtSignal(str, int)

   def stuff(self):
       self.changed.emit(value1, value2)

pyqtSignal is a type you can use to define you signal. It will come with type checking, if you don’t want type checking just do pyqtSignal(object).

Please think of the poor kittens before using the old style in your code.

A interactive command bar for QGIS


Something that has been on my mind for a long time is a interactive command interface for QGIS.  Something that you can easily open, run simple commands, and is interactive to ask for arguments when they are needed.

After using the command interface in Emacs for a little bit over the weekend – you can almost hear the Boos! from heavy Vim users :) – I thought this is something I must have in QGIS as well.  I’m sure it can’t be that hard to add.

So here it is.  A interactive command interface for QGIS.

commandbar

commandbar2

The command bar plugin (find it in the plugin installer) adds a simple interactive command bar to QGIS. Commands are defined as Python code and may take arguments.

Here is an example function:

@command.command("Name")
def load_project(name):
    """
    Load a project from the set project paths
    """
    _name = name
    name += ".qgs"
    for path in project_paths:
        for root, dirs, files in os.walk(path):
            if name in files:
                path = os.path.join(root, name)
                iface.addProject(path)
                return
    iface.addProject(_name)

All functions are interactive and if not all arguments are given when called it will prompt for each one.

Here is an example of calling the point-at function with no args. It will ask for the x and then the y

pointat

Here is calling point-at with all the args

pointatfunc

Functions can be called in the command bar like so:

my-function arg1 arg2 arg2

The command bar will split the line based on space and the first argument is always the function name, the rest are arguments passed to the function. You will also note that it will convert _ to - which is easier to type and looks nicer.

The command bar also has auto complete for defined functions – and tooltips once I get that to work correctly.

You can use CTRL + ; (CTRL + Semicolon), or CTRL + ,, to open and close the command bar.

What is a command interface without auto complete

autocomplete

Use Enter to select the item in the list.

How about a function to hide all the dock panels. Sure why not.

@command.command()
def hide_docks():
    docks = iface.mainWindow().findChildren(QDockWidget)
    for dock in docks:
        dock.setVisible(False)

alias command

You can also alias a function by calling the alias function in the command bar.

The alias command format is alias {name} {function} {args}

Here is an example of predefining the x for point-at as mypoint

-> alias mypoint point-at 100

point-at is a built in function that creates a point at x y however we can alias it so that it will be pre-called with the x argument set. Now when we call mypoint we only have to pass the y each time.

-> mypoint
(point-at) What is the Y?: 200

You can even alias the alias command – because why the heck not :)

-> alias a alias
a mypoint 100

a is now the shortcut hand for alias

WHY U NO USE PYTHON CONSOLE

The Python console is fine and dandy but we are not going for a full programming language here, that isn’t the point. The point is easy to use commands.

You could have a function called point_at in Python that would be

point_at(123,1331)

Handling incomplete functions is a lot harder because of the Python parser. In the end it’s easier and better IMO to just make a simple DSL for this and get all the power of a DSL then try and fit into Python.

It should also be noted that the commands defined in the plugin can still be called like normal Python functions because there is no magic there. The command bar is just a DSL wrapper around them.

Notes

This is still a bit of an experiment for me so things might change or things might not work as full expected just yet.

Check out the projects readme for more info on things that need to be done, open to suggestions and pull requests.

Also see the docs page for more in depth information