TransWikia.com

Rule-based symbology based on current selection in QGIS

Geographic Information Systems Asked on April 12, 2021

I have two oracle layer (point(p1) and polygon(pl1)). I want to build a rule-based symbology which is based on current selection on two cases:

Case 1– When I select a point from table p1, I want that the polygons from table pl1 to be coloured differently based one the relation that they have with table p1 which is p1.id_b=pl1.id_b (one to many).

Case 2– When I select a polygon from table pl1 other polygons from the same layer that are related to current selection to be coloured differently. Relation between polygons is on the field pl1.id_group, so polygons are grouped by the same pl1.id_group (one to many).

Software used is QGIS.

enter image description here

For illustration I select point one and the related polygons are coloured differently from the others.

2 Answers

Solution for Case 1:

  • Add two symbol layers to the polygon layer as in the image. enter image description here

  • Open Based-on selected points rule, open expression window for Filter.

  • Go to Function Editor tab and add the following script as function.

    from qgis.core import *
    from qgis.gui import *
    
    @qgsfunction(args='auto', group='Custom')
    def related_rule_based(layer_name, field1, field2, feature, parent):
        layer = QgsProject.instance().mapLayersByName(layer_name)[0]
        selected_features = layer.selectedFeatures()
        if selected_features:
            feat = selected_features[0]
            if feat[field1] == feature[field2]:
                return True
            else:
                return False
    
  • Click Save and Load Functions. Then, in Expression tab, enter the next line: (p1: point layer name, first id_b: field in point layer, second id_b: field in polygon layer)

    related_rule_based('p1', 'id_b', 'id_b')
    

This solution is for just one selected point. If you select more points, one polygon group will remain selected.

enter image description here


Solution for Case 2:

  • Add one more rule to the polygon layer.

enter image description here

  • Enter the following expression as rule.

    related_rule_based(@layer_name, 'id_b', 'id_b')
    

Note: If two cases occur, one of both will be effective.

enter image description here

Answered by Kadir Şahbaz on April 12, 2021

This script creates a rule based style which refreshes upon the selection of a feature with the logic you described.You only need to enter the layer names below and run it in QGIS.

class Restyler:
    def __init__(self, polygonLayerName, pointLayerName):
        self.polygonLayer = QgsProject.instance().mapLayersByName(polygonLayerName)[0]
        self.pointLayer = QgsProject.instance().mapLayersByName(pointLayerName)[0]

        self.polygonLayer.selectionChanged.connect(self.polygonSelected)
        self.pointLayer.selectionChanged.connect(self.pointSelected)
        self.addRules()

    def addRules(self):
        layer = self.polygonLayer
        symbol = QgsSymbol.defaultSymbol(layer.geometryType())
        renderer = QgsRuleBasedRenderer(symbol)
        root_rule = renderer.rootRule()
        rule = root_rule.children()[0].clone()
        rule.setFilterExpression('"id_b" = @selected_id_b')
        rule.symbol().setColor(QColor('pink'))

        rule2 = rule.clone()
        rule2.setFilterExpression('"id_group" = @selected_id_group')
        root_rule.appendChild(rule)
        root_rule.appendChild(rule2)
        layer.setRenderer(renderer)
        iface.layerTreeView().refreshLayerSymbology(layer.id())

    def pointSelected(self):
        if self.pointLayer.selectedFeatureCount() == 1:
            selectedIdb = self.pointLayer.selectedFeatures()[0]['id_b']
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_b', selectedIdb)
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_group', '')
            print("Point selected. id_b: {}".format(selectedIdb))
            self.polygonLayer.triggerRepaint()
        else:
            print("Error. One feature should be selected")
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_group', '')
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_b', '')

        self.polygonLayer.triggerRepaint()

    def polygonSelected(self):
        if self.polygonLayer.selectedFeatureCount() == 1:
            selectedIdGroup = self.polygonLayer.selectedFeatures()[0]['id_group']
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_group', selectedIdGroup)
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_b', '')
            print("Polygon selected. id_group: {}".format(selectedIdGroup))
        else:
            print("Error. One feature should be selected")
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_group', '')
            QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(),'selected_id_b', '')

        self.polygonLayer.triggerRepaint()

#you only need to input your layer names
polygonLayerName = 'wojewodztwa'
pointLayerName = 'testcsv_geocoded'

restyler = Restyler(polygonLayerName, pointLayerName)

result

Answered by Leon Powałka on April 12, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP