1

I have a QGIS print layout with an atlas layer for which I would like the map extents to show the current atlas feature and a nearby point. The layer provider is postgis.

It seems the only way to do this is provide separately the xmin,xmax,ymin,ymax via expression to qgis. I've also discovered it behaves oddly if the aspect ratio of the bounding box is different than the map item so I need to account for that too.

What I've tried so far:

Get a bounding box from PostGIS scaled by 10% height

SELECT t.territory,
 st_expand(t.bbox, ((st_ymax((t.bbox)) - st_ymin((t.bbox))) * (0.1))) AS geom
FROM
 (SELECT
   parcellayer.id,
   st_envelope(st_union(parcellayer.geom, 
    (SELECT pointlayer.geom FROM pointlayer LIMIT 1))
   ) AS bbox 
 FROM parcellayer) t;

this gets me a box but I need to make sure it's the same aspect ratio (2:1) I can do a bunch of complicated case statements, but is there an easier way to go about this?

4
  • If your map in the layout is 2:1 aspect ration, then it will always be... You have to only set that select as your atlas layer and you are good to go, I think. You can set atlas feature margin to 0%, or leave it at 10% and remove that scaling from select, it has the same effect.
    – DavidP
    Jun 20, 2019 at 5:39
  • Have you test the code in this blog article ? Jun 20, 2019 at 7:21
  • @DavidP I have the original feature set as atlas since my layout has two maps - one around just the feature and one showing the feature in relation to the point.
    – J M
    Jun 21, 2019 at 12:59
  • @J. monticolo good suggestion, I've previously used a custom expression for this but unfortunately custom expressions aren't very portable in qgis. If they could be distributed with the project file that might be a good solution.
    – J M
    Jun 21, 2019 at 13:01

2 Answers 2

1

So here's the answer I came up with:

(I'll wait to accept this answer until the bounty expires in case someone else can come up with something better)

In POSTGIS:

SELECT 
 t.id,
 st_centroid(t.bbox) as geom,
 greatest(
  (st_xmax(t.bbox) - st_xmin(t.bbox))*0.5,
  st_ymax(t.bbox) - st_ymin(t.bbox)
  ) as radius
FROM
 (SELECT
   parcellayer.id,
   st_envelope(st_union(parcellayer.geom, 
    (SELECT pointlayer.geom FROM pointlayer LIMIT 1))
   ) AS bbox
 FROM parcellayer) t;

This produces a point in the center of the combined bounding box as well as a 'radius' value that is either the height of the bounding box (if the box is taller than wide) or half the width (if the box is wider than tall).

in QGIS we can then assign our extents as follows:

xmin:

xmin(
 geometry(get_feature(
   'FrontMapExtents','thislayercolumnname',"atlaslayercolumnname" 
   )))
-
attribute(
 get_feature(
  'FrontMapExtents','thislayercolumnname',"atlaslayercolumnname" 
  ),
  'radius'
)

xmax: same thing but swap to 'xmax()' and add the radius instead of subtract.

ymin:

xmin(
 geometry(get_feature(
   'FrontMapExtents','thislayercolumnname',"atlaslayercolumnname" 
   )))
-
attribute(
 get_feature(
  'FrontMapExtents','thislayercolumnname',"atlaslayercolumnname" 
  ),
  'radius'
) * 0.5

basically same thing but *0.5 since the box is half as high as it is wide.

ymax: same thing but swap to 'ymax()' and add the radius instead of subtract.

One nice advantage of this method is you can just add a multiplier to the radius value to add a % buffer around the features.

0
+100

If I get this right you want a canvas having two map elements, one showing the combined features of two layers and the other showing a detail map of one of the layers features.

Try using a hidden Coverage layer with your combo BBOX covering each feature pairs, and set the extent of the feature detail map to a map-element specific margin (using Variables | @map_extent_height & @map_extent_width):

  • Get the BBOX of your combined features and the extent of the current parcel into a Coverage layer (make sure you hide it in the Atlas options):

    SELECT  ST_XMin(a.geom),
            ST_XMax(a.geom),
            ST_YMin(a.geom),
            ST_YMax(a.geom),
            ST_Envelope(ST_Collect(a.geom, b.geom)) AS geom
    FROM    parcellayer AS a,
            pointlayer AS b
    ;
    
  • Set extents of the detail map ( increased by e.g. 0.05 (5%)):

    "st_xmin" - (  sqrt( @map_extent_width ^ 2 + @map_extent_height ^ 2 ) * 0.05 )
    "st_ymin" - (  sqrt( @map_extent_width ^ 2 + @map_extent_height ^ 2 ) * 0.05 )
    "st_xmax" + (  sqrt( @map_extent_width ^ 2 + @map_extent_height ^ 2 ) * 0.05 )
    "st_ymax" + (  sqrt( @map_extent_width ^ 2 + @map_extent_height ^ 2 ) * 0.05 )
    

Now, for me this worked wonderfully on a bunch of test cases. I cannot reproduce any strange behavior with the map element scaling; if, however, you encounter any, setting the extent explicitly also for the combo map might do the trick.

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.