def setUpClass(cls):
        """Run before all tests"""
        # Create test layer
        srcpath = os.path.join(TEST_DATA_DIR, 'provider')
        cls.basetestfile = os.path.join(srcpath, 'delimited_wkt.csv')

        url = QUrl.fromLocalFile(cls.basetestfile)
        url.addQueryItem("crs", "epsg:4326")
        url.addQueryItem("type", "csv")
        url.addQueryItem("wktField", "wkt")
        url.addQueryItem("spatialIndex", "no")
        url.addQueryItem("subsetIndex", "no")
        url.addQueryItem("watchFile", "no")

        cls.vl = QgsVectorLayer(url.toString(), u'test', u'delimitedtext')
        assert cls.vl.isValid(), "{} is invalid".format(cls.basetestfile)
        cls.provider = cls.vl.dataProvider()

        cls.basetestpolyfile = os.path.join(srcpath, 'delimited_wkt_poly.csv')

        url = QUrl.fromLocalFile(cls.basetestpolyfile)
        url.addQueryItem("crs", "epsg:4326")
        url.addQueryItem("type", "csv")
        url.addQueryItem("wktField", "wkt")
        url.addQueryItem("spatialIndex", "no")
        url.addQueryItem("subsetIndex", "no")
        url.addQueryItem("watchFile", "no")

        cls.vl_poly = QgsVectorLayer(url.toString(), u'test_polygon', u'delimitedtext')
        assert cls.vl_poly.isValid(), "{} is invalid".format(cls.basetestpolyfile)
        cls.poly_provider = cls.vl_poly.dataProvider()
Exemplo n.º 2
0
    def test_refLayers2(self):
        l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
        self.assertEqual(l1.isValid(), True)
        QgsProject.instance().addMapLayer(l1)

        # referenced layers cannot be stored !
        tmp = QUrl.fromLocalFile(os.path.join(tempfile.gettempdir(), "t.sqlite")).toString()
        l2 = QgsVectorLayer("%s?layer_ref=%s" % (tmp, l1.id()), "tt", "virtual", False)
        self.assertEqual(l2.isValid(), False)
        self.assertEqual("Cannot store referenced layers" in l2.dataProvider().error().message(), True)
def test_repository_url():
    """Return the test repository URL on file system.

    :return: The test repository URL string
    :rtype: str
    """
    return QUrl.fromLocalFile(test_data_path()).toString()
Exemplo n.º 4
0
 def onHelp(self):
     helpPath = Utils.getHelpPath()
     if helpPath == '':
         url = QUrl("http://www.gdal.org/" + self.helpFileName)
     else:
         url = QUrl.fromLocalFile(helpPath + '/' + self.helpFileName)
     QDesktopServices.openUrl(url)
Exemplo n.º 5
0
    def help(self):
        localDoc = None
        html = self.grass7Name + ".html"
        if system.isWindows():
            # For MS-Windows, use the configured GRASS7 path
            localPath = os.path.join(Grass7Utils.grassPath(), "docs/html", html)
            if os.path.exists(localPath):
                localDoc = os.path.abspath(localPath)
        elif system.isMac():
            # For MacOSX official package
            localPath = os.path.join("/Applications/GRASS-7.0.app/Contents/MacOS/docs/html", html)
            if os.path.exists(localPath):
                localDoc = os.path.abspath(localPath)
        else:
            # For GNU/Linux distributions
            searchPaths = ["/usr/share/doc/grass-doc/html", "/opt/grass/docs/html", "/usr/share/doc/grass/docs/html"]
            for path in searchPaths:
                localPath = os.path.join(path, html)
                if os.path.exists(localPath):
                    localDoc = os.path.abspath(localPath)

        # Found the local documentation
        if localDoc:
            localDoc = QUrl.fromLocalFile(localDoc).toString()
            return False, localDoc

        # Return the URL if local doc is not found
        return False, "http://grass.osgeo.org/grass70/manuals/" + self.grass7Name + ".html"
Exemplo n.º 6
0
 def test_source_escaping(self):
     # the source contains ':'
     source = QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no"
     d = QgsVirtualLayerDefinition()
     d.addSource("t", source, "delimitedtext")
     l = QgsVectorLayer(d.toString(), "vtab", "virtual", False)
     self.assertEqual(l.isValid(), True)
Exemplo n.º 7
0
 def openScriptFileExtEditor(self):
     tabWidget = self.tabEditorWidget.currentWidget()
     path = tabWidget.path
     import subprocess
     try:
         subprocess.Popen([os.environ['EDITOR'], path])
     except KeyError:
         QDesktopServices.openUrl(QUrl.fromLocalFile(path))
Exemplo n.º 8
0
    def helpUrl(self):
        helpPath = Grass7Utils.grassHelpPath()
        if helpPath == '':
            return None

        if os.path.exists(helpPath):
            return QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.grass7Name))).toString()
        else:
            return helpPath + '{}.html'.format(self.grass7Name)
Exemplo n.º 9
0
    def help(self):
        helpPath = GrassUtils.grassHelpPath()
        if helpPath == '':
            return False, None

        if os.path.exists(helpPath):
            return False, QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.grassName))).toString()
        else:
            return False, '{}{}.html'.format(helpPath, self.grassName)
Exemplo n.º 10
0
    def test_CsvNoGeometry(self):
        l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
        self.assertEqual(l1.isValid(), True)
        QgsProject.instance().addMapLayer(l1)

        l2 = QgsVectorLayer("?layer_ref=" + l1.id(), "vtab", "virtual", False)
        self.assertEqual(l2.isValid(), True)

        QgsProject.instance().removeMapLayer(l1.id())
Exemplo n.º 11
0
    def helpUrl(self):
        helpPath = GdalUtils.gdalHelpPath()
        if helpPath == '':
            return None

        if os.path.exists(helpPath):
            return QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.commandName()))).toString()
        else:
            return helpPath + '{}.html'.format(self.commandName())
Exemplo n.º 12
0
    def test_DynamicGeometry(self):
        l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/testextpt.txt")).toString() + "?type=csv&delimiter=%7C&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
        self.assertEqual(l1.isValid(), True)
        QgsProject.instance().addMapLayer(l1)

        query = toPercent("select *,makepoint(x,y) as geom from vtab1")
        l2 = QgsVectorLayer("?layer_ref=%s&query=%s&geometry=geom:point:0&uid=id" % (l1.id(), query), "vtab", "virtual", False)
        self.assertEqual(l2.isValid(), True)

        QgsProject.instance().removeMapLayer(l1)
Exemplo n.º 13
0
    def test_reopen2(self):
        source = toPercent(os.path.join(self.testDataDir, "france_parts.shp"))
        tmp = QUrl.fromLocalFile(os.path.join(tempfile.gettempdir(), "t.sqlite")).toString()
        l = QgsVectorLayer("%s?layer=ogr:%s:vtab&nogeometry" % (tmp, source), "vtab2", "virtual", False)
        self.assertEqual(l.isValid(), True)

        l2 = QgsVectorLayer(tmp, "tt", "virtual", False)
        self.assertEqual(l2.isValid(), True)
        self.assertEqual(l2.dataProvider().wkbType(), 100)
        self.assertEqual(l2.dataProvider().featureCount(), 4)
Exemplo n.º 14
0
    def test_sql(self):
        l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
        self.assertEqual(l1.isValid(), True)
        QgsProject.instance().addMapLayer(l1)

        l3 = QgsVectorLayer("?query=SELECT * FROM test", "tt", "virtual")

        self.assertEqual(l3.isValid(), True)
        s = sum(f.id() for f in l3.getFeatures())
        self.assertEqual(s, 15)
    def test_resolve_path(self):
        """Test resolving the path works correctly."""
        collection_path = test_data_path('collections', 'test_collection')
        search_paths = []

        # Test case 1: local path
        img_path = test_data_path(
            'collections', 'test_collection', 'svg', 'blastoise.svg')
        fixed_path = resolve_path(img_path, collection_path, search_paths)
        self.assertEqual(img_path, fixed_path)

        # Test case 2: local url
        img_path = test_data_path(
            'collections', 'test_collection', 'svg', 'blastoise.svg')
        img_url = QUrl.fromLocalFile(img_path)
        fixed_path = resolve_path(
            img_url.toString(), collection_path, search_paths)
        self.assertEqual(fixed_path, img_path)

        # Test case 3:  http url
        img_path = 'http://qgis.org/test/image.svg'
        img_url = QUrl(img_path)
        fixed_path = resolve_path(
            img_url.toString(), collection_path, search_paths)
        self.assertEqual(fixed_path, img_path)

        # Test case 4: checking in the svg local collection path
        img_path = '/you/would/not/find/this/charizard.svg'
        fixed_path = resolve_path(img_path, collection_path, search_paths)
        expected_path = test_data_path(
            'collections', 'test_collection', 'svg', 'charizard.svg')
        self.assertEqual(fixed_path, expected_path)

        # Test case 5: checking in the image local collection path
        img_path = '/you/would/not/find/this/pikachu.png'
        fixed_path = resolve_path(img_path, collection_path, search_paths)
        expected_path = test_data_path(
            'collections', 'test_collection', 'image', 'pikachu.png')
        self.assertEqual(fixed_path, expected_path)

        # Test case 6: checking in the search paths
        search_paths = [
            test_data_path(
                'collections', 'test_collection', 'preview')
        ]
        img_path = 'prev_1.png'
        fixed_path = resolve_path(img_path, collection_path, search_paths)
        expected_path = test_data_path(
            'collections', 'test_collection', 'preview', 'prev_1.png')
        self.assertEqual(fixed_path, expected_path)

        # Test case 7: not finding anywhere (return the original path)
        img_path = '/you/would/not/find/this/anywhere.png'
        fixed_path = resolve_path(img_path, collection_path, search_paths)
        self.assertEqual(fixed_path, img_path)
Exemplo n.º 16
0
    def test_refLayer(self):
        l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
        self.assertEqual(l1.isValid(), True)
        QgsProject.instance().addMapLayer(l1)

        l2 = QgsVectorLayer("?layer_ref=" + l1.id(), "vtab", "virtual", False)
        self.assertEqual(l2.isValid(), True)

        # now delete the layer
        QgsProject.instance().removeMapLayer(l1.id())
        # check that it does not crash
        print((sum([f.id() for f in l2.getFeatures()])))
Exemplo n.º 17
0
    def delimitedTextData(self, testname, filename, requests, verbose, **params):
        # Retrieve the data for a delimited text url
        # Create a layer for the specified file and query parameters
        # and return the data for the layer (fields, data)

        filepath = os.path.join(unitTestDataPath("delimitedtext"), filename)
        url = QUrl.fromLocalFile(filepath)
        if not requests:
            requests = [{}]
        for k in params.keys():
            url.addQueryItem(k, params[k])
        urlstr = url.toString()
        log = []
        with MessageLogger('DelimitedText') as logger:
            if verbose:
                print(testname)
            layer = QgsVectorLayer(urlstr, 'test', 'delimitedtext')
            uri = unicode(layer.dataProvider().dataSourceUri())
            if verbose:
                print(uri)
            basename = os.path.basename(filepath)
            if not basename.startswith('test'):
                basename = 'file'
            uri = re.sub(r'^file\:\/\/[^\?]*', 'file://' + basename, uri)
            fields = []
            fieldTypes = []
            data = {}
            if layer.isValid():
                for nr, r in enumerate(requests):
                    if verbose:
                        print("Processing request", nr + 1, repr(r))
                    if callable(r):
                        r(layer)
                        if verbose:
                            print("Request function executed")
                    if callable(r):
                        continue
                    rfields, rtypes, rdata = self.layerData(layer, r, nr * 1000)
                    if len(rfields) > len(fields):
                        fields = rfields
                        fieldTypes = rtypes
                    data.update(rdata)
                    if not rdata:
                        log.append("Request " + str(nr) + " did not return any data")
                    if verbose:
                        print("Request returned", len(rdata.keys()), "features")
            for msg in logger.messages():
                filelogname = 'temp_file' if 'tmp' in filename.lower() else filename
                msg = re.sub(r'file\s+.*' + re.escape(filename), 'file ' + filelogname, msg)
                msg = msg.replace(filepath, filelogname)
                log.append(msg)
            return dict(fields=fields, fieldTypes=fieldTypes, data=data, log=log, uri=uri, geometryType=layer.geometryType())
