-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
plotting using secondary axis with mpl_toolkits.axes_grid1.parasite_axes.SubplotHost().twin() produces very weird outputs #7258
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
Comments
Side question: Can this, what I wanted to accomplish, be done in an easier way? Maybe without relying on mpl_toolkits.axes_grid1.parasite_axes.SubplotHost().transform()? |
You also need to define a It is feature that the ticks are located in data space (rather than in screen space) so that it is easy to put them at meaning full numbers (ex, evenly spaced in screen space ticks on a log scale would look weird). @phobson has done a fair amount of work with non-linear scales at https://phobson.github.io/mpl-probscale/ |
Thank you very much for the quick answer! And thanks for the link. |
I think one issue here is that your Inverted Transform is incomplete. If you're going to have a transform that is So I think your example would become (untested): import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
from mpl_toolkits.axes_grid1.parasite_axes import SubplotHost
def transformed_x_axis(ax, fwds, bkwds):
class MyTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = False
has_inverse = False
def __init__(self, fwds, bkwds):
mtransforms.Transform.__init__(self)
self.fwds = fwds
self.bkwds = bkwds
def transform_non_affine(self, x):
return self.fwds(x)
def inverted(self):
return MyInvertedTransform(self.bkwds, self.fwds)
class MyInvertedTransform(MyTransform):
def inverted(self):
return MyTransform(self.bkwds, self.fwds)
aux_trans = mtransforms.BlendedGenericTransform(
MyTransform(fwds, bkwds), mtransforms.IdentityTransform())
ax2 = ax.twin(aux_trans)
ax2.set_viewlim_mode("transform")
ax2.axis["right"].toggle(ticklabels=False)
return ax2
if __name__ == '__main__':
fig = plt.figure()
ax = SubplotHost(fig, 1,1,1)
fig.add_subplot(ax)
ax2 = transformed_x_axis(ax, lambda x: 2. * x, lambda x: 0.5 * x)
x = np.linspace(1., 2., 200)
ax.plot(x, np.sin(x)) |
@gritschel I updated the example above. When I run it, it looks right to me. I'm curious what you think. |
@phobson for first three plots he uses @gritschel I don not see any bugs for the first two plots.
Your last plot with @phobson's Please provide the code for the third plot. I have |
@gritschel The problem with the third plot is that the |
@phobson Thank you very much for the advice with the inverse transformation! That fixed essentially everything. Funny enough, it also works, if the attribute @Kojoley You're right, in the second plot, the only problem seems to be lack of space. Of course, if my transformation is What I was also wondering about is the fact that Please, see the code below:
... and compare this to:
I have no idea why this would happen. It seems like a bug to me. |
@phobson I checked your code again and there is still a subtle point, which I didn't recognize at first. If I run your example code, all Ticker problems are gone, but the transformation is done in the exact opposite direction! This I don't understand. The important part being Also, if I'm using
Both, again, show issues with the ticker, I think. Can someone explain this behaviour? |
The transformation part of matplotlib is complicated. Affine transformations must subclass of class Transform(TransformNode):
"""
...
All non-affine transformations should be subclasses of this class.
New affine transformations should be subclasses of
:class:`Affine2D`. |
@gritschel I think your ticks are messed up b/c your math is wrong.
In your example:
|
@phobson Oh, how stupid of me. It seems I did this too quickly. You're right, of course. With the proper back-transformation the tick problems do not occur anymore. Do you have an explanation for the wrong direction of transforms that I wrote about in my last post? Could this be the explanation, why the back-transformation is needed in the first place? From a theoretical point of view, I don't see why the back-transformation should be needed. Or what else could I be missing? |
@gritschel is there any chance you could check if this is still an issue with the latest version of Matplotlib (3.0.3)? |
3.1 will also have this support baked in natively: #11859 I'm going to close this as obsolete, but feel free to open a new issue if there is problems with the new functionality. |
For several plots I'd like to have a secondary x axis that is a non-affine transformation of the original axis. Following a very old discussion on nabble I recognized that it is only possible, if I define my own matplotlib.transforms.Transform() class or I have to set tick locations manually according to a discussion on stackoverflow. I managed to make the code from the nabble link work, but I had to rename the class method transform() to transform_non_affine(). Otherwise it would not work.
So I now have the following code, which seemed to work fine for the first few tests.
For convenience I defined a function 'transformed_x_axis()' that just accepts an original matplotlib.axes.Axes object and a transformation formula.
(Actually, I think that my use case is pretty common and matplotlib should provide such kind of function that I tried to use, here.)
Using it with
produces exactly what I want -- a plot with a secondary transformed x axis:

Unfortunately, for other transformations or for other data limits I see all kinds of weirdest things happening.
For other data ranges, e.g.

x = np.linspace(1., 5., 200)
, the ticker has problems and draws ticklabels on top of each other:If the axis approaches the critical point 0.0 of my transformation, the ticks don'e even fill the axis but only a tiny part of it:

I guess that this is a result of the linear scale of the ticklabels. It seems the ticks for the axis are chosen by value and not by position in axes coordinates, which I find kind of wrong.
Other transformations also produce weird things, e.g.
gives me a RuntimeError in an IPython Notebook and in a terminal it produces a secondary axis that contains nothing but the value 0.

For other data limits,
I get a MemoryError in the notebook. When done in the terminal, I see no secondary x axis.
The strangest things occur for simple linear transformations:
Here, in the terminal, I see, again, no secondary axis. But in the notebook, I think one can see that something goes dramatically wrong:

I think, it is the ticker that does those weird things when it faces transformed axes.
Anyway, the behavior is inconsistent, unexpected and very weird.
Cheers, Gerhard
Python 2.7.12, matplotlib 1.5.1 on Windows 64 bit
everything installed via Anaconda
The text was updated successfully, but these errors were encountered: