Archive

Tag Archives: cartography

In my previous post, I shared a flow map style that was inspired by a hand drawn map. Today’s post is inspired by a recent academic paper recommended to me by Radoslaw Panczak  and Thomas Gratier :

Jenny, B., Stephen, D. M., Muehlenhaus, I., Marston, B. E., Sharma, R., Zhang, E., & Jenny, H. (2016). Design principles for origin-destination flow maps. Cartography and Geographic Information Science, 1-15.

Jenny et al. (2016)  performed a study on how to best design flow maps. The resulting design principles are:

  • number of flow overlaps should be minimized;
  • sharp bends and excessively asymmetric flows should be avoided;
  • acute intersection angles should be avoided;
  • flows must not pass under unconnected nodes;
  • flows should be radially arranged around nodes;
  • quantity is best represented by scaled flow width;
  • flow direction is best indicated with arrowheads;
  • arrowheads should be scaled with flow width, but arrowheads for thin flows should be enlarged; and
  • overlaps between arrowheads and flows should be avoided.

Many of these points concern the arrangement of flow lines but I want to talk about those design principles that can be implemented in a QGIS line style. I’ve summarized the three core ideas:

  1. use arrow heads and scale arrow width according to flow,
  2. enlarge arrow heads for thin flows, and
  3. use nodes to arrange flows and avoid overlaps of arrow heads and flows

This slideshow requires JavaScript.

To get started, we can use a standard QGIS arrow symbol layer. To represent the flow value (“weight”) according to the first design principle, all arrow parameters are data-defined:

scale_linear("weight",0,10,0.1,3)

To enlarge the arrow heads for thin flow lines, as required by the second design principle, we can add a fixed value to the data-defined head length and thickness:

scale_linear("weight",0,10,0.1,1.5)+1.5

arrow_head_thickness

The main issue with this flow map is that it gets messy as soon as multiple arrows end at the same location. The arrow heads are plotted on top of each other and at some point it is almost impossible to see which arrow starts where. This is where the third design principle comes into play!

To fix the overlap issue, we can add big round nodes at the flow start and end points. These node buffers are both used to render circles on the map, as well as to shorten the arrows by cutting off a short section at the beginning and end of the lines:

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

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

arrow_nodes

It’s great to have some tried and evaluated design guidelines for our flow maps. As always: Know your cartography rules before you start breaking them!

PS: To draw a curved arrow, the line needs to have one intermediate point between start and end – so three points in total. Depending on the intermediate point’s position, the line is more or less curved.

The QGIS map style I want to share with you today was inspired by a hand-drawn map by Philippe Rekacewicz that I saw on Twitter:

The look reminds me of conveyor belts, thus the name choice.

You can download the symbol and a small sample dataset by adding my repo to the QGIS Resource Sharing plugin.

resourcesharing_conveyor

The conveyor belt is a line symbol that makes extensive use of Geometry generators. One generator for the circle at the flow line start and end point, respectively, another generator for the belt, and a final one for the small arrows around the colored circles. The color and size of the circle are data defined:

conveyor_details

The collection also contains a sample Geopackage dataset which you can use to test the symbol immediately. It is worth noting that the circle size has to be specified in layer CRS units.

It’s great fun playing with the power of Geometry generator symbol layers and QGIS geometry expressions. For example, this is the expression for the final geometry that is used to draw the small arrows around colored circles:

line_merge( 
  intersection(
    exterior_ring( 
      convex_hull( 
        union( 
          buffer( start_point($geometry), "start_size" ),
          buffer( end_point($geometry), 500000 )
        )
      )
    ),
    exterior_ring( 
      buffer( start_point( $geometry), "start_size" )
    )
  )
)

The expression constructs buffer circles, the belt geometry (convex_hull around buffers), and finally extracts the intersecting part from the start circle and the belt geometry.

Hope you enjoy it!

It’s holiday season, why not share one of your own symbols with the QGIS community?

In the first part of the Movement Data in GIS series, I discussed some of the common issues of modeling movement data in GIS, followed by a recommendation to model trajectories as LinestringM features in PostGIS to simplify analyses and improve query performance.