Exemplo n.º 18
0
    def shortHelp(self):
        helpPath = GdalUtils.gdalHelpPath()
        if helpPath == '':
            return

        if os.path.exists(helpPath):
            url = QUrl.fromLocalFile(os.path.join(helpPath, '{}.html'.format(self.commandName()))).toString()
        else:
            url = helpPath + '{}.html'.format(self.commandName())

        return self._formatHelp('''This algorithm is based on the GDAL {} module.
                For more info, see the <a href={}> module help</a>
                '''.format(self.commandName(), url))
Exemplo n.º 19
0
 def asHtmlEntry(self, roles):
     canInstall = "Green" if self.canOpen(roles) else "Orange"
     s = """<div class="icon"><div class="icon-container">
            <img src="{image}"></div></div>
            <div class="description"><h2>{title}</h2><p>{description}</p>
            <a class="btn{available}" href="{url}">INSTALL</a>
            </div>
         """.format(image=QUrl.fromLocalFile(self.iconPath()).toString(),
                    title=self.name,
                    description=self.description,
                    available=canInstall,
                    url=self.url
                   )
     return s
Exemplo n.º 20
0
    def test_refLayers(self):
        l1 = QgsVectorLayer(QUrl.fromLocalFile(os.path.join(self.testDataDir, "delimitedtext/test.csv")).toString() + "?type=csv&geomType=none&subsetIndex=no&watchFile=no", "test", "delimitedtext", False)
        self.assertEqual(l1.isValid(), True)
        QgsProject.instance().addMapLayer(l1)

        # cf qgis bug #12266
        for i in range(10):
            q = toPercent("select * from t" + str(i))
            l2 = QgsVectorLayer("?layer_ref=%s:t%d&query=%s&uid=id" % (l1.id(), i, q), "vtab", "virtual", False)
            QgsProject.instance().addMapLayer(l2)
            self.assertEqual(l2.isValid(), True)
            s = sum([f.id() for f in l2.dataProvider().getFeatures()])  # NOQA
            self.assertEqual(sum([f.id() for f in l2.getFeatures()]), 21)
            QgsProject.instance().removeMapLayer(l2.id())
Exemplo n.º 21
0
def getHtmlFromHelpFile(alg, helpFile):
    if not os.path.exists(helpFile):
        return None
    try:
        with open(helpFile) as f:
            descriptions = json.load(f)

        content = getHtmlFromDescriptionsDict(alg, descriptions)
        algGroup, algName = alg.id().split(':')
        filePath = os.path.join(system.tempHelpFolder(), "{}_{}.html".format(algGroup, algName))
        with open(filePath, 'w', encoding='utf-8') as f:
            f.write(content)
        return QUrl.fromLocalFile(filePath).toString()
    except:
        return None
Exemplo n.º 22
0
    def test_reopen4(self):
        source = toPercent(os.path.join(self.testDataDir, "france_parts.shp"))
        tmp = QUrl.fromLocalFile(os.path.join(tempfile.gettempdir(), "t.sqlite")).toString()
        query = toPercent("SELECT * FROM vtab")
        l = QgsVectorLayer("%s?layer=ogr:%s:vtab&query=%s&uid=objectid&nogeometry" % (tmp, source, query), "vtab2", "virtual", False)
        self.assertEqual(l.isValid(), True)

        l2 = QgsVectorLayer(tmp, "tt", "virtual", False)
        self.assertEqual(l2.isValid(), True)
        self.assertEqual(l2.dataProvider().wkbType(), 100)
        self.assertEqual(l2.dataProvider().featureCount(), 4)
        sumid = sum([f.id() for f in l2.getFeatures()])
        self.assertEqual(sumid, 10659)
        suma = sum([f.attributes()[1] for f in l2.getFeatures()])
        self.assertEqual(suma, 3064.0)
Exemplo n.º 23
0
    def _get_cursor_columns(self, c):
        tf = QTemporaryFile()
        tf.open()
        tmp = tf.fileName()
        tf.close()

        q = QUrl.toPercentEncoding(c.sql)
        p = QgsVectorLayer("%s?query=%s" % (QUrl.fromLocalFile(tmp).toString(), q), "vv", "virtual")
        if not p.isValid():
            return []
        f = [f.name() for f in p.fields()]
        if p.geometryType() != Qgis.WKBNoGeometry:
            gn = getQueryGeometryName(tmp)
            if gn:
                f += [gn]
        return f
Exemplo n.º 24
0
    def __init__(self, db, sql, parent=None):
        # create a virtual layer with non-geometry results
        q = QUrl.toPercentEncoding(sql)
        t = QTime()
        t.start()

        tf = QTemporaryFile()
        tf.open()
        tmp = tf.fileName()
        tf.close()

        p = QgsVectorLayer("%s?query=%s" % (QUrl.fromLocalFile(tmp).toString(), q), "vv", "virtual")
        self._secs = t.elapsed() / 1000.0

        if not p.isValid():
            data = []
            header = []
            raise DbError(p.dataProvider().error().summary(), sql)
        else:
            header = [f.name() for f in p.fields()]
            has_geometry = False
            if p.geometryType() != QGis.WKBNoGeometry:
                gn = getQueryGeometryName(tmp)
                if gn:
                    has_geometry = True
                    header += [gn]

            data = []
            for f in p.getFeatures():
                a = f.attributes()
                if has_geometry:
                    if f.geometry():
                        a += [f.geometry().exportToWkt()]
                    else:
                        a += [None]
                data += [a]

        self._secs = 0
        self._affectedRows = len(data)

        BaseTableModel.__init__(self, header, data, parent)
Exemplo n.º 25
0
    def run(self):
        """Run method that performs all the real work"""
        self.dlg.statusBarProcessing.setValue(0)
        #show step1 button
        self.dlg.btnExecuteClippingTask.setVisible(True)
        #self.dlg.textEdit.clear()
        ## Load layers and add to comboboxes
        #layers = self.iface.legendInterface().layers()
        #layers = QgsMapLayerRegistry.instance().mapLayers().values()
        layers = QgsProject.instance().mapLayers().values()
        #Clear combobox
        self.dlg.comboBoxInputVector.clear()
        self.dlg.comboBoxInputRaster.clear()
        #layer_list = []
        for layer in layers:
            #if layer.type() == QgsMapLayer.VectorLayer and (layer.wkbType()==QGis.WKBPolygon or layer.wkbType() == QGis.WKBMultiPolygon):
            if layer.type() == QgsMapLayer.VectorLayer and (
                    layer.wkbType() == QgsWkbTypes.Polygon
                    or layer.wkbType() == QgsWkbTypes.MultiPolygon):
                self.dlg.comboBoxInputVector.addItem(layer.name(), layer)
            if layer.type() == QgsMapLayer.RasterLayer:
                self.dlg.comboBoxInputRaster.addItem(layer.name(), layer)
            #layer_list.append(layer.name())
        #self.dlg.comboBoxInputVector.addItems(layer_list)

        self.dlg.textAboutThesis.clear()
        self.dlg.textAboutThesis.append(
            "<span><b>Crop Rows Generator (CRG) QGIS-PLUGIN</b> is part of: <br><b>AN AUTOMATIC CROP ROWS GENERATOR USING AERIAL HIGH-RESOLUTION IMAGES FOR PRECISION AGRICULTURE</b>,master research project.</span>"
        )
        self.dlg.textAboutThesis.append(
            "<span>Developed in partial fulfillment of the requirements for the degree of:</span>"
        )
        self.dlg.textAboutThesis.append(
            "<span><b>Magister en Ingenier&iacute;a con &Eacute;nfasis en Ingenier&iacute;a de Sistemas y Computaci&oacute;n</b></span>"
        )
        strFromLocalFile = os.path.abspath(
            os.path.join(os.path.dirname(__file__), "help.html"))
        urlFromLocalFile = QUrl.fromLocalFile(strFromLocalFile)
        #self.dlg.webViewHelp.load(QUrl('http://www.google.com'))
        self.dlg.webViewHelp.load(urlFromLocalFile)
        str2FromLocalFile = os.path.abspath(
            os.path.join(os.path.dirname(__file__), "noprocessing.html"))
        url2FromLocalFile = QUrl.fromLocalFile(str2FromLocalFile)
        self.dlg.webViewApiStatus.load(url2FromLocalFile)
        #self.dlg.pushButtonOutputVectorFile.clicked.connect(self.fileNameDialog_Clicked)
        self.dlg.btnExecuteClippingTask.clicked.connect(
            self.executeCropRowsClipProcessing)
        self.dlg.btnExecuteProcessingFromApi.clicked.connect(
            self.executeCropRowsProcessingFromAPI)
        self.dlg.webViewProcessingStatus.loadFinished.connect(
            self.on_webViewProcessingStatus_loadFinished)
        self.dlg.radioButtonSeed1.clicked.connect(
            partial(self.displaySeedSelectedRadioOption, "Horizontal Pattern"))
        self.dlg.radioButtonSeed2.clicked.connect(
            partial(self.displaySeedSelectedRadioOption, "Vertical Pattern"))
        self.dlg.radioButtonSeed3.clicked.connect(
            partial(self.displaySeedSelectedRadioOption,
                    "Counterclockwise Pattern"))
        self.dlg.radioButtonSeed4.clicked.connect(
            partial(self.displaySeedSelectedRadioOption, "Clockwise Pattern"))
        self.dlg.btnExecuteSaveConfig.clicked.connect(
            self.saveConfigXMLAndReloadPlugin)
        #wizard
        self.dlg.btnCancelWizard.clicked.connect(self.cancelWizard)
        #hide step2 button
        self.dlg.btnExecuteProcessingFromApi.setVisible(False)
        #hide processing tab
        self.dlg.mainTabs.setTabEnabled(1, False)

        self.dlg.statusBarProcessing.setGeometry(10, 281, 511, 31)

        nowTime = time.strftime("%c")
        QgsMessageLog.logMessage(
            '========================================================')
        QgsMessageLog.logMessage('Crop Rows GUI dialog starts:' +
                                 time.strftime('%c'))
        QgsMessageLog.logMessage(
            '========================================================')
        self.readConfigFileFromXML()
        #self.dlg.webViewProcessingStatus.loadProgress.connect(self.load_progress)
        # show the dialog
        #self.dlg.show()
        self.dlg.exec_()
