I am trying to symbolize a point layer with rectangles shaped and colored by gradient according to attribute values. I am trying to do this via label backgrounds rendered as "Geometry generator" marker symbols to prevent rectangles from overlapping and enable easy callout creation (and to enable gradient fill -- this is, to my knowledge, impossible with Ellipse markers).

Here is an overview of what I am trying to achieve. The white rectangles (these are label background symbols) are placed as I want, but I cannot color them properly. The colored rectangles are created with geometry generator, they are the desired symbols, but I cannot place them correctly.

enter image description here

I encountered a feature of geometry generator I cannot explain. Let us take the following table as an example point layer:

x   y
10  12
15  27
43  43
27  15
12  10

When I pass the code $geometry to geometry generator in the Symbology section, the points are placed where they are meant to be:

enter image description here

However, when I add labels and pass the same code to geometry generator in Labels > Background > Marker symbol, the points are placed well away from the point locations:

enter image description here

These labels change their locations as I drag the map canvas, they enclose the point layers when the points are near the upper left corner of canvas. The locations of text labels remains as usual.

I have two (three) questions:

1. Why are the geometry-generated label background symbols placed like that?

2. How can one avoid such improper placement?

(3.) Maybe there is another way to symbolize points with geometry generator and prevent them from overlapping that is less painful?

  • I'm able to reproduce this, hopefully somebody has an explanation. But why dont you use the "rectangle" background symbol, by using data defined properties on buffer size and color you should be able to do what you want ? – J.R May 18 at 13:09
  • It wanted to color it in a gradient manner, it is impossible with rectangle symbols without sophisticated buffering I am not familiar with. – taprs May 18 at 13:11
  • You mean a gradient in each polygon or one color per polygon with a repartition by polygon along a gradient – J.R May 18 at 13:52
  • I updated my question with the picture of what I was dreaming of. The gradient is slightly different in each symbol, this is how I wanted to depict the ranges of attribute in each point. – taprs May 18 at 13:54

For what you want to do, it is probably better to use Filled Marker or Points displacement style renderer instead of Single Symbol.

Screenshot: Filled marker with label: enter image description here

Screenshot: compare the two rendering options. Points displacement (right side) allows you to define a Distance and Placement method: enter image description here

If you really want to use label backgrounds, be sure to have proper setting in the placement tab: I used Offset from Point, and placed it in the middle.

Screenshot: red dots (original point symbol) and blue rectangle (label Background): enter image description here

  • I don't like the 'Points displacement' renderer as it does not point to exact locations of points (I will keep this option in mind, thank you). Using 'Offset from point' instead of 'Around point' with zero distance did not fix this issue for me (maybe you were using not 'geometry generator' background marker symbols?) – taprs May 18 at 13:12
  • I don't think you approach leads you where you want, at least there are other options using geometry generator to create a proper kind of Points displacement. However, you should explain more in detail where you want to have your symbols and under what condition. – Babel May 18 at 13:26
  • Thank you for your time! I updated my question with an image that contains the gradient-colored rectangles I want to use and rectangle labels I want to mimic in terms of placement. – taprs May 18 at 13:53
  • I tried 'Points displacement' and encountered the same problem -- the rectangles created by geometry generator do not change place as normal point symbols would do. – taprs May 18 at 14:11
  • Set a rectangle as symbol – Babel May 18 at 14:13

I did not manage to make label backgrounds work properly. I made a clumsy workaround using point symbology and the Expression Builder since I am not experienced with PyQGIS classes and functions.

This is the original data with attributes I wanted to depict with rectangles:

pop x   y   min max n   placing_x   placing_y
11  -2387981.505    3775859.307 1.01    1.13    4   right   down
12  -1941488.19 4181736.9   0.99    1.13    1   right   down
13  53559.889   2291172.327 1.01    1.12    4   left    up
14  50652.236   2291661.88  1.02    1.1 1   left    down
7   -3016462.464    4607316.088 0.98    1.1 1   left    up
8   -2968065.604    4431503.4   0.98    1.06    1   right   down
9   -3002923.802    4454940.99  0.99    1.09    1   right   up
10  -2092972.683    3321772.21  0.99    1.14    4   right   down
S2  -5801526.999    4622477.218 1.05    1.27    5   right   down
S3  -4576538.657    4279330.501 1.22    1.3 5   right   down
S4  -4586348.397    4283898.882 1.18    1.3 5   right   up
S5  -4637773.282    4278981.752 1.17    1.23    5   left    down
15  -1964593.017    4269980.772 1.01    1.11    1   right   up
21  -3165463.862    3909144.758 0.93    1.05    3   left    down
24  -3307648.848    4099644.049 0.98    1.1 2   left    down
S1  -5801526.999    4622477.218 1.15    1.41    5   right   up
S6  -4956384.622    4171352.355 1.27    1.33    5   left    up
S7  -3895551.651    2375986.041 1.21    1.33    5   right   up

I wanted rectangles to be as long as (max - min) and as high as n. The respecitive gradient coloring should have represented the part of the overall gradient ramp ranging from the minimum min value to the maximum max value. I created variables placing_x and placing_y for the convenient adjustment of rectangle position and filled them manually.

The resulting expression for the rectangle follows:

with_variable('x_offset', ("max" - "min") * 0.1 * @map_scale,
with_variable('y_offset', "n" * 0.0005 * @map_scale,
with_variable( 'rect', make_rectangle_3points(
make_point($x - @x_offset, $y - @y_offset), 
make_point($x - @x_offset, $y + @y_offset),
make_point($x + @x_offset, $y + @y_offset)
WHEN "placing_y" = 'up' AND "placing_x" = 'right' THEN
translate(@rect, 0.005 * @map_scale, 0.004 * @map_scale)
WHEN "placing_y" = 'down' AND "placing_x" = 'right' THEN
translate(@rect, 0.005 * @map_scale, -0.004 * @map_scale)
WHEN "placing_y" = 'up' AND "placing_x" = 'left' THEN
translate(@rect, -0.005 * @map_scale, 0.004 * @map_scale)
WHEN "placing_y" = 'down' AND "placing_x" = 'left' THEN
translate(@rect, -0.005 * @map_scale, -0.004 * @map_scale)

enter image description here The data-defined gradient color ramp boundaries are set as follows:

(aggregate(@layer, 'min', "min")-"min") / ("max" - "min")

for the left boundary and

1 + (aggregate(@layer, 'max', "max")-"max") / ("max"-"min")

for the right boundary.

enter image description here

Finally, I added the text labels using pop field with Cartographic positioning and data-defined position priority:

WHEN "placing_y" = 'up' AND "placing_x" = 'right' THEN 'TR'
WHEN "placing_y" = 'down' AND "placing_x" = 'right' THEN 'BR'
WHEN "placing_y" = 'up' AND "placing_x" = 'left' THEN 'TL'
WHEN "placing_y" = 'down' AND "placing_x" = 'left' THEN 'BL'

enter image description here


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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