Of course, we don’t only want to analyse movement data within the database. We also want to visualize it to gain a better understanding of the data or communicate analysis results. For example, take one trajectory:

(data credits: GeoLife project)

Visualizing movement direction is easy: just slap an arrow head on the end of the line and done. What about movement speed? Sure! Mean speed, max speed, which should it  be?

Speed along the trajectory, a value for each segment between consecutive positions.

With the usual GIS data model, we are back to square one. A line usually has one color and width. Of course we can create doted and dashed lines but that’s not getting us anywhere here. To visualize speed variations along the trajectory, we therefore split the original trajectory into its segments, 1429 in this case. Then we can calculate speed for each segment and use a graduated or data defined renderer to show the results:

trajectory_segment_features

Speed along trajectory: red = slow to blue = fast

Very unsatisfactory! We had to increase the number of features 1429 times just to show speed variations along the trajectory, even though the original single trajectory feature already contained all the necessary information and QGIS does support geometries with measurement values.

Starting from QGIS 2.14, we have an alternative way to deal with this issue. We can stick to the original single trajectory feature and render it using the new geometry generator symbol layer. (This functionality is also used under the hood of the 2.5D renderer.) Using the segments_to_lines() function, the geometry generator basically creates individual segment lines on the fly:

geomgenerator

Segments_to_lines( $geometry) returns a multi line geometry consisting of a line for every segment in the input geometry

Once this is set up, we can style the segments with a data-defined expression that determines the speed on the segment and returns the respective color along a color ramp:

segment_speed_color

Speed is calculated using the length of the segment and the time between segment start and end point. Then speed values from 0 to 50 km/h are mapped to the red-yellow-blue color ramp:

ramp_color(
  'RdYlBu',
  scale_linear(
    length( 
      transform(
	    geometry_n($geometry,@geometry_part_num),
		'EPSG:4326','ESRI:54027'
		)
    ) / (
      m(end_point(  geometry_n($geometry,@geometry_part_num))) -
      m(start_point(geometry_n($geometry,@geometry_part_num)))
    ) * 3.6,
    0,50,
    0,1
  )
)

Thanks a lot to @nyalldawson for all the help figuring out the details!

While the following map might look just like the previous one in the end, note that we now only deal with the original single line feature:

trajectory_geomgenerator

Similar approaches can be used to label segments or positions along the trajectory without having to break the original feature. Thanks to the geometry generator functionality, we can make direct use of the LinestringM data model for trajectory visualization.


This post is part of a series. Read more about movement data in GIS.

If you follow me on Twitter, you’ve probably seen previews of my experiments with round maps. These experiments were motivated by a recent question on GIS.stackexchange whether this type of map can be created in QGIS and while it’s not very convenient right now, it is definitely possible:

http://www.quantarctica.org

All maps in this post are created using data from the Quantarctica project.

I’ve been planing to try the Quantarctica datasets for a long time and this use case is just perfect. When you download and open their project, you’ll see that they have already clipped all datasets to a circle around Antarctica:

Quantarctica project with some custom styling

Quantarctica project with some custom styling

Since the map of the full extent of the dataset is already clipped to a circle, the overview map is easy to deal with. The detail map on the other hand is rectangular by default:

circle_maps_start

Since we cannot change the shape of the map item, we have to use a mask instead. To create a circular mask, we can add an ellipse shape:

circle_maps_addellipse

The main challenge when creating the mask is that there is no inverted polygon renderer for shapes in print composer. I’ve evaluated two workarounds: First, I created a style with a wide white outline that would cover all map parts outside the circle shape. But this solution slowed the print composer down a lot. An alternative, which doesn’t suffer from this slowdown is using draw effects:

circle_maps_mask_style

In particular, I created a big outer glow effect:

circle_maps_mask_style_effect

Note that the effect only works if the symbol itself is not transparent. That’s why I set the symbol fill to black and used the Lighten blending mode:

circle_maps_mask

Voilà! Both maps are nicely circular.