Exemplo n.º 26
0
    def accept(self):
        """ This is called when the user has clicked on the "OK" button to create the chart."""
        if self.layerComboBox.count() == 0:
            return
        self.readChartParams()
        uniqueCustomFields = []
        if self.selectedRadialUnit == 5 or self.selectedCircleUnit == 5:
            if self.customFieldCol == -1:
                self.iface.messageBar().pushMessage(
                    "",
                    "Custom Category Filed cannot be selected because none is selected",
                    level=Qgis.Warning,
                    duration=3)
                return
            uniqueCustomFields = self.selectedLayer.uniqueValues(
                self.customFieldCol)
            if len(uniqueCustomFields) > 40:
                # We have too many categories
                self.iface.messageBar().pushMessage(
                    "",
                    "There are too many custom categories for a chart",
                    level=Qgis.Warning,
                    duration=3)
                return
        folder = askForFolder(self)
        if not folder:
            return

        # Set aside some space to accumulate the statistics
        data = AutoDict()
        rvlist = AutoDict()
        cvlist = AutoDict()
        request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
        isdt = self.dtRadioButton.isChecked()
        attributes = []
        if isdt:
            attributes.append(self.selectedDateTimeCol)
        else:
            attributes.extend([self.selectedDateCol, self.selectedTimeCol])
        if self.customFieldCol != -1:
            attributes.append(self.customFieldCol)

        request.setSubsetOfAttributes(attributes)

        if isdt:
            col1 = self.selectedDateTimeCol
            col2 = self.selectedDateTimeCol
        else:
            col1 = self.selectedDateCol
            col2 = self.selectedTimeCol

        # Iterate through each feature and parse and process the date/time values
        iter = self.selectedLayer.getFeatures(request)
        for f in iter:
            try:
                if self.selectedRadialUnit == 5:
                    rv = f[self.customFieldCol]
                    if rv == None:
                        continue
                else:
                    rv = self.parseDateTimeValues(self.selectedRadialUnit,
                                                  f[col1], f[col2])
                if self.selectedCircleUnit == 5:
                    cv = f[self.customFieldCol]
                    if cv == None:
                        continue
                else:
                    cv = self.parseDateTimeValues(self.selectedCircleUnit,
                                                  f[col1], f[col2])
            except:
                continue

            rvlist[rv] += 1
            cvlist[cv] += 1
            data[rv][cv] += 1
        if not any(cvlist) or not any(rvlist):
            self.iface.messageBar().pushMessage("",
                                                "Valid dates were not found",
                                                level=Qgis.Warning,
                                                duration=3)
            return
        rvrange, segCnt, rvunits = self.getUnitStr(rvlist,
                                                   self.selectedRadialUnit)
        cvrange, bandCnt, cvunits = self.getUnitStr(cvlist,
                                                    self.selectedCircleUnit)
        if rvunits is None or cvunits is None:
            self.iface.messageBar().pushMessage(
                "",
                "There is too large of a year range to create chart",
                level=Qgis.Warning,
                duration=3)
            return

        # Create the web page with all the JavaScript variables
        datastr = self.formatData(data, rvrange, cvrange)

        chartSize = self.chartInnerRadius * 2 + (
            bandCnt +
            1) * 2 * self.chartBandHeight + 10  # 10 is additional margin
        style = (".legendContainer {{\n"
                 "	height: {};\n"
                 "}}\n"
                 ".legend svg {{\n"
                 "	width: {}px;\n"
                 "	height: {}px;\n"
                 "}}\n"
                 "#chart svg {{\n"
                 "	height: {}px;\n"
                 "	width: {}px;\n"
                 "}}\n").format(chartSize, self.legendBoxWidth,
                                self.legendHeight, chartSize, chartSize)

        script = []
        script.append('var segHeight={};'.format(self.chartBandHeight))
        script.append('var segCnt={};'.format(segCnt))
        script.append('var bandCnt={};'.format(bandCnt))
        script.append('var segLabels={};'.format(rvunits))
        script.append('var bandLabels={};'.format(cvunits))
        script.append('var innerRadius={};'.format(self.chartInnerRadius))
        script.append('var edata=[{}];'.format(datastr))
        script.append('var startColor="{}";'.format(self.beginningColor))
        script.append('var endColor="{}";'.format(self.endingColor))
        script.append('var noDataColor="{}";'.format(self.noDataColor))
        rl = ''
        if self.showRadialLabels:
            rl = '\n\t.segmentLabels(segLabels)'
        bl = ''
        if self.showBandLabels:
            bl = '\n\t.radialLabels(bandLabels)'
        ll = ''
        if self.showLegend:
            ll = '\n\t.legDivId("legend")\n\t.legendSettings({{width: {}, height: {}, legBlockWidth: {}}})\n\t.data(edata)\n'.format(
                self.legendBoxWidth, self.legendHeight, self.legendWidth)
        script.append(
            'var chart = circularHeatChart()\n\t.range([startColor,endColor])\n\t.nullColor(noDataColor)\n\t.segmentHeight(segHeight)\n\t.innerRadius(innerRadius)\n\t.numSegments(segCnt){}{}{};'
            .format(rl, bl, ll))
        script.append(
            'd3.select(\'#chart\')\n\t.selectAll(\'svg\')\n\t.data([edata])\n\t.enter()\n\t.append(\'svg\')\n\t.call(chart);'
        )

        if self.showDataValues:
            script.append(
                'd3.selectAll("#chart path").on(\'mouseover\', function() {\n\tvar d = d3.select(this).data();\n\td3.select("#info").text(\''
                + self.dataValueLabel + ' \' + d);\n});')

        if self.showLegend:
            script.append('d3.select("#legendTitle").html("' +
                          str(self.legendEdit.text()).replace('"', '\\"') +
                          '");\n')

        values = {
            "@TITLE@": self.chartTitle,
            "@STYLE@": style,
            "@SCRIPT@": '\n'.join(script)
        }
        template = os.path.join(os.path.dirname(__file__), "templates",
                                "index.html")
        html = replaceInTemplate(template, values)

        filename = os.path.join(folder, "index.html")
        try:
            fout = open(filename, 'w')
        except:
            self.iface.messageBar().pushMessage("",
                                                "Error opening output file",
                                                level=Qgis.Critical,
                                                duration=3)
            return
        fout.write(html)
        fout.close()
        #Copy over the d3 libraries
        copyfile(os.path.join(os.path.dirname(__file__), "d3", "d3.min.js"),
                 os.path.join(folder, "d3.min.js"))
        copyfile(
            os.path.join(os.path.dirname(__file__), "d3",
                         "circularHeatChart.js"),
            os.path.join(folder, "circularHeatChart.js"))
        # open the web browser
        url = QUrl.fromLocalFile(filename).toString()
        webbrowser.open(url, new=2)  # new=2 is a new tab if possible
        QMessageBox().information(self, "Date Time Heatmap",
                                  "Chart has been created")
Exemplo n.º 27
0
import os
from string import Template
from qgis.PyQt.QtCore import QUrl

from jinja2 import Environment, FileSystemLoader
path = os.path.join(os.path.dirname(__file__))

env = Environment(loader=FileSystemLoader(path))


def render_tample(name, **data):
    template = env.get_template('{}.html'.format(name))
    return template.render(**data)


def get_template(name):
    """
    Return a string Template for the given html file
    :param name: The name of the template to return
    :return: a string Template
    """
    html = os.path.join(os.path.dirname(__file__), "{}.html".format(name))
    with open(html) as f:
        return Template(f.read())


base = os.path.dirname(os.path.abspath(__file__))
baseurl = QUrl.fromLocalFile(base + '/')
Exemplo n.º 28
0
 def loadFile(self, htmlfile):
     self.webView.load(QUrl.fromLocalFile(htmlfile))
