G. Macia
G. Macia

Reputation: 1521

How to add a colorbar to geopandas plot with matplotlib animation

I am trying to animate a geopandas plot unsing FuncAnimation. Basically eu_private_map is a geopandas.geodataframe.GeoDataFrame and among other fields, it contains several columns with the values for parameter x in different EU states across 10 consecutive years. Each column are the values of x for one year.

from matplotlib.animation import FuncAnimation
from IPython.display import HTML
from mpl_toolkits.axes_grid1 import make_axes_locatable

fig = plt.figure() 
ax1 = fig.add_subplot(1,1,1)

def animate(year):
        ax1.clear()
        my_map = eu_private_map.plot(ax=ax1, column=year, vmin=0, vmax=30, legend=False)
        divider = make_axes_locatable(ax1)
        cax = divider.append_axes("right", size="5%", pad=0.05)
        plt.colorbar(my_map, cax=cax)

# the FuncAnimation function iterates through our animate function using the steps array
years = eu_private.columns.drop('country').tolist()
ani = FuncAnimation(fig, animate, years, interval=1000, blit=False)

HTML(ani.to_jshtml())

The colorbar is giving me a hard time. On the one hand, if I set legend = True, I do not like the fact that it does not have the same size (see figure) as the figure and it creates a weird effect (see figure). I tried this but I got an error: AttributeError: 'AxesSubplot' object has no attribute 'autoscale_None'. However I cannot spot the trouble in the code, any help to fix both issues at once? Thanks a lot

enter image description here enter image description here

Upvotes: 1

Views: 3041

Answers (3)

ShouravBR
ShouravBR

Reputation: 765

For new answer-seekers who are stumbling on to this, the idea is to use init_func parameter for the FuncAnimation function. This was answered here.

the init_func will render the colorbar whereas the animate function will not render the colorbar.

Limitation: I am assuming the colorbar and its ticks do not change and this answer will keep the old colorbar intact while updating the chart axes.

Upvotes: 0

Hei, found a way to make a log scale color plot norm=matplotlib.colors.LogNorm() does the trick:

A logarithmic colorbar in matplotlib scatter plot

and you can also add vmin and vmax like this: norm=colors.LogNorm(vmin=vmin, vmax=vmax)

good to remember though it works only for vmin and vmax positive. E.g. norm=colors.LogNorm(vmin=0.1, vmax=1000000)

Upvotes: 0

G. Macia
G. Macia

Reputation: 1521

After trying many ways that failed to work for geopandas & animate, I ended up finding a solution to make it work being the main idea to separate the colorbar from the animate function to the init function of the plot.

from matplotlib.animation import FuncAnimation
from IPython.display import HTML
from mpl_toolkits.axes_grid1 import make_axes_locatable


fig = plt.figure(figsize=(20,10)) 
ax1 = fig.add_subplot(1,1,1)

def animate(year):
        ax1.clear()
        eu_private_map.plot(color='gainsboro', ax=ax1, linewidth=0.6, edgecolor='1')
        sm = eu_private_map.dropna().plot(ax=ax1, column=year, vmin=0, vmax=30, cmap = 'viridis',
                                              legend=False, linewidth=0.6, edgecolor='1')
        ax1.set_title(year, fontdict={'fontsize': '23'})
        ax1.axis('off')

def init():
    # Create colorbar as a legend
    sm = plt.cm.ScalarMappable(cmap='viridis', norm=plt.Normalize(vmin=0, vmax=30))
    # empty array for the data range
    sm._A = []
    # add the colorbar to the figure

    divider = make_axes_locatable(ax1)
    cax = divider.append_axes("right", size="5%", pad=0.5)


    cbar = fig.colorbar(sm, cax=cax)
    cbar.ax.tick_params(labelsize=14) 


# the FuncAnimation function iterates through our animate function using the steps array
years = eu_private.columns.drop('country').tolist()[::-1]
ani = FuncAnimation(fig, animate, years, interval=1000, blit=False, init_func=init)

HTML(ani.to_jshtml())

Upvotes: 1

Related Questions