I'm trying to generate an animation for a heatmap varying through a few years. I'm having issues because I don't know how to keep the colorbar from flickering like in this GIF.
This is the function I'm working with
from matplotlib import animation
from scipy.interpolate import griddata
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable
from matplotlib.gridspec import GridSpec
def create_temperature_heatmap_animation(ny_stations, ny_station_df_names, yearly_means_df, common_years, duration=10):
from matplotlib import animation
from scipy.interpolate import griddata
from matplotlib.colors import Normalize
# Compute global min and max temperature across all years/stations
all_z = []
for year in common_years:
z = [yearly_means_df.loc[year, name] for name in ny_station_df_names]
all_z.extend(z)
global_zmin = np.nanmin(all_z)
global_zmax = np.nanmax(all_z)
# GridSpec for axes
gs = GridSpec(1, 2, width_ratios=[0.9, 0.05])
fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(gs[0])
cbar_ax = fig.add_subplot(gs[1])
# Grid setup
x = np.array(ny_stations['longitude'])
y = np.array(ny_stations['latitude'])
xi = np.linspace(x.min(), x.max(), 200)
yi = np.linspace(y.min(), y.max(), 200)
xi, yi = np.meshgrid(xi, yi)
# Initial data for the first frame
z0 = [yearly_means_df.loc[common_years[0], name] for name in ny_station_df_names]
z0 = np.array(z0)
zi0 = griddata((x, y), z0, (xi, yi), method='linear')
# Fixed normalization
norm = Normalize(vmin=global_zmin, vmax=global_zmax)
# Initialize heatmap with fixed norm
heatmap = ax.imshow(zi0, extent=(x.min(), x.max(), y.min(), y.max()),
origin='lower', cmap='coolwarm', norm=norm,
aspect='auto')
# Fixed colorbar
cbar = fig.colorbar(heatmap, cax=cbar_ax)
cbar.set_label('Temperatura promedio (°C)')
# Title and axis labels
ax.set_xlabel('Longitud')
ax.set_ylabel('Latitud')
title = ax.set_title(f'Temperatura promedio - Año {common_years[0]}')
def update(frame):
year = common_years[frame]
z = [yearly_means_df.loc[year, name] for name in ny_station_df_names]
z = np.array(z)
zi = griddata((x, y), z, (xi, yi), method='linear')
heatmap.set_data(zi)
title.set_text(f'Temperatura promedio - Año {year}')
# Compute frame rate
fps = max(1, int(np.floor(len(common_years) / duration)))
ani = animation.FuncAnimation(fig, update, frames=len(common_years), interval=1000 / fps, repeat=True)
return ani
I'm not updating cbar, but the GIF shown above is the output of this function, and it clearly changes each frame. That is not the behaviour I want, which is it being fixed as I said. Is there any way to accomplish that?