def testMatchToSymbols(self):
        """
        Test QgsCategorizedSymbolRender.matchToSymbols
        """
        renderer = QgsCategorizedSymbolRenderer()
        renderer.setClassAttribute('x')

        symbol_a = createMarkerSymbol()
        symbol_a.setColor(QColor(255, 0, 0))
        renderer.addCategory(QgsRendererCategory('a', symbol_a, 'a'))
        symbol_b = createMarkerSymbol()
        symbol_b.setColor(QColor(0, 255, 0))
        renderer.addCategory(QgsRendererCategory('b', symbol_b, 'b'))
        symbol_c = createMarkerSymbol()
        symbol_c.setColor(QColor(0, 0, 255))
        renderer.addCategory(QgsRendererCategory('c ', symbol_c, 'c'))

        matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(
            None, QgsSymbol.Marker)
        self.assertEqual(matched, 0)

        style = QgsStyle()
        symbol_a = createMarkerSymbol()
        symbol_a.setColor(QColor(255, 10, 10))
        self.assertTrue(style.addSymbol('a', symbol_a))
        symbol_B = createMarkerSymbol()
        symbol_B.setColor(QColor(10, 255, 10))
        self.assertTrue(style.addSymbol('B ', symbol_B))
        symbol_b = createFillSymbol()
        symbol_b.setColor(QColor(10, 255, 10))
        self.assertTrue(style.addSymbol('b', symbol_b))
        symbol_C = createLineSymbol()
        symbol_C.setColor(QColor(10, 255, 10))
        self.assertTrue(style.addSymbol('C', symbol_C))
        symbol_C = createMarkerSymbol()
        symbol_C.setColor(QColor(10, 255, 10))
        self.assertTrue(style.addSymbol(' ----c/- ', symbol_C))

        # non-matching symbol type
        matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(
            style, QgsSymbol.Line)
        self.assertEqual(matched, 0)
        self.assertEqual(unmatched_cats, ['a', 'b', 'c '])
        self.assertEqual(unmatched_symbols, [' ----c/- ', 'B ', 'C', 'a', 'b'])

        # exact match
        matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(
            style, QgsSymbol.Marker)
        self.assertEqual(matched, 1)
        self.assertEqual(unmatched_cats, ['b', 'c '])
        self.assertEqual(unmatched_symbols, [' ----c/- ', 'B ', 'C', 'b'])

        # make sure symbol was applied
        context = QgsRenderContext()
        renderer.startRender(context, QgsFields())
        symbol, ok = renderer.symbolForValue2('a')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#ff0a0a')
        renderer.stopRender(context)

        # case insensitive match
        matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(
            style, QgsSymbol.Marker, False)
        self.assertEqual(matched, 2)
        self.assertEqual(unmatched_cats, ['c '])
        self.assertEqual(unmatched_symbols, [' ----c/- ', 'C', 'b'])

        # make sure symbols were applied
        context = QgsRenderContext()
        renderer.startRender(context, QgsFields())
        symbol, ok = renderer.symbolForValue2('a')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#ff0a0a')
        symbol, ok = renderer.symbolForValue2('b')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#0aff0a')
        renderer.stopRender(context)

        # case insensitive match
        matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(
            style, QgsSymbol.Marker, False)
        self.assertEqual(matched, 2)
        self.assertEqual(unmatched_cats, ['c '])
        self.assertEqual(unmatched_symbols, [' ----c/- ', 'C', 'b'])

        # make sure symbols were applied
        context = QgsRenderContext()
        renderer.startRender(context, QgsFields())
        symbol, ok = renderer.symbolForValue2('a')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#ff0a0a')
        symbol, ok = renderer.symbolForValue2('b')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#0aff0a')
        renderer.stopRender(context)

        # tolerant match
        matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(
            style, QgsSymbol.Marker, True, True)
        self.assertEqual(matched, 2)
        self.assertEqual(unmatched_cats, ['b'])
        self.assertEqual(unmatched_symbols, ['B ', 'C', 'b'])

        # make sure symbols were applied
        context = QgsRenderContext()
        renderer.startRender(context, QgsFields())
        symbol, ok = renderer.symbolForValue2('a')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#ff0a0a')
        symbol, ok = renderer.symbolForValue2('c ')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#0aff0a')
        renderer.stopRender(context)

        # tolerant match, case insensitive
        matched, unmatched_cats, unmatched_symbols = renderer.matchToSymbols(
            style, QgsSymbol.Marker, False, True)
        self.assertEqual(matched, 3)
        self.assertFalse(unmatched_cats)
        self.assertEqual(unmatched_symbols, ['C', 'b'])

        # make sure symbols were applied
        context = QgsRenderContext()
        renderer.startRender(context, QgsFields())
        symbol, ok = renderer.symbolForValue2('a')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#ff0a0a')
        symbol, ok = renderer.symbolForValue2('b')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#0aff0a')
        symbol, ok = renderer.symbolForValue2('c ')
        self.assertTrue(ok)
        self.assertEqual(symbol.color().name(), '#0aff0a')
        renderer.stopRender(context)
    def testFilter(self):
        """Test filter creation"""
        renderer = QgsCategorizedSymbolRenderer()
        renderer.setClassAttribute('field')

        renderer.addCategory(
            QgsRendererCategory('a', createMarkerSymbol(), 'a'))
        renderer.addCategory(
            QgsRendererCategory('b', createMarkerSymbol(), 'b'))
        renderer.addCategory(
            QgsRendererCategory('c', createMarkerSymbol(), 'c'))
        # add default category
        renderer.addCategory(
            QgsRendererCategory('', createMarkerSymbol(), 'default'))

        fields = QgsFields()
        fields.append(QgsField('field', QVariant.String))
        fields.append(QgsField('num', QVariant.Double))

        self.assertEqual(renderer.filter(fields), '')
        # remove categories, leaving default
        assert renderer.updateCategoryRenderState(0, False)
        self.assertEqual(renderer.filter(fields),
                         "(\"field\") NOT IN ('a') OR (\"field\") IS NULL")
        assert renderer.updateCategoryRenderState(1, False)
        self.assertEqual(
            renderer.filter(fields),
            "(\"field\") NOT IN ('a','b') OR (\"field\") IS NULL")
        assert renderer.updateCategoryRenderState(2, False)
        self.assertEqual(
            renderer.filter(fields),
            "(\"field\") NOT IN ('a','b','c') OR (\"field\") IS NULL")
        # remove default category
        assert renderer.updateCategoryRenderState(3, False)
        self.assertEqual(renderer.filter(fields), "FALSE")
        # add back other categories, leaving default disabled
        assert renderer.updateCategoryRenderState(0, True)
        self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a')")
        assert renderer.updateCategoryRenderState(1, True)
        self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a','b')")
        assert renderer.updateCategoryRenderState(2, True)
        self.assertEqual(renderer.filter(fields),
                         "(\"field\") IN ('a','b','c')")

        renderer.deleteAllCategories()
        # just default category
        renderer.addCategory(
            QgsRendererCategory('', createMarkerSymbol(), 'default'))
        self.assertEqual(renderer.filter(fields), '')
        assert renderer.updateCategoryRenderState(0, False)
        self.assertEqual(renderer.filter(fields), 'FALSE')

        renderer.deleteAllCategories()
        # no default category
        renderer.addCategory(
            QgsRendererCategory('a', createMarkerSymbol(), 'a'))
        renderer.addCategory(
            QgsRendererCategory('b', createMarkerSymbol(), 'b'))
        renderer.addCategory(
            QgsRendererCategory('c', createMarkerSymbol(), 'c'))
        self.assertEqual(renderer.filter(fields),
                         "(\"field\") IN ('a','b','c')")
        assert renderer.updateCategoryRenderState(0, False)
        self.assertEqual(renderer.filter(fields), "(\"field\") IN ('b','c')")
        assert renderer.updateCategoryRenderState(2, False)
        self.assertEqual(renderer.filter(fields), "(\"field\") IN ('b')")
        assert renderer.updateCategoryRenderState(1, False)
        self.assertEqual(renderer.filter(fields), "FALSE")

        renderer.deleteAllCategories()
        renderer.setClassAttribute('num')
        # numeric categories
        renderer.addCategory(QgsRendererCategory(1, createMarkerSymbol(), 'a'))
        renderer.addCategory(QgsRendererCategory(2, createMarkerSymbol(), 'b'))
        renderer.addCategory(QgsRendererCategory(3, createMarkerSymbol(), 'c'))
        self.assertEqual(renderer.filter(fields), '(\"num\") IN (1,2,3)')
        assert renderer.updateCategoryRenderState(0, False)
        self.assertEqual(renderer.filter(fields), "(\"num\") IN (2,3)")
        assert renderer.updateCategoryRenderState(2, False)
        self.assertEqual(renderer.filter(fields), "(\"num\") IN (2)")
        assert renderer.updateCategoryRenderState(1, False)
        self.assertEqual(renderer.filter(fields), "FALSE")
    def testConvertFromCategorisedRenderer(self):
        # Test converting categorised renderer to rule based

        # First, try with a field based category (id)
        cats = []
        cats.append(QgsRendererCategory(1, QgsMarkerSymbol(), "id 1"))
        cats.append(QgsRendererCategory(2, QgsMarkerSymbol(), "id 2"))
        cats.append(QgsRendererCategory('a\'b', QgsMarkerSymbol(), "id a'b"))
        cats.append(QgsRendererCategory('a\nb', QgsMarkerSymbol(), "id a\\nb"))
        cats.append(QgsRendererCategory('a\\b', QgsMarkerSymbol(),
                                        "id a\\\\b"))
        cats.append(QgsRendererCategory('a\tb', QgsMarkerSymbol(), "id a\\tb"))
        cats.append(QgsRendererCategory(['c', 'd'], QgsMarkerSymbol(), "c/d"))
        c = QgsCategorizedSymbolRenderer("id", cats)

        r = QgsRuleBasedRenderer.convertFromRenderer(c)
        self.assertEqual(len(r.rootRule().children()), 7)
        self.assertEqual(r.rootRule().children()[0].filterExpression(),
                         '"id" = 1')
        self.assertEqual(r.rootRule().children()[1].filterExpression(),
                         '"id" = 2')
        self.assertEqual(r.rootRule().children()[2].filterExpression(),
                         '"id" = \'a\'\'b\'')
        self.assertEqual(r.rootRule().children()[3].filterExpression(),
                         '"id" = \'a\\nb\'')
        self.assertEqual(r.rootRule().children()[4].filterExpression(),
                         '"id" = \'a\\\\b\'')
        self.assertEqual(r.rootRule().children()[5].filterExpression(),
                         '"id" = \'a\\tb\'')
        self.assertEqual(r.rootRule().children()[6].filterExpression(),
                         '"id" IN (\'c\',\'d\')')

        # Next try with an expression based category
        cats = []
        cats.append(QgsRendererCategory(1, QgsMarkerSymbol(), "result 1"))
        cats.append(QgsRendererCategory(2, QgsMarkerSymbol(), "result 2"))
        cats.append(
            QgsRendererCategory([3, 4], QgsMarkerSymbol(), "result 3/4"))
        c = QgsCategorizedSymbolRenderer("id + 1", cats)

        r = QgsRuleBasedRenderer.convertFromRenderer(c)
        self.assertEqual(len(r.rootRule().children()), 3)
        self.assertEqual(r.rootRule().children()[0].filterExpression(),
                         'id + 1 = 1')
        self.assertEqual(r.rootRule().children()[1].filterExpression(),
                         'id + 1 = 2')
        self.assertEqual(r.rootRule().children()[2].filterExpression(),
                         'id + 1 IN (3,4)')

        # Last try with an expression which is just a quoted field name
        cats = []
        cats.append(QgsRendererCategory(1, QgsMarkerSymbol(), "result 1"))
        cats.append(QgsRendererCategory(2, QgsMarkerSymbol(), "result 2"))
        cats.append(
            QgsRendererCategory([3, 4], QgsMarkerSymbol(), "result 3/4"))
        c = QgsCategorizedSymbolRenderer('"id"', cats)

        r = QgsRuleBasedRenderer.convertFromRenderer(c)
        self.assertEqual(len(r.rootRule().children()), 3)
        self.assertEqual(r.rootRule().children()[0].filterExpression(),
                         '"id" = 1')
        self.assertEqual(r.rootRule().children()[1].filterExpression(),
                         '"id" = 2')
        self.assertEqual(r.rootRule().children()[2].filterExpression(),
                         '"id" IN (3,4)')
Beispiel #4
0
    def legend_test(self):
        self.atlas_map.setAtlasDriven(True)
        self.atlas_map.setAtlasScalingMode(QgsLayoutItemMap.Auto)
        self.atlas_map.setAtlasMargin(0.10)

        # add a point layer
        ptLayer = QgsVectorLayer(
            "Point?crs=epsg:4326&field=attr:int(1)&field=label:string(20)",
            "points", "memory")

        pr = ptLayer.dataProvider()
        f1 = QgsFeature(1)
        f1.initAttributes(2)
        f1.setAttribute(0, 1)
        f1.setAttribute(1, "Test label 1")
        f1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-0.638, 48.954)))
        f2 = QgsFeature(2)
        f2.initAttributes(2)
        f2.setAttribute(0, 2)
        f2.setAttribute(1, "Test label 2")
        f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(-1.682, 48.550)))
        pr.addFeatures([f1, f2])

        # categorized symbology
        r = QgsCategorizedSymbolRenderer("attr", [
            QgsRendererCategory(
                1,
                QgsMarkerSymbol.createSimple({
                    "color": "255,0,0",
                    'outline_color': 'black'
                }), "red"),
            QgsRendererCategory(
                2,
                QgsMarkerSymbol.createSimple({
                    "color": "0,0,255",
                    'outline_color': 'black'
                }), "blue")
        ])
        ptLayer.setRenderer(r)

        QgsProject.instance().addMapLayer(ptLayer)

        # add the point layer to the map settings
        layers = self.layers
        layers = [ptLayer] + layers
        self.atlas_map.setLayers(layers)
        self.overview.setLayers(layers)

        # add a legend
        legend = QgsLayoutItemLegend(self.layout)
        legend.setTitle("Legend")
        legend.attemptMove(QgsLayoutPoint(200, 100))
        # sets the legend filter parameter
        legend.setLinkedMap(self.atlas_map)
        legend.setLegendFilterOutAtlas(True)
        self.layout.addLayoutItem(legend)

        self.atlas.beginRender()

        self.atlas.seekTo(0)
        self.mLabel1.adjustSizeToText()

        checker = QgsLayoutChecker('atlas_legend', self.layout)
        myTestResult, myMessage = checker.testLayout()
        self.report += checker.report()
        self.assertTrue(myTestResult, myMessage)

        self.atlas.endRender()

        # restore state
        self.atlas_map.setLayers([layers[1]])
        self.layout.removeLayoutItem(legend)
        QgsProject.instance().removeMapLayer(ptLayer.id())
    def on_classifyPushButton_clicked(self):

        input_raster_layer_name = self.rasterLayerComboBox.currentText()
        input_vector_layer_name = self.vectorLayerComboBox.currentText()

        # 调用QGIS区域统计工具

        processing.run(
            'qgis:zonalstatistics', {
                'INPUT_RASTER': input_raster_layer_name,
                'RASTER_BAND': 1,
                'INPUT_VECTOR': input_vector_layer_name,
                'COLUMN_PREFIX': 'Band1_',
                'STATS': 2
            })
        processing.run(
            'qgis:zonalstatistics', {
                'INPUT_RASTER': input_raster_layer_name,
                'RASTER_BAND': 2,
                'INPUT_VECTOR': input_vector_layer_name,
                'COLUMN_PREFIX': 'Band2_',
                'STATS': 2
            })
        processing.run(
            'qgis:zonalstatistics', {
                'INPUT_RASTER': input_raster_layer_name,
                'RASTER_BAND': 3,
                'INPUT_VECTOR': input_vector_layer_name,
                'COLUMN_PREFIX': 'Band3_',
                'STATS': 2
            })
        # QgsProject.instance().addMapLayer(vector_layer)

        # 获取计算结果

        input_vector_layer = QgsProject.instance().mapLayersByName(
            input_vector_layer_name)[0]

        features = input_vector_layer.getFeatures()
        feature_id_list = []
        feature_band_list = []
        for feature in features:
            feature_id_list.append(feature.id())
            feature_band_list.append([
                feature['Band1_mean'], feature['Band2_mean'],
                feature['Band3_mean']
            ])

        # 聚类

        cluster_num = self.spinBox.value()
        cluster_result = cluster(np.array(feature_band_list))

        # 添加聚类结果到字段,字段存在则删除。只要涉及字段操作,每次操作都要更新字段

        field_name_list = [
            field.name() for field in input_vector_layer.fields()
        ]
        if 'cluster_id' in field_name_list:
            input_vector_layer.dataProvider().deleteAttributes(
                [field_name_list.index('cluster_id')])
            input_vector_layer.updateFields()

        input_vector_layer.dataProvider().addAttributes(
            [QgsField("cluster_id", QVariant.Int)])
        input_vector_layer.updateFields()
        field_name_list = [
            field.name() for field in input_vector_layer.fields()
        ]
        print(field_name_list)
        cluster_id_field_index = field_name_list.index('cluster_id')

        for index, fid in enumerate(feature_id_list):
            attrs = {cluster_id_field_index: int(cluster_result[index])}
            change_result = input_vector_layer.dataProvider(
            ).changeAttributeValues({fid: attrs})
            print(fid)
            print(attrs)
            print(change_result)
        input_vector_layer.updateFields()

        # 符号化

        categorized_renderer = QgsCategorizedSymbolRenderer()
        categorized_renderer.setClassAttribute('cluster_id')

        for cluster_id in range(cluster_num):
            fill_symbol = QgsFillSymbol.createSimple({})
            fill_symbol.setColor(
                QtGui.QColor(*np.random.randint(0, 256, 3), 200))
            categorized_renderer.addCategory(
                QgsRendererCategory(cluster_id, fill_symbol,
                                    f'cluster {cluster_id}'))
        input_vector_layer.setRenderer(categorized_renderer)
    def run(self):
        """Run method that performs all the real work"""
        
        layers = self.iface.mapCanvas().layers()
        layer_list = []
        self.dlg.layerComboBox.clear()
        for layer in layers:
            layer_list.append(layer.name())
        self.dlg.layerComboBox.addItems(layer_list)
        # TODO: Make the active layer the selected item in combo box  aLayer = qgis.utils.iface.activeLayer()
        
        # TODO: Add signal to update toleranceSpinBox.suffix (Degrees) from layerComboBox.crs.mapUnits when layer is selected:
        #my_UnitType = { 0: 'Meters', 1: 'Feet', 2: 'Degrees', 7: 'NauticalMiles', 8: 'Kilometers', 9: 'Yards', 10: 'Miles', 3: 'UnknownUnit'}
        #suffix = my_UnitType[aLayer.crs().mapUnits()]
        
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            if self.checkNetworkXModule() < 0:
                return -4
            import networkx as nx
            
            layerName = self.dlg.layerComboBox.currentText()
            try:
                aLayer = QgsProject.instance().mapLayersByName(layerName)[0]
            except:
                self.iface.messageBar().pushMessage("Error", "Failed to load layer!", level=Qgis.Critical)
                return -1

            try:

                previousEditingMode = True
                if not aLayer.isEditable():
                    aLayer.startEditing()
                    #self.iface.messageBar().pushMessage("Info", "Layer " + aLayer.name() + " needs to be in edit mode", level=Qgis.Info)
                    #self.iface.messageBar().pushMessage("Error", "Layer " + aLayer.name() + " needs to be in edit mode", level=Qgis.Critical)
                    #return -2
                    previousEditingMode = False
                     
                attrIdx = self.getAttributeIndex(aLayer)
                if attrIdx < 0:
                    return -3  

                progressMessageBar = self.iface.messageBar().createMessage("Creating network graph...")
                progress = QProgressBar()
                progress.setMaximum(aLayer.featureCount())
                progress.setAlignment(Qt.AlignLeft|Qt.AlignVCenter)
                progressMessageBar.layout().addWidget(progress)
                self.iface.messageBar().pushWidget(progressMessageBar, Qgis.Info)          
                
                G = nx.Graph()

                aLayer.beginEditCommand("Clear group attribute, create graph")
                # construct undirected graph
                tolerance = self.dlg.toleranceSpinBox.value()
                if tolerance == 0:
                    tolerance = 0.000001
                count = 0
                for feat in aLayer.getFeatures():
                    count += 1
                    progress.setValue(count)
                    done = aLayer.changeAttributeValue(feat.id(), attrIdx, -1)
                    geom = feat.geometry()
                    QgsGeometry.convertToSingleType(geom)       # QGIS 3.x seems to load single LineString as MultiLineString??
                    line = geom.asPolyline()
                    
                    for i in range(len(line)-1):
                        G.add_edges_from([((int(line[i][0]/tolerance), int(line[i][1]/tolerance)), (int(line[i+1][0]/tolerance), int(line[i+1][1]/tolerance)), 
                                          {'fid': feat.id()})])     # first scale by tolerance, then convert to int.  Before doing this, there were problems (in NetworkX v1) with floats not equating, thus creating disconnects that weren't there.
                    if count % 100 == 0:
                        QApplication.processEvents()      # keep the UI responsive, every 100 features
                        #TODO: check to see if Esc pressed

                aLayer.endEditCommand()
                
                self.iface.messageBar().pushMessage("Finding connected subgraphs, please wait...",  level=Qgis.Warning)     # WARNING - to highlight the next stage, where we cannot show progress
                QApplication.processEvents()
                connected_components = list(G.subgraph(c) for c in nx.connected_components(G)) # this takes a long time.  TODO: how to show progress?
                self.iface.messageBar().pushMessage("Updating group attribute...",  level=Qgis.Info)
                QApplication.processEvents()
                          
                # gather edges and components to which they belong
                fid_comp = {}
                for i, graph in enumerate(connected_components):
                   for edge in graph.edges(data=True):
                       fid_comp[edge[2].get('fid', None)] = i
                
                # write output to csv file
                #with open('C:/Tmp/Components.csv', 'wb') as f:
                #    w = csv.DictWriter(f, fieldnames=['fid', 'group'])
                #    w.writeheader()
                #    for (fid, group) in fid_comp.items():
                #        w.writerow({'fid': fid, 'group': group})
                
                aLayer.beginEditCommand("Update group attribute")
                for (fid, group) in fid_comp.items():
                    done = aLayer.changeAttributeValue(fid, attrIdx, group)
                aLayer.endEditCommand()
                
                groups = list(set(fid_comp.values()))            
                if self.dlg.stylingCheckBox.isChecked():
                    aLayer.beginEditCommand("Update layer styling")
                    categories = []
                    firstCat = True
                    for cat in groups:
                        symbol = QgsSymbol.defaultSymbol(aLayer.geometryType())
                        symbol.setColor(QColor(randint(0,255), randint(0,255), randint(0,255)))
                        if firstCat:
                            firstCat = False
                        else:
                            symbol.setWidth(symbol.width()*5)
                        category = QgsRendererCategory(cat, symbol, "%d" % cat)
                        categories.append(category)

                    field = self.dlg.attributeNameEditBox.text()
                    renderer = QgsCategorizedSymbolRenderer(field, categories)
                    aLayer.setRenderer(renderer)

