2

I have a polyline layer in QGIS representing hectometers along a railroad. I have added labels to this layer representing the hectometer number:

enter image description here

However, the project I am currently working on requires for the labels to be placed like this:

enter image description here

I have the following labeling settings on my layer:

enter image description here

I have tried fiddling around with the settings, but I can't seem to find a way to do this. I also thought of labelling a hidden point layer and offsetting the label from the point instead, however since the railroad itself (black) changes orientation quite a bit the rotation value for each offset point label would have to be different, which is not feasible for the number of features in the hectometer layer.

How can I achieve the above labelling in QGIS?

1
  • have a look at the end_point and end_angle functions
    – Ian Turton
    Commented May 15, 2020 at 11:13

4 Answers 4

9

You can try using the geometry generator in your label placement settings so you have fewer things to change (see screenshots in this slightly related answer for an example).

They typically deal with offsets in map units but you can get it to work with your zoom level by working with the @map_scale variable.

Two methods:

Method 1 - point + rotation

  1. Use the following expression for the geometry generator (set geometry type to Point/Multipoint).

    Change the 0.005 to increase or decrease the distance of the label from the end of your line depending on your CRS (preferably projected).

project(end_point($geometry),
        @map_scale*0.005, --change multiplier for distance
        radians(angle_at_vertex($geometry,num_points($geometry)-1)))
  1. Use the following data-defined override for your Rotation
angle_at_vertex($geometry,num_points($geometry)-1)+90
  1. Set the Placement to 'Offset from point'

Method 2 - line substring (easier)

2024 update

Due to updates in label placement settings in QGIS 3.16 in Oct 2020, this method is easier. It has also been updated to reflect the options available.


  1. Adapt the following expression for the geometry generator (set geometry type to LineString/MultiLineString).

    • Change the first 0.01 to increase or decrease the distance as in method 1.

    • Change $geometry to reverse($geometry) to place the label at the start of the line.

line_substring(reverse(extend($geometry, --change to reverse($geometry) for start of line
                              0,
                              @map_scale*0.01)), --change 0.01 as required
               0,
               @map_scale*0.01)
  1. Set the Placement to 'Parallel' with Allowed positions = On line (uncheck all other options)

  2. Under Label Anchoring > Settings > use End of Line for more consistent spacing between line and variable-width label

  3. Set the 'Overrun feature' setting to 5 millimetres (optional)


Results:

enter image description here

5
  • I can't find a geometry generator in the labels placement settings anywhere. Which version of QGIS are you using?
    – user32882
    Commented May 15, 2020 at 13:01
  • I am using QGIS 3.12 but geometry generator placement for labelling has been available since QGIS 3.8
    – she_weeds
    Commented May 15, 2020 at 13:12
  • Allright, I have 3.4. Better update....
    – user32882
    Commented May 15, 2020 at 13:14
  • Works. Like a charm. Thanks for helping me solve this complex problem.
    – user32882
    Commented May 15, 2020 at 13:35
  • Works very well! Thank you!
    – berkayoruc
    Commented Nov 16, 2020 at 12:51
4

Use the following setting in the 'Labels' menu

labels

Coordinate X: x(end_point($geometry)) # add some delta or interpolate the line
Coordinate Y: y(end_point($geometry)) # add some delta or interpolate the line
Horizonal Alignment: 'Left'
Vertical Alignment: 'Half'
Rotation: angle_at_vertex($geometry, num_points($geometry)-1) - 90

result

2
  • This is nice, but the labels are not centered on the line. This is also true in the example you provide... Do I have to create expressions in the "Alignment" portion? If so which ones?
    – user32882
    Commented May 15, 2020 at 11:42
  • Can you say anything about the zoom dependency? It is highly zoom dependent how these label offset from the end of the line...
    – user32882
    Commented May 15, 2020 at 12:23
4

You need to use some data defined properties on your x and y placement for your label

The idea is to retrieve the xy coordinate of the last (or first) vertex of your line layer and using these coordinate with an offset for your label position.

The two following expression do the job for me (look at the picture for other setting), they take account line rotation and scale to provide a constant offset regardless of scale

$x_at( -1)+((0.01*cos(radians(angle_at_vertex($geometry, num_points($geometry)-1) - 90)))*@map_scale)

$y_at( -1)+((-0.01*sin(radians(angle_at_vertex($geometry, num_points($geometry)-1) - 90)))*@map_scale)

(change the 0.01 offset value to your need)

For orienting the label use the following expression in the rotation setting :

angle_at_vertex($geometry, num_points($geometry)-1) - 90

and for best result set "Horizonal Alignment" as 'Center' and "Vertical Alignment" as 'Half'

enter image description here

3
  • This is nice, but the labels are not centered on the line when I use it in my case...
    – user32882
    Commented May 15, 2020 at 11:41
  • I used the horizontal and vertical alignments which work, but now the problem is that the offset distance is in map units whereas I would like for it to be in canvas units so that when I zoom out the same offset is preserved....
    – user32882
    Commented May 15, 2020 at 12:05
  • Could you place that comment (along with some background) as an answer to gis.stackexchange.com/questions/361822/… ? If no better answer is given I can accept it as final answer...
    – user32882
    Commented May 15, 2020 at 12:31
0

@Taras and @J.R both provide helpful answers, though incomplete, since the alignment is not centered. These are the expressions I ended up using under the data-defined section:

X: x(end_point($geometry))+5
Y: y(end_point($geometry))+3
Horizonal Alignment: 'Center'
Vertical Alignment: 'Half'
Rotation: angle_at_vertex($geometry, num_points($geometry)-1) - 90

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.