Repository navigation
Description
Suggestion
This would subsume #10976: see #10961 #10960 for secondary axes requests.
See #8952 for the poor state of documentation and confusing behaviour of axes_grid1.inset_axes. #10986, #10756
There are a few instances where it would make sense for an axes to have an axes as a child artist:
- an inset_axes with a subsection of the data, or some other information (ala )
matplotlib/lib/mpl_toolkits/axes_grid1/inset_locator.py
Lines 389 to 390 in adaa8e5
def inset_axes(parent_axes, width, height, loc=1, bbox_to_anchor=None, bbox_transform=None, - a secondary scale (i.e a second x-scale at the top of the axes in a different unit).
I'd propose we create an API for these. I would expect the legend API would be fine for inset axes, and would closely follow the one already in axes_grid1. An example would be:
# inset from x=0.65 to 0.95, y=0.75 to 0.95
inax = ax.inset_axes(location='upper_right', width=0.3, height=0.2, padding=0.05)
# inset from x=0 to 0.25, y=0.3 to 0.7
inax = ax.inset_axes(bbox_to_anchor=(0, 0.3, 0.25, 0.4))Secondary axes would be basically an inset_axes, except with the appropriate spines turned off:
secx = ax.extra_spine_x(location='top', convert=(lambda x: 1/x))
thirdx = ax.extra_spine_x(location=0.5, convert=(lambda x: 1/x))
secy = ax.extra_spine_y(location='right', convert=(lambda y: y**2))Implementation
I would like to have these be children of the parent axes simply for the reason that they are decorators, and should be included in the list of artists a) at draw time, and b) when the bbox for the parent axes is calculated for tools like constrained_layout and tight_layout. Also having them as children makes it possible to change the limits if the parent limits change, and avoids the messiness of twin axes, which have a peer-to-peer relationship.
Activity
ImportanceOfBeingErnest commentedon Apr 11, 2018
To avoid confusion with the existing
axes_grid1.inset_locator.inset_axesfunction what about naming thisThe question is then in how far this would be compatible with all the inset_locator module's functionality like bbox connectors,
mark_insetetc.jklymak commentedon Apr 22, 2018
inset axis is well on its way in #11026
Lets hash out an API for
ax.extra_spine_x/y? Proposal would be that this would be called asOne could also imagine an
extentandoffsetparameter...You could also imagine having an extent and offset keywords so the spine doesn't span the whole axis, but that would also need a way to map the xlims (which presumably would not be the full extent of the parent x axis. Seems complicated, and rarely used, and a need that could be met w/
inset_axis.Issues
set_aspect()work, but I think that will work OK.transform=ax.transAxes and location>0.5(or "top") then put everything on the top by default.parent.set_xlimpropagate to the children, but it'd probably be nicer to just have the complicating code in the child axes.ImportanceOfBeingErnest commentedon Apr 22, 2018
In general 👍
If I understand correctly, the return type is a
matplotlib.axes.Axesor amatplotlib.axes.Subplotor a subclass of that? In that case it should have the usualax.spinesavailable, which can be used to translate the spine to a different position? As in spine_placement_demo?What's the
transformdoing exactly? Is that necessary at all? Is it doing something other than placing the spine?Why do you need
ax.extra_spine_xandax.extra_spine_y? Wouldn't it be sufficient to havewhere loc can be any of
"top", "bottom", "left", "right"?I think it would be good to give a clear explanation of the difference to a
twinx. (Because although I was involved in some of the discussion that led to this, I'm not certain I got the point of why that is needed. Is it just because of theaspect?). I think it depends on this if and how the limits are being propagated or not?What's
extentandoffsetdoing? That example isn't very enlightening.jklymak commentedon Apr 22, 2018
transformis to assign a transform for thelocation. So if itsax.transAxesthen its in the axes co-ordinates, if itsax.transDataits in the data coordinates.xandybut thenlocationcan't take a numeric argument and be unambiguous.twinxis really meant for if you want two different data streams to have the same x-axis but different y-axes (think humidity and temperature in a weather balloon profile; https://matplotlib.org/examples/api/two_scales.html). For one thing, its orthogonal toextra_spine_x. To get that you'd usetwiny. But then the extra x-axis doesn't (and shouldn't) scale with the new one:doesn't return the correct x-axis because there is nothing tying the x-axis-es together (its the y-axis that is shared). Thats as it should be for a twinned axis; the two data types in the two axes should definitely be allowed to have independent x-axes.
extentmight make the extra x-axis shorter than the parent x-axis, but then you'd needoffsetto tell it where on the parent to go. Not 100% sure that this is that useful.ImportanceOfBeingErnest commentedon Apr 22, 2018
Ok, but let's suppose for a moment that the child is a subclass. Then it does provide the
ax.spines['left'].set_positionmethod, which can hence simply be used as with any other axes. I think this can be argument enough to actually make it a subclass.If transform is only needed for the location argument, one can refer to 1. and leave it out.
No numeric argument is needed if the spine is set via
ax.spinesSo in total I would say, similar to what exists now one would do
to place the spine at
4in data coordinates.Thanks for reminding, that makes perfect sense. In a way the extra axis is like a shared axes with a data conversion in between? Maybe it's worthwhile looking into the shared axes mechanism and see if it would be possible to add some
conversionto it or at least extend it somehow.Not sure either on the usefulness of
extent. One could argue that if you want to have the extra axes at a different position (i.e. not using the same box as the parent) you'd useinset_axesand turn the other spines off.jklymak commentedon Apr 22, 2018
I was conceiving of the extra_spine as not having a cross-spine dimension and having to track all the cross-spine info from the parent axes. That makes life a lot easier and we avoid all the issues with aspect ratios and twinning.
If we were to go that route, then
spines['top'].set_position()won't do anything because the y-direction has no data and height=0.Probably we could make it work the
spine[loc].set_position()way, but that robs the method of most of its simplicity. It also makes the exact placement an extra call, but maybe that not a big deal.ImportanceOfBeingErnest commentedon Apr 22, 2018
I was under the impression that the extra_axes would create a normal boxed axes, which just has 3 spines tuned off and whose scaling, limits, and position is tied to the parent. In that case, calling
extrax.spines["right"]on an axesextrax = ax.extra_spine(loc="top")would simply not do anything; or, it would, but you'd only see it if you turned the respecive spine on again. (One could of course add.get_spine()to it, which returns the spine in question.)I do not see the problem of the extra line. The same extra line is needed if spines of usual axes are to be manipulated. Why should the extra axes get special treatment here?
jklymak commentedon Apr 23, 2018
Yes, but that wasn't the plan given the PITA that fully-twinned axes are....
A specially-placed extra spine gets special treatment because its being specially placed.
I'm not 100% against the alternative of having a fully formed axes, but it just seems prone to inconsistencies.. i.e. if you set the aspect ratio on the main axes, and the child axes has a conversion on the x-axis, then it cannot share the aspect ratio of the parent, but rather needs to set its position based on the aspect-applied position of the parent. It can be done, but it all gets pretty complex, just for the ability to manually place the spine, which I was planning to allow anyways...
ImportanceOfBeingErnest commentedon Apr 23, 2018
Ok, I think I finally understand.. this is really just about getting a scale in some other units attached to an axes.
So at the end you have
... each of which is somehow incomplete.
jklymak commentedon Apr 23, 2018
I don't think "completeness" is necessarily desirable. Thats how you end up with the El Camino (https://en.wikipedia.org/wiki/Chevrolet_El_Camino), something which doesn't do anything well or clearly. In this case, I don't think its necessarily good for
twinyto be the way that a second x axis gets added to a parent axis, using a magical recipe that most users don't understand and is not readily discoverable.jklymak commentedon Jan 18, 2021
I think this functionality is all in now....