I need to generate a map using cartopy
and plot some data over it (using networkx
). I am able to do it, but networkx
objects are behind the map. I am trying to force the order of the layers using zorder
but... it is not working :(
My only idea is to add some transparency to the cartopy
geometries, but it does not look nice at all... (in this example it does not look so bad, but with my whole data, it looks terrible)
Any ideias on how to force the order?
Here is my code:
import cartopy.crs as ccrs
from cartopy.io import shapereader as shpreader
import matplotlib.pyplot as plt
import networkx as nx
paises = ['Portugal', 'France', 'Canada', 'Brazil', 'Kazakhstan']
cidades = ['Aveiro', 'Ust-Kamenogorsk', 'Manaus']
links = [('Aveiro', 'Ust-Kamenogorsk'),
('Manaus', 'Ust-Kamenogorsk'),
('Aveiro', 'Manaus')]
position = {'Aveiro': (-8.65, 40.6),
'Manaus': (-60.0, -3.1),
'Ust-Kamenogorsk': (82.6, 49.97)}
# map using cartopy:
shapename = 'admin_0_countries'
countries_shp = shpreader.natural_earth(resolution='110m',
category='cultural', name=shapename)
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=0.0, globe=None))
ax.set_global()
for country in shpreader.Reader(countries_shp).records():
nome = country.attributes['name_long']
if nome in paises:
i = paises.index(nome)
artist = ax.add_geometries(country.geometry, ccrs.PlateCarree(),
facecolor='yellow',
#alpha=0.5,
zorder=10)
else:
artist = ax.add_geometries(country.geometry, ccrs.PlateCarree(),
facecolor='0.9',
zorder=10)
# add some data over the cartopy map (using networkx):
G = nx.Graph()
G.add_nodes_from(cidades)
G.add_edges_from(links)
nx.draw_networkx_nodes(G, position, node_size=20, nodelist=cidades, zorder=20)
edges=nx.draw_networkx_edges(G, position, edgelist=links, zorder=20)
plt.show()
What happened is that your zorder=20
doesn't do anything; it got ignored as you can see in their source code. What networkx
do in their draw_networkx_edges
code is:
def draw_networkx_edges(G, pos,
...
edge_collection.set_zorder(1) # edges go behind nodes
...
in their draw_networkx_nodes
code is:
def draw_networkx_nodes(G, pos,
...
node_collection.set_zorder(2)
...
Now, the solution is straightforward:
zorder
in add_geometries
to 1
, nodes will then be in front of the map because it's zorder 2. But edges are still behind the map because it's zorder 1.Now the real better solution is to get both node_collection and edge_collection first:
nodes = nx.draw_networkx_nodes(G, position, node_size=20, nodelist=cidades)
edges = nx.draw_networkx_edges(G, position, edgelist=links)
Then set_zorder
for both nodes and edges:
nodes.set_zorder(20)
edges.set_zorder(20)