Reputation: 1027
I am attempting to make a choropleth plot in geopandas
. Because of the large number of objects and a highly skewed distribution, I am binning into quantiles using the built in mapclassify
support. It is working great, except the labels for the resulting legend are terrible.
As a test case, I have produced the following:
Using the following code:
import geopandas as gp
import matplotlib.pyplot as plt
world = gp.read_file(gp.datasets.get_path('naturalearth_lowres'))
fig, ax = plt.subplots()
world.plot(ax=ax,column='pop_est',
cmap='OrRd',
scheme='quantiles',
legend=True,
legend_kwds=dict(loc='upper right',
bbox_to_anchor=(1.5, .9),
fontsize='small',
title="Legend",
frameon=False)
)
ax.axis('off')
I want at a minimum to be able to have fully custom labels for the legend, for example:
However, the ideal case would be to have a continuous blocked colorbar with custom labels, for example, like the following US map (which I did not produce):
Upvotes: 2
Views: 1719
Reputation: 13880
It was not directly obvious from the comments how to do this. The following, bit verbose piece of code produce something with a custom legend:
import geopandas as gp
import matplotlib.pyplot as plt
def update_custom_legend_labels(ax, new_labels):
current_legend = ax.get_legend()
for ix_current_label, txt_current_label in enumerate(current_legend.texts):
for ix_new_label, txt_new_label in new_labels.items():
if ix_current_label == ix_new_label:
# print(f'current: {ix_current_label, txt_current_label}')
# print(f'new: {ix_new_label, txt_new_label}')
txt_current_label.set_text(txt_new_label)
# print(f'update: {txt_current_label}')
world = gp.read_file(gp.datasets.get_path('naturalearth_lowres'))
fig, ax = plt.subplots()
world.plot(ax=ax,
column='pop_est',
cmap='OrRd',
scheme='quantiles',
legend=True,
legend_kwds=dict(loc='upper right',
bbox_to_anchor=(1.5, .9),
fontsize='small',
title="Legend",
frameon=False, fmt="{:.0f}")
)
current_labels = [t.get_text() for t in ax.get_legend().get_texts()]
no_labels = len(current_labels)
new_labels = []
for ix, val in enumerate(current_labels):
if ix == 0: # first item
val = '<' + val.split(',')[0]
elif no_labels == ix + 1: # last item
val = '>' + val.split(',')[0]
else: # remaining items
val = val.replace(',', ' -')
new_labels.append((ix,val))
new_labels = dict(new_labels)
update_custom_legend_labels(ax, new_labels)
ax.set_axis_off()
plt.show()
Upvotes: 1