Skip to content

FIX: inset-axes not having proper transform #10986

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

Closed
wants to merge 1 commit into from

Conversation

jklymak
Copy link
Member

@jklymak jklymak commented Apr 8, 2018

PR Summary

This should fix the issue noted in #10756 (comment) where #10756 didn't quite do the right thing. I went a step further and said bbox_to_anchor should always be a four-tuple. See #8952.

Fixes the reversion in 2.2.2 so that this didn't work:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
xdata, ydata = np.arange(8), np.arange(8)

plt.figure(figsize=(6,3))
ax = plt.subplot(111)
ax.plot(xdata, ydata)
axins = inset_axes(ax, width=0.2, height=0.2, loc='upper left')

Now works, tests pass, and examples look right. It may break other people's perceived ideas of what these functions are supposed to do. If so, please do report the issue, but in my mind the old state of things was pretty unclear.

@jklymak
Copy link
Member Author

jklymak commented Apr 8, 2018

ping @ImportanceOfBeingErnest

@jklymak jklymak changed the title FIX: first try FIX: inset-axes not having proper transform Apr 8, 2018
@jklymak
Copy link
Member Author

jklymak commented Apr 8, 2018

OK< I think this fixes the issue. OTOH, I still don't really understand what bbox_to_anchor or bbox_transform really mean, what units they are in etc. This is all pretty poorly documented and the code non-trivial to trace through.

I still think this functionality could/should be moved to the base axes class at some point.

@ImportanceOfBeingErnest
Copy link
Member

I think this is far too restrictive. As I already pointed out somewhere, I think this should just stay as it was before the "fix".

  • Of course one may add a warning or error for the case discussed in inset_locator.inset_axes produces axes without extent and at incorrect position. #8952:

    if isinstance(bbox_to_anchor, tuple) and 
       (isinstance(width, str) or isinstance(height, str)):
        if len(bbox_to_anchor) != 4:
            warning("Using relative units for width or height requires to provide a 
                            matplotlib.transforms.BBox or a 4-tuple to `bbox_to_anchor`")
    

    Even the case from Inconsistent inset_axes position between show(), savefig(format='png') and savefig(format='pdf') #8120 (inset_axes(ax1, width=.7, height=.7,bbox_to_anchor=(100,100))) should still be allowed I think. The problem is just that it is in most cases not very useful to specify the bounding box in pixels and then change the dpi. (The problem of pdf having a fixed dpi is a totally different one; I don't think one should work around that inside of individual plotting functions.)

  • I also think the above warning/error should live in AnchoredSizeLocator.

  • The documentation should state the text from the warning.

  • There should be a test with some combinations of arguments. (I will see if I can provide those in the next couple of days)

  • The inset_locator paragraph in the axis_grid1 tutorial should be updated to show a couple of use cases (possibly the same as the test uses). The docstring should link to this paragraph.

@jklymak
Copy link
Member Author

jklymak commented Apr 10, 2018

@ImportanceOfBeingErnest Do you understand what inset_axes(ax1, width=.7, height=.7,bbox_to_anchor=(100,100)) means? I don't see where pixels is specified as the default transform, and so far as I can tell the above doesn't work at all (either with this change or without). But maybe I am completely not understanding inset_axes.

My real proposed fix to this is #11005, where we do this all properly, includding proper documentation.

OTOH, if you have a different PR to fix this, I'm not going to be offended if you push an alternate fix. i really don't understand what bbox_to_anchor is supposed to mean in inset_axes.

@ImportanceOfBeingErnest
Copy link
Member

It may indeed be useful to get proper inset_axes to the normal matplotlib.axes! They could work differently then the ones from axes_grid1 and hence be more understandable.
I would probably not change those from the axes_grid1. They are there for some reason and people have been using them.


inset_axes(ax1, width=.7, height=.7,bbox_to_anchor=(100,100)) used to work; it is actually working on 2.2.2. But the attempted fix #10756 has broken it.
This creates an inset axes, which is 0.7 inches wide and high. This is positioned relative to a bounding box of (100,100, 0,0) (note, no width, no height, just as usual with legend bbox etc). Since we do not specify any transform here, this is None and hence equivalent to bbox_transform=matplotlib.transforms.IdentityTransform(). This means it is just the raw pixel coordinates of the final figure.
The default loc is "upper right", so the upper right corner of the axes is aligned to the upper right corner of the bounding box. The bounding box having no extention, this means that the upper right corner of the axes is at pixel position (100,100).
This is not quite the case, because of the default borderpad = 0.5. This means that there is an offset of

borderpad*fontsize [points] = borderpad*fontsize * dpi / 72 ppi = 0.5*10*100/72 = 6.9 [pixels]

for the default dpi=100 and fontsize=10. And this is indeed what we observe in the final generated plot. (Again, for pdf it's different, because that seems to ignore dpi setting.)

Now it's clear that specifying a bounding box like that is usually not desirable.
In principle the inset_axes can take all arguments needed to specify more useful scenarios.
The main problem I see is that the relative width and height are specified in a rather unusual way (e.g. "100%") compared to other matplotlib specs.

I still think it's best to revert back to this old behaviour and update the documentation. This would at least make sure not get a non-working version out. I could provide a PR if desired. One problem seems that the documentation of axis_grid1 is somehow non-existent (c.f. #9582). So any update to it might not help anyone.

@jklymak
Copy link
Member Author

jklymak commented Apr 11, 2018

@ImportanceOfBeingErnest #8120 is definitely still inconsistent for me on 2.2.2. All three of the plots (on screen, pdf, png) are different.

If the point is that specifying bbox_to_anchor in pixels and expecting consistency is a user mistake and not a bug, I guess thats fair enough. Though I think pixels is a pretty dumb default in 2018.

I'm going to close as this breaks old behaviour. I'll also revert the old "fix". The associated issue should be closed as well, but only after we can write a proper workaround for the user...

test
test_pdf__1_page_
figure_1_and_1__python_testinset_py__python3_6_

@jklymak jklymak closed this Apr 11, 2018
@jklymak jklymak deleted the fix-inset-axes-trans branch April 11, 2018 16:41
@ImportanceOfBeingErnest
Copy link
Member

Just leave it as it is and I will come with a consistent PR tomorrow or so. This PR would

  • delete the two lines that have been introduced and break things now.
  • Add warnings for the cases which are truely non-sensical
  • update the documentation about it.

@jklymak
Copy link
Member Author

jklymak commented Apr 11, 2018

OK, thats great. Thanks a lot!

@ImportanceOfBeingErnest
Copy link
Member

The point of the example in #8120 is indeed that if you specify something in pixels, the output will be in pixels. If you then change dpi (which is done deliberatly for png, and unintentionally for pdf due to some other strange thing with pdf dpi), you will get seemingly arbitrary output - but they are all consistent.

I suppose this is undesired in almost all cases, but who knows... why not position something in pixels? One definitely has to tell users about this in the docs, that's clear.

@jklymak
Copy link
Member Author

jklymak commented Apr 11, 2018

Not saying pixels shouldn't be an option, but its a strange default for an inset axes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants