Color Cartopy map countries according to given values

不问归期 提交于 2021-02-11 07:10:52

问题


I am speaking to those who know Cartopy well ... because I use Cartopy to produce a map, but I do not know very well how it works.

First, I created a map of Europe (in the broadest sense, from the Atlantic to the Urals), as shown in the attached figure.

Then, I have a separate file, say dft0, indicating for each European country the time of appearance (Time0) of a certain phenomenon, counted in number of days with respect to an arbitrary date D and sorted from min to max; as an example of the first rows:

    Country     Time0
20  Italy    -16.063702
10  Denmark   -2.798684
39  Sweden    -2.711578
15  Germany    3.259436

So, the so-called phenomenon appeared first in Italy, 16.1 days before my date D, then in Denmark, 2.8 days before D, then in Sweden, 2.7 days before D, then in Germany, 3.3 days after D, etc., going to Belarus, where it appeared 52.1 days after D. 52.1.

There are 44 such values (from negative to positive) in file dft0, from -16.1 to 52.1.

My question is: knowing that I did a suitable program to draw the map of Europe, what kind of code should I have to add to the program in order to color the countries according to the variable Time0, for example from red (for Italy) to violet (for Belarus), following the colors of the visible spectrum, in which red = 800 nmand violet = 400 nm?

More precisely, if Time0 = x, I would like to color the corresponding country with the color corresponding to (approximately) y = -5.9 x + 705.6 nm.

To be more understandable, I inserted a plot showing how to calculate the color y (in nm); it's a basic linear interpolation.

I really don't know if it can be done, as it seems to be complicated (may be unnecessarily complicated). So, I am open to any other idea. The aim is to differentiate the 44 countries I have in this file dft0, with an ordered palette of colors, showing a regular decrease (or a regular growth...)

Thank you for your concern.

Added: the Cartopy program I used:

import matplotlib.pyplot as plt
import cartopy
import cartopy.io.shapereader as shpreader

plt.figure(figsize=(4, 4))

central_lon, central_lat = 0, 45
extent = [-10, 45, 35, 70]

ax = plt.axes(projection=cartopy.crs.Orthographic(central_lon, central_lat))
ax.set_extent(extent)
ax.gridlines()
ax.add_feature(cartopy.feature.BORDERS, linestyle=':', alpha=1)
ax.add_feature(cartopy.feature.OCEAN,facecolor=("lightblue"))
ax.add_feature(cartopy.feature.LAND)
ax.coastlines(resolution='10m')

plt.show()

回答1:


This solution is based on your posted code sample and draws heavily on this answer

import matplotlib.pyplot as plt
import matplotlib
import cartopy
from cartopy.io import shapereader
import cartopy.crs as ccrs
import geopandas
import numpy as np

# get natural earth data (http://www.naturalearthdata.com/)

# get country borders
resolution = '10m'
category = 'cultural'
name = 'admin_0_countries'
shpfilename = shapereader.natural_earth(resolution, category, name)

# read the shapefile using geopandas
df = geopandas.read_file(shpfilename)


# Set up the canvas
fig = plt.figure(figsize=(8, 8))
central_lon, central_lat = 0, 45
extent = [-10, 45, 35, 70]
ax = plt.axes(projection=cartopy.crs.Orthographic(central_lon, central_lat))
ax.set_extent(extent)
ax.gridlines()

# Add natural earth features and borders
ax.add_feature(cartopy.feature.BORDERS, linestyle=':', alpha=1)
ax.add_feature(cartopy.feature.OCEAN, facecolor=("lightblue"))
ax.add_feature(cartopy.feature.LAND)
ax.coastlines(resolution='10m')

# Insert your lists of countries and lag times here
countries = ['Germany', 'France', 'Italy', 'Spain', 'Ukraine']
lags = [-20,-5, 15, 0, 2]

# Normalise the lag times to between 0 and 1 to extract the colour
lags_norm = (lags-np.nanmin(lags))/(np.nanmax(lags) - np.nanmin(lags))

# Choose your colourmap here
cmap = matplotlib.cm.get_cmap('viridis')


for country, lag_norm in zip(countries, lags_norm):
    # read the borders of the country in this loop
    poly = df.loc[df['ADMIN'] == country]['geometry'].values[0]
    # get the color for this country
    rgba = cmap(lag_norm)
    # plot the country on a map
    ax.add_geometries(poly, crs=ccrs.PlateCarree(), facecolor=rgba, edgecolor='none', zorder=1)

# Add a scatter plot of the original data so the colorbar has the correct numbers. Hacky but it works
dummy_scat = ax.scatter(lags, lags, c=lags, cmap=cmap, zorder=0)
fig.colorbar(mappable=dummy_scat, label='Time lag of phenomenon', orientation='horizontal', shrink=0.8)

result:

Map of Europe with France, Germany and Italy coloured

As for the colouring by the visible spectrum, I would strongly dissuade you from dong this unless you have a very good reason to do so. Instead I have used one of matplotlib's inbuilt perceptually uniform colourmaps. There are many other colormaps you can use if viridis doesn't suit your needs. These perceptually uniform colormaps are preferable as they do not distort your data. For more information check out this page or this more in depth discussion, or search for information on perceptually uniform colourmaps. Viewers of your work (especially those with colour vision deficiency) will thank you.



来源:https://stackoverflow.com/questions/61460814/color-cartopy-map-countries-according-to-given-values

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!