Lingtypology

- Main Page
- Glottolog
- DB APIs

# Maps ¶

It is possible to draw interactive linguistic maps using `lingtypology`

In [1]:

    import lingtypology

## 0. Table of Contents¶

### 1. Maps¶

#### 1.1. Simplest example¶

#### 1.2. Save, Render or Save as an image¶

#### 1.3. Features¶

#### 1.4. Map Customization¶

#### 1.5. Popups¶

#### 1.6. Accessing Glottolog¶

#### 1.7. Customizing Features and Controls¶

#### 1.8. Stroke Features¶

#### 1.9. Heatmaps¶

#### 1.10. Title¶

#### 1.11. Lines¶

#### 1.12. Customizing markers¶

#### 1.13. Start Location/Zoom shortcuts¶

#### 1.14. Color Gradients¶

#### 1.15. Minicharts¶

#### 1.16. Overlapping Features¶

#### 1.17. Using Existing folium.Map¶

#### 1.18. Merging Maps¶

#### 1.19. Tiles¶

#### 1.20. Elevation¶

### 2. Real examples¶

#### 2.1. Circassian Example¶

#### 2.2. Another way¶

#### 2.3. Consonants Example¶

## 1. Maps ¶

In this paragraph I will consider some basic features that you can use.

### 1.1. Simplest example ¶

The simplest script that draws a map with Romanian and Ukrainian languages will be:

In [2]:

    m = lingtypology.LingMap(('Romanian', 'Afrikaans', 'Tlingit', 'Japanese'))
    m.create_map()

Out[2]:

If you have Glottocodes rather then language names, you can pass them as well (you need to set `glottocode` to `True`).

In [3]:

    m = lingtypology.LingMap(('russ1263', 'afri1274', 'tlin1245', 'nucl1643'), glottocode=True)
    m.create_map()

Out[3]:

### 1.2. Save, Render or Save as Image ¶

Be advised that `create_map()` returns a `Folium` map. In this notebook it is used because the map may be displayed this way.

To save your map as html run: `m.save('map.html')`

To get html as `str` run: `m.render()`

To get a `png` image run `m.save_static(fname=fname)` (if no arguments are given it will be returned as `bytes`).
`geckodriver` should be installed.
Note: `save_static` is an experimental method.

`m.save_static()`

### 1.3. Features ¶

Simply drawing languages on a map is not very interesting. Let's say that we want to mark some morphological features as different colors.

In [4]:

    languages = ["Adyghe", "Kabardian", "Polish", "Russian", "Bulgarian"]
    features = ["Agglutinative", "Agglutinative", "Inflected", "Inflected", "Analytic"]
    m = lingtypology.LingMap(languages)
    m.add_features(features)
    m.create_map()

Out[4]:

### 1.4. Customizing the map ¶

As you can see, the map is not centered properly. It can be fixed with passing coordinates to the `start_location` attribute. You can change start zoom as well `start_zoom`. Also, you can change colors using the `colors` attribute.

In [5]:

    m.start_location = (40, 40)
    m.start_zoom = 3
    m.colors = ("#00FFFF", "#FF00FF", "#FFFF00")
    m.create_map()

Out[5]:

### 1.5. Popups ¶

You can add popups using `add_popups` method. You can disable links to Glottolog by setting `languages_in_popups` attribute to `False`.
Basically, you can set any html-code in the popups.

In [6]:

    contents = ('Caucasus', 'Caucasus', 'Europe', 'Europe', 'Europe')
    html = '''
    <a href="https://en.wikipedia.org/wiki/{data}" target="_blank">
    {data}
    </a>
    '''
    m.add_popups([html.format(data=popup) for popup in contents])
    m.languages_in_popups = False
    m.create_map()

Out[6]:

### 1.6. Accessing Glottolog ¶

You can also use `lingtypology.glottolog` to get some data from it. For example, I want to add language affiliations to popups.
See more details here.

In [7]:

    affs = lingtypology.glottolog.get_affiliations(languages)
    m.add_popups(affs)
    m.create_map()

Out[7]:

### 1.7. Customizing features and controls ¶

You can pass additional parameters to the `add_features` method.
If for some reason you do not wish to use colors, you could use shapes.
If you want to add controls, you can do it as well.

In [8]:

    m.add_features(features, use_shapes=True, control=True)
    m.create_map()

Out[8]:

### 1.8. Stroke features ¶

It is possible to add another set of features to strokes of markers using `add_stroke_features` method.

