9

In one project, I am trying to adopt marvellous styles for flow maps created by @underdark.

At this moment I have the following output

Flow_map

Shapefile was created with the usage of Flow maps (Oursins) Plugin.

Lines have different directions, i.e. the starting point of first is the ending point of the second and vice versa. So basically the table includes lines with both directions but without any description of those directions.

Sample_of_AT


However, I faced several issues

1. Varying buffers' sizes

Buffers around points shall inherit parameters from a different layer, i.e. they are not the same size.

How to make them respond to the size of the circles' radiuses? Is there any kind of scaling factor, so to make my buffers "dynamic"?

difference(
  difference(
    $geometry,
    buffer(start_point($geometry), 500)
  ),
  buffer(end_point($geometry), 500)
)

Maybe I to apply layer_property() or dbvaluebyid() or represent_value() if I want to extract the dynamic value from a different layer?

I know that the buffer values in the expression above only produce appropriate results for line datasets which use a CRS in meters and will have to be adjusted for other units.

2. Proper allocation of arrows

I am using an expression for Arrow type > Plain

CASE
    WHEN x(start_point($geometry)) - x(end_point($geometry)) < 0 THEN 1
    ELSE 2
END

but still, I can not properly allocate orange halves of Arrows on the opposite side of blues.

3. The width of the arrows

I want to adjust the line width accordingly to the values of a field "FLUX". For that reason, I am using an expression for Arrow width.

scale_linear("FLUX",0,10,0.1,3) * CASE WHEN  "FLUX" > 1000 THEN 1 ELSE 0 END

How shall I handle those issues?


My desired output should look like this, curved lines can be ignored.

Desired_output


References:

3
  • Thinking loud: Could you half the width of your arrows and then place them on one or the other side of your line? Like CASE WHEN x(start_point($geometry)) - x(end_point($geometry)) < 0 THEN -0.5 ELSE 0.5 END entered as "offset"-value (or use 1 instead of 0.5). Or is that not desirable for your intended style?
    – Erik
    Commented Mar 1, 2019 at 13:36
  • Unfortunately, not that much, I have to have a good looking map for further investigations and research. Your idea makes sense, but not what I dream about.
    – Taras
    Commented Mar 1, 2019 at 13:40
  • What's wrong with the direction and width of the arrows? It would help if you added an image of what you want the arrows to look like.
    – csk
    Commented Mar 1, 2019 at 18:00

2 Answers 2

4
+50

1. Varying buffers size

I would recommend you to join the attributes of both layers instead of fetching layer properties. These are the expressions I used in this example:

Point layer size:

scale_exp("attributeBuffer", minTotalFlux, maxTotalFlux, @min, @max, exponent)

Geometry generator of line layer:

difference(
  difference($geometry,
  buffer(start_point($geometry), scale_exp("attributeBufferStart", minTotalFlux, maxTotalFlux, (@min/2), (@max/2), exponent),
  buffer(end_point($geometry), scale_exp("attributeBufferEnd", minTotalFlux, maxTotalFlux, (@min/2), (@max/2), exponent)
  )
)

Where "attributeFromStart" and "attributeFromEnd" are the values used to buffer the points. You need to use map units and not millimetres in your point since the geometry generator of lines will be working with map units. @project_variables were used to easily change sizes in the project properties without having to enter the changes in each layer.

2. Proper allocation of arrows

I think your problem is switching your direction in two layers. Your line geometries have opposite directions already so both should be going to the same side. It is like cars, you stick to one side of the road, otherwise, both ways would end up using the same lane.

6
  • I think you have edited the question while I was answering. Anyway, the difference() function is to make your line start and end according to your point values (same you use to buffer the point layer). For this, I joined the values in my line features. I also had some @project_variables so I could easily adjust all sizes (point buffers and line start/ends) easily.
    – Albert
    Commented Mar 4, 2019 at 8:58
  • These are project variables, you can put the min/max values of the field. I entered them as variables so I could just change them from the project properties easily without having to enter every layer. The 1.2 exponent could also be another project variable.
    – Albert
    Commented Mar 4, 2019 at 9:35
  • What do you mean by adjusting? Map units depend on the coordinate system you use. In your case I recommend you to use map units and a projected coordinate system
    – Albert
    Commented Mar 4, 2019 at 10:42
  • I have edited the answer to better explain how to adjust the lines and buffers
    – Albert
    Commented Mar 4, 2019 at 11:49
  • 1
    Let us continue this discussion in chat.
    – Albert
    Commented Mar 4, 2019 at 12:37
4

1. Varying buffers' sizes

First of all Switch to Map Unit.

With suggestions from @Albert, I have joined buffer values from a layer for start_point and end_point points and moreover, I edited the circles and visualized them as Simple marker. Using the formula scale_linear("Value", minimum("Value"), maximum("Value"), 1, 6)

The required buffer size obeyed uses a scaling factor of 2, notice the difference in range_min, range_max between two functions.

difference(
    difference($geometry,
        buffer(start_point($geometry),
        CASE
          WHEN "From_Value" IS NOT NULL THEN scale_linear("From_Value", minimum("From_Value"), maximum("From_Value"), 2, 12)
          ELSE 0
        END
        )
    ),
    buffer(end_point($geometry),
    CASE
      WHEN "To_Value" IS NOT NULL THEN scale_linear("To_Value", minimum("To_Value"), maximum("To_Value"), 2, 12)
      ELSE 0
    END)
)

Do not forget to double check values of start_point(), end_point() and min&max, they have to be the same between point and polyline layers.

2. Proper allocation of arrows

The correct expression

CASE
  WHEN x(start_point($geometry)) - x(end_point($geometry)) < 0 THEN 2
  WHEN x(start_point($geometry)) - x(end_point($geometry)) > 0 THEN NULL
  ELSE 1
END

The output will look like

Arrows_locations

Another solution can be achieved with the creation of two layers via a 'Virtual Layer' and then adjusting the styles manually. However, it is a bit time-consuming approach.

Layer 1 (Left/Exterior half):

SELECT *
FROM flow_map_sample
WHERE x(ST_StartPoint(geometry)) - x(ST_EndPoint(geometry)) < 0

Layer 2 (Right/Exterior half):

SELECT *
FROM flow_map_sample
WHERE x(ST_StartPoint(geometry)) - x(ST_EndPoint(geometry)) > 0

3. The width of the arrows

I needed to use:

scale_linear("FLUX", minimum("FLUX"), maximum("FLUX"), 0.1, 3) *
  CASE
    WHEN "FLUX" > 1000 THEN 1
    ELSE 0
  END

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.