首页 > 解决方案 > matplotlib.animation.FuncAnimation() 在每次刷新时向 seaborn.heatmap() 添加不需要的颜色条

问题描述

我正在尝试设置一个正在运行的seaborn.heatmap()s 仪表板,它将使用matplotlib.animation.FuncAnimation(). 这是一个好的 - 尽管大部分是空的 - 视觉应该看起来像 视觉的。

不幸的是,每次FuncAnimation()触发时,图右侧都会添加更多列。

import datetime

from pyodbc import connect
from pandas import DataFrame
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

#settings up here
first_cycle = True

...

#create figure with subplots
fig,_ = plt.subplots(nrow,ncol)
fig.suptitle("Animated Heatmap(s)",fontsize=16)

#set subplot spacing
plt.subplots_adjust(left=0.05, bottom=0.02, right=1.00, top=0.96, hspace=0.35, wspace=0.08)

#maximize screen
plt.get_current_fig_manager().window.state('zoomed')  #method works for Tk backend (default)

def load_figure(i, first_cycle):
    #subplot iterator
    for ax in fig.axes:
        plt.sca(ax)             #sets current axes
        plt.xticks(rotation=30)

    #get data from SQL Server
    cursor = connect('DRIVER={ODBC Driver 17 for SQL Server}; \
                       SERVER=' + server + '; \
                       DATABASE=' + database + '; \
                       Trusted_Connection=yes;').cursor()
    cursor.execute("SELECT end_of_shift, item, value FROM SecretTableName " +
                       "WHERE end_of_shift BETWEEN '" + query_start_time + "' AND CURRENT_TIMESTAMP")
    data_CT_DBout = cursor.fetchall()

    #create organized dataframes
    data_CT_ts = [nameShift( roundTime(item[0]) ) for item in data_CT_DBout]
    data_CT_item = [item[1] for item in data_CT_DBout]
    data_CT_val = [item[2] for item in data_CT_DBout]
    data_CT = DataFrame.from_dict({'Timestamp': data_CT_ts, 'CT': data_CT_item, 'Value': data_CT_val})

    #reshape data
    data_CT = data_CT.pivot(index = 'CT', columns = 'Timestamp', values = 'Value')
    data_CT.drop(drop_index_CT, inplace=True)
    data_CT.rename(index=rename_index_CT, inplace=True)

    #render as heatmap
    if first_cycle:
        graph_CT = sns.heatmap(data_SH01, annot=True, linewidths=0.5, vmax=14, vmin=8, ax = fig.axes[0], cmap=cmap, xticklabels=True, yticklabels=True)

    else:
        graph_SH01 = sns.heatmap(data_SH01, annot=True, linewidths=0.5, vmax=14, vmin=8, ax = fig.axes[0], cmap=cmap, xticklabels=True, yticklabels=True, cbar = False)


loop_animation = FuncAnimation(fig, load_figure, interval = refresh_setting * 1000, fargs=(first_cycle,))
plt.show()

几次刷新后上面的结果是这样的:彩条太多

如果我添加更改#subplot iterator为:

#subplot iterator
    for ax in fig.axes:
        ax.clear()
        plt.sca(ax)             #sets current axes
        plt.xticks(rotation=30)

结果变成给出了太多的空列,就好像它没有找到热图一样。结果

我也尝试ax.remove()在 中使用#subplot iterator,但它没有达到我的预期,我无法重新创建结果。

我正在使用fig,_ = plt.subplots(),因为最终目标是让 5 个这些热图垂直堆叠,但即使是单个图表,我也遇到了同样的问题。我能够使用fig,_ = plt.subplots()类似项目的动画散点图实现,但我可以通过更改它来解决动画问题。

任何想法或解决方案表示赞赏。

标签: pythonmatplotlibseaborn

解决方案


上面的代码没有正确利用该first_cycle变量。在其中,我尝试在函数和循环之外定义变量,然后将当前值传递给要运行的函数。经过进一步测试,即使包含在功能中print(first_cycle)也不会显示。Falsefirst_cycle = False

为了使它工作,代码应该重写如下:

first_cycle = True

...

def load_figure(i):   #removed first_cycle argument
    global first_cycle   #added - be sure to use global variable

    ...

    #render as heatmap
    if first_cycle:
        graph_CT = sns.heatmap(data_SH01, ... )
        first_cycle = False   #be sure to turn off first_cycle

    else:
        graph_SH01 = sns.heatmap(data_SH01, ... , cbar = False)


loop_animation = FuncAnimation(fig, load_figure, interval = refresh_setting * 1000)   
#removed fargs argument
plt.show()

推荐阅读