Reputation: 3886
The Problem
How can I access the colorbar instance created when plotting a GeoDataFrame? In this example, I've plotted troop movements and sizes during the French invasion of Russia, with army sizes less than 10000 plotted in red. How do I get the colorbar to show that red means under 10000?
MCVE:
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from shapely.geometry import Point, LineString
import geopandas as gpd
# ingest troop movement data
PATH = ("https://vincentarelbundock.github.io/Rdatasets/csv/HistData/"
"Minard.troops.csv")
troops = pd.read_csv(PATH)
troops['geometry'] = troops.apply(lambda row: Point(row.long, row.lat), axis=1)
troops = gpd.GeoDataFrame(troops)
# get army group paths
grouped = troops.groupby('group')
groups = [[LineString(group[['long', 'lat']].values), name]
for name, group in grouped]
groups = pd.DataFrame(groups, columns=['geometry', 'army group'])
groups = gpd.GeoDataFrame(groups)
groups.plot(color=['red', 'green', 'blue'], lw=0.5)
# plot troop sizes
cmap = mpl.cm.get_cmap('cool')
cmap.set_under('red')
troops.plot(column='survivors', ax=plt.gca(),
cmap=cmap, vmin=10000, legend=True, markersize=50)
Output:
Here, legend=True
in the last line adds the colorbar.
Attempts at a solution
I know that if I made the colorbar myself, I could just pass the argument extend='min'
to add a red triangle to the bottom of the colorbar.
And I know I can get the colorbar axes through (as suggested in this answer):
cax = plt.gcf().axes[1]
but I don't know how that helps me edit the colorbar. I can't even add a label with cax.set_label('troop size')
. (i.e. I can't see that label anywhere although cax.get_label()
does return 'troop size')
These axes appear to consist of two polygons:
In[315]: cax.artists
Out[315]:
[<matplotlib.patches.Polygon at 0x1e0e73c8>,
<matplotlib.patches.Polygon at 0x190c8f28>]
No idea what to make of that. And even if I could find the actual colorbar instance, I wouldn't know how to extend it as the docs for the Colorbar
class don't mention anything like that.
Alternatives
Is there a way to pass the extend
keyword through the GeoDataFrame.plot
function?
Can I somehow access the colorbar instance by either saving it when plotting or finding it in the figure?
How would I go about constructing the colorbar directly with Matplotlib? And how do I avoid that it deviates from the plot if I change parameters?
Upvotes: 4
Views: 4869
Reputation: 139222
There is an issue (and PR) about making it possible to pass keywords to the colorbar construction: https://github.com/geopandas/geopandas/issues/697.
But for now, the best work-around is to create the colorbar yourself I think:
Create the same figure but with legend=False
:
cmap = mpl.cm.get_cmap('cool')
cmap.set_under('red')
ax = troops.plot(column='survivors', cmap=cmap, vmin=10000, legend=False, markersize=50)
Now, we get the collection created for the points (from a scatter plot) as the first element of the ax.collections
, so we can instruct matplotlib to create a colorbar based on this mapping (and now we can pass additional keywords):
scatter = ax.collections[0]
plt.colorbar(scatter, ax=ax, extend='min')
this gives me
Upvotes: 4