• 1. Base map
  • 2. Set features
  • 3. Set pop-up boxes
  • 4. Set labels
  • 5. Set coordinates
  • 6. Set colors
  • 7. Set shapes
  • 8. Set control box
  • 9. Set an additional set of features using strokes
  • 10. Set width and an opacity feature
  • 11. Customizing legends
  • 12. Set scale bar
  • 13. Set layouts
  • 14. Add a minimap to a map
  • 15. Add minicharts instead of points
  • 16. Add a rectangle to a map
  • 17. Add a density contourplot to a map
  • 18. Add isoglosses
  • 19. Add lines

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, such as WALS and Glottolog:

map.feature(c("West Circassian", "Kabardian", "Polish", "Russian", "Bulgarian"))
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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.

m <- map.feature(c("Kabardian", "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 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:

df <- data.frame(language = c("West Circassian", "Kabardian", "Polish", "Russian", "Bulgarian"),
               features = c("polysynthetic", "polysynthetic", "fusional", "fusional", "fusional"))
df
ABCDEFGHIJ0123456789
language
<chr>
features
<chr>
West Circassianpolysynthetic
Kabardianpolysynthetic
Polishfusional
Russianfusional
Bulgarianfusional

Now we can draw a map:

map.feature(languages = df$language,
            features = df$features)
fusional
polysynthetic
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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:

df$features <- factor(df$features, levels = c("polysynthetic", "fusional"))
map.feature(languages = df$language, features = df$features)
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

Like in most functions, it is not necessary to name all arguments, so the same result can be obtained by:

map.feature(df$language, df$features)
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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. 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:

map.feature(phonological_profiles$language,
            phonological_profiles$ejectives) # categorical
FALSE
TRUE
5000 km
3000 mi
Leaflet | © OpenStreetMap contributors
map.feature(phonological_profiles$language,
            phonological_profiles$consonants) # numeric
1015202530354045

5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

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):

map.feature(phonological_profiles$language,
            phonological_profiles$consonants,
            map.orientation = "Atlantic")
1015202530354045

5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

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:

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:

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)))
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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:

df$popup <- aff.lang(df$language)

The function aff.lang() creates a vector of genealogical affiliations that can be easily mapped:

map.feature(languages = df$language, features = df$features, popup = df$popup)
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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:

# 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)
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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-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)
5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

4. Set labels

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)
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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).

map.feature(df$language, df$features,
            label = df$language,
            label.fsize = 20,
            label.position = "left",
            label.hide = FALSE)
West Circassian
Kabardian
Polish
Russian
Bulgarian
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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.

map.feature(df$language, df$features,
            label = df$language,
            label.fsize = 20,
            label.position = "left",
            label.hide = FALSE,
            label.emphasize = list(2:4, "red"))
West Circassian
Kabardian
Polish
Russian
Bulgarian
Kabardian
Polish
Russian
Kabardian
Polish
polysynthetic
fusional
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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:

head(circassian)
ABCDEFGHIJ0123456789
 
 
latitude
<dbl>
longitude
<dbl>
village
<chr>
district
<chr>
dialect
<chr>
language
<chr>
145.1833339.66667KhatukayraTemirgoyWest Circassian
243.0925243.52209PsygansukbrBaksanKabardian
343.2177543.73802Verkhny LeskenkbrBaksanKabardian
443.2602543.65379ZhemtalakbrBaksanKabardian
543.3178443.87652ErokkokbrBaksanKabardian
643.3338943.81722ProgressstvBaksanKabardian

In this dataframe you can find variables latitude and longitude that could be used:

map.feature(languages = circassian$language,
            features = circassian$dialect,
            popup = circassian$village,
            latitude = circassian$latitude,
            longitude = circassian$longitude)
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
50 km
50 mi
Leaflet | © OpenStreetMap contributors

It is possible to collapse multiple dots into clusters:

map.feature(languages = circassian$language,
            features = circassian$dialect,
            popup = circassian$village,
            latitude = circassian$latitude,
            longitude = circassian$longitude, 
            point.cluster = TRUE)
