Country labels on Basemap
Asked Answered
A

1

7

I would like to plot a trajectory on a Basemap, and have country labels (names) shown as an overlay.

Here is the current code and the map it produces:

import pandas as pd 
import matplotlib.pyplot as plt 
from mpl_toolkits.basemap import Basemap


path = "path\\to\\data"

animal_data = pd.DataFrame.from_csv(path, header=None)
animal_data.columns = ["date", "time", "gps_lat", "gps_long"]

# data cleaning omitted for clarity 

params = {
        'projection':'merc', 
        'lat_0':animal_data.gps_lat.mean(), 
        'lon_0':animal_data.gps_long.mean(), 
        'resolution':'h', 
        'area_thresh':0.1, 
        'llcrnrlon':animal_data.gps_long.min()-10, 
        'llcrnrlat':animal_data.gps_lat.min()-10, 
        'urcrnrlon':animal_data.gps_long.max()+10, 
        'urcrnrlat':animal_data.gps_lat.max()+10
}
map = Basemap(**params)

map.drawcoastlines()
map.drawcountries()
map.fillcontinents(color = 'coral')
map.drawmapboundary()          

x, y = map(animal_data.gps_long.values, animal_data.gps_lat.values)

map.plot(x, y, 'b-', linewidth=1)    
plt.show()

This results in the map: Migration

This is a map of the trajectory of a migrating bird. While this is a very nice map (!), I need country-name labels so it is easy to determine the countries the bird is flying through.

Is there a straight-forward way of adding the country names?

Antiperistalsis answered 21/6, 2015 at 9:46 Comment(2)
Wow, that bird is traveling quite some distance! If you need country names and coordinates, have a look at this question. To plot text on a map, have a look at the example of plotting pressure on this page, it seems that you can just do plt.text(x, y, text).Mohandas
Thank you! This was very helpful. I will soon post the complete solution below.Antiperistalsis
A
7

My solution relies on an external data file that may or may not be available in the future. However, similar data can be found elsewhere, so that should not be too much of a problem.

First, the code for printing the country-name labels:

import pandas as pd 
import matplotlib.pyplot as plt 
from mpl_toolkits.basemap import Basemap

class MyBasemap(Basemap):     
    def printcountries(self, d=3, max_len=12):
        data = pd.io.parsers.read_csv("http://opengeocode.org/cude/download.php?file=/home/fashions/public_html/opengeocode.org/download/cow.txt", 
                                      sep=";", skiprows=28 )
        data = data[(data.latitude > self.llcrnrlat+d) & (data.latitude < self.urcrnrlat-d) & (data.longitude > self.llcrnrlon+d) & (data.longitude < self.urcrnrlon-d)]
        for ix, country in data.iterrows():                            
                plt.text(*self(country.longitude, country.latitude), s=country.BGN_name[:max_len]) 

All this does is to download a country-location database from here, then select countries that are currently on the map, and label them.

The complete code:

import pandas as pd 
import matplotlib.pyplot as plt 
from mpl_toolkits.basemap import Basemap

class MyBasemap(Basemap):     
    def printcountries(self, d=3, max_len=12):
        data = pd.io.parsers.read_csv("http://opengeocode.org/cude/download.php?file=/home/fashions/public_html/opengeocode.org/download/cow.txt", 
                                      sep=";", skiprows=28 )
        data = data[(data.latitude > self.llcrnrlat+d) & (data.latitude < self.urcrnrlat-d) & (data.longitude > self.llcrnrlon+d) & (data.longitude < self.urcrnrlon-d)]
        for ix, country in data.iterrows():                            
                plt.text(*self(country.longitude, country.latitude), s=country.BGN_name[:max_len]) 


path = "path\\to\\data"

animal_data = pd.DataFrame.from_csv(path, header=None)
animal_data.columns = ["date", "time", "gps_lat", "gps_long"]

params = {
        'projection':'merc', 
        'lat_0':animal_data.gps_lat.mean(), 
        'lon_0':animal_data.gps_long.mean(), 
        'resolution':'h', 
        'area_thresh':0.1, 
        'llcrnrlon':animal_data.gps_long.min()-10, 
        'llcrnrlat':animal_data.gps_lat.min()-10, 
        'urcrnrlon':animal_data.gps_long.max()+10, 
        'urcrnrlat':animal_data.gps_lat.max()+10
}

plt.figure()
map = MyBasemap(**params)

map.drawcoastlines()
map.fillcontinents(color = 'coral')
map.drawmapboundary()          
map.drawcountries()
map.printcountries()

x, y = map(animal_data.gps_long.values, animal_data.gps_lat.values)

map.plot(x, y, 'b-', linewidth=1)    
plt.show()

and finally, the result:

labeld-map

Clearly this isn't as carefully labeled as one might hope, and some heuristics regarding country size, name length and map size should be implemented to make this perfect, but this is a good starting point.

Antiperistalsis answered 21/6, 2015 at 13:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.