geopandas controls legend size when using xlim, ylim

Viewed 729

I try to create a geopanda plot where I need to set specific values for xlim and ylim. It works but the legend is huge now. I would prefer for it to be as large as the actual plotted map, but can't seem to figure out how to control this behaviour.

Minimal working example

import numpy as np
import matplotlib; print(matplotlib.__version__)
import matplotlib.pyplot as plt
import geopandas; print(geopandas.__version__)
world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))    
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')

world.plot(ax=ax, column='2015', legend=True,
           legend_kwds={'label': "Population", 'orientation': "horizontal"})
minx, miny, maxx, maxy = -12, 30, 30,80 
ax.set_xlim(minx, maxx)
ax.set_ylim(miny, maxy)
ax.margins(0)
ax.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)

plt.savefig('sample.png', bbox_inches="tight", pad_inches=0)

Resulting graph, with "too large" legend

1 Answers

I couldn't really run your attached code, as it says that world is not defined. But in any case, you could try the solution provided by the official docs here. It is specifically stated that:

However, the default appearance of the legend and plot axes may not be desirable. One can define the plot axes (with ax) and the legend axes (with cax) and then pass those in to the plot call.

Nevertheless, for your case you should try this:

... # Your imports as they are
from mpl_toolkits.axes_grid1 import make_axes_locatable

fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')

divider = make_axes_locatable(ax)  # Define 'divider' for the axes
# Legend axes will be located at the 'bottom' of figure, with width '5%' of ax and
# a padding between them equal to '0.1' inches 
cax = divider.append_axes("bottom", size="5%", pad=0.1)

world.plot(ax=ax, column='2015', legend=True,
           legend_kwds={'label': "Population", 'orientation': "horizontal"},
           cax=cax)
           ^^^^^^^  # Add cax in the list of 'plot' arguments

... # Rest code as it is

For example, with your code and the additions to it I mentioned above, for world GeoDataFrame as:

world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))

and column='pop_est' the output is:

enter image description here


Brief explanation

AxesGrid toolkit is a collection of helper classes, mainly to ease displaying (multiple) images in Matplotlib. The docs state that:

In matplotlib, the axes location (and size) is specified in the normalized figure coordinates, which may not be ideal for displaying images that needs to have a given aspect ratio. For example, it helps you to have a colorbar whose height always matches that of the image.

So, in pure Matplotlib is more difficult to interfere in matching the sizes of a figure and a colorbar axes. With AxesDivider class of the toolkit you can easily sync the axes of a colorbar with the master axes of figure, as illustrated above.

Related