Joooeey
Joooeey

Reputation: 3886

Change colorbar in Geopandas

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:

enter image description here

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

  1. Is there a way to pass the extend keyword through the GeoDataFrame.plot function?

  2. Can I somehow access the colorbar instance by either saving it when plotting or finding it in the figure?

  3. 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

Answers (1)

joris
joris

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

enter image description here

Upvotes: 4

Related Questions