Reputation: 1293
I have a basic setting for plotting data on the African map with Python matplotlib
. Unfortunately the geopandas
natural earth database does not include the small island states that would be essential to have included as well.
My basic setting is like this:
import geopandas as gpd
import numpy as np
import matplotlib.pyplot as plt
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
africa = world.query('continent == "Africa"')
africa.plot(column="pop_est")
plt.show()
And the figure I get is like this:
Instead, I would like to have a figure that is something like this, where small island states are neatly presented by visible dots:
(The source of the figure is: https://en.wikipedia.org/wiki/African_Continental_Free_Trade_Area#/media/File:AfricanContinentalFreeTradeArea.svg)
There are two problems I have: 1) geopandas
natural earth data do not include the island states, and 2) I don't know how to draw the otherwise invisible island states as visible dots.
I saw some related questions in SO for R, but it is specifically the Python solution that I am after.
Upvotes: 5
Views: 3373
Reputation: 1293
I got a working solution by finding the centroid data for each country. I used R for that, based on this post: https://gis.stackexchange.com/a/232959/68457
and made a GeoDataFrame
that had a country identifier and geometry
column for centroid points.
Then I applied geopandas
function buffer
to the centroid points, i.e.:
dfCentroids["geometry"] = dfCentroids.buffer(1)
where 1 is the radius of the resulting spherical polygon. Then concatenating that with the geopandas
naturalearth
dataset, I got a geocoded data for plotting the map with dots on island states.
Upvotes: 1
Reputation: 18812
This is an interesting challenge. The following is a runnable code with output map that should meet the requirements stated in the question. Since I put many comments within the code, I should write short introduction here.
# Module imports
import matplotlib.pyplot as plt
import matplotlib
import cartopy
from cartopy.io import shapereader
import cartopy.crs as ccrs
import geopandas as gpd
import numpy as np
import pandas as pd
# get natural earth data from http://www.naturalearthdata.com/
# for country borders
use_res = '50m' # medium resolution of (10m, 50m, 110m)
category = 'cultural'
name = 'admin_0_countries'
shpfilename = shapereader.natural_earth(use_res, category, name)
# read the shapefile using geopandas
df = gpd.read_file(shpfilename)
# select countries in Africa
africa = df[df['CONTINENT'] == "Africa"]
# It is possible to select the small island states by other methods without using their names
# .. but using names is presented here
# Select only countries in a list (small island states)
islnd_cts = ['Cabo Verde', 'Mauritius', 'Comoros', 'São Tomé and Principe', 'Seychelles']
islnds = df[df['NAME'].isin(islnd_cts)]
# collect name and centroid of countries in `islnds` dataframe
names, points, popest, iso_a3 = [], [], [], []
# this part can be improved
#
for i, col_dict in islnds[['NAME', 'POP_EST', 'ISO_A3', 'geometry']].iterrows():
#df1.loc[i, 'Result1'] = col_dict['NAME'] + col_dict['POP_EST']
#print(col_dict['NAME'], col_dict['POP_EST'])
names.append(col_dict['NAME'])
points.append(col_dict['geometry'].centroid)
popest.append(col_dict['POP_EST'])
iso_a3.append(col_dict['ISO_A3'])
# prep a dict useful to build a dataframe
# population_estimate is intentionally omitted
ilsdict = {'NAME': names, 'ISO_A3': iso_a3, 'CENTROID': points}
# make it a dataframe
df6c = pd.DataFrame(ilsdict)
# create geodataframe of the island states
gdf6c = gpd.GeoDataFrame(df6c, crs={'init': 'epsg:4326'}, geometry='CENTROID')
# can do plot check with:
#gdf6c.plot()
# Setup canvas for plotting multi-layered data (need cartopy here)
fig = plt.figure(figsize=(10, 10))
# set extent to cover Africa
extent =[-28,60, -32, 40] #lonmin, lonmax, latmin, latmax
ax = plt.axes(projection=cartopy.crs.PlateCarree())
ax.set_extent(extent)
# This do in batch, not possible to filter/check individual rows of data
africa.plot(ax=ax, edgecolor="black", facecolor='lightgray', lw=0.25) #returns axes
# This layer of plot: island states, as colored dots
gdf6c.plot(ax=ax, facecolor='salmon', markersize=90)
# Annotate: iso-a3 abbrev-name of island states
for i, geo in gdf6c.centroid.iteritems():
#print(str(i), ak['admin'][i], geo.x, geo.y)
ax.annotate(s=gdf6c['ISO_A3'][i], xy=[geo.x, geo.y], color="blue")
# Draw other map features
ax.coastlines(resolution = use_res, lw=0.4)
ax.gridlines(draw_labels=True)
plt.title("African Island States", pad=20)
plt.show()
Upvotes: 2
Reputation: 365
Can't comment yet, but I'll put this here. Using swatchai's method and the geopandas
.area
method, you could even set a threshold to plot circles/polygons.
Upvotes: 0