-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
FIX: savefig)...,transparent=True) now makes inset_axes transparent a… #22816
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
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.
Thank you for opening your first PR into Matplotlib!
If you have not heard from us in a while, please feel free to ping @matplotlib/developers
or anyone who has commented on the PR. Most of our reviewers are volunteers and sometimes things fall through the cracks.
You can also join us on gitter for real-time discussion.
For details on testing, writing docs, and our review process, please see the developer guide
We strive to be a welcoming and open project. Please follow our Code of Conduct.
Thank you for working on this @sramesh750 . The implementation looks reasonable to me, however it needs at least one test so we can be sure that the issues does not comeback. Looking at this, I also suspect that we failing to set sub-figures (and their Axes) to be transparent. Would you be willing to also address that issue while you are working on this (and thinking about the right way to test it ;)) ? |
@tacaswell Am I supposed to commit the result_images file that was created when running the tests? I am currently unsure of why I have some checks that are failing, such as the AppVeyor build. |
Appveyor failing is unrelated (a new release of a jlab extension had a file who's name is too long for the windows version in the appveyor image). |
@tacaswell Thank you for all the help! Is there anything else I need to do in order to get this pull request approved? |
I do not fully understand the fully transparent image? I guess before you would see the outlines of the sub-figures? However, as it stands the test is not great because if you deleted the body of the test function it would still pass! |
I believe this new test should not cause false positives since I added visible subplots. |
Can you squash this down to one commit? I expect this to fail because you added and then changed the image file in this PR (we only want the good version in the history!). If you are not comfortable doing the squashing we can do that for you. |
I'm not as comfortable with squashing, so I would appreciate if you could take care of that! |
lib/matplotlib/tests/test_figure.py
Outdated
@@ -557,6 +557,26 @@ def test_savefig_pixel_ratio(backend): | |||
assert ratio1 == ratio2 | |||
|
|||
|
|||
@image_comparison(['transparent_inset_axes'], | |||
extensions=['png'], savefig_kwarg={'transparent': True}) |
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.
- please use
remove_text=True
to remove the ticklabels (this makes the images more robust against underlying changes of the library. - please combine the two tests together (by putting the inset_axes into an axes in a subfigure).
Other than that, this looks good to me.
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.
(don't forget to remove the now unneeded images)
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.
Done!
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.
Just needs a squash first.
I'm not too familiar with squashing. Which commits need to be squashed, or is this something that can be done for me? |
Done. |
Thank you so much! |
Just to make sure: as mentioned in the original issue it may be that one not always would like this. Is there a way to make the "main figure" transparent, but not the inset? Should there be a release note for this? Some users may rely on the current behavior. (In the long run one probably would like the inset to not show content from the main axes that happens to end up inside the inset area.) |
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.
Are you sure the figure returns to previous settings if subfigures are used?
The docstring needs to be updated.
To @oscargus comment, a) this is pretty new, b) if folks want to toggle transparency of individual elements, they can just not use the transparent kwarg. OTOH, I could imagine a situation where it would be a breaking change for the transparency to be applied to the inset axes, and it would ruin a figure. (imagine a line plot inset over an image).
lib/matplotlib/figure.py
Outdated
@@ -3061,10 +3061,18 @@ def savefig(self, fname, *, transparent=None, **kwargs): | |||
if transparent: | |||
kwargs.setdefault('facecolor', 'none') | |||
kwargs.setdefault('edgecolor', 'none') | |||
for subfig in self.subfigs: | |||
subfig.set_facecolor('none') |
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.
I don't think this gets reversed when the savefig is completed?
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.
Oopsie, good catch.
lib/matplotlib/figure.py
Outdated
@@ -3061,10 +3061,18 @@ def savefig(self, fname, *, transparent=None, **kwargs): | |||
if transparent: | |||
kwargs.setdefault('facecolor', 'none') | |||
kwargs.setdefault('edgecolor', 'none') | |||
for subfig in self.subfigs: | |||
subfig.set_facecolor('none') |
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.
Oopsie, good catch.
@jklymak could you please clarify in more detail what changes need to be made? I am a bit confused on the functionality that needs to be added. Do we want users to be able to make the figure transparent but not the subfigure? Also a bit confused what you mean by "this gets reversed". Thank you so much! |
The transparent kwarg should only affect the figure during printing. Once the printing context is left, the figure should revert to whatever state it was in before the print started. Here you are losing the original state and just changing the subfigure facecolor. |
I updated the code, but I will need help with squashing the commit again. |
@sramesh750 I fixed this by dropping your merge commit and then cherry-picking the new commit. The issue is that when you updated locally Antony had squashed all of your commit into one which, despite having identical changes, git viewed as different from your local branch (which to be fair it is a different history!). Because there were some commits on github and some commits on your local system, when you added your last commit and tried to push GH helpfully said "I can not do that because the histories do not match! Try running this command to fix it: What you want to do to prevent this in the future is
before you do any more work. 🤦🏻 I now see that this also has to be squashed...doing that too. |
I feel like I keep moving the goal posts, but I think this will only work as expected for 1 level of sub-figures (that is sub-figure that have sub-figures that have axes that have insets will not behave as expected). I think we can fix that by pulling the loops out into a (locally defined) function that looks something like def _recursively_make_transparent(exit_stack, subfig):
exit_stack.enter_context(subfig, ....)
for ax in subfig.axes:
...
for sub_subfig is subfig.subfigs:
_recursively_make_transparent(exit_stack, sub_subfig) I'm fine with this going in as-is as an improvement and opening an issue for the more general case or having it done here if you are feeling up to it @sramesh750 ! |
@tacaswell I am unfortunately busy in the next few weeks, so for now I think it would be best to merge these improvements and open up a new issue for the more general case. If no one gets onto that new issue, I will definitely be interested in working on it as soon as I can! |
@jklymak OK! Makes sense. I was more thinking of the case where one puts an inset over a plotted line to illustrate e.g. a detail of the plot. Currently, one can simply rely on the transparent kwarg, but with this one need to change approach (although still doable). Considering it is recent and this does not seem to be considered a problem, I will not argue against it. (One can also argue that the current PR is probably more "correct" than the earlier behavior.) Just wanted to make sure that the potential drawback was considered. |
@oscargus fair, I see both sides, but lean towards making all backgrounds transparent as it is a simpler rule (no special cases). |
@@ -3061,10 +3061,24 @@ def savefig(self, fname, *, transparent=None, **kwargs): | |||
if transparent: | |||
kwargs.setdefault('facecolor', 'none') | |||
kwargs.setdefault('edgecolor', 'none') | |||
# set subfigure to appear transparent in printed image | |||
for subfig in self.subfigs: |
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.
Subfigures can be nested arbitrarily; this only handles one level.
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.
I think another issue was supposed to be opened to handle this general case.
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.
The nesting should be handled here.
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.
@tacaswell noted how to do this recursively here #22816 (comment)
This could also be done with a stack approach:
subfigs = [*self.subfigs]
while subfigs:
this_subfig = subfigs.pop(0)
subfigs.extend(this_subfig.subfigs)
# Do something with this_subfig
On a side note (and not for this PR), I wonder if we want some kind of self.iter_subfigures
or similar that would do the above iteration with a callable.
I'm a little confused about the status of this one... @anntzer you approved, but its not showing as approved, so not clear if you still have questions? |
Actually I think this can be done without a new baseline image?
fig.add_subfigure(gs[0:2, 1]) | ||
fig.add_subplot(gs[0:2, 1]) | ||
ax2 = plt.gca() | ||
ax2.inset_axes([.1, .2, .3, .4]) |
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.
I think you can add ax.spines[:].set_visible(False); ax.set(xticks=[], yticks=[])
to all axes instantiations, which effectively makes them invisible (and thus the entire savefig should be invisible). Then you can check_figures_equal with a fully empty plot.
This still needs a bit of revision. Moving to draft until addressed... |
@sramesh750 do you still plan to work on this? If not, one of the core devs or somebody else could take over. |
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.
The recurniveness of sub-figures needs to be handled.
Pushing this to 3.8 |
@sramesh750 do you plan to work on this? If not, I'd like to pick up this PR to finish the work. |
@chahak13 No, you can finish the work if you'd like |
This has been replaced by #24816. |
PR Summary
This PR makes inset_axes in save fig(...,transparent=True) function transparent in addition to the parent axes.
Addresses issue #22674
PR Checklist
Tests and Styling
pytest
passes).flake8-docstrings
and runflake8 --docstring-convention=all
).Documentation
doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).