Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Masking labels doesn't work with rule based labeling #46402

Closed
1 of 2 tasks
Forna73 opened this issue Dec 7, 2021 · 27 comments · Fixed by #60325 or #60490
Closed
1 of 2 tasks

Masking labels doesn't work with rule based labeling #46402

Forna73 opened this issue Dec 7, 2021 · 27 comments · Fixed by #60325 or #60490
Assignees
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter! Labeling Related to QGIS map labeling

Comments

@Forna73
Copy link

Forna73 commented Dec 7, 2021

What is the bug or the crash?

Simple... I've any masking for labels even enabling the mask in label and selecting the masking options in layer properties

Steps to reproduce the issue

  1. create a line layer
  2. create a label and enable the masking option
  3. in the layer properties select both check box to enable the masking

Versions

Versione di QGIS
3.16.6-Hannover
Revisione codice QGIS
bfd36fd
Compilato con Qt
5.11.2
Esecuzione con Qt
5.11.2
Compilato con GDAL/OGR
3.1.4
Esecuzione con GDAL/OGR
3.1.4
Compilato con GEOS
3.8.1-CAPI-1.13.3
Esecuzione con GEOS
3.8.1-CAPI-1.13.3
Compilato su SQLite
3.29.0
In esecuzione su SQLite
3.29.0
Versione client PostgreSQL
11.5
Versione SpatiaLite
4.3.0
Versione QWT
6.1.3
Versione QScintilla2
2.10.8
Compilato con PROJ
6.3.2
Esecuzione con PROJ
Rel. 6.3.2, May 1st, 2020
Versione SO
Windows 10 (10.0)
Attiva python plugin
AzimuthDistanceCalculator;
batch_hillshader-master;
clipper;
coordinates_converter;
DigitizingTools;
latlontools;
map-coords-plugin;
points2one;
profiletool;
Qgis2threejs;
zoom_level;
db_manager;
MetaSearch;
processing

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

@Forna73 Forna73 added the Bug Either a bug report, or a bug fix. Let's hope for the latter! label Dec 7, 2021
@gioman gioman added the Feedback Waiting on the submitter for answers label Dec 7, 2021
@gioman
Copy link
Contributor

gioman commented Dec 7, 2021

@Forna73 have you

"Select this mask shape as a mask source in the overlapping layer properties labelmask Mask tab (see Masks Properties)."

as explained here?

https://docs.qgis.org/3.22/en/docs/user_manual/style_library/label_settings.html?highlight=masking#mask-tab

@gioman
Copy link
Contributor

gioman commented Dec 7, 2021

When you do that:

image

@Forna73
Copy link
Author

Forna73 commented Dec 7, 2021

I selcted them. I have only 1 layer, so it's the layer label that should mask its line, not an element of another layer.

@Forna73
Copy link
Author

Forna73 commented Dec 7, 2021

I've just noticed that the check box doesn't remain selected. If I exit the layer properties panel and then I reopen it, the check boxes aren't selected.
I tried "apply" maintaining the panel opened but nothing happens.

@Forna73
Copy link
Author

Forna73 commented Dec 7, 2021

as you can see:
1
2

@gioman
Copy link
Contributor

gioman commented Dec 7, 2021

as you can see:

@Forna73 attach a sample project+data, the issue may be data/expression dependent.

@Forna73
Copy link
Author

Forna73 commented Dec 7, 2021

it's done all from scratch.
you can simply create a line layer and a label.....

@gioman
Copy link
Contributor

gioman commented Dec 7, 2021

it's done all from scratch.
you can simply create a line layer and a label.....

@Forna73 in your screenshot you are using rule based labeling with an expression. With the most simple case ("you can simply create a line layer and a label") it works.

@Forna73
Copy link
Author

Forna73 commented Dec 7, 2021

Ok.... You are right... simplest way works, I continued applying my rule; but this mean I can't use rule based labelling... is that expected to be right?

@gioman
Copy link
Contributor

gioman commented Dec 7, 2021

is that expected to be right?

@Forna73 please attach a minimal sample project with data that shows the behavior you describe.

@Forna73
Copy link
Author

Forna73 commented Dec 8, 2021

Hi!
In the meanwhile I was saving the file to attach I did some more tests and I discovered that only with "Rule based label" the mask doesn't work.
With "single label", even with expression, it works.
So the problem is apparently only with "rule based label".

@gioman
Copy link
Contributor

gioman commented Dec 8, 2021

So the problem is apparently only with "rule based label".

@Forna73 still works fine here. You really should attach a sample project with data that shows the issue.

@gioman
Copy link
Contributor

gioman commented Dec 8, 2021

@Forna73 nevermind, as soon as two mask sources are enabled masking stops to work. Thanks for the report.