4
31
10
16
16
2
78
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
50 km
50 mi
Leaflet | © OpenStreetMap contributors

6. Set colors

You can set your own colors using the argument color:

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"))
fusional
polysynthetic
500 km
300 mi
Leaflet | © OpenStreetMap contributors

Arguments from RColorBrewer or viridis also can be used as a color argument:

map.feature(phonological_profiles$language,
            phonological_profiles$consonants,
            color= "magma")
1015202530354045

5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

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:

map.feature(languages = circassian$language,
            features = circassian$language,
            latitude = circassian$latitude,
            longitude = circassian$longitude,
            shape = TRUE)
West Circassian
Kabardian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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:

map.feature(languages = circassian$language,
            features = circassian$dialect,
            latitude = circassian$latitude,
            longitude = circassian$longitude,
            shape = 1:10,
            shape.size = 14)
8
2
2
2
2
2
2
2
2
2
2
9
2
2
2
2
9
9
2
2
2
9
2
2
2
9
2
2
2
9
2
2
2
2
2
2
2
9
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
9
9
2
2
2
2
2
2
2
2
2
2
2
2
2
6
2
2
10
2
10
2
2
2
6
2
5
2
6
5
7
5
10
10
10
5
8
5
8
5
7
5
5
9
5
3
5
7
3
5
5
5
5
5
4
4
5
4
8
3
4
3
7
4
4
4
4
4
4
4
5
4
4
4
4
4
4
4
4
4
4
4
8
4
4
7
8
4
8
7
8
1
4
4
7
8
7
3
8
8
8
8
8
8 Temirgoy
2 Baksan
9 Terek
6 Malkin
10 Xakuch
5 Kuban
7 Shapsug
3 Besleney
4 Bzhedukh
1 Abadzex
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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:

map.feature(languages = df$language,
            features = df$features,
            control = c("a", "b", "b", "b", "a"))
fusional
polysynthetic
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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:

map.feature(circassian$language,
            features = circassian$dialect,
            stroke.features = circassian$language,
            latitude = circassian$latitude,
            longitude = circassian$longitude)
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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)
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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:

map.feature(circassian$language,
            features = circassian$dialect,
            stroke.features = circassian$language,
            latitude = circassian$latitude,
            longitude = circassian$longitude,
            width = 7, stroke.radius = 13)
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors
map.feature(circassian$language,
            features = circassian$dialect,
            stroke.features = circassian$language,
            latitude = circassian$latitude,
            longitude = circassian$longitude,
            opacity = 0.7, stroke.opacity = 0.6)
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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.

map.feature(circassian$language,
            features = circassian$dialect,
            stroke.features = circassian$language,
            latitude = circassian$latitude,
            longitude = circassian$longitude,
            legend = FALSE, stroke.legend = TRUE)
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors
map.feature(circassian$language,
            features = circassian$dialect,
            stroke.features = circassian$language,
            latitude = circassian$latitude,
            longitude = circassian$longitude,
            title = "Circassian dialects", stroke.title = "Languages")
Circassian dialects
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
Languages
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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 orFALSE) and its position (use scale.bar.position argument values “topright”, “bottomright”, “bottomleft” or”topleft”).

map.feature(c("West Circassian", "Polish", "Kabardian", "Russian"),
            scale.bar= TRUE,
            scale.bar.position = "topright")
500 km
300 mi
Leaflet | © OpenStreetMap contributors

13. Set layouts

It is possible to use different tiles on the same map using the tile argument. For more tiles see here.

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")
fusion
polysynthetic
500 km
300 mi
Leaflet | Tiles © Esri — Esri, DeLorme, NAVTEQ

It is possible to use different map tiles on the same map. Just add a vector with tiles.

map.feature(df$lang, df$feature, df$popup,
            tile = c("OpenStreetMap", "Esri.WorldGrayCanvas"))
fusion
polysynthetic
500 km
300 mi
Leaflet | © OpenStreetMap contributors

It is possible to name tiles using the tile.name argument.

map.feature(df$lang, df$feature, df$popup,
            tile = c("OpenStreetMap", "Esri.WorldGrayCanvas"),
            tile.name = c("colored", "b & w"))
