lingtypology
: creating mapsmap.feature
The most important part of the lingtypology
package is the function map.feature
. This function allows you to produce maps similarto known projects within the Cross-Linguistic Linked Data philosophy, such as WALS and Glottolog:
map.feature(c("Adyghe", "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 formore information about editing pop-up boxes). By default, they contain language names linked to the glottolog site.
If forsome reasons you are not using RStudio oryou want to automatically create and save a lot of maps, you can save a map to a variable and use the htmlwidgets
package forsaving created maps to an .html file. I would like to thank Timo Roettgerformentioning this problem.
m <- map.feature(c("Adyghe", "Korean"))
# install.packages("htmlwidgets")
library(htmlwidgets)
saveWidget(m, file="TYPE_FILE_PATH/m.html")
There is an export button in RStudio, but forsome reason it is not so easy to save a map as a .png or.jpg file using code. Here is a possible solution.
The goal of this package is to allow typologists (orany otherlinguists) to map language features. A list of languages and correspondent features can be stored in a data.frame
as follows:
df <- data.frame(language = c("Adyghe", "Kabardian", "Polish", "Russian", "Bulgarian"),
features = c("polysynthetic", "polysynthetic", "fusional", "fusional", "fusional"))
df
Now we can draw a map:
map.feature(languages = df$language,
features = df$features)
If you have a lot of features and they appearin the legend in a senseless order(by default it is ordered alphabetically), you can reorderthem using factors (a vectorwith ordered levels, formore information see ?factor
). Forexample, I want the feature polysynthetic to be listed first, followed by fusional:
df$features <- factor(df$features, levels = c("polysynthetic", "fusional"))
map.feature(languages = df$language, features = df$features)
Like in most rfunctions, it is not necessary to name all arguments, so the same result can be obtained by:
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 rand map.feature
works differently depending on the variable type. I will use a build in data set ejective_and_n_consonants
that contains 19 languages from UPSyD database. This dataset have three variables: the categorical variable ejectives
indicates whethersome language has any ejective sound, numeric variables consonants
and vowels
that contains information about the numberof consonants and vowels (based on UPSyD database). We can create two maps with categorical variable and with numeric variable:
map.feature(ejective_and_n_consonants$language,
ejective_and_n_consonants$ejectives) # categorical
map.feature(ejective_and_n_consonants$language,
ejective_and_n_consonants$consonants) # numeric
Default colors are not perfect forthis goal, but the main point is clear. Forcreating a correct map, you should correctly define the type of the variable.
This dataset also can be used to show one otherparameterof the map.feature
function. There are two possible ways to show the World map: with the Atlantic sea orwith the Pacific sea in the middle. If you don’t need default Pacific view use the map.orientation
parameter(thanks @languageSpaceLabs and @tzakharko forthat idea):
map.feature(ejective_and_n_consonants$language,
ejective_and_n_consonants$consonants,
map.orientation = "Atlantic")
Sometimes it is a good idea to add some additional information (e.g. language affiliation, references oreven examples) to pop-up boxes that appearwhen points are clicked. In orderto do so, first of all we need to create an extra vectorof strings in ourdataframe:
df$popup <- aff.lang(df$language)
The function aff.lang()
creates a vectorof genealogical affiliations that can be easily mapped:
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 oreven a video and sound. Here is how pop-up boxes can demonstrate language examples:
# 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:
# Create a dataframe with links to video
sign_df <- data.frame(languages = c("American Sign Language", "Russian 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)
An alternative way to add some short text to a map is to use the label
option.
map.feature(df$language, df$features,
label = df$language)
There are some additional arguments forcustomization: label.fsize
forsetting font size, label.position
forcontrolling 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).
map.feature(df$language, df$features,
label = df$language,
label.fsize = 20,
label.position = "left",
label.hide = FALSE)
There is an additional tool foremphasis of some points on the map. The argument label.emphasize
allows to emphasize selected points with the colorspecified by a user.
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 vectorof the list in the label.emphasize
argument is vector2:4
that produce elements 2
, 3
and 4
. You can create yourown selected rows. e. g. c(1, 3, 4)
. The second vectorof the list is the string with a color.
Using label.only
argument It is possible to use labels without points markers.
map.feature(c("Russian", "Adyghe"),
label = c("Russian", "Adyghe"),
label.only = TRUE)
You can set yourown 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:
map.feature(languages = circassian$language,
features = circassian$dialect,
popup = circassian$village,
latitude = circassian$latitude,
longitude = circassian$longitude)
By default the colorpalette is created by the rainbow()
function, but you can set yourown colors using the argument color
:
df <- data.frame(language = c("Adyghe", "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 orviridis also can be used as a colorargument:
map.feature(ejective_and_n_consonants$language,
ejective_and_n_consonants$consonants,
color= "magma")
The package can generate a control box that allows users to toggle the visibility of points and features. To enable it, there is an argument control
in the map.feature
function:
map.feature(languages = df$language,
features = df$features,
control = TRUE)
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 fortwo levels it will be black and white, forthree — black, grey, white end so on), but you can set yourown colors using the argument stroke.color
:
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.
# 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)
All markers have theirown radius and opacity, so you can set it. Just use the arguments radius
, stroke.radius
, opacity
and stroke.opacity
:
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)
By default the legend appears in the bottom left corner. If there are stroke features, two legends are generated. There are additional arguments that control the appearence and the title of the legends.
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.
A scale baris automatically added to a map, but you can control its appearance (set scale.bar
argument to TRUE
orFALSE
) and its position (use scale.bar.position
argument values “topright”, “bottomright”, “bottomleft” or“topleft”).
map.feature(c("Adyghe", "Polish", "Kabardian", "Russian"),
scale.bar= TRUE,
scale.bar.position = "topright")
It is possible to use different tiles on the same map using the tile
argument. Formore tiles see here.
df <- data.frame(lang = c("Adyghe", "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 = "Thunderforest.OpenCycleMap")
It is possible to use different map tiles on the same map. Just add a vectorwith tiles.
df <- data.frame(lang = c("Adyghe", "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 = c("OpenStreetMap.BlackAndWhite", "Thunderforest.OpenCycleMap"))
It is possible to name tiles using the tile.name
argument.
df <- data.frame(lang = c("Adyghe", "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 = c("OpenStreetMap.BlackAndWhite", "Thunderforest.OpenCycleMap"),
tile.name = c("b & w", "colored"))
It is possible to combine the tiles’ control box with the features’ control box.
df <- data.frame(lang = c("Adyghe", "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 = c("OpenStreetMap.BlackAndWhite", "Thunderforest.OpenCycleMap"),
control = TRUE)
It is possible to add a minimap to a map.
map.feature(c("Adyghe", "Polish", "Kabardian", "Russian"),
minimap = TRUE)
You can control its appearance (by setting the minimap
argument to TRUE orFALSE), 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
).
map.feature(c("Adyghe", "Polish", "Kabardian", "Russian"),
minimap = TRUE,
minimap.position = "topright",
minimap.height = 100,
minimap.width = 100)
This part is created using the beutifull leaflet.minicharts
library. The argument minichart
allows you to add piechart orbarplot instead of standard point markers. In this part I will use a build in data set ejective_and_n_consonants
that contains 19 languages from UPSyD database. Here is an example of barplot:
map.feature(languages = ejective_and_n_consonants$language,
minichart.data = ejective_and_n_consonants[, c("vowels", "consonants")],
minichart = "bar")
Here is an example of piechart:
map.feature(languages = ejective_and_n_consonants$language,
minichart.data = ejective_and_n_consonants[, c("vowels", "consonants")],
minichart = "pie")
Colors and opacity could be changed, legend moved:
map.feature(languages = ejective_and_n_consonants$language,
minichart.data = ejective_and_n_consonants[, c("vowels", "consonants")],
minichart = "bar",
color= c("yellowgreen", "navy"),
opacity = 0.7,
label = ejective_and_n_consonants$language,
legend.position = "topleft")
It is possible to add values using argument minichart.labels
:
map.feature(languages = ejective_and_n_consonants$language,
minichart.data = ejective_and_n_consonants[, c("vowels", "consonants")],
minichart = "pie",
minichart.labels = TRUE)
It is possible to highlight some part of yourmap with a rectangle. You need to provide a latitude and longitude of the diagonal (rectangle.lat
and rectangel.lng
) and colorof the rectangle (rectangle.color
):
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")
Sometimes it is easier to look at a density contourplot. It can be created using density.estimation
argument:
map.feature(circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language)
Density estimation plot can be colored by :
map.feature(circassian$language,
features = circassian$dialect,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language)
It is possible to remove points and display only the kernal density estimation plot, using the density.points
argument:
map.feature(circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language,
density.points = FALSE)
It is possible to change kernal density estimation plot opacity using thedensity.estimation.opacity
argument:
map.feature(circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = circassian$language,
density.estimation.opacity = 0.9)
Since this type of visualisation is based on the kernal density estimation, there are parameters density.longitude.width
and density.latitude.width
that increase/decrease area:
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = "Circassian",
density.longitude.width = 0.3,
density.latitude.width = 0.3,
color= c("darkgreen", "blue"))
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = "Circassian",
density.longitude.width = 0.7,
density.latitude.width = 0.7,
color= c("darkgreen", "blue"))
map.feature(circassian$language,
features = circassian$language,
longitude = circassian$longitude,
latitude = circassian$latitude,
density.estimation = "Circassian",
density.longitude.width = 1.3,
density.latitude.width = 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 betterto use a different coordinate projection. That allows not to treat Earth as a flat object.
It is possible to show some lines on the map using coordinates (line.lng
and line.lat
arguments).
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 colorof the line using the line.color
argument.
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 forcalculation).
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.
map.feature(c("Russian", "Adyghe"),
graticule = 5)