@gioman gioman added Labeling Related to QGIS map labeling and removed Feedback Waiting on the submitter for answers labels Dec 8, 2021
@gioman gioman changed the title Masking label doesn't work Masking labels doesn't work with rule based labeling Dec 8, 2021
@gioman
Copy link
Contributor

gioman commented Dec 8, 2021

The problem seems to be that when there are more than 1 masking sources then the selection for the sources and "masked symbol layer" do not stick in the layer properties, it seems that on ok/apply the selections are removed.

@Forna73
Copy link
Author

Forna73 commented Dec 8, 2021

I do confirm!

@hawstom
Copy link

hawstom commented Jul 8, 2023

Any progress on this bug? I am experiencing it with v 3.28.8-Firenze. I am new to GIS and QGIS, but I can attach my minimal qgz file and layer file if you tell me what is the expected layer file format.

@jfbourdon
Copy link
Contributor

The issue can be replicated with the snippet below. Up to QGIS 3.28.15, the masks works with a rule based labeling but it disappears if I open the layer properties window and click "OK". It doesn't matter if I change a setting or not, simply clicking "OK" does the job. However, clicking "Cancel" does not cause the mask to disappear. It must be noted that trying to set the same label parameters manually via the GUI does not allow to successfully apply the mask.

Starting at QGIS 3.30.0, my snippet breaks because of a change to the QgsSymbolLayerReference class. I haven't been able to figure out how to reference the symbol id in the new QgsSymbolLayerReference class...

# Make two simple lines
elev_fieldname = "ELEV"
layer = QgsVectorLayer(f"linestring?crs=epsg:32198&field={elev_fieldname}:integer", "contours", "memory")
for wkt, elev in [('LineString (0 400000, 100 400000)', 5), ('LineString (0 400010, 100 400010)', 10)]:
    geom = QgsGeometry.fromWkt(wkt)
    fet = QgsFeature(layer.fields())
    fet.setGeometry(geom)
    fet[elev_fieldname] = elev
    layer.dataProvider().addFeature(fet)

QgsProject.instance().addMapLayer(layer)


# Labeling
# Only the label of the upper line, with an elevation of 10, should be displayed
label_settings = QgsPalLayerSettings()
label_settings.placement = QgsPalLayerSettings.Line
label_settings.placementFlags = QgsPalLayerSettings.OnLine
label_settings.fieldName = elev_fieldname

mask = QgsTextMaskSettings()
mask.setEnabled(True)
mask.setSize(2)
mask.setMaskedSymbolLayers( [QgsSymbolLayerReference(layer.id(), QgsSymbolLayerId("", 0))] )  # Breaks starting at QGIS 3.30

text_format = label_settings.format()
text_format.setMask(mask)
label_settings.setFormat(text_format)

root = QgsRuleBasedLabeling.Rule(QgsPalLayerSettings())
rule = QgsRuleBasedLabeling.Rule(label_settings)
rule.setDescription("Only 10s")
rule.setFilterExpression(f"\"{elev_fieldname}\" % 10 = 0")
rule.setActive(True)
root.appendChild(rule)
rules_settings = QgsRuleBasedLabeling(root)
layer.setLabelsEnabled(True)
layer.setLabeling(rules_settings)

layer.labeling().setSettings(label_settings)
layer.triggerRepaint()

@effjot
Copy link

effjot commented Aug 27, 2024

The problem still exists in the settings dialog in version 3.34.6 and 3.34.10.
Also, it still is possible to turn on masking in the layer style dock.

@jfbourdon
Copy link
Contributor

I'm trying to understand what exactly QgsSymbolLayerReference expects as a second argument now (since 3.30) in place of a QgsSymbolLayerId. The documentation says to use a QUuid string, but I can't find how to construct that string. I thought that there was a way to extract a uuid from a QgsSymbolLayerId object but that doesn't seem possible (and the QgsSymbolLayerId class is deprecated since 3.30). I'm at a loss...

@troopa81 Could you help on this matter as you seems to have edited the related lines of code related to these classes? Thanks.

@troopa81
Copy link
Contributor

Just discovering this issue

The problem seems to be that when there are more than 1 masking sources then the selection for the sources and "masked symbol layer" do not stick in the layer properties, it seems that on ok/apply the selections are removed.

You mean like this (2 mask sources, 1 masked symbol layer) ?

smaskedit

And it does work (in master but pretty sure it works with recent one)

smask

It would be very better if someone could share a project so I can reproduce the issue

@troopa81
Copy link
Contributor

I'm trying to understand what exactly QgsSymbolLayerReference expects as a second argument now (since 3.30) in place of a QgsSymbolLayerId

