Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Why does setting imshow(animated=True) still show an image? #18985

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

Open
thomasaarholt opened this issue Nov 20, 2020 · 8 comments · May be fixed by #30052
Open

Why does setting imshow(animated=True) still show an image? #18985

thomasaarholt opened this issue Nov 20, 2020 · 8 comments · May be fixed by #30052
Labels
Good first issue Open a pull request against these issues if there are no active ones! status: has patch patch suggested, PR still needed topic: animation topic: images

Comments

@thomasaarholt
Copy link

Bug report

Bug summary
Setting animated=True during a plot call is supposed to make matplotlib artists not be drawn unless explicitly called. Source

With plt.plot([1,2,3], animated=True), calling plt.show() shows an empty axes.
However, plt.imshow([[1,2],[3,4], animated=True) does show an image.

I observe this behaviour with both the qt5 and tk backends.
Have I misunderstood something? Or is this a discrepancy?

Code for reproduction

Here is a full example:

import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(ncols=2)
imdata = np.random.random((20,20))
lndata = imdata[0]
im = ax1.imshow(imdata, animated=True)
(ln,) = ax2.plot(lndata, animated=True)
plt.show()

Actual outcome
Image plotted after calling code

Expected outcome
Two blank axes.

Matplotlib version

  • Operating system: Win 10
  • Matplotlib version: 3.1.3
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 3.8
  • Jupyter version (if applicable):
  • Other libraries:
@ianhi
Copy link
Contributor

ianhi commented Dec 8, 2020

I just saw this as well after reading that tutorial. This feels like a bug to me.

I think the relevant lines are:

if not self.figure.canvas.is_saving():
artists = [a for a in artists
if not a.get_animated() or a in self.images]
artists = sorted(artists, key=attrgetter('zorder'))

which was introduced in #4014 with the commit message "Guard against removing animated images" Although I can't see any discussion of this in the discussion on the PR.

So it looks like images are being treated specially, but I totally don't understand why. Anyone with deeper knowledge of matplotlib artists know what's going on?

@ianhi
Copy link
Contributor

ianhi commented Dec 8, 2020

Commenting out the check for in self.image doesn't seem to break anything obvious - at least examples/images_contours_and_fields/image_demo.py and examples/animated/dynamic_image.py both run seemingly correctly.

There some mention in the PR of "The great artist rewrite of '15", Maybe after that rewrite this guard was no longer necessary?

@QuLogic
Copy link
Member

QuLogic commented Dec 8, 2020

It was almost 6 years ago, so I'm not sure if @blink1073 would remember why. It did not seem to be necessary for tests to pass as the previous commit worked.

@marcusmchale
Copy link

marcusmchale commented Jun 30, 2023

The code changed slightly 2 years ago but AxesImage objects (such as the artist from imshow) are still always drawn, regardless of the animate setting. I am not sure why this check is needed, but it is still an issue for animations in figures with AxesImage objects.

if not self.figure.canvas.is_saving():
artists = [
a for a in artists
if not a.get_animated() or isinstance(a, mimage.AxesImage)]
artists = sorted(artists, key=attrgetter('zorder'))

@tacaswell
Copy link
Member

The core of this chases back to #4014 where that check was added to fix tests.....

@tacaswell
Copy link
Member

ah, but the logic it was replacing goes back to 5e65bbe (2013) when blame stops working (due to that commit splitting up a huge file into three), but it looks like we used to:

  • make a list of all artists that were not images
  • filter them by if they are animated
  • add the images if we were not compositing (independent if they are animated)
  • [the rest of draw]

The change in #4014 just maintained that behavior.

From 2015 there has been some changes in how we do the compositing (it is now handled in a helper that instead of compositing all of the images into to (ignoring zorder) it will composite images into runs). This naming is a bit weird because you could argue all of our drawing is infact compositing, but what is going on here is that we are reducing N renderer.draw_image call into 1 which for vector backends can lead to large reductions in output filesize in cases where there are many over-lapping images).

I suspect in 2015, we needed to keep holding the images out to not mess with the z-order, but there is a chance it will work now given the other improvements to the image compositing code.

diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py
index 6d7336d311..e9ce32ae10 100644
--- a/lib/matplotlib/axes/_base.py
+++ b/lib/matplotlib/axes/_base.py
@@ -3025,7 +3025,7 @@ class _AxesBase(martist.Artist):
         if not self.figure.canvas.is_saving():
             artists = [
                 a for a in artists
-                if not a.get_animated() or isinstance(a, mimage.AxesImage)]
+                if not a.get_animated()]
         artists = sorted(artists, key=attrgetter('zorder'))

         # rasterize artists with negative zorder

passes tests for me on main.

Labeling this as a good first issue (as there is a patch). The remaining work to do is:

  • verify this patch actually solves the problem described in this issue (I just ran the test suite)
  • add a test to make sure we do not break this again

@tacaswell tacaswell added this to the v3.8.0 milestone Jul 3, 2023
@tacaswell tacaswell added Good first issue Open a pull request against these issues if there are no active ones! status: has patch patch suggested, PR still needed labels Jul 3, 2023
@github-actions
Copy link

github-actions bot commented Jul 3, 2023

Good first issue - notes for new contributors

This issue is suited to new contributors because it does not require understanding of the Matplotlib internals. To get started, please see our contributing guide.

We do not assign issues. Check the Development section in the sidebar for linked pull requests (PRs). If there are none, feel free to start working on it. If there is an open PR, please collaborate on the work by reviewing it rather than duplicating it in a competing PR.

If something is unclear, please reach out on any of our communication channels.

@ksunden ksunden removed this from the v3.8.0 milestone Sep 15, 2023
@Impaler343
Copy link
Contributor

Impaler343 commented Mar 2, 2024

Hey, I was trying to figure this out, and I found that the get_rasterized() method returns False for both the plots, but the get_visible() method returns True for both. I've also seen that the objects ln and im are artists in the axes 1 and 2, while the expected behavior should be that it only is in ax1. Im not able to figure out why one is plotting and the other is not. Any help would be greatly appreciated. Have been working on this for quite some time :(

import numpy as np
fig, (ax1, ax2) = plt.subplots(ncols=2)
imdata = np.random.random((20,20))
lndata = imdata[0]
im = ax1.imshow(imdata, animated=True)
(ln,) = ax2.plot(lndata, animated=True)
plt.show()

print(ln.get_rasterized())
print(im.get_rasterized())

print(ln.get_visible())
print(im.get_visible())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Good first issue Open a pull request against these issues if there are no active ones! status: has patch patch suggested, PR still needed topic: animation topic: images
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants