0

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?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.