EFZ
EFZ

Reputation: 157

Editing Colorbar (Legend) in Geopandas?

There are multiple thing I want to edit with the colorbar in a geopandas world choropleth I'm creating. Namely the size (so that it roughly matches the map itself), the text size (which currently shows up far too small) and I also wanted to add a label to it. It seems from reading about a bit there's no easy way of doing that explicitly within geopandas and so i was wondering if anyone might have any workarounds at all to offer? Any help would be greatly appreciated.

This is the piece of code I'm currently using (for some context the mid section is simply merging lists with figures by country, which I'm using as the basis of the colouring, to the frame)

fig, ax = plt.subplots(figsize=(40,29.171))
world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))

world=pd.DataFrame(world)
world['LEADS']=0.1
world = world.set_index('name')
world['name']=world.index
for x, y in zip(Countries, country_counts):
    world.loc[x, 'LEADS'] = y
world=geopandas.GeoDataFrame(world)

world = world[(world.index != "Antarctica")]
ax.set_axis_off()
#ax.legend(title="Leads")
world.plot(ax=ax, column='LEADS', cmap='Oranges', legend=True,linewidth = 1.5)
plt.tight_layout()

plt.savefig('plot_image.png', bbox_inches='tight', transparent=True)

An ideal solution here would maintain the colours that the legend option has, specify size and text size and enable a label at the top of the bar. I'm struglling to work out how any of this is done myself unfortunatley.

Upvotes: 5

Views: 10024

Answers (3)

Lombrix208
Lombrix208

Reputation: 11

Apparently, when creating a colorbar, a new axis is always created (as showed here).

Thus, to adapt the ticks size and location, adapt them directly to the newly created axis. There is a minimal working example:

import geopandas as gpd
import matplotlib.pyplot as plt
data = gpd.read_file(gpd.datasets.get_path("nybb"))
    
#only one plots
ax = data.plot("BoroCode", legend=True)
colorbar_ax = ax.get_figure().axes[-1] #to get the last axis of the figure, it's the colorbar axes
colorbar_ax.set_title("Borow Code", size=30)
colorbar_ax.tick_params(labelsize=20)
plt.show()

If you already have several axes, you can sort them to obtain only the axes of the color bar:

#multiple subplots
fig, axs = plt.subplots(1,2)
data.plot("BoroCode", ax=axs[1], legend=True, legend_kwds={"label":"Borow Code"})
data.plot("Shape_Area", ax=axs[0],legend=True)
colorbar_axs = [ax for ax in fig.axes if ax not in axs] #to get only the colorbar axis
colorbar_axs[0].set_ylabel("Borow Code", size=30)
colorbar_axs[0].tick_params(labelsize=20)
colorbar_axs[1].set_title("Shape Area", size=15)
colorbar_axs[0].tick_params(labelsize=3)
plt.show()

Note that the colorbar axes seams to always be in the order that you created them, and not the apparent order when you plot the figure.

Upvotes: 1

ale-6
ale-6

Reputation: 365

The answer found here helped me find a workaround.

import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize = (30,25))
vmin = data.column.min()
vmax = data.column.max()
data.plot(ax=ax,column = column,edgecolor='black',cmap = 'YlOrRd',legend = False)
plt.xlim([6,19])
plt.ylim([36,47.7])
plt.xticks([], [])
plt.yticks([], [])

cax = fig.add_axes([1, 0.1, 0.03, 0.8])
sm = plt.cm.ScalarMappable(cmap='YlOrRd', norm=plt.Normalize(vmin=vmin, vmax=vmax))
sm._A = []
cbr = fig.colorbar(sm, cax=cax,)
cbr.ax.tick_params(labelsize=200) 
plt.tight_layout()
plt.savefig(os.path.join('out','fig.png'),format = 'png',bbox_inches='tight')
plt.show()

Once you have your Colorbar object my_cbar, you can set properties in a matplotlib fashion. Here I changed the label size. Remember to use bbox_inches='tight' if you need to save the figure: otherwise the colorbar is not saved. My output is something like this, with modified colorbar fontsize. map with colorbar

Upvotes: 7

MoMiJi
MoMiJi

Reputation: 93

How about creating a colourbar in a separate figure?

Using the first example found here you can create a function:

import matplotlib as mpl
import numpy as np
import matplotlib.pyplot as plt

def create_colourbar(cmap, vmin, vmax, label, save_path=None):
    ''' Creates colourbar in separate figure 
    :param cmap: Cmap string or object
    :param vmin: minimum value in data array
    :param vmax: maximum value in data array
    :param label: colourbar label
    :param save_path: Save path, optional
    '''

    fig, ax = plt.subplots(figsize=(5, 1))

    cb1 = mpl.colorbar.ColorbarBase(cmap=cmap,
                                    norm=Normalize(vmin=vmin,
                                                   vmax=vmax),
                                    orientation='horizontal', ax=ax)
    cb1.set_label(label, fontsize=6)
    plt.tight_layout()
    if save_path:
        plt.savefig(save_path3)
    plt.show()

where:

vmax = np.nanmax(world['LEADS'].values)
vmin = np.nanmin(world['LEADS'].values)

and cmap is a colormap string or object.

Upvotes: 0

Related Questions