1

I have a line layer which is my project axis (red line in the picture). Along that layer I have created points with a spacing of 100 meters.

Those point geometries are represented as line symbols. Using the "align points to feature" algorithm I generated a column to made the line symbols perpendicular to the axis (black lines in the picture).

Now I would like to label the distance (which is an existing attribute of my points) at the end of the line at the same angle.

I managed to rotate the text of the label so that it is parallel to my marker but the position is off. Is there a way to tell QGIS in which direction it should apply the distance offset?

enter image description here

3
  • related gis.stackexchange.com/questions/361811/…
    – Mapperz
    Commented Feb 2 at 15:02
  • Just to clarify, the perpendicular lines are actually point geometries, but depicted as lines using geometry generator (and rotated based on rotation field derived from the Align points to features algorithm)?
    – she_weeds
    Commented Feb 3 at 0:50
  • Yes the perpendicular lines are points. I figured it was easier this way and more flexible if I wanted to change the length of the lines down the road Commented Feb 4 at 5:49

1 Answer 1

3

Concept: place label relative to line symbol, not original point geometry

Labels are placed by default in relation to the layer's original geometry (in this case, point). To achieve your goal, you need the label to "access" the line representation, and place the label in relation to that.

But also, you mentioned wanting to change the line symbol length as required. So the label has to be able to access this length value, and adjust the label location dynamically.

There are two solutions:

  1. Use a Geometry Generator symbol for the line, and a Font Marker symbol for the distance text. This method is more straightforward, but far more restrictive in text style/placement.

  2. Set a Layer variable to control your line symbol length (the line symbol can be Simple Marker or Geometry Generator), and a Geometry Generator in the label settings (under the Placement tab) to recreate a section of the line symbol to guide label placement. Most of this answer explains this method. This allows you to use the entire suite of label settings.

Notes:

  • Both methods assume your layer is in a projected CRS.

  • For Method 2 you must use projected map units/metres for the symbol size (Simple Marker) or geometry generator symbol settings.

  • Assume your rotation field is "angle" and the value you want to display as label text is "distance"

  • If you want to generate regular chainage points and labels as a geometry generator style or virtual layer, without an in-between layer, refer to this answer. You can adapt the styles below accordingly


Method 1: GG symbol + Font marker

  1. Create a geometry generator symbol to display your points as lines with the following expression:

    with_variable('line_length',
                  20,        -- change length of line symbol here
                  make_line(project($geometry,
                                    -@line_length * 0.5,
                                    radians("angle"+90)),
                            project($geometry,
                                    @line_length * 0.5,
                                    radians("angle"+90))))
    
  2. Create another symbol layer underneath Geometry Generator and make it a Marker Line, then change its Simple Marker to a Font Marker.

    enter image description here

  3. Use the following data-defined overrides for the font marker:

    enter image description here

    Rotation (based on this style via @pigreco):

    CASE WHEN azimuth(start_point($geometry),end_point($geometry))> pi()
    THEN angle_at_vertex($geometry,0) + 90 + @map_rotation
    ELSE
    angle_at_vertex($geometry,0) - 90 + @map_rotation 
    END
    

    Offset:

    array(CASE WHEN 
              azimuth(start_point($geometry),end_point($geometry))> pi()
              THEN regexp_substr(@value,'([^,]+),') * -1
              ELSE
              to_real(regexp_substr(@value,'([^,]+),'))
              END,
         regexp_substr(@value,',([^,]+)'))
    

    Character(s):

    to_string("distance") --replace with distance field in point layer
    
  4. To change the distance of the text from the line, change the x value in the Font Marker offset directly in the GUI after applying the above data-defined overrides.

    enter image description here

  5. To change line symbol length, change the @line_length variable value in the Geometry Generator symbol expression in step 1 (shown as 20).

    enter image description here



Method 2: Layer variable + GG label

  1. Set your line symbol length (must be in map units/metres) as a layer variable under Layer Properties > Variables. For example, line_length_m.

    enter image description here

  2. Then adjust your symbology depending on what you used:

    • Simple Marker line symbol → set Size data-defined override to @line_length_m
    • Geometry generator symbol → change expression to use @line_length_m

    enter image description here

  3. Under Labels > Placement enable the Geometry generator, set it to LineString geometry, and paste the following expression using @line_length_m:

    with_variable('text_distance',
    2, --change text distance here
    --if using negative vals above, set overrun distance in label settings
    line_substring(
                   reverse(extend(make_line($geometry,
                                             project($geometry,
                                             @line_length_m * 0.5,     --symbol length variable
                                             radians("angle"+90))), --replace angle column as required
                                  0,
                                  @map_scale*(0.01 + (@text_distance * 0.001)))),
                   0,
                   @map_scale*0.01)
                   )
    

    And also go to Label Anchoring > Settings and set it to End of Line.

    enter image description here

    • For an explanation of the expression, scroll down
  4. To change the distance of the text from the line, change the text distance variable (second line) in the label geometry generator expression as above.

    enter image description here

  5. To change the line symbol length, change the variable in Layer Properties and hit 'Apply' to preview. Unfortunately, there isn't a way to access layer variables from the main window/panels at this time.

    enter image description here


Explanation for Method 2 expression

Let's say you have a line symbol that is 50 metres long (must be map units).

You can recreate the outer half of the line symbol (25 metres), using this expression in a Geometry Generator symbol:

make_line($geometry,
          project($geometry,
                  25,                     --replace length as required
                  radians("angle"+90)))   --replace angle column as required

Here is a visualisation of what that generated geometry would look like - the green parts:

enter image description here

Now by pasting the expression in the label geometry generator section instead, the label engine visualises the geometry for its own use (not visible to user), and applies the label accordingly.

Next: how do we place labels at the end outside the line? This has already been answered here (method 2) (recently updated).

The expression extends the linestring input a bit and snips it, with the effect of placing the label on an imaginary extension past the input line.

enter image description here

Change the distance by which to extend the imaginry linestring and it pushes it (and therefore the label) further away.

enter image description here

That answer is for actual linestring geometry layers, where the linestring input is simply $geometry, but here we have a line expression. So replace $geometry in that expression with the line expression above.

1
  • Thanks a lot, for taking the time to answer in such detail. Works perfectly and thanks to your thorough explantation I can adapt this in the future if needed. One point that did not work at first by just following your instructions was the vertical allignment of the text at the end of the line. I had to change the "allowed positions" under the "general" in the Placement tab to only "on line". Maybe thats the default and I changed it previously while playing with the settings Commented Feb 7 at 7:54

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