Method 1
According to geopandas's changelog, you can pass a fmt
in legend_kwds
since version 0.8.0 (June 24, 2020) to format the legend labels. For example, if you want no decimal point, you can set fmt='{:.0f}'
, like how you format numbers with a f-string. Here's an example for a quantiles map:
import matplotlib.pyplot as plt
import numpy as np
import mapclassify
import geopandas as gpd
gdf = gpd.read_file(
gpd.datasets.get_path('naturalearth_lowres')
)
np.random.seed(0)
gdf = gdf.assign(
random_col=np.random.normal(100, 10, len(gdf))
)
# plot quantiles map
fig, ax = plt.subplots(figsize=(10, 10))
gdf.plot(
column='random_col',
scheme='quantiles', k=5, cmap='Blues',
legend=True,
legend_kwds=dict(fmt='{:.0f}', interval=True),
ax=ax
)
This gives us:
Method 2
In fact, GeoPandas uses PySal's mapclassify to calculate and generate map legends. For the quantiles map (k=5) above, we can get the classification via .Quantiles()
in mapclassify
.
mapclassify.Quantiles(gdf.random_col, k=5)
The function returns an object of mapclassify.classifiers.Quantiles
:
Quantiles
Interval Count
------------------------
[ 74.47, 91.51] | 36
( 91.51, 97.93] | 35
( 97.93, 103.83] | 35
(103.83, 109.50] | 35
(109.50, 123.83] | 36
The object has an attribute bins
, which returns an numpy array containing the upper bounds in all classes.
array([ 91.51435701, 97.92957441, 103.83406507, 109.49954895,
123.83144775])
Thus, we can use this function to get all the bounds of the classes since the upper bound in a lower class equals the lower bound in the higher class. The only one missing is the lower bound in the lowest class, which equals the minimum value of the column you are trying to classify in your DataFrame. Here's an example to round all numbers to integers:
# get all upper bounds
upper_bounds = mapclassify.Quantiles(gdf.random_col, k=5).bins
# insert minimal value in front to get all bounds
bounds = np.insert(upper_bounds, 0, gdf.random_col.min())
# format the numerical legend here
intervals = [
f'{bounds[i]:.0f}-{bounds[i+1]:.0f}' for i in range(len(bounds)-1)
]
# get all the legend labels
legend_labels = ax.get_legend().get_texts()
# replace the legend labels
for interval, legend_label in zip(intervals, legend_labels):
legend_label.set_text(interval)
We will eventually get:
As you can see, since we are doing things in a lower level, we are able to customize how the legend labels look like, such as removing those brackets but using a -
in the middle.
Method 3
In addition to GeoPandas' .plot()
method, you can also consider .choropleth()
function offered by geoplot in which you can easily use different types of scheme and number of classes while passing a legend_labels
arg to modify the legend labels. For example,
import geopandas as gpd
import geoplot as gplt
gdf = gpd.read_file(
gpd.datasets.get_path('naturalearth_lowres')
)
legend_labels = [
'< 2.4', '2.4 - 6', '6 - 15', '15 - 38', '38 - 140 M'
]
gplt.choropleth(
gdf, hue='pop_est', cmap='Blues', scheme='quantiles',
legend=True, legend_labels=legend_labels
)
which gives you