12

Using native QGIS layer property definitions, I have successfully labelled each polygon in my layer with its area and perimeter.

Never satisfied, I now wish to label each side of each polygon with its length.

It would seem to be a common-enough requirement but I'm not getting good hits.

3
  • 1
    You have to unbuild polygons into edges
    – FelixIP
    Oct 7 '15 at 0:57
  • 2
    I think you will have to convert polygon to lines. And label it using $length expression. Oct 7 '15 at 2:38
  • How can we make it in Qgis 3.4 because seems Networks doesnt have the option split regard Apr 15 '19 at 2:15
13

Dec 2020 update

The method posted in this Twitter link included in the original version of this reply using nodes_to_points() doesn't render properly in QGIS 3.12+.

So I have rewritten this reply. You can, it turns out, just use segments_to_lines(). The method below works in QGIS 3.6 onwards.

Method

  1. Create a geometry generator symbology (geometry type LineString/MultiLineString) with the following expression:

segments_to_lines(force_rhr($geometry))
  1. Create a Marker Line symbology under #1. Set marker placement to "on central point", line offset to -5 millimetres (or as preferred), and set marker symbology to 'Font marker'

  2. Under 'Font marker' go 'Character', select the data-defined override > Edit and enter the following expression

format_number(length(geometry_n($geometry,@geometry_part_num)),1)||'m'
  1. Optional - To prevent upside down labels, disable 'Rotate marker to follow line direction' under the Marker Line symbology (QGIS 3.10 onwards) and use the following data defined override for Rotation under the Font Marker symbology

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

enter image description here

You can also download and import the 'Polygon_Dimension_QGIS3x' xml style from QGIS Style Hub as a base with the CAD-style dimension styling, but I recommend changing the geometry generator to include force_rhr()

QGIS 2.18 - 3.6

The style can also work in QGIS 2.18, however you need to remove force_rhr() from the above expressions and ensure all your polygons observe the right hand rule.

See example screenshot from QGIS 2.18 (with polygons observing RHR) which is how it looks like in QGIS 3.6 onwards (regardless of polygon orientation) with additional CAD dimension styling.

enter image description here

2
  • Do you know why it doesn't work in the Geometry Generator inside Labels->Placement?
    – Felippe M.
    Feb 3 at 19:35
  • 1
    Because each individual side is not its own geometry so the label engine can't calculate the length of each side and put that value in the right location. You can use Labels->Placement to have a label placed on every side of the polygon of course, but the label text won't dynamically change. The only other work around afaik is to use Rule-based Labels to manually set up a label for every potential side. Which is hugely time consuming
    – she_weeds
    Feb 4 at 6:19
12

The "networks" plugin in QGIS has a facility to split polygons into individual line segments which you can then label with length. I discovered this by trying various search terms in the plugin installer menu. Searching for "split" there did the trick. Install "networks" from the plugins menu.

First convert your polygons to lines using the standard "Vector -> Geometry Tools -> Polygons to Lines" menu option, creating a new shapefile and layer in the process. This won't touch your polygons.

Then select the new lines layer, turn editing on via the pencil icon, and select all the features, then run the "Vector -> Networks -> Split" item. Now you have many line segments! Turn editing off, and save the changes.

Turn on labelling, and use $length for the label. There were too many decimals when I first did this, so I used substr($length, 1, 4) to get this:

labelled line segment lengths

You could also use round($length, 2) for the same effect, but if your line lengths are in thousands or millions of units then you'll still get long labels. You could scale them by 1000000 in the labelling expression, but you will have difficulty getting consistent length labels if your line lengths span several orders of magnitude. It is possible to write a custom python function for formatting numbers in scientific notation to a constant width, and I've just done that and it looks okay.

If you give your line layer an invisible line style then you'll just get your polygon styling with labels on the edges.

enter image description here

Note the 0.37 and 0.10 on the upper left feature seem to be labelling the same side, but that's because there's a node splitting that line. If this is a problem with your case then I suspect a generalisation with a very small, or even zero, tolerance should be enough to remove nodes where you have perfectly straight sides defined by more than one line segment. You can map the nodes of your polygons by using "Vector -> Geometry Tools -> Extract Nodes" to create a point shapefile if you can't see where they are.

3
  • could you add a point symbol on each node to show the splits?
    – Ian Turton
    Oct 7 '15 at 8:03
  • @iant yes, I can do this by adding a "marker line" symbol layer with the marker set to appear every vertex. Neater than making a new layer.
    – Spacedman
    Oct 7 '15 at 9:26
  • Thank-you @SpacedMan for pointing me to the Networks plug-in and the effort you put into this answer.
    – Bad Loser
    Oct 8 '15 at 7:24
4

If you want to automate that, it can all be done with Processing.

1) Convert to lines using the "Polygons to lines" algorithm

2) split single segments using the "Explode lines" algorithm

Style your layer as explained above, and save the style as a qml file

3) apply the style using the "Set style for vector layer" and the style that you just saved

Now if you put the three steps above in a model using the Processing modeler, you can create a new algorithm that takes a polygon layer and generates your labels in a single step

It should look something like this

enter image description here

4
  • I really like the Processing Modeller approach but it is causing me severe grief. According to this [wiki] (docs.qgis.org/2.6/en/docs/user_manual/processing_algs/qgis/…) the Set style for vector layer algorithm should have a definable output Styled layer. The dialog is allowing me to define the parameters Vector layer and Style file but that is all. Consequently the styling is never rendered and nor is it possible to follow the algorithm with another. Do you see the results of the styling on your canvas?
    – Bad Loser
    Oct 8 '15 at 7:57
  • Will open this as a new question in order to easily provide further data.
    – Bad Loser
    Oct 8 '15 at 20:40
  • New question link: gis.stackexchange.com/questions/165888/…
    – Bad Loser
    Oct 8 '15 at 21:54
  • hmm, it works fine here, but you are right that this is a strange case, since the output is hidden. Reason for this is that the output is the input itself, not a different file, so the UI should not let the user select the output filename. Oct 9 '15 at 10:50

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.