-
Notifications
You must be signed in to change notification settings - Fork 1
/
README.Rmd
229 lines (177 loc) · 7.06 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
---
output: github_document
---
[![CRAN status](https://www.r-pkg.org/badges/version/flowmapper)](https://CRAN.R-project.org/package=flowmapper)
<!-- [![CRAN downloads](https://cranlogs.r-pkg.org/badges/last-month/flowmapper?color=brightgreen)](https://CRAN.R-project.org/package=flowmapper) -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,message = FALSE,warning=FALSE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "70%",
dpi=300
# fig.width=7
)
```
# flowmapper
flowmapper allows to create ggplots with flowmaps in the style of <https://flowmap.gl/>.
## Installation
You can install the released version of flowmapper from CRAN:
``` r
install.packages("flowmapper")
```
Or, you can install the development version of flowmapper like so:
``` r
devtools::install_github("https://github.com/JohMast/flowmapper")
```
## Details
flowmapper uses a single function `add_flowmap` to add a flowmap layer to an existing ggplot. `add_flowmap` requires as inputs a single data.frame (or tibble) that contains for every combination of two nodes a and b
- the x and y coordinates of each these nodes,
- a unique id for each of these nodes,
- the intensity of flow between those nodes in both directions (from a to b, and from b to a).
The data.frame should have the following columns:
```{r example}
testdata <-
data.frame(
id_a = c("X1","X2","X3","X3","X1","X2","X2"),
id_b = c("X5","X4","X1","X5","X4","X5","X3"),
xa = c(2,14,10,10,2,14,14),
ya = c(6,10,9,9,6,10,10),
xb = c(10,4,2,10,4,10,10),
yb = c(4,10,6,4,10,4,9),
flow_ab = c(1,2,3,3,1,1,4),
flow_ba = c(2,3,2,5,2,1,5)
)
```
The dataframe and the ggplot that the flowmap should be added to are then passed into `add_flowmap`.
```{r c2, warning=FALSE}
library(ggplot2)
plot <- ggplot() # empty ggplot
library(flowmapper)
plot |>
add_flowmap(testdata)+
coord_equal() # coord equal is highly recommended to create symmetric shapes
```
If the number of nodes is very high, the plot will appear cluttered. In that case, nodes can be clustered and merged by proximity, with `k_nodes` controlling the number of clusters.
```{r t1}
plot |>
add_flowmap(testdata,k_nodes = 4)+
coord_equal()
```
Transparency and outline of the arrows can be controlled with the `outline_col` and `alpha` arguments.
```{r t3}
plot |>
add_flowmap(testdata, outline_col = "orange", alpha=0.5)+
coord_equal() # coord equal is highly recommended to create symmetric shapes
```
The flow arrows are geom_polygons, with the flow mapped to the fill aesthetic. Thus, the fill can be adjusted like for any geom.
```{r t4}
plot |>
add_flowmap(testdata)+
coord_equal() +
scale_fill_gradient(low="black", high = "red")
```
Size of the edges and offset (distance between two paired edges) can be controlled with `edge_width_factor` and `edge_offset_factor` .
```{r t5}
plot |>
add_flowmap(testdata, edge_offset_factor = 4, edge_width_factor = 2)+
coord_equal()
```
Finally, the size of the nodes can be adjusted with `node_radius_factor`, and the distance between nodes and edges with `node_buffer_factor`.
```{r t6}
plot |>
add_flowmap(testdata, node_radius_factor = 2, node_buffer_factor = 0.5)+
coord_equal()
```
Because the edges are polygons and not linked to an aesthetic, a typical ggplot legend cannot be created for their width. As an alternative, a legend can be added to the bottom of the main panel by using `add_legend`.
```{r t7}
# debug(add_flowmap)
plot |>
add_flowmap(testdata,add_legend = "left")+
coord_equal()
```
Instead of a monotone legend, the legend color can be set to represent the flow intensity with `legend_gradient`.
```{r t7_5}
# debug(add_flowmap)
plot |>
add_flowmap(testdata, add_legend = "bottom",legend_gradient=T)+
coord_equal()+
theme(legend.position = "none")
```
The flowmap can be turned into an interactive plot using the [plotly](https://github.com/plotly/plotly.R) library. The names of the nodes and flows are mapped to the `text` aesthetic and can be used in the tooltips.
```{r t8, eval=FALSE, include=TRUE}
library(plotly)
plot <-
plot |>
add_flowmap(testdata)+
coord_equal()
ggplotly(plot,tooltip = c("text","fill"))
```
![](man/figures/plotly_example.PNG)
## Example
The code below shows an example of real world data from Switzerland (same data used in [this](https://www.flowmap.blue/15kwLB4baXZ7jpip8q0JjgR6zDoS5Gt3gMLCTUAboQxk?v=46.719075,7.817990,7.51&a=0&d=1&c=0<=1&col=Default&f=45) flowmap). The data contains migration flows between the 26 Cantons of Switzerland.
```{r t9}
library(dplyr,warn.conflicts = FALSE)
library(ggplot2,warn.conflicts = FALSE)
library(sf)
library(flowmapper)
# load migration data
data <-
flowmapper::CH_migration_data
head(data)
```
As a background for the flow map, a ggplot is created using the administrative boundaries, sourced from the [GADM](https://gadm.org/index.html) dataset.
```{r t10}
cantons <- flowmapper::cantons
st_crs(cantons) <- 3857
# basic plot with just the admin units
p <- ggplot(cantons)+
geom_sf(fill=NA,col="gray30",linewidth=0.5) +
ggdark::dark_theme_bw()+
theme(panel.border = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank())+
labs(title = "Migration in Switzerland 2016",
caption = "Data: Federal Statistical Office, Switzerland")
p
```
The flowmap is then added to the base plot by using `add_flowmap`, applying some clustering to reduce the number of nodes from 26 to 10. A custom color scale is applied which matches the dark background.
```{r t11}
p2 <-
p|>
add_flowmap(flowdat = data,
add_legend = "bottom",
edge_width_factor = 0.7,
k_nodes = 10,legend_gradient=T,
outline_col = NA)+
theme(panel.grid = element_blank())+
scale_fill_gradient("Migration",
low = "darkblue",
high="white")
p2
```
The flowmap uses the *color* and *fill* aesthetics, which can be limiting when the ggplot also should contain other layers using the same aesthetic. In such cases, the [ggnewscale](https://eliocamp.github.io/ggnewscale/) package can be used to enable a new scale for those aesthetics. The following example shows a flowmap being added to a basemap from the [basemaps](https://jakob.schwalb-willmann.de/basemaps/) package, which itself uses the *fill* aesthetic.
```{r t12}
library(basemaps)
p <- basemap_ggplot(cantons,
map_service = "esri",
map_type = "world_hillshade",
alpha=0.3)+
theme_bw()+
theme(
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank())+
scale_x_continuous(expand = expansion(0,0))+
scale_y_continuous(expand = expansion(0,0))+
ggnewscale::new_scale_fill()+
labs(title = "Migration in Switzerland 2016",
caption = "Data: Federal Statistical Office, Switzerland")
p|>
add_flowmap(flowdat = data,
edge_width_factor = 0.7,k_nodes = 10,
outline_col = NA)+
theme(panel.grid = element_blank())+
scale_fill_gradient("Migration",low = "gray",high="red")
```