2

Is there a way of testing whether a layer (name) exists in QGIS in order to write a conditional expression?

My particular problem is that I am trying to rotate a point object (a gate), using a data-defined expression.

If the 'road' layer exists (a line layer), I will use the angle of the nearest road segment (using the approach discussed here: Find angle of segment of line geometry nearest to point).

If the 'road' layer does not exist, I will use the "symbolrotation" field in the point layer.

The challenge is that while the layer is named 'road' in the Layer Panel, it will have a layer ID similar to 'road_b3cb9198_b4d5_4e05_b465_ed2e1c291774'. So checking whether 'road' exists in the @layer_ids variable isn't likely to work.

Is there an alternative way?

4 Answers 4

3

You can use function try() together with any other function that uses a layer's name as argument (e.g. overlay_nearest()): if the layer is not found, the function returns an error. try() returns if the enclosed expression is error-free. So you get the desired result using this expression:

try (overlay_nearest ('road')) is TRUE
3

Create an array of all layer names in a project with variable @layers() (all the map layers in the current project as a list) and function layer_property(), then test if a certain layer name (here: 'road') exists in the array with array_contains(). Use this expression:

array_contains (
    array_foreach (
        @layers,
        layer_property (@element,'name')),
    'road' -- name of the layer you're looking for
)
3

You can use is_layer_visible, it should return false if the layer is not visible or if there is no such layer in the project.

Example:

is_layer_visible('road')

add that as the condition in your CASE or if expression.

In the example below I just change the size of the points if the layer exists:

if( is_layer_visible('road'),10,2)

since the road layer exists and is visible the points aresized at 10 and not 2.

enter image description here

Important note

Using a simple layer name and not IDs can lead to wrong results if two or more layers share the same name (usually done for cartographic reasons at different scales)

4
  • is_layer_visible returns false if the layer exists, but the checkbox next to it is unchecked. Also in my QGIS installation (3.34 an Win 10), is_layer_visible somehow is not available, don't know why.
    – Babel
    Nov 16, 2023 at 7:32
  • That's why I wrote that is checks visibility too, the assumption being that he wishes to change the symbology in accordance with the appearance of roads. About the missing function, it can be contextual, not all expression function appear in all the time (which can get annoying). In the expressions controlling an aspect of the symbology it should be available.
    – Dror Bogin
    Nov 16, 2023 at 7:36
  • Yes, function is contextual, I missed that point. Still, I understood that OP asks "testing whether a layer (name) exists", regardless of it's visibility, than is_layer_visible is too restrictive, but can have advantages if indeed the intended task depends not only on existence, but on visibility as well.
    – Babel
    Nov 16, 2023 at 7:47
  • I had originally looked at this option and discarded it. But I can see scenarios where there may be a need to have the layer in the list, and occasionally turned off - in which case it would be useful. Nov 16, 2023 at 21:00
3

If the problem is just the discrepance between @layer_id an the layer's name, you can use operator ~ to perform a regular expression match:

@layer_id ~ 'point'

Or, if it is not just the current layer, but all layers:

array_sum (
    array_foreach (@layer_ids, @element ~ 'road')
)>0

Because 'road_b3cb9198_b4d5_4e05_b465_ed2e1c291774' ~ 'road' returns true (layer's name road is contained in the longer layer id string).

enter image description here

1
  • 1
    In this case there are also potential layers 'roadBridge' and 'roadTunnel'! However, you could change the code above to @element ~ 'road_' and I think that would solve for most circumstances. Nov 16, 2023 at 20:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.