The unique symbol layer id. Like for instance

>>> iface.activeLayer().renderer()
<qgis._core.QgsSingleSymbolRenderer object at 0x7f7b5034c3a0>
>>> iface.activeLayer().renderer().symbol().symbolLayers()
[<qgis._core.QgsSimpleLineSymbolLayer object at 0x7f7b5044a290>, <qgis._core.QgsSimpleLineSymbolLayer object at 0x7f7b50331120>]
>>> iface.activeLayer().renderer().symbol().symbolLayers()[0].id()
'{6220c894-fcba-4f9f-86cf-d8884f4c49a5}'

The last one is the expected id. Before my modifications, it was the order of the symbol layer regarding its parent symbol and it was a mess (like for instance when you were changing the order). So now we have a generated unique id.

@jfbourdon
Copy link
Contributor

Thanks!

My snippet below now works for >= 3.30. It displays two parallel lines with a label only on the upper one with a mask applied. The mask work, but like I said in my first comment, it stops working if the layer properties window is opened and then closed by clicking "OK", even without changing any setting.

Before opening the layer properties window
image

After opening and closing the layer properties window
image

# Make two simple lines
elev_fieldname = "ELEV"
layer = QgsVectorLayer(f"linestring?crs=epsg:32198&field={elev_fieldname}:integer", "contours", "memory")
for wkt, elev in [('LineString (0 400000, 100 400000)', 5), ('LineString (0 400010, 100 400010)', 10)]:
    geom = QgsGeometry.fromWkt(wkt)
    fet = QgsFeature(layer.fields())
    fet.setGeometry(geom)
    fet[elev_fieldname] = elev
    layer.dataProvider().addFeature(fet)

QgsProject.instance().addMapLayer(layer)


# Labeling
# Only the label of the upper line, with an elevation of 10, should be displayed
label_settings = QgsPalLayerSettings()
label_settings.placement = QgsPalLayerSettings.Line
label_settings.placementFlags = QgsPalLayerSettings.OnLine
label_settings.fieldName = elev_fieldname

mask = QgsTextMaskSettings()
mask.setEnabled(True)
mask.setSize(2)
mask.setMaskedSymbolLayers([
    QgsSymbolLayerReference(
        layer.id(),
        layer.renderer().symbol().symbolLayers()[0].id()
    )
])

text_format = label_settings.format()
text_format.setMask(mask)
label_settings.setFormat(text_format)

root = QgsRuleBasedLabeling.Rule(QgsPalLayerSettings())
rule = QgsRuleBasedLabeling.Rule(label_settings)
rule.setDescription("Only 10s")
rule.setFilterExpression(f"\"{elev_fieldname}\" % 10 = 0")
rule.setActive(True)
root.appendChild(rule)
rules_settings = QgsRuleBasedLabeling(root)
layer.setLabelsEnabled(True)
layer.setLabeling(rules_settings)

layer.labeling().setSettings(label_settings)
layer.triggerRepaint()

@troopa81
Copy link
Contributor

@jfbourdon OK, thanks! I I manage to reproduce the issue.

I'll fix the issue for next bugfix round (in january 2025) except if someone is willing to fund the fix

@troopa81
Copy link
Contributor

The issue comes from symbol layers sharing the same ids which are supposedly unique.

I fixed copy/paste symbol and converting from rule to categorized to avoid having duplicate id from the UI but already broken project would remain broken. Best is to recreate each rule symbol from scratch, or create one, and copy/paste with the version integrating the fix.

@jfbourdon
Copy link
Contributor

@troopa81 You obviously fixed some things related to masking labels but I just tested my snippet on the Windows Qt5 build including your PR (from both dc2e6b3 and c527bed) and this particular issue persists.

@troopa81
Copy link
Contributor

troopa81 commented Feb 6, 2025

@jfbourdon True. I'm looking into it

troopa81 added a commit to troopa81/QGIS that referenced this issue Feb 6, 2025
rule key is used by other object as reference (masking for instance)

Fixes qgis#46402
@troopa81
Copy link
Contributor

troopa81 commented Feb 6, 2025

@jfbourdon #60490 will fix it!

nyalldawson pushed a commit that referenced this issue Feb 7, 2025
rule key is used by other object as reference (masking for instance)

Fixes #46402
qgis-bot pushed a commit that referenced this issue Feb 7, 2025
rule key is used by other object as reference (masking for instance)

Fixes #46402
nyalldawson pushed a commit that referenced this issue Feb 9, 2025
rule key is used by other object as reference (masking for instance)

Fixes #46402
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Either a bug report, or a bug fix. Let's hope for the latter! Labeling Related to QGIS map labeling
Projects
None yet
6 participants