Advertisements

New style: flow map arrows

Last time, I wrote about the little details that make a good flow map. The data in that post was made up and simpler than your typical flow map. That’s why I wanted to redo it with real-world data. In this post, I’m using domestic migration data of Austria.

Raw migration data

Raw migration data, line width scaled to flow strength

With 9 states, that makes 72 potential flow arrows. Since that’s too much to map, I’ve decided in a first step to only show flows with more than 1,000 people.

Following the recommendations mentioned in the previous post, I first designed a basic flow map where each flow direction is rendered as a black arrow:

migration_basic

Basic flow map

Even with this very limited number of flows, the map gets pretty crowded, particularly around the north-eastern node, the Austrian capital Vienna.

To reduce the number of incoming and outgoing lines at each node, I therefore decided to change to colored one-sided arrows that share a common geometry:

migration_twocolor

Colored one-sided arrows

The arrow color is determined automatically based on the arrow direction using the following expression:

CASE WHEN
 "weight" < 1000 THEN color_rgba( 0,0,0,0)
WHEN
 x(start_point( $geometry)) - x(end_point($geometry)) < 0
THEN
 '#1f78b4'
ELSE
 '#ff7f00'
END

The same approach is used to control the side of the one-sided arrow head. The arrow symbol layer has two “arrow type” options for rendering the arrow head: on the inside of the curve or on the outside. This means that, if we wouldn’t use a data-defined approach, the arrow head would be on the same side – independent of the line geometry direction.

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

Obviously, this ignores the corner case of start and end points at the same x coordinate but, if necessary, this case can be added easily.

Of course the results are far from perfect and this approach still requires manual tweaking of the arrow geometries. Nonetheless, I think it’s very interesting to see how far we can push the limits of data-driven styling for flow maps.

Give it a try! You’ll find the symbol and accompanying sample data on the QGIS resource sharing plugin platform:

resourcesharing_flowmap

Advertisements
14 comments
  1. Antony Zonato said:

    It would be much more interesting and useful if you would post the code / way to get from one map to another.

      • Antony Zonato said:

        I’m having big trouble getting from map 1 to map 2 (curved lines).

      • Please have a look at the sample data provided with the style. To draw a curved arrow, the line needs to have one intermediate point between start and end. Depending on the intermediate point’s position, the line is more or less curved.

      • Antony Zonato said:

        Thank you! I thought that this intermediate point was dynamically generated within the style of the layer itself. It never occurred to me that there would be an intermediate point, so I did not look for it in your package.

  2. Antony Zonato said:

    Just tried it this morning and the curved lines works great! Thanks!

  3. Adriana Quezada said:

    Hi Anita, I´m very interested in use the flow style that you´ve created. For that reason, I would like to know which plugin did you use to create the line flows. I´ve created them using Points2One, but it doesn`t give me the option to create a line for each vertices, then -I`ve used Points to path plugin, and I`ve created lines for each vertices, but when I transform them in arrows (using the layer properties style) it doesn`t allow me to creat curved arrows. Do you know what could be happening?. Thanks!

    • I created the lines manually. Please have a look at the sample data provided with the style. To draw a curved arrow, the line needs to have one intermediate point between start and end. Depending on the intermediate point’s position, the line is more or less curved.

      • Adriana Quezada said:

        Thanks !

    • Morten Agerlin said:

      I am aware of two Qgis plugins to create flow maps but you will only get straight lines between start and end points. They are called Oursins and FlowMapper. I prefer the first as the second is working with .txt files outside of Qgis.

      Perhaps one could add some intelligent addition intermediate points on the lines?

      • That’s an interesting idea. You could get in contact with the plugin authors. Particularly if you can help implement generating the intermediate points.

  4. Mld said:

    Hello, in first time i discovered your site a few days ago and i like it so much !
    My question is : how could we create automatically the third point to curve lines and so use your nice style on many flow.
    I create the lines flow in postgis with st_makeline(geom_origine, geom_destination) and i wonder which fonction could create the third point in a good position like st_makeline(geom_origine, ….??????…., geom_destination).

    I think it necessite to use many spatial fonction of postgis to make this third point but i don t know sql very well…

    • Hi Mld! I’m afraid positioning the third point automatically is a non-trivial task. I’m currently not aware of an algorithm that could be translated to SQL.

      • Mld said:

        I found a solution with…Pythagore theorem !
        We’ve to use this ooooold souvenir to deduct third point coordinates T(Xt,Yt).

        Firstly scuse for my english, I’m rench……

        I share the sql script I use in Postgis to make the line with 3 points. I don’t know how use this method in Qgis.

        So, for A(Xa,Ya) point of origine of the flow, B(Xb,Yb) point of destination with knew coordinates.
        We deduct coordinates of M(Xm,Ym), center of OD.
        Xm=(Xa+Xb)/2=(Xa+Xb)*0.5
        Ym=(Ya+Yb)/2=(Ya+Yb)*0.5

        We have to choose the distance MT to define the position of the third point on the perpendicular of AB which cut the center M.
        For this example we can take MT= AB/4.

        So with this knew elements we have :

        Xt = abs((st_x(geometry_A)+st_x(geometry_B)*0.5)+((st_distance(geometry_A,geometry_B)/4)*cbrt(0.5)))

        and

        Yt = abs((st_y(geometry_A)+st_y(geometry_B)*0.5)-((st_distance(geometry_A,geometry_B)/4)*cbrt(0.5)))

        And we create the line with :
        st_makeline(ARRAY[geometry_A,st_makepoint(Xt,Yt),geometry_B]) assigning common SRC to the differents geometry.

        To understand this script => draw the “problem” on checked sheet with orthonormal and remember Pythagore theorem !

        Obviously we can refine parameters to adjust third point T position.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: