Skip to content

Commit 2a4a0a2

Browse files
timhoffmmeeseeksmachine
authored andcommitted
Backport PR #29073: Update secondary_axis tutorial
1 parent e25bfee commit 2a4a0a2

File tree

1 file changed

+25
-27
lines changed

1 file changed

+25
-27
lines changed

galleries/examples/subplots_axes_and_figures/secondary_axis.py

+25-27
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import numpy as np
1818

1919
import matplotlib.dates as mdates
20-
from matplotlib.ticker import AutoMinorLocator
2120

2221
fig, ax = plt.subplots(layout='constrained')
2322
x = np.arange(0, 360, 1)
@@ -96,48 +95,47 @@ def one_over(x):
9695
plt.show()
9796

9897
# %%
99-
# Sometime we want to relate the axes in a transform that is ad-hoc from
100-
# the data, and is derived empirically. In that case we can set the
101-
# forward and inverse transforms functions to be linear interpolations from the
102-
# one data set to the other.
98+
# Sometime we want to relate the axes in a transform that is ad-hoc from the data, and
99+
# is derived empirically. Or, one axis could be a complicated nonlinear function of the
100+
# other. In these cases we can set the forward and inverse transform functions to be
101+
# linear interpolations from the one set of independent variables to the other.
103102
#
104103
# .. note::
105104
#
106105
# In order to properly handle the data margins, the mapping functions
107106
# (``forward`` and ``inverse`` in this example) need to be defined beyond the
108-
# nominal plot limits.
109-
#
110-
# In the specific case of the numpy linear interpolation, `numpy.interp`,
111-
# this condition can be arbitrarily enforced by providing optional keyword
112-
# arguments *left*, *right* such that values outside the data range are
113-
# mapped well outside the plot limits.
107+
# nominal plot limits. This condition can be enforced by extending the
108+
# interpolation beyond the plotted values, both to the left and the right,
109+
# see ``x1n`` and ``x2n`` below.
114110

115111
fig, ax = plt.subplots(layout='constrained')
116-
xdata = np.arange(1, 11, 0.4)
117-
ydata = np.random.randn(len(xdata))
118-
ax.plot(xdata, ydata, label='Plotted data')
119-
120-
xold = np.arange(0, 11, 0.2)
121-
# fake data set relating x coordinate to another data-derived coordinate.
122-
# xnew must be monotonic, so we sort...
123-
xnew = np.sort(10 * np.exp(-xold / 4) + np.random.randn(len(xold)) / 3)
124-
125-
ax.plot(xold[3:], xnew[3:], label='Transform data')
126-
ax.set_xlabel('X [m]')
112+
x1_vals = np.arange(2, 11, 0.4)
113+
# second independent variable is a nonlinear function of the other.
114+
x2_vals = x1_vals ** 2
115+
ydata = 50.0 + 20 * np.random.randn(len(x1_vals))
116+
ax.plot(x1_vals, ydata, label='Plotted data')
117+
ax.plot(x1_vals, x2_vals, label=r'$x_2 = x_1^2$')
118+
ax.set_xlabel(r'$x_1$')
127119
ax.legend()
128120

121+
# the forward and inverse functions must be defined on the complete visible axis range
122+
x1n = np.linspace(0, 20, 201)
123+
x2n = x1n**2
124+
129125

130126
def forward(x):
131-
return np.interp(x, xold, xnew)
127+
return np.interp(x, x1n, x2n)
132128

133129

134130
def inverse(x):
135-
return np.interp(x, xnew, xold)
136-
131+
return np.interp(x, x2n, x1n)
137132

133+
# use axvline to prove that the derived secondary axis is correctly plotted
134+
ax.axvline(np.sqrt(40), color="grey", ls="--")
135+
ax.axvline(10, color="grey", ls="--")
138136
secax = ax.secondary_xaxis('top', functions=(forward, inverse))
139-
secax.xaxis.set_minor_locator(AutoMinorLocator())
140-
secax.set_xlabel('$X_{other}$')
137+
secax.set_xticks([10, 20, 40, 60, 80, 100])
138+
secax.set_xlabel(r'$x_2$')
141139

142140
plt.show()
143141

0 commit comments

Comments
 (0)