Wednesday, January 27, 2021

Running a custom python function in QGIS

 In this post, I will explain how custom python functions are made in QGIS. 

Functions in QGIS are listed with the following categories:-

Aggregates Functions
Array Functions
Color Functions
Conditional Functions
Conversions Functions
Custom Functions
Date and Time Functions
Fields and Values
Files and Paths Functions
Form Functions
Fuzzy Matching Functions
General Functions
Geometry Functions
Layout Functions
Map Layers
Maps Functions
Mathematical Functions
Operators
Processing Functions
Rasters Functions
Record and Attributes Functions
Relations
String Functions
User Expressions
Variables
Recent Functions


So, if QGIS has all these functions why would one ever need a custom function?

The answer is simple, these are not all the functions in the world. So, most likely there is a function that hasn't been implemented then you can write your custom function.

Lets look at a simple scenario.

Assuming, we have this little python script that generates Hex color codes like these: #40B994, #13E7BC, #3F50EB, #E28326 etc and we want to use it to generate new attribute column with random hex color codes.

from random import choice

def color_func():
    hex = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F"]

    hex_list = [str(choice(hex)) for x in range(6)]

    hex_string = '#' + ''.join(hex_list)
    return hex_string

The function will be called like this in the field calculator. Note the function's name is: color_func()



How to add the function to QGIS

From the 'Function Editor' tab (you can access this from any 'Expression' window), create new function script by clicking on the green plus button and give the script a name.



You should see a template function script as seen below.


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

@qgsfunction(args='auto', group='Custom')
def my_sum(value1, value2, feature, parent):
    """
    Calculates the sum of the two parameters value1 and value2.
    <h2>Example usage:</h2>
    <ul>
      <li>my_sum(5, 8) -> 13</li>
      <li>my_sum("field1", "field2") -> 42</li>
    </ul>
    """
    return value1 + value2

We just need to edit the function definition, while keeping the last two parameters (feature, parent) that is this part:-

def my_sum(value1, value2, feature, parent):
    """
    Calculates the sum of the two parameters value1 and value2.
    <h2>Example usage:</h2>
    <ul>
      <li>my_sum(5, 8) -> 13</li>
      <li>my_sum("field1", "field2") -> 42</li>
    </ul>
    """
    return value1 + value2

The new custom function will look like this:-

from qgis.core import *
from qgis.gui import *
from random import choice

@qgsfunction(args='auto', group='Custom')
def color_func(feature, parent):
        hex = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F"]

        hex_list = [str(choice(hex)) for x in range(6)]

        hex_string = '#' + ''.join(hex_list)
        return hex_string


Note that the last two parameters (feature, parent) are included in the new custom function. If you omit them, the following error will occur.

Traceback (most recent call last):
  File "", line 6, in
  File "C:/PROGRA~1/QGIS3~1.12/apps/qgis/./python\qgis\core\additions\qgsfunction.py", line 170, in wrapper
    return register_function(func, args, group, **kwargs)
  File "C:/PROGRA~1/QGIS3~1.12/apps/qgis/./python\qgis\core\additions\qgsfunction.py", line 110, in register_function
    if args[-1] == 'context':
IndexError: list index out of range


Also, not the 'Decorator' @qgsfunction(args='auto', group='Custom') above the function. It has to be above the function definition and you don't need to change it, it is there to help QGIS engine in a way to change, enhance or alter the way the function works.


Finally, we click on the 'Save and Load function' button to save our new custom function. The it can be used from the expression tab by calling it.

Thank is it!

No comments:

Post a Comment