2

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

11
  • Providing a sample project would help testing
    – Babel
    Dec 26, 2022 at 12:47
  • @Babel Good idea! I've edited the post with a link.
    – HenriQue
    Dec 26, 2022 at 14:04
  • Sorry: whicht layout do you use in the project you provided?
    – Babel
    Dec 26, 2022 at 14:22
  • Exemplos_OSM 3. I also provided a template layout file in that folder if that doesn't work.
    – HenriQue
    Dec 26, 2022 at 14:25
  • So you don't use altas function? You manually set the extent of the layout? Why then would you create the municipality name automatically? Seems I don't quite understand your use case. In my solution, I used an atlas with the polygons as coverage layer.
    – Babel
    Dec 26, 2022 at 14:27

2 Answers 2

2

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.

1
  • 1
    That was it! I never even thought about the CRS. Thanks a lot for the help!
    – HenriQue
    Jan 2 at 10:15
2

Rather then using your approach, which is very inefficients (still, see a solution for that in my other answer), I would heavily advice using the atlas function.

  1. Create a new layer called coverage with polygons representing the extent of the layouts you want (see screenshot at the bottom). When you set up the atlas, QGIS will automatically generate a layout for each polygon with the extent of this polygon - this is a very handy way to get a separate page for different areas of interest and still keep the same layout settings, but with dynamic parameters that respect the current extent for each layout sheet.

  2. In your layout, go to the tab Atlas check the box Generate an atlas and select the layer created in step 1 as Coverage layer.

    enter image description here

  3. Got to Item Properties of your map and check the box Controlled by Atlas. enter image description here

  4. Now go to your text field and use this expression:

     attribute (
         get_feature_by_id(
             'Cont_AAD_CAOP2021',
             overlay_intersects ('Cont_AAD_CAOP2021', $id, sort_by_intersection_size:='des')[0]
         ),
         'Concelho'
     )
    

enter image description here

Coverage layer with polygons in pink, the one highlighted in yellow is the one producing the layout above: enter image description here

1
  • I didn't have your project. I have now updated the solution based on the project you provided.
    – Babel
    Dec 28, 2022 at 11:54

Your Answer

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

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