fusion
polysynthetic
500 km
300 mi
Leaflet | © OpenStreetMap contributors

It is possible to combine the tiles’ control box with the features’ control box.

map.feature(df$lang, df$feature, df$popup,
            tile = c("OpenStreetMap", "Esri.WorldGrayCanvas"),
            control = TRUE)
fusion
polysynthetic
500 km
300 mi
Leaflet | © OpenStreetMap contributors

14. Add a minimap to a map

It is possible to add a minimap to a map.

map.feature(c("West Circassian", "Polish", "Kabardian", "Russian"),
            minimap = TRUE)
500 km
300 mi
Leaflet | © OpenStreetMap contributors

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).

map.feature(c("West Circassian", "Polish", "Kabardian", "Russian"),
            minimap = TRUE,
            minimap.position = "topright",
            minimap.height = 100,
            minimap.width = 100)
500 km
300 mi
Leaflet | © OpenStreetMap contributors

15. Add minicharts instead of points

This part is created using the beutifull leaflet.minicharts library. 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. Here is an example of barplot:

map.feature(languages = phonological_profiles$language,
            minichart.data = phonological_profiles[, c("vowels", "consonants")])
vowels
consonants
5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

Here is an example of piechart:

map.feature(languages = phonological_profiles$language,
            minichart.data = phonological_profiles[, c("vowels", "consonants")],
            minichart = "pie")
vowels
consonants
5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

Colors and opacity could be changed, legend moved:

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")
vowels
consonants
5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

It is possible to add values using argument minichart.labels:

map.feature(languages = phonological_profiles$language,
            minichart.data = phonological_profiles[, c("vowels", "consonants")],
            minichart = "pie",
            minichart.labels = TRUE)
1222112142251514265854381782820221020620111812248257477306281324
vowels
consonants
5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

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!):

map.feature(languages = phonological_profiles$language,
            minichart.data = phonological_profiles[, c("tone", "long_vowels", "stress", "ejectives")],
            minichart = "pie", 
            width = 3)
tone
long_vowels
stress
ejectives
5000 km
3000 mi
Leaflet | © OpenStreetMap contributors

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):

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")
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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]))
map.feature(circassian$language,
            longitude = circassian$longitude,
            latitude = circassian$latitude,
            density.estimation = circassian$language,
            density.width = 0.15)
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

Density estimation plot can be separated by features variable:

map.feature(circassian$language,
            features = circassian$dialect,
            longitude = circassian$longitude,
            latitude = circassian$latitude,
            density.estimation = circassian$language,
            density.width = 0.15)
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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.width = 0.15,
            density.points = FALSE)
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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.width = 0.15,
            density.estimation.opacity = 0.2)
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

If you want to use kernal density estimation, you need to change method type and provide a vector of parameters that increase/decrease area:

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"))
Kabardian
West Circassian
Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors
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"))
Kabardian
West Circassian
Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors
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"))
Kabardian
West Circassian
Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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:

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)
Abadzex
Baksan
Besleney
Bzhedukh
Kuban
Malkin
Shapsug
Temirgoy
Terek
Xakuch
50 km
50 mi
Leaflet | © OpenStreetMap contributors

It is possible to create true isoglosses by hand, see tools for it here.

19. Add lines

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))
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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.

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")
Kabardian
West Circassian
50 km
50 mi
Leaflet | © OpenStreetMap contributors

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).

map.feature(circassian$language,
            features = circassian$language,
            longitude = circassian$longitude,
            latitude = circassian$latitude,
            line.type = "logit")
Kabardian
West Circassian
100 km
100 mi
Leaflet | © OpenStreetMap contributors

It is possible to add a graticule to a map.

map.feature(c("Russian", "Kabardian"),
            graticule = 5)
-20
-15
-10
-5
0
5
10
15
20
25
30
35
40
45
50
55
60
65
70
75
80
85
90
95
100
105
110
30
35
40
45
50
55
60
65
70
(0,0)
500 km
300 mi
Leaflet | © OpenStreetMap contributors




© G. Moroz code on GitHub