3

I have this script which creates an elevation profile with annotated points in a matplotlib.pyplot window.

It works perfectly in the console, but I want to add it to the QGIS toolbox so it can be run without opening the python console and editor (and so additional files/layers can be selected before running).

The algorithm is just the code wrapped in QGIS's QgsProcessingAlgorithm class. Running it crashes QGIS and I'm pretty sure it hangs at .show().

PyQt5 example plot that works

import sys
import matplotlib
matplotlib.use('Qt5Agg')

from PyQt5 import QtCore, QtGui, QtWidgets

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure

class MplCanvas(FigureCanvasQTAgg):

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        super(MplCanvas, self).__init__(fig)

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        sc = MplCanvas(self, width=5, height=4, dpi=100)
        sc.axes.plot([0,1,2,3,4], [10,1,20,3,40])

        # Create toolbar, passing canvas as first parament, parent (self, the MainWindow) as second.
        toolbar = NavigationToolbar(sc, self)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(toolbar)
        layout.addWidget(sc)

        widget = QtWidgets.QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.show()
        print('[end of main window]')

app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
app.exec_()
print('[FINISHED]')

processing script that doesn't

from qgis.core import (
    QgsProcessing,
    QgsProcessingAlgorithm,
    QgsProcessingMultiStepFeedback,
    QgsProcessingParameterFile,
    QgsProcessingParameterVectorLayer,
    QgsProject,
    QgsPoint)
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Qt5Agg')
from PyQt5 import (QtCore, 
    QtGui, 
    QtWidgets)
from matplotlib.backends.backend_qt5agg import (
    FigureCanvasQTAgg, 
    NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
import os
import sys
import processing

class MplCanvas(FigureCanvasQTAgg):

    def __init__(self, parent=None, width=18, height=5, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        super(MplCanvas, self).__init__(fig)


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__()#*args, **kwargs)

        sc = MplCanvas(self, width=5, height=4, dpi=100)
        sc.axes.plot([0,1,2,3,4], [10,1,20,3,40])

        toolbar = NavigationToolbar(sc, self)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(toolbar)
        layout.addWidget(sc)

        widget = QtWidgets.QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.show()
        print('[FINISHED]')

class PlotProfileAKO(QgsProcessingAlgorithm):

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterFile('DrillingProgram', 'Drilling Program', behavior=QgsProcessingParameterFile.File, fileFilter='All Files (*.*)', defaultValue=None))

    def processAlgorithm(self, parameters, context, model_feedback):
        # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
        # overall progress through the model
        feedback = QgsProcessingMultiStepFeedback(1, model_feedback)
        results = {}
        outputs = {}
        
        w = MainWindow()
        QtWidgets.QApplication(sys.argv)
        
        feedback.setCurrentStep(1)
        if feedback.isCanceled():
            return {}

        return {}

    def name(self):
        return 'Plot Profile AKO test 1'

    def displayName(self):
        return 'Plot Profile AKO test 1'

    def group(self):
        return ''

    def groupId(self):
        return ''

    def createInstance(self):
        return PlotProfileAKO()
2
  • 1
    What you need is a PyQT5 canvas to show your plot on. You could try this answer stackoverflow.com/a/29791498/5874767
    – Dror Bogin
    Commented Nov 2, 2020 at 6:02
  • Thankyou @DrorBogin I have tried to start a QtWidget however QGIS crashes at the same point (self.show()). Is QgsProcessingAlgorithm the right class to use, or could QgsPythonRunner work?
    – Andre Geo
    Commented Nov 16, 2020 at 19:35

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.