12

Background:

As part of a route selection process I have multiple route options which often share segments. I need to keep the underlying data correct while displaying all routes in a way that they don't obscure each other.

Desired Result:

I would like to do this by offsetting the different routes, but only where they share segments with other routes, something like this (taken from another SE question): enter image description here

What I've Tried:

Giving each route an offset in its symbology works OK when the routes are overlapping but this method breaks down when they are not because the route is now being shown in the wrong place.

I tried following this answer to a similar question: https://gis.stackexchange.com/a/141627/98170 but the result is the same as manually applying offsets as above.

This question and answer look great: Display overlapping polyline segments as multiple lines with offsets? but it is for Leaflet not QGIS.

This answer https://gis.stackexchange.com/a/239370/98170 is almost there but I don't want it to pinch back in at each vertex and I don't know how it would work when the lines are no longer overlapping.

I've tried messing around in the geometry generator but to no avail also.

Any help with this would be much appreicated.

5
  • You could create a new line layer, divided into segments, where each segment has one field for each route in the original layer, and yes or no for the value. Then use a rule-based style for the new layer. Eg, one rule would have this filter: "route1 = 'yes' and "route2" = 'yes' and "route3" = 'no', with a style that has a line for route 1 and a line for route 2, with appropriate offsets.
    – csk
    Commented Sep 3, 2019 at 19:06
  • @csk The problem is that the number of overlaps can change so that at one section route 3 would need to be offset but 1 but at another section it may need to be offset by 3 Commented Sep 4, 2019 at 8:05
  • That's what I meant by "divided into segments." The section where that route needs to be offset by 1 should be a separate segment from the section where it needs to be offset by 3. Make sure each route has a unique "route name" or "route number" attribute so you can make their color depend on that attribute.
    – csk
    Commented Sep 4, 2019 at 16:52
  • I found this method to get a count of how many route overlap each segment: gis.stackexchange.com/a/290883/81764
    – csk
    Commented Sep 4, 2019 at 18:25
  • Thanks @csk, I think that would be the best method for a smaller number of routes, however at the moment I can have any combination of 16 routes overlapping in different sections so that may be too time consuming. Great idea about having a single line which lists each route it is included in though. Thank you Commented Sep 6, 2019 at 10:32

2 Answers 2

5
+50

I truly believe that I have got your question correctly. Thus, you want an offset where transport lines share same geometry otherwise they have to remain at the same place.

Let's assume there is a point layer "transport_routes" with its corresponding attribute table accordingly, see image below.

input

For Labelling I used this expression:

array_to_string(array_agg("Line", group_by:=geom_to_wkt($geometry)))

IMHO here is a workflow.

Step 1. Perform what @Kazuhito suggested in his answer, i.e. break the polylines into segments. Alternatively check this article Splitting all lines in layer at vertices using QGIS?.

Step 2. Proceed with RMC > Symbology > Offset > Edit... and using an expression below, see image below.

window_offset

The expression:

range(count(1, group_by:=geom_to_wkt($geometry)), group_by:="Line")

The result will look like

result


References:

3
  • But how angles edges will look like? Do they are connected correctly?
    – M-Rick
    Commented Jul 6, 2020 at 17:28
  • That is why there is a requirement of breaking the polylines into segments on vertices or lines overlap
    – Taras
    Commented Jul 6, 2020 at 17:31
  • I tried it, but angles are not connecting. Every segment is independent. ibb.co/xY8qKmQ
    – M-Rick
    Commented Jul 6, 2020 at 19:47
1

Instead of offsetting multiple routes when the routes overlap segments, how about increasing the symbol width by multiples based on

  1. How many overlapping routes exist on a segment, and
  2. The cartographer-selected stacking order.

You can compute the count of overlapping segments as Kazuhito suggests in this related question.

Add four columns to your routes:

  1. Base_symbol_width
  2. Prefered_stack_order
  3. Overlap_count
  4. Final_symbol_width

Methodology:

  • Populate the 1st column with a single value for overall default width.
  • Populate a unique integer value for stack order based on aesthetics, or arbitrarily. In OPs sample image, orange over green over blue over red would work, so assign orange 1, green 2, blue 3, and red 4.
  • Populate the number of overlaps as in 1 which will also split the route by segment.
  • Populate the final symbol width by iterating all route segments, assign the base width to the segment with minimum stack order, assign 2xbase width to the next in the stack order, assign 3xbase width to the next, etc. You will see that the final symbol width = (iterator_index)x(base_width) when the iteration is sorted in ascending stack order.

For the sample image, the orange is single width, green is double width, blue is triple width, and red is quadruple width in the segment where they all overlap; orange is above green above blue above red. In the segment where green and blue overlap, green is single width while blue is double.

The keys are: applying the stacking order before breaking up the segments by the overlaps, and of course the iterator for each route applying the final width.

Also note that stack order does not enter into the final width computation, it is simply a sort field in each segment's iterator, while the count of segments is the iterator stop value (upper bounds.)

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.