/
lingtypology_creating_maps.Rmd
591 lines (478 loc) · 25 KB
/
lingtypology_creating_maps.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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
---
title: "`lingtypology`: creating maps"
author: "George Moroz"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
%\VignetteEncoding{UTF-8}
%\VignetteIndexEntry{`lingtypology`: creating maps}
%\VignetteEngine{knitr::rmarkdown}
editor_options:
chunk_output_type: console
---
```{r, include=FALSE}
library(lingtypology)
knitr::opts_chunk$set(eval = FALSE)
```
### 1. Base map
The most important part of the `lingtypology` package is the function `map.feature`. This function allows you to produce maps similar to known projects within [the Cross-Linguistic Linked Data philosophy](https://clld.org/), such as [WALS](https://wals.info/) and [Glottolog](https://glottolog.org/):
```{r}
map.feature(c("West Circassian", "Kabardian", "Polish", "Russian", "Bulgarian"))
```
As shown in the picture above, this function generates an interactive Leaflet map. All specific points on the map have a pop-up box that appears when markers are clicked (see section 3.3 for more information about editing pop-up boxes). By default, they contain language names linked to the glottolog site.
If for some reasons you are not using RStudio or you want to automatically create and save a lot of maps, you can save a map to a variable and use the `htmlwidgets` package for saving created maps to an .html file. I would like to thank Timo Roettger for mentioning this problem.
```{r, eval = FALSE}
m <- map.feature(c("West Circassian", "Korean"))
# install.packages("htmlwidgets")
library(htmlwidgets)
saveWidget(m, file="TYPE_FILE_PATH/m.html")
```
There is an export button in RStudio, but for some reason it is not so easy to save a map as a .png or.jpg file using code. [Here](https://stackoverflow.com/a/34672309/6056442) is a possible solution.
### 2. Set features
The goal of this package is to allow typologists (or any other linguists) to map language features. A list of languages and correspondent features can be stored in a `data.frame` as follows:
```{r}
df <- data.frame(language = c("West Circassian", "Kabardian", "Polish", "Russian", "Bulgarian"),
features = c("polysynthetic", "polysynthetic", "fusional", "fusional", "fusional"))
df
```
Now we can draw a map:
```{r}
map.feature(languages = df$language,
features = df$features)
```
If you have a lot of features and they appear in the legend in a senseless order(by default it is ordered alphabetically), you can reorderthem using factors (a vector with ordered levels, for more information see `?factor`). for example, I want the feature polysynthetic to be listed first, followed by fusional:
```{r}
df$features <- factor(df$features, levels = c("polysynthetic", "fusional"))
map.feature(languages = df$language, features = df$features)
```
Like in most functions, it is not necessary to name all arguments, so the same result can be obtained by:
```{r}
map.feature(df$language, df$features)
```
As shown in the picture above, all points are grouped by feature, colored and counted. As before, a pop-up box appears when markers are clicked. A control feature allows users to toggle the visibility of points grouped by feature.
There are several types of variables in R and `map.feature` works differently depending on the variable type. I will use a build in data set `phonological_profiles` that contains 19 languages from [UPSyD database](https://lapsyd.huma-num.fr/lapsyd/). This dataset have three variables: the categorical variable `ejectives` indicates whether some language has any ejective sound, numeric variables `consonants` and `vowels` that contains information about the number of consonants and vowels (based on UPSyD database). We can create two maps with categorical variable and with numeric variable:
```{r}
map.feature(phonological_profiles$language,
phonological_profiles$ejectives) # categorical
map.feature(phonological_profiles$language,
phonological_profiles$consonants) # numeric
```
The main point is that for creating a correct map, you should correctly define the type of the variable.
This dataset also can be used to show one other parameter of the `map.feature` function. There are two possible ways to show the World map: with the Atlantic sea or with the Pacific sea in the middle. If you don't need default Pacific view use the `map.orientation` parameter(thanks @languageSpaceLabs and @tzakharko for that idea):
```{r}
map.feature(phonological_profiles$language,
phonological_profiles$consonants,
map.orientation = "Atlantic")
```
Sometimes the result image legend are too small. It is possible to increase size of legend using some trick described here. In order to do this assign your map to a variable:
```{r}
m <- map.feature(languages = df$language,
features = df$features)
```
Map will not appear, but now you can get it calling the variable `m`. After this in order to increase the legend font one can use code like this:
```{r}
library(htmltools)
browsable(
tagList(
list(
tags$head(
tags$style(
".leaflet .legend {
line-height: 20px;
font-size: 20px;
}",
".leaflet .legend i{
width: 20px;
height: 20px;
}"
)
),
m)))
```
### 3. Set pop-up boxes
Sometimes it is a good idea to add some additional information (e.g. language affiliation, references or even examples) to pop-up boxes that appear when points are clicked. In order to do so, first of all we need to create an extra vector of strings in our dataframe:
```{r}
df$popup <- aff.lang(df$language)
```
The function `aff.lang()` creates a vector of genealogical affiliations that can be easily mapped:
```{r}
map.feature(languages = df$language, features = df$features, popup = df$popup)
```
Pop-up strings can contain HTML tags, so it is easy to insert a link, a couple of lines, a table or even a video and sound. Here is how pop-up boxes can demonstrate language examples:
```{r}
# change a df$popup vector
df$popup <- c("sɐ s-ɐ-k'ʷɐ<br> 1sg 1sg.abs-dyn-go<br>'I go'",
"sɐ s-o-k'ʷɐ<br> 1sg 1sg.abs-dyn-go<br>'I go'",
"id-ę<br> go-1sg.npst<br> 'I go'",
"ya id-u<br> 1sg go-1sg.npst <br> 'I go'",
"id-a<br> go-1sg.prs<br> 'I go'")
# create a map
map.feature(df$language,
features = df$features,
popup = df$popup)
```
How to say _moon_ in Sign Languages? Here is an example:
```{r}
# Create a dataframe with links to video
sign_df <- data.frame(languages = c("American Sign Language", "Russian-Tajik Sign Language", "French Sign Language"),
popup = c("https://media.spreadthesign.com/video/mp4/13/48600.mp4", "https://media.spreadthesign.com/video/mp4/12/17639.mp4", "https://media.spreadthesign.com/video/mp4/10/17638.mp4"))
# Change popup to an HTML code
sign_df$popup <- paste("<video width='200' height='150' controls> <source src='",
as.character(sign_df$popup),
"' type='video/mp4'></video>", sep = "")
# create a map
map.feature(languages = sign_df$languages, popup = sign_df$popup)
```
### 4. Set labels
An alternative way to add some short text to a map is to use the `label` option.
```{r}
map.feature(df$language, df$features,
label = df$language)
```
There are some additional arguments for customization: `label.fsize` for setting font size, `label.position` for controlling the label position, and `label.hide` to control the appearance of the label: if `TRUE`, the labels are displayed on mouse over(as on the previous map), if `FALSE`, the labels are always displayed (as on the next map).
```{r}
map.feature(df$language, df$features,
label = df$language,
label.fsize = 20,
label.position = "left",
label.hide = FALSE)
```
There is an additional tool for emphasis of some points on the map. The argument `label.emphasize` allows to emphasize selected points with the color specified by a user.
```{r}
map.feature(df$language, df$features,
label = df$language,
label.fsize = 20,
label.position = "left",
label.hide = FALSE,
label.emphasize = list(2:4, "red"))
```
In this example the first vector of the list in the `label.emphasize` argument is vector `2:4` that produce elements `2`, `3` and `4`. You can create youro wn selected rows. e. g. `c(1, 3, 4)`. The second vector of the list is the string with a color.
### 5. Set coordinates
You can set your own coordinates using the arguments `latitude` and `longitude`. It is important to note, that `lingtypology` works only with decimal degrees (something like this: 0.1), not with degrees, minutes and seconds (something like this: 0° 06′ 0″). I will illustrate this with the dataset `circassian` built into the `lingtypology` package. This dataset comes from fieldwork collected during several expeditions in the period 2011-2016 and contains a list of Circassian villages:
```{r}
head(circassian)
```
In this dataframe you can find variables `latitude` and `longitude` that could be used:
```{r}
map.feature(languages = circassian$language,
features = circassian$dialect,
popup = circassian$village,
latitude = circassian$latitude,
longitude = circassian$longitude)
```
It is possible to collapse multiple dots into clusters:
```{r}
map.feature(languages = circassian$language,
features = circassian$dialect,
popup = circassian$village,
latitude = circassian$latitude,
longitude = circassian$longitude,
point.cluster = TRUE)
```
### 6. Set colors
You can set your own colors using the argument `color`:
```{r}
df <- data.frame(language = c("West Circassian", "Kabardian", "Polish", "Russian", "Bulgarian"),
features = c("polysynthetic", "polysynthetic", "fusional", "fusional", "fusional"))
map.feature(languages = df$language,
features = df$features,
color= c("yellowgreen", "navy"))
```
Arguments from [RColorBrewer](https://CRAN.R-project.org/package=RColorBrewer) or [viridis](https://CRAN.R-project.org/package=viridis) also can be used as a color argument:
```{r}
map.feature(phonological_profiles$language,
phonological_profiles$consonants,
color= "magma")
```
### 7. Set shapes
For some scientific papers it is not possible to use colors for destinguishing features. In that cases it is posible to use `shape` argument:
```{r}
map.feature(languages = circassian$language,
features = circassian$language,
latitude = circassian$latitude,
longitude = circassian$longitude,
shape = TRUE)
```
The argument `shape = TRUE` works fine only with 6 or less levels in `features` variable. If there are more levels in `fetures` argument, user need to provide a vector with corresponding shapes:
```{r}
map.feature(languages = circassian$language,
features = circassian$dialect,
latitude = circassian$latitude,
longitude = circassian$longitude,
shape = 1:10,
shape.size = 14)
```
Arguments `shape.size` and `shape.color` help to change corresponding features of markers.
### 8. Set control box
The package can generate a control box that allows users to toggle the visibility of some points. To enable it, there is an argument `control` in the `map.feature` function:
```{r}
map.feature(languages = df$language,
features = df$features,
control = c("a", "b", "b", "b", "a"))
```
As you can see the `control` and `features` arguments are independent of each other.
### 9. Set an additional set of features using strokes
The `map.feature` function has an additional argument `stroke.features`. Using this argument it becomes possible to show two independent sets of features on one map. By default strokes are colored in grey (so for two levels it will be black and white, for three --- black, grey, white and so on), but you can set your own colors using the argument `stroke.color`:
```{r}
map.feature(circassian$language,
features = circassian$dialect,
stroke.features = circassian$language,
latitude = circassian$latitude,
longitude = circassian$longitude)
```
It is important to note that `stroke.features` can work with `NA` values. The function won't plot anything if there is an `NA` value. Let's set a language value to `NA` in all Baksan villages from the `circassian` dataset.
```{r, message= F}
# create newfeature variable
newfeature <- circassian[,c(5,6)]
# set language feature of the Baksan villages to NA and reduce newfeature from dataframe to vector
newfeature <- replace(newfeature$language, newfeature$language == "Baksan", NA)
# create a map
map.feature(circassian$language,
features = circassian$dialect,
latitude = circassian$latitude,
longitude = circassian$longitude,
stroke.features = newfeature)
```
### 10. Set width and an opacity feature
All markers have their own width and opacity, so you can set it. Just use the arguments `width`, `stroke.radius`, `opacity` and `stroke.opacity`:
```{r}
map.feature(circassian$language,
features = circassian$dialect,
stroke.features = circassian$language,
latitude = circassian$latitude,
longitude = circassian$longitude,
width = 7, stroke.radius = 13)
map.feature(circassian$language,
features = circassian$dialect,
stroke.features = circassian$language,
latitude = circassian$latitude,
longitude = circassian$longitude,
opacity = 0.7, stroke.opacity = 0.6)
```
### 11. Customizing legends
By default the legend appears in the top right corner. If there are stroke features, two legends are generated. There are additional arguments that control the appearence and the title of the legends.
```{r}
map.feature(circassian$language,
features = circassian$dialect,
stroke.features = circassian$language,
latitude = circassian$latitude,
longitude = circassian$longitude,
legend = FALSE, stroke.legend = TRUE)
map.feature(circassian$language,
features = circassian$dialect,
stroke.features = circassian$language,
latitude = circassian$latitude,
longitude = circassian$longitude,
title = "Circassian dialects", stroke.title = "Languages")
```
The arguments `legend.position` and `stroke.legend.position` allow you to change a legend's position using "topright", "bottomright", "bottomleft" or"topleft" strings.
### 12. Set scale bar
A scale bar is automatically added to a map, but you can control its appearance (set `scale.bar` argument to `TRUE` or`FALSE`) and its position (use `scale.bar.position` argument values "topright", "bottomright", "bottomleft" or"topleft").
```{r}
map.feature(c("West Circassian", "Polish", "Kabardian", "Russian"),
scale.bar= TRUE,
scale.bar.position = "topright")
```
### 13. Set layouts
It is possible to use different tiles on the same map using the `tile` argument. For more tiles see [here](https://leaflet-extras.github.io/leaflet-providers/preview/index.html).
```{r}
df <- data.frame(lang = c("West Circassian", "Kabardian", "Polish", "Russian", "Bulgarian"),
feature = c("polysynthetic", "polysynthetic", "fusion", "fusion", "fusion"),
popup = c("Adyghe", "Adyghe", "Slavic", "Slavic", "Slavic"))
map.feature(df$lang, df$feature, df$popup,
tile = "Esri.WorldGrayCanvas")
```
It is possible to use different map tiles on the same map. Just add a vector with tiles.
```{r}
map.feature(df$lang, df$feature, df$popup,
tile = c("OpenStreetMap", "Esri.WorldGrayCanvas"))
```
It is possible to name tiles using the `tile.name` argument.
```{r}
map.feature(df$lang, df$feature, df$popup,
tile = c("OpenStreetMap", "Esri.WorldGrayCanvas"),
tile.name = c("colored", "b & w"))
```
It is possible to combine the tiles' control box with the features' control box.
```{r}
map.feature(df$lang, df$feature, df$popup,
tile = c("OpenStreetMap", "Esri.WorldGrayCanvas"),
control = TRUE)
```
### 14. Add a minimap to a map
It is possible to add a minimap to a map.
```{r}
map.feature(c("West Circassian", "Polish", "Kabardian", "Russian"),
minimap = TRUE)
```
You can control its appearance (by setting the `minimap` argument to `TRUE` or `FALSE`), its position (by using the values "topright", "bottomright", "bottomleft" or"topleft" of the `minimap.position` argument) and its height and width (with the arguments `minimap.height` and `minimap.width`).
```{r}
map.feature(c("West Circassian", "Polish", "Kabardian", "Russian"),
minimap = TRUE,
minimap.position = "topright",
minimap.height = 100,
minimap.width = 100)
```
### 15. Add minicharts instead of points
This part is created using the beutifull [`leaflet.minicharts` library](https://CRAN.R-project.org/package=leaflet.minicharts). The argument `minichart` allows you to add piecharts or barplots instead of standard point markers. In this part I will use a build in data set `phonological_profiles` that contains 19 languages from [UPSyD database](https://lapsyd.huma-num.fr/lapsyd/). Here is an example of barplot:
```{r}
map.feature(languages = phonological_profiles$language,
minichart.data = phonological_profiles[, c("vowels", "consonants")])
```
Here is an example of piechart:
```{r}
map.feature(languages = phonological_profiles$language,
minichart.data = phonological_profiles[, c("vowels", "consonants")],
minichart = "pie")
```
Colors and opacity could be changed, legend moved:
```{r}
map.feature(languages = phonological_profiles$language,
minichart.data = phonological_profiles[, c("vowels", "consonants")],
color= c("yellowgreen", "navy"),
opacity = 0.7,
label = phonological_profiles$language,
legend.position = "topleft")
```
It is possible to add values using argument `minichart.labels`:
```{r}
map.feature(languages = phonological_profiles$language,
minichart.data = phonological_profiles[, c("vowels", "consonants")],
minichart = "pie",
minichart.labels = TRUE)
```
It is also possible to use pie chart in non-convenient way: just indicating with `TRUE` or `FALSE` of pressence of some feature (thanks to Diana Forker for the task!):
```{r}
map.feature(languages = phonological_profiles$language,
minichart.data = phonological_profiles[, c("tone", "long_vowels", "stress", "ejectives")],
minichart = "pie",
width = 3)
```
Unfortunately this kind of visualisation doesn't work, when you have some lines in your dataset that contain only `FALSE` values. This is **non-convenient** way of category visualisation, so visualisation experts could have a negative opinion about it. This kind of visualisation is also bad for huge number of variables.
### 16. Add a rectangle to a map
It is possible to highlight some part of your map with a rectangle. You need to provide a latitude and longitude of the diagonal (`rectangle.lat` and `rectangel.lng`) and color of the rectangle (`rectangle.color`):
```{r}
map.feature(circassian$language,
circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
rectangle.lng = c(42.7, 45),
rectangle.lat = c(42.7, 44.4),
rectangle.color= "green")
```
### 17. Add a density contourplot to a map
Sometimes it is easier to look at a density contourplot. It can be created using `density.estimation` argument. There are two possibility for creation a density contourplot in `lingtypology`:
* `density.method = "fixed distance"`. First algorithm creates circle polygons with fixed radius around each point and then merge all polygons that are overlapped. It has only one parameter that should be estimated: radius of the circle (`density.width`).
* `density.method = "kernal density estimation"`. Second algorithm uses a kernal density estimation and has two parameters that should be estimated: latitude and longitude bandwidths (`density.width[1]` and (`density.width[2]`))
```{r}
map.feature(circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language,
density.width = 0.15)
```
Density estimation plot can be separated by `features` variable:
```{r}
map.feature(circassian$language,
features = circassian$dialect,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language,
density.width = 0.15)
```
It is possible to remove points and display only the kernal density estimation plot, using the `density.points` argument:
```{r}
map.feature(circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language,
density.width = 0.15,
density.points = FALSE)
```
It is possible to change kernal density estimation plot opacity using the`density.estimation.opacity` argument:
```{r}
map.feature(circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language,
density.width = 0.15,
density.estimation.opacity = 0.2)
```
If you want to use kernal density estimation, you need to change method type and provide a vector of parameters that increase/decrease area:
```{r}
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = "Circassian",
density.method = "kernal density estimation",
density.width = c(0.3, 0.3),
color= c("darkgreen", "blue"))
```
```{r}
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = "Circassian",
density.method = "kernal density estimation",
density.width = c(0.7, 0.7),
color= c("darkgreen", "blue"))
```
```{r}
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = "Circassian",
density.method = "kernal density estimation",
density.width = c(1.3, 0.9),
color= c("darkgreen", "blue"))
```
It is important to note, that this type of visualization have some shortcomings. The kernel density estimation is calculated without any adjustment, so longitude and latitude values used as a values in Cartesian coordinate system. To reduce consequences of that solution it is better to use a different coordinate projection. That allows not to treat Earth as a flat object.
### 18. Add isoglosses
It is possible to try to catch isoglosses, using the kernel density estimation algorithm. The `map.feature` argument `isogloss` recieves a dataframe with set of features:
```{r}
map.feature(languages = circassian$language,
latitude = circassian$latitude,
longitude = circassian$longitude,
features = circassian$dialect,
label = circassian$dialect,
legend = TRUE,
isogloss = as.data.frame(circassian[,"dialect"]),
isogloss.width = 0.15)
```
It is possible to create true isoglosses by hand, see tools for it [here](https://ropensci.github.io/lingtypology/lingtypology_dplyr.html#2_leaflet).
### 19. Add lines
It is possible to show some lines on the map using coordinates (`line.lng` and `line.lat` arguments).
```{r}
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
line.lng = c(39, 43),
line.lat = c(44.5, 43))
```
If there are more then two coordinates, multiple lines will appear. It is also possible to change the color of the line using the `line.color` argument.
```{r}
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
line.lng = c(43, 39, 38.5),
line.lat = c(43, 44.5, 45),
line.color= "green")
```
If there are two levels in the `features` variable, it is possible to draw a boundary line between point clusters (the logistic regression is used for calculation).
```{r}
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
line.type = "logit")
```
It is possible to add a graticule to a map.
```{r}
map.feature(c("Russian", "West Circassian"),
graticule = 5)
```