Exemplo n.º 29
0
    def exportAsPdf(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As PDF'), '',
                                                           self.tr('PDF files (*.pdf *.PDF)'))
        if not filename:
            return

        if not filename.lower().endswith('.pdf'):
            filename += '.pdf'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        printerRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        printer = QPrinter()
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setOutputFileName(filename)
        printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel)
        printer.setFullPage(True)

        painter = QPainter(printer)
        self.scene.render(painter, printerRect, totalRect)
        painter.end()

        self.bar.pushMessage("", self.tr("Successfully exported model as PDF to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
    def __init__(self, settingsdict, num_data_cols, rowheader_colwidth_percent,
                 empty_row_between_tables, page_break_between_tables,
                 from_active_layer, sql_table):
        #show the user this may take a long time...
        utils.start_waiting_cursor()

        self.nr_header_rows = 3

        reportfolder = os.path.join(QDir.tempPath(), 'midvatten_reports')
        if not os.path.exists(reportfolder):
            os.makedirs(reportfolder)
        reportpath = os.path.join(reportfolder, "w_qual_report.html")
        f = codecs.open(reportpath, "wb", "utf-8")

        #write some initiating html
        rpt = r"""<head><title>%s</title></head>""" % ru(
            QCoreApplication.translate(
                'Wqualreport',
                'water quality report from Midvatten plugin for QGIS'))
        rpt += r""" <meta http-equiv="content-type" content="text/html; charset=utf-8" />"""  #NOTE, all report data must be in 'utf-8'
        rpt += "<html><body>"
        f.write(rpt)

        if from_active_layer:
            utils.pop_up_info(
                ru(
                    QCoreApplication.translate(
                        'CompactWqualReport',
                        'Check that exported number of rows are identical to expected number of rows!\nFeatures in layers from sql queries can be invalid and then excluded from the report!'
                    )), 'Warning!')
            w_qual_lab_layer = qgis.utils.iface.activeLayer()
            if w_qual_lab_layer is None:
                raise utils.UsageError(
                    ru(
                        QCoreApplication.translate('CompactWqualReport',
                                                   'Must select a layer!')))
            if not w_qual_lab_layer.selectedFeatureCount():
                w_qual_lab_layer.selectAll()
            data = self.get_data_from_qgislayer(w_qual_lab_layer)
        else:
            data = self.get_data_from_sql(sql_table,
                                          utils.getselectedobjectnames())

        report_data, num_data = self.data_to_printlist(data)
        utils.MessagebarAndLog.info(bar_msg=ru(
            QCoreApplication.translate(
                'CompactWqualReport',
                'Created report from %s number of rows.')) % str(num_data))

        for startcol in range(1, len(report_data[0]), num_data_cols):
            printlist = [[row[0]] for row in report_data]
            for rownr, row in enumerate(report_data):
                printlist[rownr].extend(
                    row[startcol:min(startcol + num_data_cols, len(row))])

            filtered = [row for row in printlist if any(row[1:])]

            self.htmlcols = len(filtered[0])
            self.WriteHTMLReport(
                filtered,
                f,
                rowheader_colwidth_percent,
                empty_row_between_tables=empty_row_between_tables,
                page_break_between_tables=page_break_between_tables)

        # write some finishing html and close the file
        f.write("\n</body></html>")
        f.close()

        utils.stop_waiting_cursor(
        )  # now this long process is done and the cursor is back as normal

        if report_data:
            QDesktopServices.openUrl(QUrl.fromLocalFile(reportpath))
Exemplo n.º 31
0
 def showHelp(self):
     """Display application help to the user."""
     help_file = os.path.join(
         os.path.split(os.path.dirname(__file__))[0], 'help', 'index.html')
     QDesktopServices.openUrl(QUrl.fromLocalFile(help_file))
Exemplo n.º 32
0
    def exportAsImage(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As Image'), '',
                                                           self.tr('PNG files (*.png *.PNG)'))
        if not filename:
            return

        if not filename.lower().endswith('.png'):
            filename += '.png'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        img = QImage(totalRect.width(), totalRect.height(),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(Qt.white)
        painter = QPainter()
        painter.setRenderHint(QPainter.Antialiasing)
        painter.begin(img)
        self.scene.render(painter, imgRect, totalRect)
        painter.end()

        img.save(filename)

        self.bar.pushMessage("", self.tr("Successfully exported model as image to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
Exemplo n.º 33
0
 def help(self):
     QDesktopServices.openUrl(QUrl.fromLocalFile(
                      self.plugin_dir + "/help/html/index.html"))
Exemplo n.º 34
0
    def saveModel(self, saveAs):
        if not self.can_save():
            return
        self.model.setName(str(self.textName.text()))
        self.model.setGroup(str(self.textGroup.text()))
        if self.model.sourceFilePath() and not saveAs:
            filename = self.model.sourceFilePath()
        else:
            filename, filter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model'),
                                                           ModelerUtils.modelsFolders()[0],
                                                           self.tr('Processing models (*.model3 *.MODEL3)'))
            if filename:
                if not filename.endswith('.model3'):
                    filename += '.model3'
                self.model.setSourceFilePath(filename)
        if filename:
            if not self.model.toFile(filename):
                if saveAs:
                    QMessageBox.warning(self, self.tr('I/O error'),
                                        self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1])))
                else:
                    QMessageBox.warning(self, self.tr("Can't save model"), QCoreApplication.translate('QgsPluginInstallerInstallingDialog', (
                        "This model can't be saved in its original location (probably you do not "
                        "have permission to do it). Please, use the 'Save as…' option."))
                    )
                return
            self.update_model.emit()
            if saveAs:
                self.bar.pushMessage("", self.tr("Model was correctly saved to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
            else:
                self.bar.pushMessage("", self.tr("Model was correctly saved"), level=Qgis.Success, duration=5)

            self.hasChanged = False
Exemplo n.º 35
0
    def exportAsPython(self):
        filename, filter = QFileDialog.getSaveFileName(self,
                                                       self.tr('Save Model As Python Script'), '',
                                                       self.tr('Processing scripts (*.py *.PY)'))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.model.asPythonCode()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)

        self.bar.pushMessage("", self.tr("Successfully exported model as python script to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
Exemplo n.º 36
0
    def exportAsSvg(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As SVG'), '',
                                                           self.tr('SVG files (*.svg *.SVG)'))
        if not filename:
            return

        if not filename.lower().endswith('.svg'):
            filename += '.svg'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        svgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        svg = QSvgGenerator()
        svg.setFileName(filename)
        svg.setSize(QSize(totalRect.width(), totalRect.height()))
        svg.setViewBox(svgRect)
        svg.setTitle(self.model.displayName())

        painter = QPainter(svg)
        self.scene.render(painter, svgRect, totalRect)
        painter.end()

        self.bar.pushMessage("", self.tr("Successfully exported model as SVG to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
 def help(self):
     # Display html help
     url = QUrl.fromLocalFile(self.plugin_dir + "/help" + self.translate_str("/index_en.html")).toString()
     webbrowser.open(url, new=2)
Exemplo n.º 38
0
 def open_help(self):
     QDesktopServices.openUrl(
         QUrl.fromLocalFile(
             os.path.join(os.path.dirname(__file__), "doc", "build", "html",
                          "index.html")))
Exemplo n.º 39
0
 def setHelpPage(self, helppath):
     self.webView.load(QUrl.fromLocalFile(helppath))
Exemplo n.º 40
0
 def load_content(self):
     self.html_loaded = False
     base_url = QUrl.fromLocalFile(self.layout().project().absoluteFilePath())
     self.web_page.setViewportSize(QSize(self.rect().width() * self.html_units_to_layout_units,
                                         self.rect().height() * self.html_units_to_layout_units))
     self.web_page.mainFrame().setHtml(self.create_plot(), base_url)
Exemplo n.º 41
0
 def setHTML(self, file_path):
     self.html_file = file_path
     self.WebV.load(QUrl.fromLocalFile(self.html_file))
Exemplo n.º 42
0
    def exportAsImage(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As Image'), '',
                                                           self.tr('PNG files (*.png *.PNG)'))
        if not filename:
            return

        if not filename.lower().endswith('.png'):
            filename += '.png'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        imgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        img = QImage(totalRect.width(), totalRect.height(),
                     QImage.Format_ARGB32_Premultiplied)
        img.fill(Qt.white)
        painter = QPainter()
        painter.setRenderHint(QPainter.Antialiasing)
        painter.begin(img)
        self.scene.render(painter, imgRect, totalRect)
        painter.end()

        img.save(filename)

        self.bar.pushMessage("", self.tr("Successfully exported model as image to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
    def __init__(self, settingsdict, num_data_cols, rowheader_colwidth_percent,
                 empty_row_between_tables, page_break_between_tables,
                 from_active_layer, sql_table, sort_parameters_alphabetically,
                 sort_by_obsid, date_time_as_columns, date_time_format, method,
                 data_column):
        #show the user this may take a long time...

        reportfolder = os.path.join(QDir.tempPath(), 'midvatten_reports')
        if not os.path.exists(reportfolder):
            os.makedirs(reportfolder)
        reportpath = os.path.join(reportfolder, "w_qual_report.html")
        f = codecs.open(reportpath, "wb", "utf-8")

        #write some initiating html
        rpt = r"""<head><title>%s</title></head>""" % ru(
            QCoreApplication.translate(
                'Wqualreport',
                'water quality report from Midvatten plugin for QGIS'))
        rpt += r""" <meta http-equiv="content-type" content="text/html; charset=utf-8" />"""  #NOTE, all report data must be in 'utf-8'
        rpt += "<html><body>"
        f.write(rpt)

        if date_time_as_columns:
            data_columns = [
                'obsid', 'date_time', 'report', 'parameter', 'unit',
                data_column
            ]
        else:
            data_columns = [
                'obsid', 'date_time', 'parameter', 'unit', data_column
            ]

        if from_active_layer:
            w_qual_lab_layer = qgis.utils.iface.activeLayer()
            if w_qual_lab_layer is None:
                raise utils.UsageError(
                    ru(
                        QCoreApplication.translate('CompactWqualReport',
                                                   'Must select a layer!')))
            if not w_qual_lab_layer.selectedFeatureCount():
                w_qual_lab_layer.selectAll()
            df = self.get_data_from_qgislayer(w_qual_lab_layer, data_columns)
        else:
            df = self.get_data_from_sql(sql_table,
                                        utils.getselectedobjectnames(),
                                        data_columns)

        if date_time_as_columns:
            columns = ['obsid', 'date_time', 'report']
            rows = ['parunit']
            values = [data_column]
            report_data = self.data_to_printlist(
                df, list(columns), list(rows), values,
                sort_parameters_alphabetically, sort_by_obsid, method,
                date_time_format)
        else:
            columns = ['obsid']
            rows = ['parunit', 'date_time']
            values = [data_column]
            report_data = self.data_to_printlist(
                df, list(columns), list(rows), values,
                sort_parameters_alphabetically, sort_by_obsid, method,
                date_time_format)

        # Split the data into separate tables with the specified number of columns
        for startcol in range(len(rows), len(report_data[0]), num_data_cols):
            printlist = [row[:len(rows)] for row in report_data]
            for rownr, row in enumerate(report_data):
                printlist[rownr].extend(
                    row[startcol:min(startcol + num_data_cols, len(row))])

            filtered = [row for row in printlist if any(row[len(rows):])]

            self.htmlcols = len(filtered[0])
            self.write_html_table(
                filtered,
                f,
                rowheader_colwidth_percent,
                empty_row_between_tables=empty_row_between_tables,
                page_break_between_tables=page_break_between_tables,
                nr_header_rows=len(columns),
                nr_row_header_columns=len(rows))

        # write some finishing html and close the file
        f.write("\n</body></html>")
        f.close()

        if report_data:
            QDesktopServices.openUrl(QUrl.fromLocalFile(reportpath))
Exemplo n.º 44
0
 def open_collection(self):
     """Slot called when the user clicks the 'Open' button."""
     collection_path = local_collection_path(self._sel_coll_id)
     directory_url = QUrl.fromLocalFile(str(collection_path))
     QDesktopServices.openUrl(directory_url)
Exemplo n.º 45
0
 def updateDescription(self, current, previous):
     if isinstance(current, TreeResultItem):
         html = '<b>Algorithm</b>: {}<br><b>File path</b>: <a href="{}">{}</a>'.format(current.algorithm, QUrl.fromLocalFile(current.filename).toString(), QDir.toNativeSeparators(current.filename))
         self.txtDescription.setHtml(html)
Exemplo n.º 46
0
 def openResult(self, item, column):
     QDesktopServices.openUrl(QUrl.fromLocalFile(item.filename))
Exemplo n.º 47
0
    def exportAsSvg(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As SVG'), '',
                                                           self.tr('SVG files (*.svg *.SVG)'))
        if not filename:
            return

        if not filename.lower().endswith('.svg'):
            filename += '.svg'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        svgRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        svg = QSvgGenerator()
        svg.setFileName(filename)
        svg.setSize(QSize(totalRect.width(), totalRect.height()))
        svg.setViewBox(svgRect)
        svg.setTitle(self.model.displayName())

        painter = QPainter(svg)
        self.scene.render(painter, svgRect, totalRect)
        painter.end()

        self.bar.pushMessage("", self.tr("Successfully exported model as SVG to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
Exemplo n.º 48
0
    def saveModel(self, saveAs) -> bool:
        if not self.validateSave(QgsModelDesignerDialog.SaveAction.SaveAsFile):
            return False

        model_name_matched_file_name = self.model().modelNameMatchesFilePath()
        if self.model().sourceFilePath() and not saveAs:
            filename = self.model().sourceFilePath()
        else:
            if self.model().sourceFilePath():
                initial_path = Path(self.model().sourceFilePath())
            elif self.model().name():
                initial_path = Path(ModelerUtils.modelsFolders()[0]) / (
                    self.model().name() + '.model3')
            else:
                initial_path = Path(ModelerUtils.modelsFolders()[0])

            filename, _ = QFileDialog.getSaveFileName(
                self, self.tr('Save Model'), initial_path.as_posix(),
                self.tr('Processing models (*.model3 *.MODEL3)'))
            if not filename:
                return False

            filename = QgsFileUtils.ensureFileNameHasExtension(
                filename, ['model3'])
            self.model().setSourceFilePath(filename)

            if not self.model().name() or self.model().name() == self.tr(
                    'model'):
                self.setModelName(Path(filename).stem)
            elif saveAs and model_name_matched_file_name:
                # if saving as, and the model name used to match the filename, then automatically update the
                # model name to match the new file name
                self.setModelName(Path(filename).stem)

        if not self.model().toFile(filename):
            if saveAs:
                QMessageBox.warning(
                    self, self.tr('I/O error'),
                    self.tr('Unable to save edits. Reason:\n {0}').format(
                        str(sys.exc_info()[1])))
            else:
                QMessageBox.warning(
                    self, self.tr("Can't save model"),
                    self.
                    tr("This model can't be saved in its original location (probably you do not "
                       "have permission to do it). Please, use the 'Save as…' option."
                       ))
            return False

        self.update_model.emit()
        if saveAs:
            self.messageBar().pushMessage(
                "",
                self.tr("Model was saved to <a href=\"{}\">{}</a>").format(
                    QUrl.fromLocalFile(filename).toString(),
                    QDir.toNativeSeparators(filename)),
                level=Qgis.Success,
                duration=5)

        self.setDirty(False)
        return True
Exemplo n.º 49
0
    def saveModel(self, saveAs):
        if not self.can_save():
            return
        self.model.setName(str(self.textName.text()))
        self.model.setGroup(str(self.textGroup.text()))
        if self.model.sourceFilePath() and not saveAs:
            filename = self.model.sourceFilePath()
        else:
            filename, filter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model'),
                                                           ModelerUtils.modelsFolders()[0],
                                                           self.tr('Processing models (*.model3 *.MODEL3)'))
            if filename:
                if not filename.endswith('.model3'):
                    filename += '.model3'
                self.model.setSourceFilePath(filename)
        if filename:
            if not self.model.toFile(filename):
                if saveAs:
                    QMessageBox.warning(self, self.tr('I/O error'),
                                        self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1])))
                else:
                    QMessageBox.warning(self, self.tr("Can't save model"), QCoreApplication.translate('QgsPluginInstallerInstallingDialog', (
                        "This model can't be saved in its original location (probably you do not "
                        "have permission to do it). Please, use the 'Save as…' option."))
                    )
                return
            self.update_model.emit()
            if saveAs:
                self.bar.pushMessage("", self.tr("Model was correctly saved to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
            else:
                self.bar.pushMessage("", self.tr("Model was correctly saved"), level=Qgis.Success, duration=5)

            self.hasChanged = False
Exemplo n.º 50
0
def openfolder(folder):
    """
    Open a folder using the OS
    :param folder: The path to the folder to open.
    """
    QDesktopServices.openUrl(QUrl.fromLocalFile(folder))
Exemplo n.º 51
0
class PlotFactory(QObject):  # pylint:disable=too-many-instance-attributes
    """
    Plot factory which creates Plotly Plot objects

    Console usage:

    .. code-block:: python
        # create (and customize) plot settings, where
        # plot_type (string): 'scatter'
        # plot_properties (dictionary): {'x':[1,2,3], 'marker_width': 10}
        # layout_properties (dictionary): {'legend'; True, 'title': 'Plot Title'}
        settings = PlotSettings(plot_type, plot_properties, layout_properties)
        # create the factory, which will create plots using the specified settings
        factory = PlotFactory(settings)
        # Use the factory to build a plot
        output_file_path = factory.build_figure()
    """

    # create fixed class variables as paths for local javascript files
    POLY_FILL_PATH = QUrl.fromLocalFile(
        os.path.realpath(
            os.path.join(os.path.dirname(__file__), '..',
                         'jsscripts/polyfill.min.js'))).toString()
    PLOTLY_PATH = QUrl.fromLocalFile(
        os.path.realpath(
            os.path.join(os.path.dirname(__file__), '..',
                         'jsscripts/plotly-1.52.2.min.js'))).toString()

    PLOT_TYPES = {t.type_name(): t for t in PlotType.__subclasses__()}

    plot_built = pyqtSignal()

    # Add function to QDate and QDateTime classes that the PlotlyJSONEncoder expects from date objects
    if not hasattr(QDate, 'isoformat'):
        QDate.isoformat = lambda d: d.toString(Qt.ISODate)
    if not hasattr(QDateTime, 'isoformat'):
        QDateTime.isoformat = lambda d: d.toString(Qt.ISODate)

    def __init__(self,
                 settings: PlotSettings = None,
                 context_generator: QgsExpressionContextGenerator = None,
                 visible_region: QgsReferencedRectangle = None,
                 polygon_filter: FilterRegion = None):
        super().__init__()
        if settings is None:
            settings = PlotSettings('scatter')

        self.settings = settings
        self.context_generator = context_generator
        self.raw_plot = None
        self.plot_path = None
        self.selected_features_only = self.settings.properties[
            'selected_features_only']
        self.visible_region = visible_region
        self.polygon_filter = polygon_filter
        self.trace = None
        self.layout = None
        self.source_layer = QgsProject.instance().mapLayer(
            self.settings.source_layer_id
        ) if self.settings.source_layer_id else None

        self.rebuild()

        if self.source_layer:
            self.source_layer.layerModified.connect(self.rebuild)
            if self.selected_features_only:
                self.source_layer.selectionChanged.connect(self.rebuild)

    def fetch_values_from_layer(self):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        """
        (Re)fetches plot values from the source layer.
        """

        # Note: we keep things nice and efficient and only iterate a single time over the layer!

        if not self.context_generator:
            context = QgsExpressionContext()
            context.appendScopes(
                QgsExpressionContextUtils.globalProjectLayerScopes(
                    self.source_layer))
        else:
            context = self.context_generator.createExpressionContext()
            # add a new scope corresponding to the source layer -- this will potentially overwrite any other
            # layer scopes which may be present in the context (e.g. from atlas layers), but we need to ensure
            # that source layer fields and attributes are present in the context
            context.appendScope(
                self.source_layer.createExpressionContextScope())

        self.settings.data_defined_properties.prepare(context)

        self.fetch_layout_properties(context)

        def add_source_field_or_expression(field_or_expression):
            field_index = self.source_layer.fields().lookupField(
                field_or_expression)
            if field_index == -1:
                expression = QgsExpression(field_or_expression)
                if not expression.hasParserError():
                    expression.prepare(context)
                return expression, expression.needsGeometry(
                ), expression.referencedColumns()

            return None, False, {field_or_expression}

        x_expression, x_needs_geom, x_attrs = add_source_field_or_expression(self.settings.properties['x_name']) if \
            self.settings.properties[
                'x_name'] else (None, False, set())
        y_expression, y_needs_geom, y_attrs = add_source_field_or_expression(self.settings.properties['y_name']) if \
            self.settings.properties[
                'y_name'] else (None, False, set())
        z_expression, z_needs_geom, z_attrs = add_source_field_or_expression(self.settings.properties['z_name']) if \
            self.settings.properties[
                'z_name'] else (None, False, set())
        additional_info_expression, additional_needs_geom, additional_attrs = add_source_field_or_expression(
            self.settings.layout['additional_info_expression']
        ) if self.settings.layout['additional_info_expression'] else (None,
                                                                      False,
                                                                      set())

        attrs = set().union(
            self.settings.data_defined_properties.referencedFields(), x_attrs,
            y_attrs, z_attrs, additional_attrs)

        request = QgsFeatureRequest()

        if self.settings.data_defined_properties.property(
                PlotSettings.PROPERTY_FILTER).isActive():
            expression = self.settings.data_defined_properties.property(
                PlotSettings.PROPERTY_FILTER).asExpression()
            request.setFilterExpression(expression)
            request.setExpressionContext(context)

        request.setSubsetOfAttributes(attrs, self.source_layer.fields())

        if not x_needs_geom and not y_needs_geom and not z_needs_geom and not additional_needs_geom and not self.settings.data_defined_properties.hasActiveProperties(
        ):
            request.setFlags(QgsFeatureRequest.NoGeometry)

        visible_geom_engine = None
        if self.settings.properties.get(
                'visible_features_only',
                False) and self.visible_region is not None:
            ct = QgsCoordinateTransform(
                self.visible_region.crs(), self.source_layer.crs(),
                QgsProject.instance().transformContext())
            try:
                rect = ct.transformBoundingBox(self.visible_region)
                request.setFilterRect(rect)
            except QgsCsException:
                pass
        elif self.settings.properties.get(
                'visible_features_only',
                False) and self.polygon_filter is not None:
            ct = QgsCoordinateTransform(
                self.polygon_filter.crs(), self.source_layer.crs(),
                QgsProject.instance().transformContext())
            try:
                rect = ct.transformBoundingBox(
                    self.polygon_filter.geometry.boundingBox())
                request.setFilterRect(rect)
                g = self.polygon_filter.geometry
                g.transform(ct)

                visible_geom_engine = QgsGeometry.createGeometryEngine(
                    g.constGet())
                visible_geom_engine.prepareGeometry()
            except QgsCsException:
                pass

        if self.selected_features_only:
            it = self.source_layer.getSelectedFeatures(request)
        else:
            it = self.source_layer.getFeatures(request)

        # Some plot types don't draw individual glyphs for each feature, but aggregate them instead.
        # In that case it doesn't make sense to evaluate expressions for settings like marker size or color for each
        # feature. Instead, the evaluation should be executed only once for these settings.
        aggregating = self.settings.plot_type in ['box', 'histogram']
        executed = False

        xx = []
        yy = []
        zz = []
        additional_hover_text = []
        marker_sizes = []
        colors = []
        stroke_colors = []
        stroke_widths = []
        for f in it:
            if visible_geom_engine and not visible_geom_engine.intersects(
                    f.geometry().constGet()):
                continue

            self.settings.feature_ids.append(f.id())
            context.setFeature(f)

            x = None
            if x_expression:
                x = x_expression.evaluate(context)
                if x == NULL or x is None:
                    continue
            elif self.settings.properties['x_name']:
                x = f[self.settings.properties['x_name']]
                if x == NULL or x is None:
                    continue

            y = None
            if y_expression:
                y = y_expression.evaluate(context)
                if y == NULL or y is None:
                    continue
            elif self.settings.properties['y_name']:
                y = f[self.settings.properties['y_name']]
                if y == NULL or y is None:
                    continue

            z = None
            if z_expression:
                z = z_expression.evaluate(context)
                if z == NULL or z is None:
                    continue
            elif self.settings.properties['z_name']:
                z = f[self.settings.properties['z_name']]
                if z == NULL or z is None:
                    continue

            if additional_info_expression:
                additional_hover_text.append(
                    additional_info_expression.evaluate(context))
            elif self.settings.layout['additional_info_expression']:
                additional_hover_text.append(
                    f[self.settings.layout['additional_info_expression']])

            if x is not None:
                xx.append(x)
            if y is not None:
                yy.append(y)
            if z is not None:
                zz.append(z)

            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_MARKER_SIZE):
                default_value = self.settings.properties['marker_size']
                context.setOriginalValueVariable(default_value)
                value, _ = self.settings.data_defined_properties.valueAsDouble(
                    PlotSettings.PROPERTY_MARKER_SIZE, context, default_value)
                marker_sizes.append(value)
            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_STROKE_WIDTH):
                default_value = self.settings.properties['marker_width']
                context.setOriginalValueVariable(default_value)
                value, _ = self.settings.data_defined_properties.valueAsDouble(
                    PlotSettings.PROPERTY_STROKE_WIDTH, context, default_value)
                stroke_widths.append(value)

            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_COLOR) and (not aggregating
                                                      or not executed):
                default_value = QColor(self.settings.properties['in_color'])
                value, conversion_success = self.settings.data_defined_properties.valueAsColor(
                    PlotSettings.PROPERTY_COLOR, context, default_value)
                if conversion_success:
                    # We were given a valid color specification, use that color
                    colors.append(value.name())
                else:
                    try:
                        # Attempt to interpret the value as a list of color specifications
                        value_list = self.settings.data_defined_properties.value(
                            PlotSettings.PROPERTY_COLOR, context)
                        color_list = [
                            QgsSymbolLayerUtils.decodeColor(item).name()
                            for item in value_list
                        ]
                        colors.extend(color_list)
                    except TypeError:
                        # Not a list of color specifications, use the default color instead
                        colors.append(default_value.name())

            if self.settings.data_defined_properties.isActive(
                    PlotSettings.PROPERTY_STROKE_COLOR) and (not aggregating
                                                             or not executed):
                default_value = QColor(self.settings.properties['out_color'])
                value, conversion_success = self.settings.data_defined_properties.valueAsColor(
                    PlotSettings.PROPERTY_STROKE_COLOR, context, default_value)
                if conversion_success:
                    # We were given a valid color specification, use that color
                    stroke_colors.append(value.name())
                else:
                    try:
                        # Attempt to interpret the value as a list of color specifications
                        value_list = self.settings.data_defined_properties.value(
                            PlotSettings.PROPERTY_STROKE_COLOR, context)
                        color_list = [
                            QgsSymbolLayerUtils.decodeColor(item).name()
                            for item in value_list
                        ]
                        stroke_colors.extend(color_list)
                    except TypeError:
                        # Not a list of color specifications, use the default color instead
                        stroke_colors.append(default_value.name())

            executed = True

        self.settings.additional_hover_text = additional_hover_text
        self.settings.x = xx
        self.settings.y = yy
        self.settings.z = zz
        if marker_sizes:
            self.settings.data_defined_marker_sizes = marker_sizes
        if colors:
            self.settings.data_defined_colors = colors
        if stroke_colors:
            self.settings.data_defined_stroke_colors = stroke_colors
        if stroke_widths:
            self.settings.data_defined_stroke_widths = stroke_widths

    def fetch_layout_properties(self, context):  # pylint: disable=too-many-statements
        """
        (Re)fetches layout properties.
        """

        title = ''
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_TITLE):
            default_value = self.settings.layout['title']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsString(
                PlotSettings.PROPERTY_TITLE, context, default_value)
            title = value
        legend_title = ''
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_LEGEND_TITLE):
            default_value = self.settings.layout['legend_title']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsString(
                PlotSettings.PROPERTY_LEGEND_TITLE, context, default_value)
            legend_title = value
        x_title = ''
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_X_TITLE):
            default_value = self.settings.layout['x_title']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsString(
                PlotSettings.PROPERTY_X_TITLE, context, default_value)
            x_title = value
        y_title = ''
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_Y_TITLE):
            default_value = self.settings.layout['y_title']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsString(
                PlotSettings.PROPERTY_Y_TITLE, context, default_value)
            y_title = value
        z_title = ''
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_Z_TITLE):
            default_value = self.settings.layout['z_title']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsString(
                PlotSettings.PROPERTY_Z_TITLE, context, default_value)
            z_title = value
        x_min = None
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_X_MIN):
            default_value = self.settings.layout['x_min']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsDouble(
                PlotSettings.PROPERTY_X_MIN, context, default_value)
            x_min = value
        x_max = None
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_X_MAX):
            default_value = self.settings.layout['x_max']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsDouble(
                PlotSettings.PROPERTY_X_MAX, context, default_value)
            x_max = value
        y_min = None
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_Y_MIN):
            default_value = self.settings.layout['y_min']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsDouble(
                PlotSettings.PROPERTY_Y_MIN, context, default_value)
            y_min = value
        y_max = None
        if self.settings.data_defined_properties.isActive(
                PlotSettings.PROPERTY_Y_MAX):
            default_value = self.settings.layout['y_max']
            context.setOriginalValueVariable(default_value)
            value, _ = self.settings.data_defined_properties.valueAsDouble(
                PlotSettings.PROPERTY_Y_MAX, context, default_value)
            y_max = value

        self.settings.data_defined_title = title
        self.settings.data_defined_legend_title = legend_title
        self.settings.data_defined_x_title = x_title
        self.settings.data_defined_y_title = y_title
        self.settings.data_defined_z_title = z_title
        self.settings.data_defined_x_min = x_min
        self.settings.data_defined_x_max = x_max
        self.settings.data_defined_y_min = y_min
        self.settings.data_defined_y_max = y_max

    def set_visible_region(self, region: QgsReferencedRectangle):
        """
        Sets the visible region associated with the factory, possibly triggering a rebuild
        of a filtered plot
        """
        if self.settings.properties.get('visible_features_only', False):
            self.visible_region = region
            self.rebuild()

    def rebuild(self):
        """
        Rebuilds the plot, re-fetching current values from the layer
        """
        if self.source_layer:
            self.fetch_values_from_layer()

        self.trace = self._build_trace()
        self.layout = self._build_layout()
        self.plot_built.emit()

    def _build_trace(self):
        """
        Builds the final trace calling the go.xxx plotly method
        this method here is the one performing the real job

        From the initial object created (e.g. p = Plot(plot_type, plot_properties,
        layout_properties)) this methods checks the plot_type and elaborates the
        plot_properties dictionary passed

        :return: the final Plot Trace (final Plot object, AKA go.xxx plot type)
        """
        assert self.settings.plot_type in PlotFactory.PLOT_TYPES

        return PlotFactory.PLOT_TYPES[self.settings.plot_type].create_trace(
            self.settings)

    def _build_layout(self):
        """
        Builds the final layout calling the go.Layout plotly method

        From the initial object created (e.g. p = Plot(plot_type, plot_properties,
        layout_properties)) this methods checks the plot_type and elaborates the
        layout_properties dictionary passed

        :return: the final Plot Layout (final Layout object, AKA go.Layout)
        """
        assert self.settings.plot_type in PlotFactory.PLOT_TYPES

        return PlotFactory.PLOT_TYPES[self.settings.plot_type].create_layout(
            self.settings)

    @staticmethod
    def js_callback(_):
        """
        Returns a string that is added to the end of the plot. This string is
        necessary for the interaction between plot and map objects

        WARNING! The string ReplaceTheDiv is a default string that will be
        replaced in a second moment
        """

        js_str = '''
        <script>
        // additional js function to select and click on the data
        // returns the ids of the selected/clicked feature

        var plotly_div = document.getElementById('ReplaceTheDiv')
        var plotly_data = plotly_div.data

        // selecting function
        plotly_div.on('plotly_selected', function(data){
        var dds = {};
        dds["mode"] = 'selection'
        dds["type"] = data.points[0].data.type

        featureIds = [];
        featureIdsTernary = [];

        data.points.forEach(function(pt){
        featureIds.push(parseInt(pt.id))
        featureIdsTernary.push(parseInt(pt.pointNumber))
        dds["id"] = featureIds
        dds["tid"] = featureIdsTernary
            })
        //console.log(dds)
        window.status = JSON.stringify(dds)
        })

        // clicking function
        plotly_div.on('plotly_click', function(data){
        var featureIds = [];
        var dd = {};
        dd["fidd"] = data.points[0].id
        dd["mode"] = 'clicking'

        // loop and create dictionary depending on plot type
        for(var i=0; i < data.points.length; i++){

        // scatter plot
        if(data.points[i].data.type == 'scatter'){
            dd["uid"] = data.points[i].data.uid
            dd["type"] = data.points[i].data.type

            data.points.forEach(function(pt){
            dd["fid"] = pt.id
            })
        }

        // pie

        else if(data.points[i].data.type == 'pie'){
          dd["type"] = data.points[i].data.type
          dd["label"] = data.points[i].label
          dd["field"] = data.points[i].data.name
          console.log(data.points[i].label)
          console.log(data.points[i])
        }

        // histogram
        else if(data.points[i].data.type == 'histogram'){
            dd["type"] = data.points[i].data.type
            dd["uid"] = data.points[i].data.uid
            dd["field"] = data.points[i].data.name

            // correct axis orientation
            if(data.points[i].data.orientation == 'v'){
                dd["id"] = data.points[i].x
                dd["bin_step"] = data.points[i].fullData.xbins.size
            }
            else {
                dd["id"] = data.points[i].y
                dd["bin_step"] = data.points[i].fullData.ybins.size
            }
        }

        // box plot
        else if(data.points[i].data.type == 'box'){
            dd["uid"] = data.points[i].data.uid
            dd["type"] = data.points[i].data.type
            dd["field"] = data.points[i].data.customdata[0]

                // correct axis orientation
                if(data.points[i].data.orientation == 'v'){
                    dd["id"] = data.points[i].x
                }
                else {
                    dd["id"] = data.points[i].y
                }
            }

        // violin plot
        else if(data.points[i].data.type == 'violin'){
            dd["uid"] = data.points[i].data.uid
            dd["type"] = data.points[i].data.type
            dd["field"] = data.points[i].data.customdata[0]

                // correct axis orientation (for violin is viceversa)
                if(data.points[i].data.orientation == 'v'){
                    dd["id"] = data.points[i].x
                }
                else {
                    dd["id"] = data.points[i].y
                }
            }

        // bar plot
        else if(data.points[i].data.type == 'bar'){
            dd["uid"] = data.points[i].data.uid
            dd["type"] = data.points[i].data.type
            dd["field"] = data.points[i].data.customdata[0]

                // correct axis orientation
                if(data.points[i].data.orientation == 'v'){
                    dd["id"] = data.points[i].x
                }
                else {
                    dd["id"] = data.points[i].y
                }
            }

        // ternary
        else if(data.points[i].data.type == 'scatterternary'){
            dd["uid"] = data.points[i].data.uid
            dd["type"] = data.points[i].data.type
            dd["field"] = data.points[i].data.customdata
            dd["fid"] = data.points[i].pointNumber
            }

            }
        window.status = JSON.stringify(dd)
        });
        </script>'''

        return js_str

    def build_html(self, config) -> str:
        """
        Creates the HTML for the plot

        Calls the go.Figure plotly method and builds the figure object adjust the
        html file and add some line (including the js_string for the interaction)
        save the html plot file in a temporary directory and return the path
        that can be loaded in the QWebView

        This method is directly usable after the plot object has been created and
        the 2 methods (buildTrace and buildLayout) have been called

        params:
            config (dict): config = {'scrollZoom': True, 'editable': False}

        config argument is necessary to specify which buttons should appear in
        the plotly toolbar, if the user can edit the plot inline, etc.
        With this parameter is possible to hide the toolbar only in print layouts
        and not in the normal plot canvas.

        :return: the final html content representing the plot

        Console usage:
        .. code-block:: python
            # create the initial object
            settings = PlotSettings(plot_type, plot_properties, layout_properties)
            factory = PlotFactory(settings)
            # finally create the Figure
            html_content  = factory.build_html()
        """
        fig = go.Figure(data=self.trace, layout=self.layout)

        # first lines of additional html with the link to the local javascript
        raw_plot = '<head><meta charset="utf-8" /><script src="{}">' \
                   '</script><script src="{}"></script></head>'.format(
            self.POLY_FILL_PATH, self.PLOTLY_PATH)
        # set some configurations
        # call the plot method without all the javascript code
        raw_plot += plotly.offline.plot(fig,
                                        output_type='div',
                                        include_plotlyjs=False,
                                        show_link=False,
                                        config=config)
        # insert callback for javascript events
        raw_plot += self.js_callback(raw_plot)

        # use regex to replace the string ReplaceTheDiv with the correct plot id generated by plotly
        match = re.search(r'Plotly.newPlot\(\s*[\'"](.+?)[\'"]', raw_plot)
        substr = match.group(1)
        raw_plot = raw_plot.replace('ReplaceTheDiv', substr)
        return raw_plot

    def build_figure(self) -> str:
        """
        Creates the final plot (single plot)

        Calls the go.Figure plotly method and builds the figure object adjust the
        html file and add some line (including the js_string for the interaction)
        save the html plot file in a temporary directory and return the path
        that can be loaded in the QWebView

        This method is directly usable after the plot object has been created and
        the 2 methods (buildTrace and buildLayout) have been called

        :return: the final html path containing the plot

        Console usage:
        .. code-block:: python
            # create the initial object
            settings = PlotSettings(plot_type, plot_properties, layout_properties)
            factory = PlotFactory(settings)
            # finally create the Figure
            path_to_output = factory.build_figure()
        """

        self.plot_path = os.path.join(tempfile.gettempdir(),
                                      'temp_plot_name.html')
        config = {
            'scrollZoom':
            True,
            'editable':
            True,
            'modeBarButtonsToRemove':
            ['toImage', 'sendDataToCloud', 'editInChartStudio']
        }

        with open(self.plot_path, "w", encoding="utf8") as f:
            f.write(self.build_html(config))

        return self.plot_path

    def build_figures(self, plot_type, ptrace, config=None) -> str:
        """
        Overlaps plots on the same map canvas

        params:
            plot_type (string): 'scatter'
            ptrace (list of Plot Traces): list of all the different Plot Traces

        plot_type argument in necessary for Bar and Histogram plots when the
        options stack is chosen.
        In this case the layouts of the firsts plot are deleted and only the last
        one is taken into account (so to have the stack option).

        self.layout is DELETED, so the final layout is taken from the LAST plot
        configuration added

        :return: the final html path containing the plot with the js_string for
        the interaction

        Console usage:
        .. code-block:: python
            # create the initial object
            settings = PlotSettings(plot_type, plot_properties, layout_properties)
            factory = PlotFactory(settings)
            # finally create the Figures
            path_to_output = factory.build_figures(plot_type, ptrace)
        """

        # assign the variables from the kwargs arguments
        # plot_type = kwargs['plot_type']
        # ptrace = kwargs['pl']

        # check if the plot type and render the correct figure
        if plot_type in ('bar', 'histogram'):
            del self.layout
            self.layout = PlotFactory.PLOT_TYPES[plot_type].create_layout(
                self.settings)
            figures = go.Figure(data=ptrace, layout=self.layout)

        else:
            figures = go.Figure(data=ptrace, layout=self.layout)

        # set some configurations
        if config is None:
            config = {'scrollZoom': True, 'editable': True}
        # first lines of additional html with the link to the local javascript
        self.raw_plot = '<head><meta charset="utf-8" /><script src="{}">' \
                        '</script><script src="{}"></script></head>'.format(
            self.POLY_FILL_PATH, self.PLOTLY_PATH)
        # call the plot method without all the javascript code
        self.raw_plot += plotly.offline.plot(figures,
                                             output_type='div',
                                             include_plotlyjs=False,
                                             show_link=False,
                                             config=config)
        # insert callback for javascript events
        self.raw_plot += self.js_callback(self.raw_plot)

        # use regex to replace the string ReplaceTheDiv with the correct plot id generated by plotly
        match = re.search(r'Plotly.newPlot\(\s*[\'"](.+?)[\'"]', self.raw_plot)
        substr = match.group(1)
        self.raw_plot = self.raw_plot.replace('ReplaceTheDiv', substr)

        self.plot_path = os.path.join(tempfile.gettempdir(),
                                      'temp_plot_name.html')
        with open(self.plot_path, "w", encoding="utf8") as f:
            f.write(self.raw_plot)

        return self.plot_path

    def build_sub_plots(self, grid, row, column, ptrace):  # pylint:disable=too-many-arguments
        """
        Draws plot in different plot canvases (not overlapping)

        params:
            grid (string): 'row' or 'col'. Plot are created in rows or columns
            row (int): number of rows (if row is selected)
            column (int): number of columns (if column is selected)
            ptrace (list of Plot Traces): list of all the different Plot Traces

        :return: the final html path containing the plot with the js_string for
        the interaction

        Console usage:
        .. code-block:: python
            # create the initial object
            settings = PlotSettings(plot_type, plot_properties, layout_properties)
            factory = PlotFactory(settings)
            # finally create the Figures
            path_to_output = factory.build_sub_plots('row', 1, gr, pl, tt)
        """

        if grid == 'row':

            fig = subplots.make_subplots(rows=row, cols=column)

            for i, itm in enumerate(ptrace):
                fig.add_trace(itm, row, i + 1)

        elif grid == 'col':

            fig = subplots.make_subplots(rows=row, cols=column)

            for i, itm in enumerate(ptrace):
                fig.add_trace(itm, i + 1, column)

        # set some configurations
        config = {'scrollZoom': True, 'editable': True}
        # first lines of additional html with the link to the local javascript
        self.raw_plot = '<head><meta charset="utf-8" /><script src="{}"></script>' \
                        '<script src="{}"></script></head>'.format(
            self.POLY_FILL_PATH, self.PLOTLY_PATH)
        # call the plot method without all the javascript code
        self.raw_plot += plotly.offline.plot(fig,
                                             output_type='div',
                                             include_plotlyjs=False,
                                             show_link=False,
                                             config=config)
        # insert callback for javascript events
        self.raw_plot += self.js_callback(self.raw_plot)

        # use regex to replace the string ReplaceTheDiv with the correct plot id generated by plotly
        match = re.search(r'Plotly.newPlot\(\s*[\'"](.+?)[\'"]', self.raw_plot)
        substr = match.group(1)
        self.raw_plot = self.raw_plot.replace('ReplaceTheDiv', substr)

        self.plot_path = os.path.join(tempfile.gettempdir(),
                                      'temp_plot_name.html')
        with open(self.plot_path, "w", encoding="utf8") as f:
            f.write(self.raw_plot)

        return self.plot_path

    def build_plot_dict(self) -> dict:
        """
        Returns a python dictionary of the whole Figure object.

        This method is not used in the plugin itself, but it is used in the
        testing suite to avoid finding the Figure parameters with weird regex
        from the html

        :return: dictionary of the Figure object
        """

        fig = go.Figure(data=self.trace, layout=self.layout)

        return fig.to_dict()