#                    if self.iface.mapCanvas().isCachingEnabled():
#                        aLayer.setCacheImage(None)
#                    else:
#                        self.iface.mapCanvas().refresh()
                    aLayer.triggerRepaint()
                    aLayer.endEditCommand()            
                   
                self.iface.messageBar().clearWidgets()   
                self.iface.messageBar().pushMessage("Found main network and %d disconnected islands in layer %s" % (len(groups)-1, aLayer.name()),  level=Qgis.Success)

                aLayer.commitChanges()
#                if not previousEditingMode: 
    
            except Exception as e:
                self.iface.messageBar().pushMessage("Error", "Exception caught: %s.  Please report an issue to the author of the plugin." % repr(e), level=Qgis.Critical)
                
Beispiel #7
0
    def stylePoly(self, layer, metric: str):
        """
        Style isochrone polygon layer.

        :param QgsVectorLayer layer: Polygon layer to be styled.
        :param str metric: distance or time.
        """
        field = layer.fields().lookupField('contour')
        unique_values = sorted(layer.uniqueValues(field))

        colors = {
            "distance": {
                0: QColor('#FCF0EE'),
                1: QColor('#F9E1DC'),
                2: QColor('#F6D2CB'),
                3: QColor('#F3C3BA'),
                4: QColor('#F0B3A8'),
                5: QColor('#EDA396'),
                6: QColor('#EA9485'),
                7: QColor('#E78573'),
                8: QColor('#E47662'),
                9: QColor('#E16651')
            },
            "time": {
                0: QColor('#2b83ba'),
                1: QColor('#64abb0'),
                2: QColor('#9dd3a7'),
                3: QColor('#c7e9ad'),
                4: QColor('#edf8b9'),
                5: QColor('#ffedaa'),
                6: QColor('#fec980'),
                7: QColor('#f99e59'),
                8: QColor('#e85b3a'),
                9: QColor('#d7191c')
            }
        }

        categories = []

        for cid, unique_value in enumerate(unique_values):
            # initialize the default symbol for this geometry type
            symbol = QgsSymbol.defaultSymbol(layer.geometryType())

            # configure a symbol layer
            symbol_layer = QgsSimpleFillSymbolLayer(
                color=colors[metric][cid], strokeColor=QColor('#000000'))

            # replace default symbol layer with the configured one
            if symbol_layer is not None:
                symbol.changeSymbolLayer(0, symbol_layer)

            # create renderer object
            category = QgsRendererCategory(unique_value, symbol,
                                           str(unique_value) + ' mins')
            # entry for the list of category items
            categories.append(category)

        # create renderer object
        renderer = QgsCategorizedSymbolRenderer('contour', categories)

        # assign the created renderer to the layer
        if renderer is not None:
            layer.setRenderer(renderer)
        layer.setOpacity(0.5)

        layer.triggerRepaint()
Beispiel #8
0
def open_file(dialog: QDialog = None,
              osm_file: str = None,
              output_geom_types: list = None,
              white_list_column: dict = None,
              key: Union[str, List[str]] = None,
              layer_name: str = "OsmFile",
              config_outputs: dict = None,
              output_dir: str = None,
              output_format: Format = None,
              final_query: str = None,
              prefix_file: str = None,
              subset: bool = False,
              subset_query: str = None,
              feedback: QgsFeedback = None) -> int:
    """
    Open an osm file.

    Memory layer if no output directory is set, or Geojson in the output
    directory.

    :param final_query: The query where the file comes from. Might be empty if
    it's a local OSM file.
    :type final_query: basestring
    """

    if output_geom_types is None:
        output_geom_types = OSM_LAYERS
    # Legacy, waiting to remove the OsmParser for QGIS >= 3.6
    # Change in osm_file_dialog.py L131 too
    output_geom_legacy = [geom.value.lower() for geom in output_geom_types]
    if not white_list_column:
        white_list_column = None

    LOGGER.info('The OSM file is: {}'.format(osm_file))
    if feedback:
        if feedback.isCanceled():
            return None

    # Parsing the file
    osm_parser = OsmParser(osm_file=osm_file,
                           layers=output_geom_legacy,
                           output_format=output_format,
                           output_dir=output_dir,
                           prefix_file=prefix_file,
                           layer_name=layer_name,
                           key=key,
                           white_list_column=white_list_column,
                           subset=subset,
                           subset_query=subset_query,
                           feedback=feedback)

    if dialog:
        osm_parser.signalText.connect(dialog.set_progress_text)
        osm_parser.signalPercentage.connect(dialog.set_progress_percentage)

    start_time = time.time()
    layers = osm_parser.processing_parse()
    elapsed_time = time.time() - start_time
    parser_time = time.strftime("%Hh %Mm %Ss", time.gmtime(elapsed_time))
    LOGGER.info('The OSM parser took: {}'.format(parser_time))

    if feedback:
        if feedback.isCanceled():
            return None

    # Finishing the process with an output format or memory layer
    num_layers = 0

    for i, (layer, item) in enumerate(layers.items()):
        if dialog:
            dialog.set_progress_percentage(i / len(layers) * 100)
        QApplication.processEvents()
        if item['featureCount'] and (LayerType(layer.capitalize())
                                     in output_geom_types):

            final_layer_name = layer_name
            # If configOutputs is not None (from My Queries)
            if config_outputs:
                if config_outputs[layer]['namelayer']:
                    final_layer_name = config_outputs[layer]['namelayer']

            new_layer = item['vector_layer']
            new_layer.setName(final_layer_name)

            # Try to set styling if defined
            if config_outputs and config_outputs[layer]['style']:
                new_layer.loadNamedStyle(config_outputs[layer]['style'])
            else:
                if "colour" in item['tags']:
                    index = item['tags'].index('colour')
                    colors = new_layer.uniqueValues(index)
                    categories = []
                    for value in colors:
                        if str(value) == 'None':
                            value = ''
                        if layer in ['lines', 'multilinestrings']:
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.LineGeometry)
                        elif layer == "points":
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.PointGeometry)
                        elif layer == "multipolygons":
                            symbol = QgsSymbol.defaultSymbol(
                                QgsWkbTypes.PolygonGeometry)
                        symbol.setColor(QColor(value))
                        category = QgsRendererCategory(str(value), symbol,
                                                       str(value))
                        categories.append(category)

                    renderer = QgsCategorizedSymbolRenderer(
                        "colour", categories)
                    new_layer.setRenderer(renderer)

            # Add action about OpenStreetMap
            actions.add_actions(new_layer, item['tags'])

            QgsProject.instance().addMapLayer(new_layer)

            if final_query:
                QgsExpressionContextUtils.setLayerVariable(
                    new_layer, 'quickosm_query', final_query)
                actions.add_relaunch_action(new_layer, final_layer_name)
                if dialog:
                    dialog.iface.addCustomActionForLayer(
                        dialog.reload_action, new_layer)

            metadata = QgsLayerMetadata()
            metadata.setRights([tr("© OpenStreetMap contributors")])
            metadata.setLicenses(['https://openstreetmap.org/copyright'])
            new_layer.setMetadata(metadata)
            num_layers += 1

    return num_layers
