Title: | Draw Flows (Migration, Goods, Money, Information) on 'ggplot2' Plots |
---|---|
Description: | Adds flow maps to 'ggplot2' plots. The flow maps consist of 'ggplot2' layers which visualize the nodes as circles and the bilateral flows between the nodes as bidirectional half-arrows. |
Authors: | Johannes Mast [aut, cre] |
Maintainer: | Johannes Mast <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.1.3 |
Built: | 2025-03-10 04:19:15 UTC |
Source: | https://github.com/johmast/flowmapper |
Add a flow map to a ggplot
add_flowmap( p, flowdat = NULL, od = NULL, nodes = NULL, outline_linewidth = 0.01, alpha = 0.8, nodes_alpha = 0.8, outline_col = "black", k_nodes = NULL, node_buffer_factor = 1.2, node_radius_factor = 1, edge_offset_factor = 1, node_fill_factor = NULL, edge_width_factor = 1.2, arrow_point_angle = 45, add_legend = "none", legend_nudge_x = 0, legend_nudge_y = 0, legend_col = "gray", legend_gradient = FALSE )
add_flowmap( p, flowdat = NULL, od = NULL, nodes = NULL, outline_linewidth = 0.01, alpha = 0.8, nodes_alpha = 0.8, outline_col = "black", k_nodes = NULL, node_buffer_factor = 1.2, node_radius_factor = 1, edge_offset_factor = 1, node_fill_factor = NULL, edge_width_factor = 1.2, arrow_point_angle = 45, add_legend = "none", legend_nudge_x = 0, legend_nudge_y = 0, legend_col = "gray", legend_gradient = FALSE )
p |
The plot to which the flowmap should be added. |
flowdat |
Input dataframe. See details below. |
od |
As an alternative to |
nodes |
As an alternative to |
outline_linewidth |
The linewidth of the outline of the arrows. |
alpha |
Opacity of the edges. |
nodes_alpha |
Opacity of the nodes. |
outline_col |
Color of the outline of the edges. |
k_nodes |
Number of clusters to group nodes into. If defined, nodes will be clustered hierarchically based on spatial proximity. By default, no clustering will be applied. |
node_buffer_factor |
Controls the distance between the nodes and the edges ( in multiple of the nodes' radii). |
node_radius_factor |
Controls the size of the nodes. |
edge_offset_factor |
Controls the distance between the parallel arrows. |
node_fill_factor |
Controls the downscaling of the fill of the nodes ( as to not outshine the edges ). |
edge_width_factor |
Controls the width of the edges. |
arrow_point_angle |
Controls the pointiness of the edges. |
add_legend |
Add a legend for width to the plot? Must be one of "none","bottom","top","left", or "right". (Experimental) |
legend_nudge_x |
Adjusts the horizontal position of the legend in map units. |
legend_nudge_y |
Adjusts the vertical position of the legend in map units. |
legend_col |
If |
legend_gradient |
If TRUE, the legend color will be a gradient from min to max flow. If FALSE, the legend will be a single color. |
The function requires as inputs a dataframe flowdat
which contains for every combination of two nodes a and b the coordinates of these nodes as well as the intensity of flow between those nodes in both directions (a to b, b to a). The dataframe should have the following columns:
id_a: The unique id of node a
id_b: The unique id of node b
xa: The x coordinate of node a
ya: The y coordinate of node a
xb: The x coordinate of node b
yb: The y coordinate of node b
flow_ab: The intensity of flow from node a to node b
flow_ba: The intensity of flow from node b to node a
Alternatively, the function can take as input a dataframe od
which contains the origin-destination pairs and the flow between them. The dataframe should have the following columns:
o: The unique id of the origin node
d: The unique id of the destination node
value: The intensity of flow between the origin and destination
In this case, the function also requires a dataframe nodes
which contains the coordinates of the nodes. The dataframe should have the following columns:
name: The unique id of the node
x: The x coordinate of the node
y: The y coordinate of the node
The function will impose coord_equal() on the ggplot.
Inspired by flowmap.gl.
The ggplot with an additional polygon layer for the flow arrows and an additional polygon layer for the nodes
Johannes Mast
testdata <- data.frame( id_a = c("X1","X2","X3","X3","X1"), id_b = c("X8","X7","X1","X8","X7"), xa = c(2,14,10,10,2), ya = c(6,10,9,9,6), xb = c(10,4,2,10,4), yb = c(4,10,6,4,10), flow_ab = c(2,1,1,1,1), flow_ba = c(5,1,1,1,2) ) library(ggplot2) plot <- ggplot() plot |> add_flowmap(testdata)
testdata <- data.frame( id_a = c("X1","X2","X3","X3","X1"), id_b = c("X8","X7","X1","X8","X7"), xa = c(2,14,10,10,2), ya = c(6,10,9,9,6), xb = c(10,4,2,10,4), yb = c(4,10,6,4,10), flow_ab = c(2,1,1,1,1), flow_ba = c(5,1,1,1,2) ) library(ggplot2) plot <- ggplot() plot |> add_flowmap(testdata)
Geometries of Cantons of Switzerland. CRS is unassigned, but should be EPSG:3857.
cantons
cantons
cantons
A sf object with 26 rows and 2 columns:
Name of Canton
polygon coordinates
GADM database https://gadm.org/
Internal migrations between Cantons of Switzerland, 2011-2016.
CH_migration_data
CH_migration_data
CH_migration_data
A data frame with 325 rows and 8 columns:
Names of Cantons A and B
Number of migrations from A to B
Number of migrations from B to A
Longitude and latitude of the centroid of Canton A. Web-Mercator projection (EPSG: 3857)
Longitude and latitude of the centroid of Canton B. Web-Mercator projection (EPSG: 3857)
Federal Statistical Office of Switzerland, under OPEN-BY-ASK terms of use: https://www.bfs.admin.ch/bfs/de/home/statistiken/bevoelkerung/migration-integration/binnenwanderung.assetdetail.3222163.html
Helper function to create coordinates for circles of nodes
get_circle_coords(center = c(0, 0), r = 1, npoints = 25)
get_circle_coords(center = c(0, 0), r = 1, npoints = 25)
center |
center y and y coordinates |
r |
radius |
npoints |
number of points |
a dataframe with x and y coordinates of the circle
Johannes Mast, Credit to https://stackoverflow.com/a/6863490
Use hierarchical clustering to merge nodes based on proximity
hca_flowdat(flowdat, k = 20, return_cluster_assignment = FALSE)
hca_flowdat(flowdat, k = 20, return_cluster_assignment = FALSE)
flowdat |
The data containing flows from a to b, b to a, and the coordinates of a and b |
k |
The number of nodes to keep. |
return_cluster_assignment |
Instead of an updated flowdat, return a dataframe with the cluster assignment of each node. |
a dataframe of the same format as flowdat, but with some nodes (and their flows) merged. Note that this will in most cases contain some circular flows (a to a) even if the input flowdat did not.
Create short scale format for numbers in the legend
short_scale(x, digits = 3)
short_scale(x, digits = 3)
x |
The number |
digits |
Significant digits |
Johannes Mast, credit: https://stackoverflow.com/a/59086755
This function takes a flow data frame in long format and a data frame with the nodes coordinates and returns a flowdat data frame
util_data_flow_to_flowdat(nodes, flows)
util_data_flow_to_flowdat(nodes, flows)
nodes |
A data frame with the nodes of the network |
flows |
A data frame with the flow data |
Helper function to merge od data in long data and nodes to flowdat format
A data frame with the flow data in flowdat format
Johannes Mast,
#nodes <- data.frame(name=c("a","b","c"),x=c(0,1,2),y=c(0,1,2)) #flow <- data.frame(o=c("a","b"),d=c("b","c"),value=c(1,2)) #util_data_flow_to_flowdat(nodes,flow)
#nodes <- data.frame(name=c("a","b","c"),x=c(0,1,2),y=c(0,1,2)) #flow <- data.frame(o=c("a","b"),d=c("b","c"),value=c(1,2)) #util_data_flow_to_flowdat(nodes,flow)