In [9]:

    stroke_features = ['Ergative', 'Ergative', 'Accusative', 'Accusative', 'Accusative']
    m = lingtypology.LingMap(languages)
    m.add_features(features)
    m.add_stroke_features(stroke_features)
    m.create_map()

Out[9]:

### 1.9. Heatmaps ¶

It would seem unfair if we could only draw circles.
Let's draw a heatmap (the more density, the more languages with Large consonant inventory) using `add_heatmap` method.
It is from Wals. For more information consult this.

In [10]:

    from lingtypology.db_apis import Wals
    wals_page = Wals('1a').get_df()

    #First initialize LingMap without languages
    m = lingtypology.LingMap()
    #Add heatmap from  the Wals data
    m.add_heatmap(wals_page[wals_page._1A_desc == 'Large'].coordinates)
    m.create_map()

    Citation for feature 1A:
    Ian Maddieson. 2013. Consonant Inventories.
    In: Dryer, Matthew S. & Haspelmath, Martin (eds.)
    The World Atlas of Language Structures Online.
    Leipzig: Max Planck Institute for Evolutionary Anthropology.
    (Available online at http://wals.info/chapter/1, Accessed on 2019-06-07.)

Out[10]:

### 1.10. Title ¶

To add title, use `title` attribute.

In [11]:

    m.title = 'Large Consonant Inventories'
    m.create_map()

Out[11]:

### 1.11. Lines ¶

Let's say we have this list of languages:

In [12]:

    balkan = ['Modern Greek', 'Romanian', 'Bulgarian', 'Macedonian', 'Gheg Albanian']
    other = ['Ukrainian', 'Turkish', 'Italian']
    languages_all = balkan + other

We want the ones from Balkan sprachbund connected with lines with a popup that says 'Balkan'. It is possible using `add_line` method.

In [13]:

    #Let's get the coordinates that we need to draw a line
    coordinates = map(lingtypology.glottolog.get_coordinates, balkan)
    m = lingtypology.LingMap(languages_all)
    m.add_line(coordinates, popup='Balkan')
    m.start_location = (43, 27)
    m.start_zoom = 5
    m.create_map()

Out[13]:

### 1.12. Customizing markers ¶

It is possible to set opacity and width of markers.

In [14]:

    m = lingtypology.LingMap(languages)
    m.add_features(features, radius=7, opacity=0.9)
    m.add_stroke_features(stroke_features, opacity=0.7)
    m.create_map()

Out[14]:

### 1.13. Start Location/Zoom shortcuts ¶

There are some shortcuts that can allow not to choose `start_location` and `start_zoom` manually.

In [15]:

    m = lingtypology.LingMap([
        'Irish', 'Estonian', 'Norwegian', 'Romanian', 'Polish',
        'Italian', 'Turkish', 'French', 'English', 'Spanish'
    ])
    m.start_location = 'Central Europe'
    m.create_map()

Out[15]:

Full list of shortcuts:

In [16]:

    m.start_location_mapping

Out[16]:

    {'Central Europe': {'start_location': (50, 0), 'start_zoom': 4},
     'Caucasus': {'start_location': (43, 42), 'start_zoom': 6},
     'Australia & Oceania': {'start_location': (-16, 159), 'start_zoom': 3},
     'Papua New Guinea': {'start_location': (-5, 141), 'start_zoom': 6},
     'Africa': {'start_location': (3, 22), 'start_zoom': 3},
     'Asia': {'start_location': (36, 100), 'start_zoom': 3},
     'North America': {'start_location': (51, -102), 'start_zoom': 3},
     'Central America': {'start_location': (19, -81), 'start_zoom': 4},
     'South America': {'start_location': (-27, -49), 'start_zoom': 3}}

### 1.14. Color gradients ¶

There are two ways to use color gradients. Let's say we have features called "Millions of native speakers".

In [17]:

    native_speakers = [0, 1, 5, 24, 44, 62, 78, 78, 378, 442]
    m.legend_title = 'Native speakers (mln)'
    m.legend_position = 'topright'

The first way is simply pass the features as `numeric`:

In [18]:

    m.add_features(native_speakers, numeric=True)
    m.colormap_colors = ('white', 'red')
    m.create_map()

Out[18]:

Or you can simply set attribute `color` to a gradient using `gradient` function.

In [19]:

    m.add_features(native_speakers)
    m.colors = lingtypology.gradient(10, 'white', 'red')
    m.create_map()

Out[19]:

### 1.15. Minicharts ¶

You can add minicharts to the map using `add_minicharts` method. Just pass all the data.

Note, that if you are passing data as anything except for `pandas.Series` you should specify `names` parameter (e.g. `names=('consonants', 'vowels')`).

In [20]:

    import pandas
    data = pandas.read_csv(
        'https://raw.githubusercontent.com/ropensci/lingtypology/master/database_creation/ejective_and_n_consonants.csv',
        delimiter=',',
        header=0,
    )
    data = data[data.language != 'Paraguayan Guarani']

In [21]:

    m = lingtypology.LingMap(data.language)
    m.add_minicharts(data.consonants, data.vowels)
    m.create_map()

Out[21]:

It is possible to customize them using these parameters:

1. `colors`
   Colors for your features. If not given, default colors (`LingMap().colors`) will be used.

2. `size`
   Size of the chart. Please, bear in mind that they should be small. Default: `0.6`.

3. `startangle`
   Start angle. Default `90`. Pie-chart only.
4. `labels`
   Show values inside the chart. Pie-chart only.
5. `textprops`
   Set text properties (`matplotlib` format). Default: `None`. E.g.: `textprops={'color': 'red'}`.

In [22]:

    m = lingtypology.LingMap(data.language)
    m.add_minicharts(
        data.consonants, data.vowels,
        colors = ('#0020c2', '#c22000'),
        size = 0.8,
        startangle = 45,
        labels = True,
        textprops = {'color': 'white'}
    )
    m.create_map()

Out[22]:

You can also use bar charts.

In [23]:

    m = lingtypology.LingMap(data.language)
    m.add_minicharts(
        data.consonants, data.vowels,
        typ = 'bar',
        colors = ('blue', 'red'),
        size = 0.4
    )
    m.create_map()

Out[23]:

### 1.16. Overlapping Features ¶

Let's say we want to see info about whether language:

1. is ergative;
2. has cases;
3. is slavic.

It is possible with `add_overlapping_features` method. It allows to draw several markers of different radius and color for each given language.

In [24]:

    languages = ('Tsakhur', 'Russian', 'Bulgarian')
    m = lingtypology.LingMap(languages)
    m.add_overlapping_features([
        ['ergative', 'has cases'],
        ['has cases', 'slavic'],
        ['slavic']
    ])
    m.create_map()

Out[24]:

You can use these parameters:

1. `radius` Default radius. Default: 7.
2. `radius_increment` Radius increment. By how much the size of the marker increases with each additional feature. Default: 4.
3. `mapping` If you want to use custom colors, use this parameter. If it is not given, the default color will be used.

In [25]:

    m.add_overlapping_features(
        [
            ['ergative', 'has cases'],
            ['has cases', 'slavic'],
            ['slavic']
        ],
        radius = 10,
        radius_increment = 5,
        mapping = {
            'ergative': '#e6194b',
            'has cases': '#4be619',
            'slavic': '#194be6'
        }
    )
    m.create_map()

Out[25]:

### 1.17. Using Existing Folium Map ¶

If you already have a `folium.Map` that you want to edit using `lingtypology`, you can pass it as `base_map` attribute.

In [26]:

    import folium
    folium_map = folium.Map((0, 0), zoom_start=2)
    marker = folium.Marker((0, 0))
    icon = folium.DivIcon(
        html='<img src="https://raw.githubusercontent.com/OneAdder' + \
        '/lingtypology/master/data_processing/waifu6060.jpg"></img>'
    )
    marker.add_child(icon)
    folium_map.add_child(marker)

    m = lingtypology.LingMap(('Russian', 'Afrikaans'))
    m.base_map = folium_map
    m.create_map()

Out[26]:

### 1.18. Merging Maps ¶

You can also draw two `lingtypology` maps the way it is described in 1.16. However, it is not recommended and may cause glitches.

You can use `lingtypology.merge`. Let's merge examples from 1.12 and 1.13

In [27]:

    m1 = lingtypology.LingMap([
        'Irish', 'Estonian', 'Norwegian', 'Romanian', 'Polish',
        'Italian', 'Turkish', 'French', 'English', 'Spanish'
    ])
    m1.add_features(native_speakers, numeric=True)
    m1.colormap_colors = ('white', 'red')
    m1.legend_title = 'Native Speakers'
    m1.legend_position = 'bottomleft'

    m2 = lingtypology.LingMap(data.language)
    m2.legend_title = 'Consonants/Vowels'
    m2.add_minicharts(data.consonants, data.vowels)

    m = lingtypology.merge(m1, m2)
    m.create_map()

Out[27]:

### 1.19. Using Different Tiles ¶

You can change tiles using `tiles` attribute. Let's use `Stamen Terrain`.

In [28]:

    m2 = lingtypology.LingMap(data.language)
    m2.tiles = 'Stamen Terrain'
    m2.legend_title = 'Consonants/Vowels'
    m2.add_minicharts(data.consonants, data.vowels, colors=('black', 'white'))
    m2.create_map()

Out[28]:

### 1.20. Using Elevation Data ¶

`lingtypology` package contains data on elevation (raw data taken from here) for each language from Glottolog.
You can get elevation for any language using `lingtypology.get_elevations` function.

In [29]:

    m = lingtypology.LingMap(data.language)
    data['elevation'] = lingtypology.get_elevations(data.language)
    m.add_features(data.elevation, numeric=True)
    m.add_tooltips(data.elevation)
    m.create_map()

Out[29]:

## 2. Some real examples ¶

### 2.1. Circassian Example ¶

Let's draw a map based on data from this CSV.

In [30]:

    import pandas

In [31]:

    circassian = pandas.read_csv(
        'https://raw.githubusercontent.com/ropensci/lingtypology/master/database_creation/circassian.csv',
        delimiter=',',
        header=0,
    )
    circassian.head()

Out[31]:

| latitude | longitude | village | district | dialect | language
--- | --- | --- | --- | --- | --- | ---
0 | 45.183330 | 39.666670 | Khatukay | ra | Temirgoy | Adyghe
1 | 43.092518 | 43.522085 | Psygansu | kbr | Baksan | Kabardian
2 | 43.217748 | 43.738020 | Verkhny Lesken | kbr | Baksan | Kabardian
3 | 43.260246 | 43.653788 | Zhemtala | kbr | Baksan | Kabardian
4 | 43.317842 | 43.876519 | Erokko | kbr | Baksan | Kabardian

In [32]:

    coordinates = zip(list(circassian.latitude), list(circassian.longitude))
    dialects = circassian.dialect
    languages = circassian.language
    popups = circassian.village

In [33]:

    #Creating LingMap object
    m = lingtypology.LingMap(languages)
    #Setting up start location
    m.start_location = (44.21, 42.32)
    #Setting up start zoom
    m.start_zoom = 7
    #Inner features < dialect
    m.add_features(dialects, opacity=0.7)
    #Outer features < language
    m.add_stroke_features(languages, opacity=0.8)
    #Popups < village
    m.add_popups(popups)
    #Tooltips < language
    m.add_tooltips(languages)
    #Custom coordinates (override the ones from Glottolog)
    m.add_custom_coordinates(coordinates)
    #Inner legend title and position
    m.legend_title = 'Dialects'
    m.legend_position = 'bottomright'
    #Outer legend title and position
    m.stroke_legend_title = 'Languages'
    m.stroke_legend_position = 'topright'
    m.create_map()

Out[33]:

### 2.2. Another way ¶

If you are used to the R package, you may find this way to program the second example more appealing.
However, it is not recommended because most of customization is impossible.

In [34]:

    coordinates = zip(list(circassian.latitude), list(circassian.longitude))
    dialects = circassian.dialect
    languages = circassian.language
    popups = circassian.village

    lingtypology.map_feature(
        languages,
        custom_coordinates = coordinates,
        features = dialects,
        stroke_features = languages,
        popups = popups,
        tooltips = languages,
        legend_title = 'Dialects',
        legend_position = 'bottomright',
        stroke_legend_title = 'Languages',
        stroke_legend_position = 'topright',
        start_zoom = 7,
        start_location = (44.21, 42.32),
        save_html = 'circassian.html',
    )

### 2.3. Consonants Example ¶

Map based on this data.

In [35]:

    data = pandas.read_csv(
        'https://raw.githubusercontent.com/ropensci/lingtypology/master/database_creation/ejective_and_n_consonants.csv',
        delimiter=',',
        header=0,
    )

In [36]:

    m = lingtypology.LingMap(data.language)
    m.legend_title = 'Amount of consonants'
    m.add_tooltips(data.consonants)
    #If numeric is True, it will look like this
    m.add_features(data.consonants, numeric=True)
    m.create_map()

Out[36]:

Go back up