It is worth noting though that this workaround has a downside: it is not possible to create automatic grids/graticules for these maps. The graticule in the overview map only works because it is a layer in the main project that was already clipped to the circular shape.

Finally, you can add more depth to your map by adding shadows. To create the shadow effect, I added additional ellipse items which are styled with a drop shadow draw effect. If you only enable the drop shadow effect, you will notice that the shadow is cut off at the ellipse bounding box. To avoid this undesired effect, you can add a transform effect, which reduces the size of the drawn shape and it’s shadow so that the shadow fits into the bounding box:

circle_maps_mask_shadow_effect

It requires some manual adjustments to place the shadow at the optimal location on top of the mask:

circle_maps_mask_shadow

Add another ellipse to create the shadow for the overview map.

For more cartography tips and tricks check my new book QGIS Map Design or join my QGIS training courses.

Following up on last week’s post, Nyall has continued his work on the QGIS gradient editor:

Latest version of the new QGIS interactive gradient edit. This now includes an interactive plot of the color hue/saturation/lightness/alpha, allowing a visual overview of these color components and easy editing.

Another equally awesome demo has been posted by Nathan, who is currently working on usability improvements for labeling and styling without blocking dialogs:

This is going to be great for map design work because it makes many complex styles much easier to create since you can interact with the map and attribute table at the same time.

These are definitely two developments to follow closely!

Interesting developments going on if you like creating your own gradients. After all, that’s not as easy as it might initially seem, as Gregor Aisch describes in his post “Mastering Multi-hued Color Scales with Chroma.js”:

The issues with simple color interpolations, which include nonuniform changes in lightness between classes, also haunt us in cartography. Just have a look at the map and legend on the left-hand side, which has been created using a normal custom QGIS gradient with colors ranging from black to red, yellow and finally white. We end up with three classes in yellow which are nearly impossible to tell apart:

comparing_ramps

For comparison, on the right side, I’ve used Gregor’s corrected color ramp, which ensures that lightness changes evenly from one class to the next.

Wouldn’t it be great if the built-in gradient tool in QGIS could correct for lightness? Too bad the current dialog is not that great:

My first reaction therefore was to write a short script to import gradients from Gregor’s Chroma.js Color Scale Helper into QGIS:

https://twitter.com/underdarkGIS/status/716389969850404864

But we’ll probably have a much better solution in QGIS soon since Nyall Dawson has picked up the idea and is already working on a completely new version of the gradient tool. You can see a demo of the current work in progress here:

I’m really looking forward to trying this out once it hits master!

Today’s post was motivated by a question on GIS.StackExchange, which is looking for an automated way to symbolize the amenities available at a location using a series of icons, like this:

Screenshot 2016-03-19 23.02.30

Assuming the information is available in  a format similar to this example attribute table

Screenshot 2016-03-19 23.02.00

we can create a symbol, which adapts to the values in the icon columns using data-defined overrides:

Screenshot 2016-03-19 23.04.17

The five potential symbol locations are aligned next to each other using offsets. We use the following expression to determine the correct SVG symbol:

CASE
WHEN "icon4" = 'dinner'
 THEN 'C:/OSGeo4W64/apps/qgis-dev/svg/entertainment/amenity=restaurant.svg'
WHEN "icon4" = 'sleep'
 THEN 'C:/OSGeo4W64/apps/qgis-dev/svg/accommodation/accommodation_hotel2.svg'
WHEN "icon4" = 'ship'
 THEN 'C:/OSGeo4W64/apps/qgis-dev/svg/transport/amenity=ferry_terminal.svg'
WHEN "icon4" = 'house'
 THEN 'C:/OSGeo4W64/apps/qgis-dev/svg/accommodation/accommodation_house.svg'
 ELSE  ''
END

To hide icons if the icon value is NULL, the marker size is set to 0 using, for example:

CASE
WHEN "icon4" is not NULL
 THEN 4
 ELSE 0
END

Finally, to ensure that the labels don’t cover the icons, we can use the cartographic label placement with the position priority set to ‘TR,TL,BL’, which restricts labels to the top right, top left, and bottom left position.

Screenshot 2016-03-19 23.04.43