Beispiel #9
0
    def testLegendRenderWithMapTheme(self):
        """Test rendering legends linked to map themes"""
        QgsProject.instance().removeAllMapLayers()

        point_path = os.path.join(TEST_DATA_DIR, 'points.shp')
        point_layer = QgsVectorLayer(point_path, 'points', 'ogr')
        line_path = os.path.join(TEST_DATA_DIR, 'lines.shp')
        line_layer = QgsVectorLayer(line_path, 'lines', 'ogr')
        QgsProject.instance().clear()
        QgsProject.instance().addMapLayers([point_layer, line_layer])

        marker_symbol = QgsMarkerSymbol.createSimple({
            'color': '#ff0000',
            'outline_style': 'no',
            'size': '5'
        })
        point_layer.setRenderer(QgsSingleSymbolRenderer(marker_symbol))
        point_layer.styleManager().addStyleFromLayer("red")

        line_symbol = QgsLineSymbol.createSimple({
            'color': '#ff0000',
            'line_width': '2'
        })
        line_layer.setRenderer(QgsSingleSymbolRenderer(line_symbol))
        line_layer.styleManager().addStyleFromLayer("red")

        red_record = QgsMapThemeCollection.MapThemeRecord()
        point_red_record = QgsMapThemeCollection.MapThemeLayerRecord(
            point_layer)
        point_red_record.usingCurrentStyle = True
        point_red_record.currentStyle = 'red'
        red_record.addLayerRecord(point_red_record)
        line_red_record = QgsMapThemeCollection.MapThemeLayerRecord(line_layer)
        line_red_record.usingCurrentStyle = True
        line_red_record.currentStyle = 'red'
        red_record.addLayerRecord(line_red_record)
        QgsProject.instance().mapThemeCollection().insert('red', red_record)

        marker_symbol1 = QgsMarkerSymbol.createSimple({
            'color': '#0000ff',
            'outline_style': 'no',
            'size': '5'
        })
        marker_symbol2 = QgsMarkerSymbol.createSimple({
            'color': '#0000ff',
            'name': 'diamond',
            'outline_style': 'no',
            'size': '5'
        })
        marker_symbol3 = QgsMarkerSymbol.createSimple({
            'color': '#0000ff',
            'name': 'rectangle',
            'outline_style': 'no',
            'size': '5'
        })

        point_layer.setRenderer(
            QgsCategorizedSymbolRenderer('Class', [
                QgsRendererCategory('B52', marker_symbol1, ''),
                QgsRendererCategory('Biplane', marker_symbol2, ''),
                QgsRendererCategory('Jet', marker_symbol3, ''),
            ]))
        point_layer.styleManager().addStyleFromLayer("blue")

        line_symbol = QgsLineSymbol.createSimple({
            'color': '#0000ff',
            'line_width': '2'
        })
        line_layer.setRenderer(QgsSingleSymbolRenderer(line_symbol))
        line_layer.styleManager().addStyleFromLayer("blue")

        blue_record = QgsMapThemeCollection.MapThemeRecord()
        point_blue_record = QgsMapThemeCollection.MapThemeLayerRecord(
            point_layer)
        point_blue_record.usingCurrentStyle = True
        point_blue_record.currentStyle = 'blue'
        blue_record.addLayerRecord(point_blue_record)
        line_blue_record = QgsMapThemeCollection.MapThemeLayerRecord(
            line_layer)
        line_blue_record.usingCurrentStyle = True
        line_blue_record.currentStyle = 'blue'
        blue_record.addLayerRecord(line_blue_record)
        QgsProject.instance().mapThemeCollection().insert('blue', blue_record)

        layout = QgsLayout(QgsProject.instance())
        layout.initializeDefaults()

        map1 = QgsLayoutItemMap(layout)
        map1.attemptSetSceneRect(QRectF(20, 20, 80, 80))
        map1.setFrameEnabled(True)
        map1.setLayers([point_layer, line_layer])
        layout.addLayoutItem(map1)
        map1.setExtent(point_layer.extent())
        map1.setFollowVisibilityPreset(True)
        map1.setFollowVisibilityPresetName('red')

        map2 = QgsLayoutItemMap(layout)
        map2.attemptSetSceneRect(QRectF(20, 120, 80, 80))
        map2.setFrameEnabled(True)
        map2.setLayers([point_layer, line_layer])
        layout.addLayoutItem(map2)
        map2.setExtent(point_layer.extent())
        map2.setFollowVisibilityPreset(True)
        map2.setFollowVisibilityPresetName('blue')

        legend = QgsLayoutItemLegend(layout)
        legend.setTitle("Legend")
        legend.attemptSetSceneRect(QRectF(120, 20, 80, 80))
        legend.setFrameEnabled(True)
        legend.setFrameStrokeWidth(QgsLayoutMeasurement(2))
        legend.setBackgroundColor(QColor(200, 200, 200))
        legend.setTitle('')
        layout.addLayoutItem(legend)
        legend.setLinkedMap(map1)

        legend2 = QgsLayoutItemLegend(layout)
        legend2.setTitle("Legend")
        legend2.attemptSetSceneRect(QRectF(120, 120, 80, 80))
        legend2.setFrameEnabled(True)
        legend2.setFrameStrokeWidth(QgsLayoutMeasurement(2))
        legend2.setBackgroundColor(QColor(200, 200, 200))
        legend2.setTitle('')
        layout.addLayoutItem(legend2)
        legend2.setLinkedMap(map2)

        checker = QgsLayoutChecker('composer_legend_theme', layout)
        checker.setControlPathPrefix("composer_legend")
        result, message = checker.testLayout()
        self.report += checker.report()
        self.assertTrue(result, message)

        QgsProject.instance().clear()
Beispiel #10
0
 def testRendererCategory(self):
     self.assertEqual(QgsRendererCategory().__repr__(), '<QgsRendererCategory>')
     self.assertEqual(QgsRendererCategory(5, None, None).__repr__(), '<QgsRendererCategory: 5>')
     self.assertEqual(QgsRendererCategory('abc', None, None).__repr__(), '<QgsRendererCategory: abc>')
     self.assertEqual(QgsRendererCategory('abc', None, 'my class').__repr__(), '<QgsRendererCategory: abc (my class)>')
Beispiel #11
0
    def processAlgorithm(self, parameters, context, feedback):
        project = QgsProject()
        project.setFileName(
            os.path.join(parameters[self.FOLDER], "all-outputs-qgis.qgs"))
        project.setCrs(QgsCoordinateReferenceSystem('EPSG:27700'))

        def getMaxValue(layer, fieldname):
            maxfound = float("-inf")
            for f in layer.getFeatures():
                attr = f.attribute(fieldname)
                assert attr >= 0
                if attr > maxfound:
                    maxfound = attr
            return maxfound

        with open(
                os.path.join(parameters[self.FOLDER],
                             "all-town-metadata.json")) as f:
            metadata = json.load(f)

        classmethods = {
            'quantile': QgsClassificationQuantile,
            'jenks': QgsClassificationJenks,
            'equal': QgsClassificationEqualInterval
        }

        html = ""
        output = []
        views_sorted_by_mode = sorted(metadata["views"],
                                      key=lambda v: v["mode"])
        for view in views_sorted_by_mode:
            keysymbol = u'🔑'
            viewname = view["label"]
            keysign = ""
            if viewname.find(keysymbol) != -1:
                viewname = viewname.replace(keysymbol, '', 1)
                keysign = "*** "
            viewname = keysign + view["mode"] + " " + viewname

            html += f"""
                    <h2>{viewname}</h2>
                    {view["description"]}
                    <ul>
                    """
            for layer in view["layers"]:
                layername = viewname + " - " + layer["scalar_field_units"]

                layerpath = os.path.join(parameters[self.FOLDER],
                                         layer["file"])
                vlayer = QgsVectorLayer(layerpath, layername, "ogr")
                if not vlayer.isValid():
                    feedback.pushInfo("Layer failed to load: " + layerpath)
                else:
                    context.temporaryLayerStore().addMapLayer(vlayer)
                    html += f"""<li><b>file:</b> {layer["file"]}"""
                    if "symbol_field" in layer:
                        html += f"""<ul>
                                    <li><b>symbol field:</b> {layer["symbol_field"]}
                                  </ul>
                                """
                        categories = []
                        scalar_fieldname = layer["scalar_field"]
                        maxvalue = getMaxValue(vlayer, scalar_fieldname)
                        feedback.pushInfo("Max value for %s is %f" %
                                          (scalar_fieldname, maxvalue))
                        for formality in ["I", "F"]:
                            for severity, colour in [(3, 'red'), (2, 'yellow'),
                                                     (1, 'green')]:
                                colour = {
                                    ("I", "red"): "#FF0000",
                                    ("I", "yellow"): "#FFFF00",
                                    ("I", "green"): "#00FF00",
                                    ("F", "red"): "#FF9999",
                                    ("F", "yellow"): "#FFFF66",
                                    ("F", "green"): "#99FF99",
                                }[(formality, colour)]
                                symbol_code = "%s%d" % (formality, severity)
                                if formality == "F":
                                    symbol = QgsMarkerSymbol.createSimple({
                                        'color':
                                        colour,
                                        'size':
                                        '3',
                                        'outline_color':
                                        '#888888'
                                    })
                                else:
                                    assert (formality == "I")
                                    symbol = QgsMarkerSymbol.createSimple({
                                        'color':
                                        colour,
                                        'size':
                                        '3',
                                        'outline_color':
                                        '#000000',
                                        'name':
                                        'star'
                                    })

                                objTransf = QgsSizeScaleTransformer(
                                    QgsSizeScaleTransformer.Flannery,
                                    0,  #minvalue
                                    maxvalue,  #maxvalue
                                    3,  #minsize
                                    10,  #maxsize
                                    0,  #nullsize
                                    1)  #exponent
                                objProp = QgsProperty()
                                objProp.setField(scalar_fieldname)
                                objProp.setTransformer(objTransf)
                                symbol.setDataDefinedSize(objProp)
                                label = {
                                    "F": "Formal",
                                    "I": "Informal"
                                }[formality] + " " + {
                                    3: "Major",
                                    2: "Secondary",
                                    1: "Tertiary"
                                }[severity]
                                cat = QgsRendererCategory(
                                    symbol_code, symbol, label, True)
                                categories.append(cat)
                        renderer = QgsCategorizedSymbolRenderer(
                            "Crossings", categories)
                        renderer.setClassAttribute(layer["symbol_field"])
                        vlayer.setRenderer(renderer)
                    else:
                        html += f"""<ul>
                                    <li><b>field:</b> {layer["scalar_field"]}
                                    <li><b>units:</b> {layer["scalar_field_units"]}
                                    <li><b>recommended classification:</b> {layer["classes"]}
                                  </ul>
                                """
                        default_style = QgsStyle().defaultStyle()
                        color_ramp = default_style.colorRamp('bt')
                        renderer = QgsGraduatedSymbolRenderer()
                        renderer.setClassAttribute(layer["scalar_field"])
                        classmethod = classmethods[layer["classes"]]()
                        renderer.setClassificationMethod(classmethod)
                        renderer.updateClasses(vlayer, 5)
                        renderer.updateColorRamp(color_ramp)
                        vlayer.setRenderer(renderer)

                    project.addMapLayer(vlayer)
                    feedback.pushInfo("Loaded " + layerpath)
            html += "</ul>"

        project.write()
        town = views_sorted_by_mode[0]["town"]
        with open(os.path.join(parameters[self.FOLDER], "metadata.html"),
                  "w") as htmlfile:
            htmlfile.write(
                f"<html><head><title>{town} metadata</title></head><body><h1>{town}</h1>{html}</body></html>"
            )
        return {self.OUTPUT: output}