QGIS icon indicating copy to clipboard operation
QGIS copied to clipboard

Color in Legend not the same as in canvas, when defining through field type value in table

Open TristanMi opened this issue 2 years ago • 8 comments

What is the bug or the crash?

When setting the colour of a simple marker through field type the colour in the canvas is changed, but the colour of the simple marker and the thereby the legend is not changed.

Steps to reproduce the issue

  • making a csv table of items with columns "Name" and column "RBG" for colours in HTML-Notation,
  • linking this table to a point vector layer with column "Name"
  • making the symbology of the layer as simple marker with the colour defined through field type column "RGB"
  • the colour in the canvas is the right one, but the colour of the legend has to be changed manually.

  • changing symbology to rule-based and classified by "Name" when e.g. having a table of many items this becomes very impractible.

Wouldn't it be good to have the colour of the simple marker and the legend changed when a colour is defined through the field type?

Versions

QGIS-Version 3.22.4-Białowieża QGIS-Codezweig Release 3.22
Qt-Version 5.15.3
Python-Version 3.10.3
GDAL-Version 3.4.1
PROJ-Version 8.2.1
EPSG-Registraturdatenbankversion v10.041 (2021-12-03)
GEOS-Version 3.10.2-CAPI-1.16.0
SQLite-Version 3.37.2
PostgreSQL-Client-Version 14.2 (Ubuntu 14.2-1)
SpatiaLite-Version 5.0.1
QWT-Version 6.1.4
QScintilla2-Version 2.11.6
BS-Version Ubuntu 22.04.2 LTS
       