Exemplo n.º 52
0
 def fromLocalFile(cls, filename):
     return cls(QUrl.fromLocalFile(filename))
 def help(self):
     '''Display a help page'''
     url = QUrl.fromLocalFile(os.path.dirname(__file__) + "/index.html").toString()
     webbrowser.open(url, new=2)
Exemplo n.º 54
0
    def __init__(self, iface, parent=None):
        super(MainDialog, self).__init__(parent)
        QDialog.__init__(self)
        self.setupUi(self)
        self.iface = iface

        self.previewUrl = None
        self.layer_search_combo = None
        self.exporter_combo = None

        self.feedback = FeedbackDialog(self)
        self.feedback.setModal(True)

        stgs = QSettings()

        self.restoreGeometry(
            stgs.value("qgis2web/MainDialogGeometry",
                       QByteArray(),
                       type=QByteArray))

        self.verticalLayout_2.addStretch()
        self.horizontalLayout_6.addStretch()
        if stgs.value("qgis2web/previewOnStartup", Qt.Checked) == Qt.Checked:
            self.previewOnStartup.setCheckState(Qt.Checked)
        else:
            self.previewOnStartup.setCheckState(Qt.Unchecked)
        if stgs.value("qgis2web/closeFeedbackOnSuccess",
                      Qt.Checked) == Qt.Checked:
            self.closeFeedbackOnSuccess.setCheckState(Qt.Checked)
        else:
            self.closeFeedbackOnSuccess.setCheckState(Qt.Unchecked)
        self.previewFeatureLimit.setText(
            stgs.value("qgis2web/previewFeatureLimit", "1000"))

        self.appearanceParams.setSelectionMode(
            QAbstractItemView.SingleSelection)
        self.preview = None
        if webkit_available:
            widget = QWebView()
            self.preview = widget
            try:
                # if os.environ["TRAVIS"]:
                self.preview.setPage(WebPage())
            except Exception:
                print("Failed to set custom webpage")
            webview = self.preview.page()
            webview.setNetworkAccessManager(QgsNetworkAccessManager.instance())
            self.preview.settings().setAttribute(
                QWebSettings.DeveloperExtrasEnabled, True)
            self.preview.settings().setAttribute(
                QWebSettings.DnsPrefetchEnabled, True)
        else:
            widget = QTextBrowser()
            widget.setText(
                self.tr('Preview is not available since QtWebKit '
                        'dependency is missing on your system'))
        self.right_layout.insertWidget(0, widget)
        self.populateConfigParams(self)
        self.populate_layers_and_groups(self)
        self.populateLayerSearch()

        writer = WRITER_REGISTRY.createWriterFromProject()
        self.setStateToWriter(writer)

        self.exporter = EXPORTER_REGISTRY.createFromProject()
        self.exporter_combo.setCurrentIndex(
            self.exporter_combo.findText(self.exporter.name()))
        self.exporter_combo.currentIndexChanged.connect(
            self.exporterTypeChanged)

        self.toggleOptions()
        if webkit_available:
            if self.previewOnStartup.checkState() == Qt.Checked:
                self.autoUpdatePreview()
            self.buttonPreview.clicked.connect(self.previewMap)
        else:
            self.buttonPreview.setDisabled(True)
        QgsProject.instance().cleared.connect(self.reject)
        self.layersTree.model().dataChanged.connect(self.populateLayerSearch)
        self.ol3.clicked.connect(self.changeFormat)
        self.leaflet.clicked.connect(self.changeFormat)
        self.buttonExport.clicked.connect(self.saveMap)
        helpText = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                "helpFile.md")
        self.helpField.setSource(QUrl.fromLocalFile(helpText))
        if webkit_available:
            self.devConsole = QWebInspector(self.preview)
            self.devConsole.setFixedHeight(0)
            self.devConsole.setObjectName("devConsole")
            self.devConsole.setPage(self.preview.page())
            self.devConsole.hide()
            self.right_layout.insertWidget(1, self.devConsole)
        self.filter = devToggleFilter()
        self.filter.devToggle.connect(self.showHideDevConsole)
        self.installEventFilter(self.filter)
        self.setModal(False)
