EDIT: Added import statements to make code example completely self-contained.
I'm trying to UPDATE pyplot charts that have already been drawn IN PLACE, without drawing a new chart. I found this thread on the subject and I think I followed all the advice it contained, but I still can't get it to work. That thread was about updating a SINGLE figure. I'm trying to switch back and forth between two figures, and I think that's what causing the problems. It feels like somehow switching back to the already active figure with plt.figure() is creating a new figure instead of re-activating the existing one.
Here's my code:
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")
I realize that the calls to ax.clear() are redundant after fig.clf(). I was just trying to cover every possible base. Also, I tried just about every conceivable combination of omitting or including each of the clear, clf, draw and flush operations. Nothing I do seems to work.
Curiously, the figure sizes set in the main code (at the bottom) are used the FIRST time the display_charts() function runs. But all subsequent executions result in new charts being displayed at the much smaller default figure size. That leads me to conclude that new figures are being created rather than old ones being updated, but I can't figure out why.
Thanks in advance for any insights!!!
p.s. The reason I'm using two separate figures rather than 2 subplots in a single figure is that in the actual code (this post contains a simplification for the sake of clarity), there are completely different xticks and yticks settings and a bunch of other figure settings are different. There are also 3 rather than 2 charts. The real code was stripped down to the simplest version that reproduces the problem, shown above.