QGIS-Version 3.22.4-Białowieża QGIS-Codezweig [Release 3.22](https://github.com/qgis/QGIS/tree/release-3_22) Qt-Version 5.15.3 Python-Version 3.10.3 GDAL-Version 3.4.1 PROJ-Version 8.2.1 EPSG-Registraturdatenbankversion v10.041 (2021-12-03) GEOS-Version 3.10.2-CAPI-1.16.0 SQLite-Version 3.37.2 PostgreSQL-Client-Version 14.2 (Ubuntu 14.2-1) SpatiaLite-Version 5.0.1 QWT-Version 6.1.4 QScintilla2-Version 2.11.6 BS-Version Ubuntu 22.04.2 LTS

Supported QGIS version

  • [ ] I'm running a supported QGIS version according to the roadmap.

New profile

  • [ ] I tried with a new QGIS profile

Additional context

No response

TristanMi avatar May 10 '23 11:05 TristanMi

What color should it be though? The point of data defined properties is they're dependent on a specific feature. So the legend symbology could use the color of the first feature, but I'm no sure this would be an improvement...

YoannQDQ avatar May 10 '23 15:05 YoannQDQ

I have a database of tree species and they all should have a different colour, mostly depending on the fruit colour. So it's about 100 different species, in the future probably many more. So when I place a point names Oak it should get the colour of oak, and the legend should read oak with the same colour. And another point should be Apple in a different colour. At the moment the all read the name but they have random colours

TristanMi avatar May 10 '23 15:05 TristanMi

The colour in the canvas is the right one but not in the legend

TristanMi avatar May 10 '23 15:05 TristanMi

Create one legend entry for each symbol and have the static color be displayed without an expression. The symbol in the legend are an abstraction and not a feature. Since it doesn't have any attribute it will only display default/static colors.

roya0045 avatar May 18 '23 10:05 roya0045

When I add a new species to the table then I have to also add a new one symbol with legend entry in the Vectorlayer. Is there a reason or a case why the symbol in the legend is an abstraction and not a feature? Wouldn't it be better for it to be a feature so the colours in the canvas and the legend are the same?

TristanMi avatar May 31 '23 09:05 TristanMi

Is there a way to write a script to update the fill colour/legend colour according to the colour given through field type value?

TristanMi avatar May 31 '23 10:05 TristanMi

Confirming that I have the same issue. See screenshot attached. Polygon fill colors are set from columns containing R,G,B integers, and are shown correctly in the canvas (either using color_rgb or color_rgba functions). However, the legend colors do not reflect the canvas colors.

QGIS Legend

a0wunsch avatar Jun 09 '23 17:06 a0wunsch

The QGIS project highly values your report and would love to see it addressed. However, this issue has been left in feedback mode for the last 14 days and is being automatically marked as "stale". If you would like to continue with this issue, please provide any missing information or answer any open questions. If you could resolve the issue yourself meanwhile, please leave a note for future readers with the same problem and close the issue. In case you should have any uncertainty, please leave a comment and we will be happy to help you proceed with this issue. If there is no further activity on this issue, it will be closed in a week.

github-actions[bot] avatar Jun 24 '23 02:06 github-actions[bot]

I wrote a script that somewhat fixes the problem for me. I wonde if a function like that could be integrated in QGIS, so that the dynamic value from the csv changes the legend color too.

from qgis.core import ( QgsProject, QgsCategorizedSymbolRenderer, QgsSymbolLayerRegistry, QgsMarkerSymbol, QgsSimpleMarkerSymbolLayer, QgsProperty, QgsExpressionContext, QgsExpression, QgsField, QgsFeatureRequest, QgsRendererCategory )

Define the function to update symbology

def update_symbology(layer_name): # Get the layer by its name layer = QgsProject.instance().mapLayersByName(layer_name)[0]

# Get the renderer
renderer = layer.renderer()

if renderer.type() == 'categorizedSymbol':
    # Get the categories
    categories = renderer.categories()

    # Create a new categorized symbol renderer
    new_renderer = QgsCategorizedSymbolRenderer('Name')

    # Create a dictionary to store the symbols for each attribute value
    symbol_dict = {}

    # Iterate through the categories and update the symbol color and size
    for category in categories:
        # Get the attribute value for the category
        attribute_value = category.value()

        # Skip the category if the attribute value is missing
        if attribute_value is None:
            print("kein attribute_value")
            continue

        # Check if a symbol for the attribute value already exists in the dictionary
        if attribute_value in symbol_dict:
            symbol = symbol_dict[attribute_value]
        else:
            # Create a feature request to retrieve the features with the matching attribute value
            request = QgsFeatureRequest().setFilterExpression('"Name" = \'' + attribute_value + '\'')

            # Get the first feature that matches the request
            feature = next(layer.getFeatures(request), None)

            # Skip the category if no feature is found
            if feature is None:
                print("kein featue")
                continue

            # Get the HTML notation for the color from the feature attributes
            html_color = feature['Artentabelle_RGB']
            size_expression = feature['Anz.Breite']

            # Skip the category if the RGB value or size expression is missing
            if html_color is None or size_expression is None:
                print("kein html_color oder size_expression")
                continue

            # Create a new symbol layer with the desired color and size
            symbol_layer = QgsSimpleMarkerSymbolLayer()
            color = QColor(html_color)
            symbol_layer.setColor(color)
            symbol_layer.setDataDefinedProperty(
                QgsSymbolLayer.PropertySize,
                QgsProperty.fromExpression(str(size_expression))
            )

            # Create a marker symbol with the symbol layer
            symbol = QgsMarkerSymbol()
            symbol.changeSymbolLayer(0, symbol_layer)

            # Store the symbol in the dictionary
            symbol_dict[attribute_value] = symbol

        # Set the symbol to the category
        new_renderer.addCategory(QgsRendererCategory(attribute_value, symbol, str(attribute_value)))

    # Set the new renderer to the layer
    layer.setRenderer(new_renderer)

    # Refresh the layer to reflect the changes
    layer.triggerRepaint()

Usage example

layer_name = 'Pflanzen Kopie' update_symbology(layer_name)

TristanMi avatar Sep 20 '23 12:09 TristanMi