Exemplo n.º 55
0
    def exportAsPdf(self):
        self.repaintModel(controls=False)
        filename, fileFilter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model As PDF'), '',
                                                           self.tr('PDF files (*.pdf *.PDF)'))
        if not filename:
            return

        if not filename.lower().endswith('.pdf'):
            filename += '.pdf'

        totalRect = self.scene.itemsBoundingRect()
        totalRect.adjust(-10, -10, 10, 10)
        printerRect = QRectF(0, 0, totalRect.width(), totalRect.height())

        printer = QPrinter()
        printer.setOutputFormat(QPrinter.PdfFormat)
        printer.setOutputFileName(filename)
        printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel)
        printer.setFullPage(True)

        painter = QPainter(printer)
        self.scene.render(painter, printerRect, totalRect)
        painter.end()

        self.bar.pushMessage("", self.tr("Successfully exported model as PDF to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
        self.repaintModel(controls=True)
 def helpUrl(self):
     file = os.path.dirname(__file__) + '/index.html'
     if not os.path.exists(file):
         return ''
     return QUrl.fromLocalFile(file).toString(QUrl.FullyEncoded)
Exemplo n.º 57
0
    def exportAsPython(self):
        filename, filter = QFileDialog.getSaveFileName(self,
                                                       self.tr('Save Model As Python Script'), '',
                                                       self.tr('Processing scripts (*.py *.PY)'))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.model.asPythonCode()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)

        self.bar.pushMessage("", self.tr("Successfully exported model as python script to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5)
Exemplo n.º 58
0
def qgis_composer_html_renderer(impact_report, component):
    """HTML to PDF renderer using QGIS Composer.

    Render using qgis composer for a given impact_report data and component
    context for html input.

    :param impact_report: ImpactReport contains data about the report that is
        going to be generated.
    :type impact_report: safe.report.impact_report.ImpactReport

    :param component: Contains the component metadata and context for
        rendering the output.
    :type component:
        safe.report.report_metadata.QgisComposerComponentsMetadata

    :return: Whatever type of output the component should be.

    .. versionadded:: 4.0
    """
    context = component.context

    # QGIS3: not used
    # qgis_composition_context = impact_report.qgis_composition_context

    # create new layout with A4 portrait page
    layout = QgsPrintLayout(QgsProject.instance())
    page = QgsLayoutItemPage(layout)
    page.setPageSize('A4', orientation=QgsLayoutItemPage.Portrait)
    layout.pageCollection().addPage(page)

    if not context.html_frame_elements:
        # if no html frame elements at all, do not generate empty report.
        component.output = ''
        return component.output

    # Add HTML Frame
    for html_el in context.html_frame_elements:
        mode = html_el.get('mode')
        html_element = QgsLayoutItemHtml(layout)
        margin_left = html_el.get('margin_left', 10)
        margin_top = html_el.get('margin_top', 10)
        width = html_el.get('width', component.page_width - 2 * margin_left)
        height = html_el.get('height', component.page_height - 2 * margin_top)

        html_frame = QgsLayoutFrame(layout, html_element)
        html_frame.attemptSetSceneRect(
            QRectF(margin_left, margin_top, width, height))
        html_element.addFrame(html_frame)

        if html_element:
            if mode == 'text':
                text = html_el.get('text')
                text = text if text else ''
                html_element.setContentMode(QgsLayoutItemHtml.ManualHtml)
                html_element.setResizeMode(
                    QgsLayoutItemHtml.RepeatUntilFinished)
                html_element.setHtml(text)
                html_element.loadHtml()
            elif mode == 'url':
                url = html_el.get('url')
                html_element.setContentMode(QgsLayoutItemHtml.Url)
                html_element.setResizeMode(
                    QgsLayoutItemHtml.RepeatUntilFinished)
                qurl = QUrl.fromLocalFile(url)
                html_element.setUrl(qurl)

    # Attempt on removing blank page. Notes: We assume that the blank page
    # will always appears in the last x page(s), not in the middle.

    pc = layout.pageCollection()
    index = pc.pageCount()
    while pc.pageIsEmpty(index):
        pc.deletePage(index)
        index -= 1

    # process to output

    # in case output folder not specified
    if impact_report.output_folder is None:
        impact_report.output_folder = mkdtemp(dir=temp_dir())
    component_output_path = impact_report.component_absolute_output_path(
        component.key)
    component_output = None

    output_format = component.output_format

    doc_format = QgisComposerComponentsMetadata.OutputFormat.DOC_OUTPUT
    template_format = QgisComposerComponentsMetadata.OutputFormat.QPT
    if isinstance(output_format, list):
        component_output = []
        for i in range(len(output_format)):
            each_format = output_format[i]
            each_path = component_output_path[i]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    layout,
                    each_format,
                    component)
                component_output.append(result_path)
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, layout)
                component_output.append(result_path)
    elif isinstance(output_format, dict):
        component_output = {}
        for key, each_format in list(output_format.items()):
            each_path = component_output_path[key]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    layout,
                    each_format,
                    component)
                component_output[key] = result_path
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, layout)
                component_output[key] = result_path
    elif (output_format in
            QgisComposerComponentsMetadata.OutputFormat.SUPPORTED_OUTPUT):
        component_output = None

        if output_format in doc_format:
            result_path = create_qgis_pdf_output(
                impact_report,
                component_output_path,
                layout,
                output_format,
                component)
            component_output = result_path
        elif output_format == template_format:
            result_path = create_qgis_template_output(
                component_output_path, layout)
            component_output = result_path

    component.output = component_output

    return component.output
Exemplo n.º 59
0
 def fromLocalFile(cls, filename):
     return cls(QUrl.fromLocalFile(filename))
Exemplo n.º 60
0
def qgis_composer_renderer(impact_report, component):
    """Default Map Report Renderer using QGIS Composer.

    Render using qgis composer for a given impact_report data and component
    context.

    :param impact_report: ImpactReport contains data about the report that is
        going to be generated.
    :type impact_report: safe.report.impact_report.ImpactReport

    :param component: Contains the component metadata and context for
        rendering the output.
    :type component:
        safe.report.report_metadata.QgisComposerComponentsMetadata

    :return: Whatever type of output the component should be.

    .. versionadded:: 4.0
    """
    context = component.context
    qgis_composition_context = impact_report.qgis_composition_context

    # load composition object
    layout = QgsPrintLayout(QgsProject.instance())

    # load template
    main_template_folder = impact_report.metadata.template_folder

    # we do this condition in case custom template was found
    if component.template.startswith('../qgis-composer-templates/'):
        template_path = os.path.join(main_template_folder, component.template)
    else:
        template_path = component.template

    with open(template_path) as template_file:
        template_content = template_file.read()

    document = QtXml.QDomDocument()

    # Replace
    for k, v in context.substitution_map.items():
        template_content = template_content.replace('[{}]'.format(k), v)

    document.setContent(template_content)

    rwcontext = QgsReadWriteContext()
    load_status = layout.loadFromTemplate(
        document, rwcontext)

    if not load_status:
        raise TemplateLoadingError(
            tr('Error loading template: %s') % template_path)

    # replace image path
    for img in context.image_elements:
        item_id = img.get('id')
        path = img.get('path')
        image = layout_item(layout, item_id, QgsLayoutItemPicture)
        if image and path:
            image.setPicturePath(path)

    # replace html frame
    for html_el in context.html_frame_elements:
        item_id = html_el.get('id')
        mode = html_el.get('mode')
        html_element = layout_item(layout, item_id, QgsLayoutItemHtml)
        if html_element:
            if mode == 'text':
                text = html_el.get('text')
                text = text if text else ''
                html_element.setContentMode(QgsLayoutItemHtml.ManualHtml)
                html_element.setHtml(text)
                html_element.loadHtml()
            elif mode == 'url':
                url = html_el.get('url')
                html_element.setContentMode(QgsLayoutItemHtml.Url)
                qurl = QUrl.fromLocalFile(url)
                html_element.setUrl(qurl)

    original_crs = impact_report.impact_function.crs
    destination_crs = qgis_composition_context.map_settings.destinationCrs()
    coord_transform = QgsCoordinateTransform(original_crs,
                                             destination_crs,
                                             QgsProject.instance())

    # resize map extent
    for map_el in context.map_elements:
        item_id = map_el.get('id')
        split_count = map_el.get('grid_split_count')
        layers = [
            _layer for _layer in map_el.get('layers') if isinstance(
                _layer, QgsMapLayer)
        ]
        map_extent_option = map_el.get('extent')
        composer_map = layout_item(layout, item_id, QgsLayoutItemMap)

        for index, _layer in enumerate(layers):
            # we need to check whether the layer is registered or not
            registered_layer = (
                QgsProject.instance().mapLayer(_layer.id()))
            if registered_layer:
                if not registered_layer == _layer:
                    layers[index] = registered_layer
            else:
                QgsProject.instance().addMapLayer(_layer)

        """:type: qgis.core.QgsLayoutItemMap"""
        if composer_map:

            # Search for specified map extent in the template.
            min_x = composer_map.extent().xMinimum() if (
                impact_report.use_template_extent) else None
            min_y = composer_map.extent().yMinimum() if (
                impact_report.use_template_extent) else None
            max_x = composer_map.extent().xMaximum() if (
                impact_report.use_template_extent) else None
            max_y = composer_map.extent().yMaximum() if (
                impact_report.use_template_extent) else None

            composer_map.setKeepLayerSet(True)
            layer_set = [_layer for _layer in layers if isinstance(
                _layer, QgsMapLayer)]
            composer_map.setLayers(layer_set)
            map_overview_extent = None
            if map_extent_option and isinstance(
                    map_extent_option, QgsRectangle):
                # use provided map extent
                extent = coord_transform.transform(map_extent_option)
                for layer in layer_set:
                    layer_extent = coord_transform.transform(layer.extent())
                    if layer.name() == map_overview['id']:
                        map_overview_extent = layer_extent
            else:
                # if map extent not provided, try to calculate extent
                # from list of given layers. Combine it so all layers were
                # shown properly
                extent = QgsRectangle()
                extent.setMinimal()
                for layer in layer_set:
                    # combine extent if different layer is provided.
                    layer_extent = coord_transform.transform(layer.extent())
                    extent.combineExtentWith(layer_extent)
                    if layer.name() == map_overview['id']:
                        map_overview_extent = layer_extent

            width = extent.width()
            height = extent.height()
            longest_width = width if width > height else height
            half_length = longest_width / 2
            margin = half_length / 5
            center = extent.center()
            min_x = min_x or (center.x() - half_length - margin)
            max_x = max_x or (center.x() + half_length + margin)
            min_y = min_y or (center.y() - half_length - margin)
            max_y = max_y or (center.y() + half_length + margin)

            # noinspection PyCallingNonCallable
            square_extent = QgsRectangle(min_x, min_y, max_x, max_y)

            if component.key == 'population-infographic' and (
                    map_overview_extent):
                square_extent = map_overview_extent

            composer_map.zoomToExtent(square_extent)
            composer_map.invalidateCache()

            actual_extent = composer_map.extent()

            # calculate intervals for grid
            x_interval = actual_extent.width() / split_count
            composer_map.grid().setIntervalX(x_interval)
            y_interval = actual_extent.height() / split_count
            composer_map.grid().setIntervalY(y_interval)

    # calculate legend element
    for leg_el in context.map_legends:
        item_id = leg_el.get('id')
        title = leg_el.get('title')
        layers = [
            _layer for _layer in leg_el.get('layers') if isinstance(
                _layer, QgsMapLayer)
        ]
        symbol_count = leg_el.get('symbol_count')
        column_count = leg_el.get('column_count')

        legend = layout_item(layout, item_id, QgsLayoutItemLegend)
        """:type: qgis.core.QgsLayoutItemLegend"""
        if legend:
            # set column count
            if column_count:
                legend.setColumnCount(column_count)
            elif symbol_count <= 7:
                legend.setColumnCount(1)
            else:
                legend.setColumnCount(symbol_count / 7 + 1)

            # set legend title
            if title is not None and not impact_report.legend_layers:
                legend.setTitle(title)

            # set legend
            root_group = legend.model().rootGroup()
            for _layer in layers:
                # we need to check whether the layer is registered or not
                registered_layer = (
                    QgsProject.instance().mapLayer(_layer.id()))
                if registered_layer:
                    if not registered_layer == _layer:
                        _layer = registered_layer
                else:
                    QgsProject.instance().addMapLayer(_layer)
                # used for customizations
                tree_layer = root_group.addLayer(_layer)
                if impact_report.legend_layers or (
                        not impact_report.multi_exposure_impact_function):
                    QgsLegendRenderer.setNodeLegendStyle(
                        tree_layer, QgsLegendStyle.Hidden)
            legend.adjustBoxSize()
            legend.updateFilterByMap(False)

    # process to output

    # in case output folder not specified
    if impact_report.output_folder is None:
        impact_report.output_folder = mkdtemp(dir=temp_dir())

    output_format = component.output_format
    component_output_path = impact_report.component_absolute_output_path(
        component.key)
    component_output = None

    doc_format = QgisComposerComponentsMetadata.OutputFormat.DOC_OUTPUT
    template_format = QgisComposerComponentsMetadata.OutputFormat.QPT
    if isinstance(output_format, list):
        component_output = []
        for i in range(len(output_format)):
            each_format = output_format[i]
            each_path = component_output_path[i]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    layout,
                    each_format,
                    component)
                component_output.append(result_path)
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, layout)
                component_output.append(result_path)
    elif isinstance(output_format, dict):
        component_output = {}
        for key, each_format in list(output_format.items()):
            each_path = component_output_path[key]

            if each_format in doc_format:
                result_path = create_qgis_pdf_output(
                    impact_report,
                    each_path,
                    layout,
                    each_format,
                    component)
                component_output[key] = result_path
            elif each_format == template_format:
                result_path = create_qgis_template_output(
                    each_path, layout)
                component_output[key] = result_path
    elif (output_format in
            QgisComposerComponentsMetadata.OutputFormat.SUPPORTED_OUTPUT):
        component_output = None

        if output_format in doc_format:
            result_path = create_qgis_pdf_output(
                impact_report,
                component_output_path,
                layout,
                output_format,
                component)
            component_output = result_path
        elif output_format == template_format:
            result_path = create_qgis_template_output(
                component_output_path, layout)
            component_output = result_path

    component.output = component_output

    return component.output