Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Description
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 onnabble 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 onstackoverflow. 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.
import numpy as npimport matplotlib.pyplot as pltimport matplotlib.transforms as mtransformsfrom mpl_toolkits.axes_grid1.parasite_axes import SubplotHostdef transformed_x_axis(ax, transformation): class MyTransform(mtransforms.Transform): input_dims = 1 output_dims = 1 is_separable = False has_inverse = False def transform_non_affine(self, x): return transformation(x) def inverted(self): return MyInvertedTransform() class MyInvertedTransform(MyTransform): def inverted(self): return MyTransform() aux_trans = mtransforms.BlendedGenericTransform( MyTransform(), mtransforms.IdentityTransform()) ax2 = ax.twin(aux_trans) ax2.set_viewlim_mode("transform") ax2.axis["right"].toggle(ticklabels=False) return ax2
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
fig = plt.figure()ax = SubplotHost(fig, 1,1,1)fig.add_subplot(ax)ax2 = transformed_x_axis(ax, lambda x: 1. / x)x = np.linspace(1., 2., 200)ax.plot(x, np.sin(x))plt.show()
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.
fig = plt.figure()ax = SubplotHost(fig, 1,1,1)fig.add_subplot(ax)ax2 = transformed_x_axis(ax, lambda x: np.exp(x))x = np.linspace(1., 5., 200)ax.plot(x, np.sin(x))plt.show()
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,
ax2 = transformed_x_axis(ax, lambda x: np.exp(x))x = np.linspace(1., 2., 200)ax.plot(x, np.sin(x))
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:
fig = plt.figure()ax = SubplotHost(fig, 1,1,1)fig.add_subplot(ax)ax2 = transformed_x_axis(ax, lambda x: 2. * x)x = np.linspace(1., 2., 200)ax.plot(x, np.sin(x))plt.show()
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