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
    May 15 '20 at 11:13
6

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 + overrun

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

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

.

reverse(line_substring(reverse(extend($geometry,0,@map_scale*0.01)),0,@map_scale*0.01))
  1. Set the 'Overrun feature' setting to 5 millimetre at least.

  2. Set the Placement to 'Parallel' with Allowed positions = On line (uncheck all other options)


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
    May 15 '20 at 13:01
  • I am using QGIS 3.12 but geometry generator placement for labelling has been available since QGIS 3.8
    – she_weeds
    May 15 '20 at 13:12
  • Allright, I have 3.4. Better update....
    – user32882
    May 15 '20 at 13:14
  • Works. Like a charm. Thanks for helping me solve this complex problem.
    – user32882
    May 15 '20 at 13:35
  • Works very well! Thank you!
    – berkayoruc
    Nov 16 '20 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
    May 15 '20 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
    May 15 '20 at 12:23
3

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
    May 15 '20 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
    May 15 '20 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
    May 15 '20 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, privacy policy and cookie policy

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