I have a QGIS 3.22 vector layer which comes from an OGC API - Feature provider (WFS-3). This service is feeding features as large GeoJSON objects, all with the same structure but which content (mostly under properties) varies from feature to feature. And it varies both in length (a few word vs a whole paragraph) for a same field, or sometimes some fields are simply not filled (null).

I have already built a small multi-A4-pages atlas in the print layout, rendering some specific parts of the GeoJSON object properties as separate "labels" (i.e. block of text), rendered as HTML with the help of Python functions to parse the JSON structure as I need:

a multi A4 pages atlas Fig.1: My current 3 A4 pages atlas layout.

As the content of the GeoJSON properties is highly variable, all reddish blocks (fig.1) shall have an adaptable height, represented by the right arrows, according to their content.

From here, I'm mainly facing two problems:

  1. The first one is that if for example, the block 1 or 3 do not have any data in their original property field in the GeoJSON object, there will be a large blank portion on the page, which is not aesthetic (fig. 2).
  2. The block 5 is so large that it may spread over more than 1 A4 page.

white blanks in the atlas Fig.2: Behaviour of my current 3 A4 pages atlas layout when some data blocks are empty.

Therefore, how could I "glue" the dynamic blocks together, i.e. by letting virtual springs (fig. 3) attached to them so that there won't be any blank space left, i.e. all content will move up according to the free space on their top (if any) in cases where there is no or too few data?

Bonus question, but still related, how to handle page breaks when a label content is large? Because for the moment, if I draw a large label rectangle over two pages, some text lines are printed in the small space "between" the two A4 pages, so this text is "cut", hence not rendered by the printer.

atlas with springs Fig.3: How I'd like my 3 A4 pages atlas layout to actually behave; content should dynamically 'stick' to their respective predecessor block.

I already tried to play with this: https://docs.qgis.org/3.22/en/docs/training_manual/map_composer/dynamic_layout.html but it doesn't help much as I cannot place a label "relative" to its predecessor (or any other label on the page by filter it's id for example, cf image below), which I guess would be the perfect feature for solving this problem.

What I was hoping for (kind of)
Fig.4: This is the kind of (theoretical) parameter I am searching for.

  • Can't you combine the text fields that belong together (like Header + block 2; block 4 + 5 etc.) together to one single field and use html styling options to make them look as you want?
    – Babel
    Commented Jan 2, 2022 at 19:36

1 Answer 1


Short answer

Use data driven override for the height of both text boxes as well as for the vertical position of the second text box, whereas this latter value is the sum (pseudocode) of: vertical position (box_1) + height (box_1) + white_space. Height of box 1 as well as box 2 is a function based on the length of the respective text fields: length("text").

Vertical position of textbox 2 adapts to textbox 1, height of both textboxes adapt to the length of the text contained: enter image description here

Answer in detail

To have the the size of the text label change dynamically based on the length of the content (text), in the item properties go to Position and Size and for Height select the data driven override icon and choose Assistant...

enter image description here

Insert an expression that returns the length of your text: length(text), load Valus from/to and set Output from/to to values that fit for your texts (trial and error). These values depend of course on the width of the text box, the font and size of the text etc. Now the size of the first text label will adapt to the length of the text.

enter image description here

For the second text field, the trick is now to use a data driven override in Position and Size for the Y value (the one that positions the upper boundary) to a data driven ovverride, consisting of three elements that should be added:

  • (1) The Y value of the first text box +
  • (2) height of the first text box +
  • (3) an additional distance for blank space between first and second text boxes .

No 1. can be copied from the Y value of box 1.

No. 2 can be copied from the first textboxes Height / Data Driven Override / Edit... field, where you find what we created with the assistant as an expression, something like: coalesce(scale_linear(length(text), 8, 6389, 5, 260), 0).

No. 3 can be chosen freely.

So the final data driven override for Y value (vertical position) of textfield 2 looks something like:

4 + coalesce(scale_linear(length(text), 8, 6389, 5, 260), 0) + 2
  • 4 = Y-value of text box 1
  • coalesce ([...]) = data driven override of Height value of text box 1
  • 2 = additional white space between box 1 and 2.

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.