-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
FIX: make_image should not modify original array #29892
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
Conversation
lib/matplotlib/tests/test_image.py
Outdated
@@ -281,6 +281,17 @@ def test_imshow_alpha(fig_test, fig_ref): | |||
ax3.imshow(rgbau) | |||
|
|||
|
|||
def test_imshow_rgba_multi_draw(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You do this conditionally - may be helpful to test the conditions where you are not doing the copy to demonstrate that they work fine on redraw
This adds another copy of the input image, which for medium to large images is not neglegible. Running the script below I get a peak memory usage of ~450 MB, but with this PR I get a peak usage of ~580MB (as expected the difference is ~one copy of the input image, which is ~120MB). I guess the other way to fix this is to multiply in-place, then divide in place after the resample. That would avoid the extra memory, but if it's constantly happening during a window resize I could imagine it has performace implications, and perhaps floating point errors could accumulate pretty fast with all the multiplications and divisions? I can't think of another option to solve this without going back to applying alpha in resampled space (ie undoing #29776). Perhaps @anntzer has some thoughts as the original PR author? import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
rgba = np.random.random((2000, 2000, 4))
fig, ax = plt.subplots()
ax.imshow(rgba)
fig.canvas.draw() |
The fix looks correct to me, sorry for introducing the bug. re: performance:
Thoughts? |
I guess we can add "input was uint8" to my list of reasons not to copy, since we already cast to float. |
In my opinion #29776 should remain. The previous results were incorrect, and I think having correct results should trump efficiency. We copy the user data in |
👍 to doing the right thing at the expense of memory - at a glance I think there might be ways to save creating extra memory for the alpha channel, but for simplicity I think worth getting this in as is and then optimizing (if possible) later. |
The problem is that we divide the RGB part of the array by its alpha on each draw. The simple fix is to make a copy but I assume for efficiency we should only copy when necessary. * If we didn't start with float RGBA, we already made a copy * If alpha was an array, we already made a copy * If the alpha channel is one everywhere, it does not matter
Either #29453, or some not-yet-pushed version of it, does attempt to do some of this deduplication. I don't have time to look at that again until I finish the text stuff, but it may yet be a possibility to reduce the memory footprint, which can be done after this PR at least fixes the bug. |
That's fine as long as we remember to remove the extra copy this introduces. |
I thought #29776 removed a copy (from |
Sure? But we still will want to remove this copy? |
I just want to clarify the issue is that we are modifying our copy of the array not the object the user passed to us. |
Yes, this is correct |
PR summary
Fixes #29891. The problem is that we divide the RGB part of the array by its alpha on each draw. The simple fix is to make a copy but I assume for efficiency we should only copy when necessary.
PR checklist