With these settings in place, we can zoom out and the labeling algorithm picks the most suitable position from the list of allowed positions:

Screenshot 2016-03-19 23.02.11

For more cartography tips and tricks check my new book QGIS Map Design or join my QGIS training courses.

Today’s post was motivated by a recent question on the #gistribe Twitter chat:

So what’s the issue?

Default polygon symbols come with a fill and a border color:

Screenshot 2016-03-12 15.40.37

When they are used in a graduated renderer, the fill color is altered for each class:

Screenshot 2016-03-12 15.40.26

What if you want to change the border color instead?

The simplest solution is to add an outline symbol layer to your polygon symbol:

Screenshot 2016-03-12 15.40.46

The outline layer has only one color property and it will be altered by the graduated renderer.

If you now hit ok, the graduated renderer will alter both the simple fill’s fill color and the outline’s color. To stop the fill color from changing, select the simple fill and lock it using the small lock icon below the list of symbol layers:

Screenshot 2016-03-12 15.40.50

Voilà:

Screenshot 2016-03-12 15.40.58

For more cartography tips and tricks check my new book QGIS Map Design or join my QGIS training courses.

My latest book “QGIS Map Design”, co-authored with well-known cartography expert Gretchen Peterson and with a foreword by the founder of QGIS, Gary Sherman himself, is now available as e-book.

In three parts, the book covers layer styling, labeling, and designing print maps. All recipes come with data and project files so you can reproduce the maps yourself.

Check the book website for the table of contents and a sample chapter.

Just in time for the big QGIS 2.14 LTR release, the paperback will be available March 1st.

On a related note, I am also currently reviewing the latest proofs of the 3rd edition of “Learning QGIS”, which will be updated to QGIS 2.14 as well.

Happy QGISing!

It’s been a while since my last blog post mostly because I’ve been busy with some more long form writing. Most notably, I’ve been writing a paper on the QGIS Projcessing framework in the open access ISPRS International Journal of Geo-Information together with Victor Olaya and I’m still in the process of writing a new book titled “QGIS Map Design” together with Gretchen Peterson which is scheduled for early 2016.

Today’s post has been on my todo list for a while now. It’s inspired by a talk at a recent cartography conference I attended:

https://twitter.com/underdarkGIS/status/664402693801287681

(For a summary of the whole event, check the storify I compiled.)

The idea of this slide and several more was to show all the attention to detail which goes into designing a good road map. One aspect seemed particularly interesting to me since I had never considered it before: what do we communicate by our choice of line caps? The speaker argued that we need different caps for different situations, such as closed square caps at the end of a road and open flat caps when a road turns into a narrower path.

I’ve been playing with this idea to see how to reproduce the effect in QGIS …

https://twitter.com/underdarkGIS/status/665638297998331905

So first of all, I created a small test dataset with different types of road classes. The dataset is pretty simple but the key to recreating the style is in the attributes for the road’s end node degree values (degree_fro and degree_to), the link’s road class as well as the class of the adjacent roads (class_to and class_from). The degree value simply states how many lines connect to a certain network node. So a dead end as a degree of 1, a t-shaped intersection has a degree of 3, and so on. The adjacent class columns are only filled if the a neighbor is of class minor since I don’t have a use for any other values in this example. Filling the degree and adjacent class columns is something that certainly could be automated but I haven’t looked into that yet.

roadattributes

 

The layer is then styled using rules. There is one rule for each road class value. Rendering order is used to ensure that bridges are drawn on top of all other lines.

roadrules

Now for the juicy part: the caps are defined using a data-defined expression. The goal of the expression is to detect where a road turns into a narrow path and use a flat cap there. In all other cases, square cap should be used.

roadrule

Like some of you noted on Twitter after I posted the first preview, there is one issue and that is that we can only set one cap style per line and it will affect both ends of the line in the same way. In practice though, I’m not sure this will actually cause any issues in the majority of cases.

I wonder if it would be possible to automate this style in a way such that it doesn’t require any precomputed attributes but instead uses some custom functions in the data-defined expressions which determine the correct style on the fly. Let me know if you try it!