QGIS: Running Scripts in the Python Console

The QGIS Python console is great for doing one-off tasks or experimenting with the API. Sometimes you might want to automate a task using a script, and do it without writing a full blown plugin. Currently QGIS does not have a way to load an arbitrary Python script and run it.[1] Until it does, this post illustrates a way you can create a script and run it from the console.

There are a couple of requirements to run a script in the console:

  1. The script must be in your PYTHONPATH
  2. Just like a QGIS plugin, the script needs a reference to qgis.utils.iface

Setting up the Environment

By default, the Python path includes the .qgis/python directory. The location depends on your platform:

  • Windows: in your home directory under .qgis\python. For example, C:\Documents and Settings\gsherman\.qgis\python
  • Linux and OS X: $HOME/.qgis/python

To see what is in your PYTHONPATH you can do the following in QGIS Python console:

    import sys
    sys.path

While you could use the .qgis\python directory for your custom scripts, a better way is to create a directory specifically for that purpose and add that directory to the PYTHONPATH environment variable. On Windows you can do this using the Environment Variables page in your system properties:

On Linux or OS X, you can add it to your .bash_profile, .profile, or other login script in your home directory:


    export PYTHONPATH=$PYTHONPATH:/home/gsherman/qgis_scripts
    

Writing the Script

With the environment set, we can create scripts to automate QGIS tasks and run them from the console. For this example, we will use a simple script to load all shapefiles in a specified directory. There are a couple of ways to do this:

  1. Write a simple script with a function that accepts qgis.utils.iface as an argument, along with a path to the shapefiles

  2. Create a Python class that uses an init method to store a reference to the iface object and then add methods to do the work

We will use the latter approach because it is more flexible and allows us to initialize once and then call methods without having to pass the iface object each time.

The script looks like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    #!/usr/bin/env Python
    """Load all shapefiles in a given directory.
      This script (loader.py) runs from the QGIS Python console.
      From the console, use:
        from loader import Loader
        ldr = Loader(qgis.utils.iface)
        ldr.load_shapefiles('/my/path/to/shapefile/directory')
    
      """
    from glob import glob
    from os import path
    
    class Loader:
        def __init__(self, iface):
            """Initialize using the qgis.utils.iface 
            object passed from the console.
            
            """
            self.iface = iface
    
        def load_shapefiles(self, shp_path):
            """Load all shapefiles found in shp_path"""
            print "Loading shapes from %s" % path.join(shp_path, "*.shp")
            shps = glob(path.join(shp_path, "*.shp"))
            for shp in shps:
                (shpdir, shpfile) = path.split(shp)
                self.iface.addVectorLayer(shp, shpfile, 'ogr' )

Running the Script

To open the console use the Plugins->Python Console menu item.

The comment at the head of the script explains how to use it.

First we import the Loader class from the script file (named loader.py). This script resides in the qgis_scripts directory that is our PYTHONPATH.

    from loader import Loader

We then create an instance of Loader, passing it the reference to the iface object:

    ldr = Loader(qgis.utils.iface)

This creates the Loader object and calls the init method to initialize things.

Once we have an instance of Loader we can load all the shapefiles in a directory by calling the load_shapefiles method, passing it the full path to the directory containing the shapefiles:

    ldr.load_shapefiles('/home/gsherman/qgis_sample_data/vmap0_shapefiles')

The load_shapefiles method uses the path to get a list of all the shapefiles and then adds them to QGIS using addVectorLayer.

Here is the result, rendered in the random colors and order that the shapefiles were loaded:

Some Notes

  • When testing a script in the console you may need to reload it as you make changes. This can be done using reload and the name of the module. In our example, reload(loader) does the trick.

  • You can add more methods to your class to do additional tasks

  • You can create a “driver” script that accepts the iface object and then initializes additional classes to do more complex tasks

[1]. I have plans on the drawing board to implement this feature.