QGIS Layout Label Display – Attribute Value from Overlapping Shapefile

attribute-tablelayoutsqgis

I'm trying to make it so that a layout label always displays the name of the municipality which intersects with the center of the layout map extent.

To do this I've tried using the following expression:

aggregate(layer:='Cont_AAD_CAOP2021',
aggregate:='concatenate',expression:="Concelho",
filter:=intersection( geometry(Cont_AAD_CAOP2021),
geometry(item_variables('Map 1')['map_extent_center'])))

In which "Cont_AAD_CAOP2021" is the shapefile containing municipality information, and "Concelho" is a string field containing the municipality names. "Map 1" is the name of the map in the layout.

However, all I get is an empty output, even if the expression gives no error message. I'm guessing the problem is with the filter, but I'm not sure.

I'm using QGIS 3.22.5

EDIT: The data I'm using and an example project can be found here

Best Answer

You approach is possible, but very inefficient. I would heavily advice to create an atlas (see my other solution). However, just to answer your question and show a way to solve your problem with the approach you tried. There are in fact two problems with what you tried:

  • CRS issue
  • Wrong syntax.

enter image description here

CRS issue

Use the same CRS for the project and the layer(s) you use to get the intersection. You had EPSG:32629 as project CRS (used also for your layout), but EPSG:3763 for the layer Cont_AAD_CAOP2021. Reproject the layer to the project CRS, then intersection will work.

Expression/syntax

Now use the following expression - see below for explanation:

 array_max(
     array_foreach (
         aggregate( 'Cont_AAD_CAOP2021', 'array_agg', $id),
     if(
         intersects (
             map_get (item_variables('Map 1'), 'map_extent_center'),
             geometry (get_feature_by_id ('Cont_AAD_CAOP2021', @element))
         ),
         attribute (
             get_feature_by_id ('Cont_AAD_CAOP2021', @element),
             'Concelho'
         ),
         ''
     )
 ))

Explanation:

  1. The correct syntax to get the center of the current layout page is: map_get (item_variables ('Map 1'), 'map_extent_center'), see item_variables() and map_get().

  2. Instead of aggregate/concatenate the names of the attribute "Concelho" and filtering by intersection, rather use aggregate/array_agg to get an array of all id's of the layer, then use get_feature_by_id () and geometry() to get an array of the geometries from the layer. With array-foreach() an an if() clause then test if these geometries intersect with the center of the layout (step 2).

  3. For the geometry that returns true (intersects with the center of the current layout), get the value of the field Concelho using attribute().

  4. Use array_max() to get rid of the empty values and keep only the value of the field Concelho that indeed intersects the layout's center.

Related Question