New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updating a plot doesn't clear old plots, if event trigger came from another figure? #10183
Comments
You should use fig.canvas.draw() (a matplotlib method), not update() (a Qt method). Because the call was to update(), the window was not cleared first... except that pause() itself triggers a draw(), but only on the active window (and is explicitly documented as such), which is the one you clicked on:
I guess pause() could be changed to redraw all pyplot-managed windows (so leaving this issue open for discussion). |
For my actual application, draw() is way too slow, and I can't use it. I am kinda stuck with update() cause it's much faster. Any suggestions? |
@clsmt You have half re-invented blitting, see https://matplotlib.org/api/animation_api.html?highlight=blitting#funcanimation The thing you are missing is caching and restoring the figure without your animated artist on it. |
and if you want to change the limits you will have to re-draw the whole axes (all of the artists in it + the tick labels). |
@tacaswell
|
No, When you call In the right-hand axes I am not quite sure what is going on to end up with those ticks, but each curve is drawn with a different set of limits (none of which match the tick labels). Below is code that does what I think you want. import matplotlib.pyplot as plt
import numpy as np
import time
bg_cache = None
current_timer = None
def onclick(event):
global current_timer
j = 0
cv = event.canvas
fig = cv.figure
frames = 100
def update():
nonlocal j
# restore the background
cv.restore_region(bg_cache)
# update the data
ii = j * np.pi / frames
y1 = y * np.sin(ii)
# update the line on the fixed limit axes
line1.set_ydata(y1)
ax.draw_artist(line1)
# update the line on the limit adjusted axes
line2.set_ydata(-y1)
ax2.set_ylim(y1.min(), y1.max())
fig.draw_artist(ax2)
# update the screen
cv.blit(fig.bbox)
# update counter
j += 1
# if we are more than 100 times through, bail!
if j > frames:
print(f'fps : {frames / (time.time() - start_time)}')
return False
start_time = time.time()
current_timer = cv.new_timer(
interval=100, callbacks=[(update, (), {})])
current_timer.start()
def ondraw(event):
global bg_cache
cv = event.canvas
fig = cv.figure
bg_cache = cv.copy_from_bbox(fig.bbox)
ax.draw_artist(line1)
fig.draw_artist(ax2)
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)
fig = plt.figure()
ax = fig.add_subplot(1, 2, 1)
line1, = ax.plot(x, y, animated=True)
ax2 = fig.add_subplot(1, 2, 2)
ax2.set_animated(True)
line2, = ax2.plot(x, y)
d_cid = fig.canvas.mpl_connect('draw_event', ondraw)
bp_cid = fig.canvas.mpl_connect('button_press_event', onclick)
plt.show() The various globals are required so things do not get garbage collected. The two callbacks should probably be bound into a class and some checking like (if a timer is running, don't start another one). For a 640x480 pix figure I can get ~60 fps and 200fps if only updating the left axes (if you turn the interval down to 1ms) on a 4 year old laptop. |
@tacaswell Thanks a lot for the reply. It is very helpful to me. I think I had several misunderstandings before this thread, and thanks to all the help I got here I could clear them up. I will write those as notes (with some more questions) here in case someone else had the same confusions.
I am an end user of matplotlib, and I don't have much knowledge of the backstage stuff. I learned through scraping information online and reading bits and pieces of the documentation. If anyone out there is in a similar situation and end up with similar confusions, I hope this thread helps you. |
Ok, one more questoin: why is it that in my original code, after all the updating is done, when you resize the firgure, all the previous curves but the latest are gone? |
Where would you have expected to look in the documentation to have found this information? Do the two PRs linked above make it better or worse? |
I would also consider using |
Deepest apologies for not responding sooner.
|
A further problem with
|
This is not related to being in the class, you can reproduce it via import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_animated(True)
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)
ax.plot(x, y)
fig.canvas.draw()
fig.draw_artist(ax)
plt.show() The issue is that fig.canvas.blit(fig.bbox) |
where should I place this line? I tried place it after Also, in your example above , why do the axes show up initially? Is it because
Also in the example, The Qt method In my original example, why does it matter where the event trigger is from the same figure or not? Is it because of the way |
This seems to be more like a user question than a feature request or a bug report, so I'm going to close this. You can continue any questions on https://discourse.matplotlib.org/ |
Bug report
Bug summary
I am updating a line plot. There is an event trigger that starts this updating. If the trigger came from the figure that contains the plot, everything is fine. However, if the trigger came from another figure, then weird results happen: the line that's been updated appears to leave its trace uncleared.
Code for reproduction
Actual outcome
Expected outcome
Not the many curves saw in the above figure, just one curve being updated in each cycle. In the code snippet, if use
then it works as intended.
Also note, if you resize the plot, or save it as figure, then all the residue curves will be gone.
Matplotlib version
print(matplotlib.get_backend())
): Qt4AggThe text was updated successfully, but these errors were encountered: