Create EnMAP-Box Applications

Applications for the EnMAP-Box define an EnMAPBoxApplication instance that describes basic information like the Applications name and how a user can start it. The following examples are taken from the examples/minimumexample package, which you might copy and modify to implement own EnMAPBox Applications.

1. Initialize a new EnMAP-Box Application

An EnMAP-Box application inherits from EnMAPBoxApplication and defines basic information like a name and version. The variable license defaults to GNU GPL-3, but might be changed:

from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QMenu, QAction, QWidget, QHBoxLayout, QLabel, QPushButton
from enmapbox.gui.applications import EnMAPBoxApplication
from qgis.core import *

VERSION = '0.0.1'
APP_DIR = os.path.dirname(__file__)

APP_NAME = 'My First EnMAPBox App'

class ExampleEnMAPBoxApp(EnMAPBoxApplication):
    This Class inherits from an EnMAPBoxApplication
    def __init__(self, enmapBox, parent=None):
        super(ExampleEnMAPBoxApp, self).__init__(enmapBox, parent=parent)

        #specify the name of this app = APP_NAME

        #specify a version string

        self.version = VERSION

        #specify a licence under which you distribute this application
        self.licence = LICENSE

2. Define an Menu

To become accessible via a menu of the EnMAP-Box, the application needs to implement…) to return a QAction or (better) a QMenu with multiple QActions. By default, the returned object is added to the EnMAP-Box “Application” menu from where users can start the QAction that you defined:

def menu(self, appMenu):
    Returns a QMenu that will be added to the parent `appMenu`
    :param appMenu:
    :return: QMenu
    assert isinstance(appMenu, QMenu)
    Specify menu, submenus and actions that become accessible from the EnMAP-Box GUI
    :return: the QMenu or QAction to be added to the "Applications" menu.

    # this way you can add your QMenu/QAction to an other menu entry, e.g. 'Tools'
    # appMenu ='Tools')

    menu = appMenu.addMenu('My Example App')

    #add a QAction that starts a process of your application.
    #In this case it will open your GUI.
    a = menu.addAction('Show ExampleApp GUI')
    assert isinstance(a, QAction)

    return menu

3. Define QgsProcessingAlgorithms for the EnMAPBoxAlgorithm Provider

Your Application might provide one or multiple QgsProcessingAlgorithms for the QGIS Processing Framework. This way your algorithms become visible in the QGIS Processing Toolbox and can be used in the QGIS Model Builder. To add your QgsProcessingAlgorithms to the EnMAP-Box Algorithm Provider implement EnMAPBoxApplication.processingAlgorithms(…).

For the sake of simplicity, let’s define a simple function and a QgsProcessingAlgorithm to call it:

def exampleAlgorithm(*args, **kwds)->list:
    An dummy algorithm that prints the provided arguments and keywords and returns its inputs.
    print('Start exampleAlgorithm...')

    text = ['Arguments: {}'.format(len(args))]
    for i, a in enumerate(args):
        text.append('Argument {} = {}'.format(i+1, str(a)))

    text.append('Keywords: {}'.format(len(kwds)))
    for key, parameter in kwds.items():
        text.append('{} = {}'.format(key, parameter))
    print('exampleAlgorithm finished')

    return args, kwds

class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
    Exemplary implementation of a QgsProcessingAlgorithm.
    See for API documentation
    def __init__(self):
        super(ExampleProcessingAlgorithm, self).__init__()

    def createInstance(self)->QgsProcessingAlgorithm:
        Creates a new instance of the algorithm class.
        :return: QgsProcessingAlgorithm
        return ExampleProcessingAlgorithm()

    def name(self)->str:
        return 'examplealgorithm'

    def displayName(self):
        return 'Minimal Example Algorithm'

    def groupId(self)->str:
        Returns the unique ID of the group this algorithm belongs to.
        :return: str
        return GROUP_ID

    def group(self)->str:
        Returns the name of the group this algorithm belongs to.
        :return: str
        return APP_NAME

    def initAlgorithm(self, configuration:dict=None):
        Initializes the algorithm using the specified configuration.
        :param configuration: dict
        self.addParameter(QgsProcessingParameterRasterLayer('pathInput', 'The Input Dataset'))
        self.addParameter(QgsProcessingParameterNumber('value','The value', QgsProcessingParameterNumber.Double, 1, False, 0.00, 999999.99))
        self.addParameter(QgsProcessingParameterRasterDestination('pathOutput', 'The Output Dataset'))

    def processAlgorithm(self, parameters:dict, context:QgsProcessingContext, feedback:QgsProcessingFeedback):
        Runs the algorithm using the specified parameters.
        :param parameters: dict
        :param context: QgsProcessingContext
        :param feedback: QgsProcessingFeedback
        :return: dict
        assert isinstance(parameters, dict)
        assert isinstance(context, QgsProcessingContext)
        assert isinstance(feedback, QgsProcessingFeedback)

        args, kwds  = exampleAlgorithm(parameters)

        outputs = {'args' : args, 'kwds': kwds}
        return outputs

Now define EnMAPBoxApplication.processingAlgorithms(…) to add the ExampleProcessingAlgorithm to the EnMAPBoxProcessingProvider:

def processingAlgorithms(self)->list:
    This function returns the QGIS Processing Framework algorithms specified by your application
    :return: [list-of-QgsProcessingAlgorithms]

    return [ExampleProcessingAlgorithm()]

Calling the ExampleProcessingAlgorithm from the QGIS Processing Toolbox should now create a printout on your python console like:

pathInput = <qgis._core.QgsRasterLayer object at 0x0000018AA3C47A68>
pathOutput = <QgsProcessingOutputLayerDefinition {'sink':C:/Users/ivan_ivanowitch/AppData/Local/Temp/processing_cb76d9820fc64087aa8264f0f8505334/642d8e0abb764557881346399dda9c68/pathOutput.bsq, 'createOptions': {'fileEncoding': 'System'}}>
value = 1.0

4. Create a Graphical User Interface

The startGUI() function is used to open the graphical user interface. A very simple GUI could be:

def onButtonClicked():
    print('Button was pressed')

w = QWidget()
w.layout().addWidget(QLabel('Hello World'))
btn = QPushButton()
btn.setText('click me')

A GUI quickly becomes complex if programmed line-by-line only. We prefer to use the QDesigner. It allows to draw the GUI frontend which then is saved as *.ui XML file. This file can be translated into the PyQt code where you just write the backend.

List of environmental variables


This will be changed soon

The following environmental variables can be set to change the starting behaviour of the EnMAP-Box.

Name Values, * = Default Description
EMB_LOAD_PF TRUE*/FALSE Load QGIS processing framework.
EMB_LOAD_EA TRUE*/FALSE Loads external applications.
EMB_DEBUG TRUE/FALSE* Enable additional debug printouts.
EMB_SPLASHSCREEN TRUE*/FALSE Splashscreen on EnMAP-Box start.
EMB_MESSAGE_TIMEOUT integer Timeout in seconds for popup messages in the message bar.
EMB_APPLICATION_PATH string list of directories (separated by ‘;’ or ‘n’ (newline)) to load EnMAPBoxApplications from.