首页 > 解决方案 > 重新绘制 2 个 pyplot 图表而不重新绘制新图表

问题描述

编辑:添加了导入语句以使代码示例完全独立。

我正在尝试更新已经在原地绘制的 pyplot 图表,而不绘制新图表。我在这个主题上找到了这个帖子,我想我遵循了它包含的所有建议,但我仍然无法让它发挥作用。该线程是关于更新一个单一的数字。我试图在两个数字之间来回切换,我认为这就是导致问题的原因。感觉好像用 plt.figure() 以某种方式切换回已经激活的图形正在创建一个新图形,而不是重新激活现有图形。

这是我的代码:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import ipywidgets as widgets
import time 

    def display_charts( data1, data2, fig1, fig2 ):

#    Plot charts

    #plt.figure(fig1.number) # Intended to make EXISTING figure current, without creating new one

    fig1.clf()       # I was hoping this would clear the figure allowing it to be re-drawn in-price, but
                     # it doesn't seem to help
    ax=fig1.gca()     # Get axes for this figure

    ax.clear()       # Tried this based on Stack Overflow thread, but doesn't seem to help

    data1.plot.line(ax=ax)

    fig1.canvas.draw()           # Got these two lines from a stack overflow discussion about redrawing
    fig1.canvas.flush_events()   # charts in-place but they don't seem to help.

    #plt.figure(fig2.number)
    fig2.clf()
    ax2 = fig2.gca()
    ax2.clear()
    data2.plot.bar(ax=ax2)

    fig2.canvas.draw() 
    fig2.canvas.flush_events()



def update_button_callback(_):
    # My hope was that this would allow the charts to be re-drawn in place with new data. But that
    # doesn't work. Instead, when the button is clicked, 2 new smaller charts are drawn under the
    # original ones.

    display_charts( df3, df4, fig1, fig2 ) # I want this to update the charts in place, not draw them a 2nd time!!!

# Set up sample data for illustration

df1 = pd.DataFrame([1.2,3.4,5.6,7.8,9.0],[3.4,5.6,7.8,9.0,1.2])
df2 = pd.DataFrame([11.2,13.4,15.16,17.18,19.0],[13.14,15.16,17.8,19.0,11.2])
df3 = pd.DataFrame([21.2,23.4,25.6,27.8,29.0],[23.4,25.6,27.8,29.0,21.2])
df4 = pd.DataFrame([31.2,33.4,35.6,37.8,39.0],[33.4,35.6,37.8,39.0,31.2])

# Configure and display UI controls

plt.ion()               # I don't think this should be required, but threw it in just in case...

fig1=plt.figure(figsize=(30,20)) # These figure sizes get used the FIRST time the charts are drawn, but
fig2=plt.figure(figsize=(30,20)) # when I try and update in place, the result is to draw new charts which
                                 # default to a smaller display size.

update_button = widgets.Button(description="Update Chart")
display(update_button)

update_button.on_click(update_button_callback)

display_charts(df1,df2, fig1, fig2) # Display first 2 df's. Button click callback will update them.
plt.show()

time.sleep(5) # Isolate out any issues with the button control being the problem by waiting 5 seconds
              # then calling display_charts() a 2nd time with the other df's.

print("Updating charts now...")
display_charts(df3,df4, fig1, fig2) # Display first 2 df's. Button click callback will update them.
plt.show()

time.sleep(10)
print("exiting cell")

我意识到在 fig.clf() 之后对 ax.clear() 的调用是多余的。我只是试图覆盖所有可能的基础。此外,我尝试了几乎所有可能的组合,即省略或包括每个 clear、clf、draw 和 flush 操作。我所做的一切似乎都不起作用。

奇怪的是,在 display_charts() 函数第一次运行时使用了主代码(底部)中设置的图形大小。但是所有后续执行都会导致新图表以小得多的默认图形大小显示。这使我得出结论,正在创建新数据而不是更新旧数据,但我不知道为什么。

提前感谢您的任何见解!

ps 我在一个图中使用两个单独的图而不是 2 个子图的原因是在实际代码中(为了清楚起见,这篇文章包含了一个简化),有完全不同的 xticks 和 yticks 设置以及一堆其他图设置不同。还有 3 个而不是 2 个图表。真正的代码被精简为重现问题的最简单版本,如上所示。

标签: pythonmatplotlibcharts

解决方案


这是一个选项,在按下按钮时清除输出。

#Cell 1
%matplotlib inline

#Cell 2
import matplotlib.pyplot as plt
import pandas as pd
import ipywidgets as widgets
from IPython.display import display, clear_output
import time

#Cell 3
def display_charts(data1, data2):
    ax1.clear()
    data1.plot.line(ax=ax1)

    ax2.clear()
    data2.plot.line(ax=ax2)

df1 = pd.DataFrame([1.2,3.4,5.6,7.8,9.0],[3.4,5.6,7.8,9.0,1.2])
df2 = pd.DataFrame([11.2,13.4,15.16,17.18,19.0],[13.14,15.16,17.8,19.0,11.2])
df3 = pd.DataFrame([21.2,23.4,25.6,27.8,29.0],[23.4,25.6,27.8,29.0,21.2])
df4 = pd.DataFrame([31.2,33.4,35.6,37.8,39.0],[33.4,35.6,37.8,39.0,31.2])


fig1, ax1 = plt.subplots(figsize=(8,6)) 
fig2, ax2 = plt.subplots(figsize=(8,6)) 

def update_button_callback(evt):
        clear_output(True)
        display(update_button)
        display_charts(df3, df4)
        display(fig1)
        display(fig2)

update_button = widgets.Button(description="Update Chart")   
update_button.on_click(update_button_callback)

display(update_button)
display_charts(df1,df2)

推荐阅读