From cd1c6cc2331b592b91de393cde054486d944aeb8 Mon Sep 17 00:00:00 2001 From: Danny Date: Mon, 4 Nov 2024 19:35:07 -0500 Subject: [PATCH 1/5] Update secondary_axis tutorial when the second axis is interpolated from the first. In this case the interpolation must be defined outside the bounds of the data that is plotted. Moreover the tutorial in question has been simplified. --- .../secondary_axis.py | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/galleries/examples/subplots_axes_and_figures/secondary_axis.py b/galleries/examples/subplots_axes_and_figures/secondary_axis.py index d6dfd33f62c1..676bee8c1ec3 100644 --- a/galleries/examples/subplots_axes_and_figures/secondary_axis.py +++ b/galleries/examples/subplots_axes_and_figures/secondary_axis.py @@ -17,7 +17,6 @@ import numpy as np import matplotlib.dates as mdates -from matplotlib.ticker import AutoMinorLocator fig, ax = plt.subplots(layout='constrained') x = np.arange(0, 360, 1) @@ -96,48 +95,50 @@ def one_over(x): plt.show() # %% -# Sometime we want to relate the axes in a transform that is ad-hoc from -# the data, and is derived empirically. In that case we can set the -# forward and inverse transforms functions to be linear interpolations from the -# one data set to the other. +# Sometime we want to relate the axes in a transform that is ad-hoc from the data, and +# is derived empirically. Or, one axis could be a complicated nonlinear function of the +# other. In these cases we can set the forward and inverse transform functions to be +# linear interpolations from the one set of independent variables to the other. # # .. note:: # # In order to properly handle the data margins, the mapping functions # (``forward`` and ``inverse`` in this example) need to be defined beyond the -# nominal plot limits. -# -# In the specific case of the numpy linear interpolation, `numpy.interp`, -# this condition can be arbitrarily enforced by providing optional keyword -# arguments *left*, *right* such that values outside the data range are -# mapped well outside the plot limits. +# nominal plot limits. This condition can be enforced by extending the +# interpolation beyond the plotted values, both to the left and the right, +# see ``x1n`` and ``x2n`` below. fig, ax = plt.subplots(layout='constrained') -xdata = np.arange(1, 11, 0.4) -ydata = np.random.randn(len(xdata)) -ax.plot(xdata, ydata, label='Plotted data') - -xold = np.arange(0, 11, 0.2) -# fake data set relating x coordinate to another data-derived coordinate. -# xnew must be monotonic, so we sort... -xnew = np.sort(10 * np.exp(-xold / 4) + np.random.randn(len(xold)) / 3) - -ax.plot(xold[3:], xnew[3:], label='Transform data') -ax.set_xlabel('X [m]') +x1_vals = np.arange(2, 11, 0.4) +# second independent variable is a nonlinear function of the other. +# this simple example can be more easily handled without interpolation, and is done +# this way only for pedagogical purposes. +x2_vals = x1_vals ** 2 +ydata = 50.0 + 20 * np.random.randn(len(x1_vals)) +ax.plot(x1_vals, ydata, label='Plotted data') +ax.plot(x1_vals, x2_vals, label=r'$x_2(x_1)$') +ax.set_xlabel(r'$x_1$') ax.legend() +# need to define mapped values outside of plotted range to ensure the secondary +# axis is plotted correctly +x1n = np.concatenate(([0.0], x1_vals, [20])) +x2n = np.concatenate(([0.0], x2_vals, [20**2])) + def forward(x): - return np.interp(x, xold, xnew) + return np.interp(x, x1n, x2n) def inverse(x): - return np.interp(x, xnew, xold) - + return np.interp(x, x2n, x1n) +# use axvline to prove that the derived secondary axis is correctly plotted +ax.axvline(np.sqrt(40), color="grey", ls="--") +ax.axvline(10, color="grey", ls="--") secax = ax.secondary_xaxis('top', functions=(forward, inverse)) -secax.xaxis.set_minor_locator(AutoMinorLocator()) -secax.set_xlabel('$X_{other}$') +secax.set_xticks([10, 20, 40, 60, 80, 100]) +secax.set_xlabel(r'$x_2$') plt.show() From de88555f2a6eba5ca441cca8292883b62b483a6a Mon Sep 17 00:00:00 2001 From: Daniel Weiss <32396142+dkweiss31@users.noreply.github.com> Date: Tue, 5 Nov 2024 08:13:34 -0500 Subject: [PATCH 2/5] Update galleries/examples/subplots_axes_and_figures/secondary_axis.py make endpoints large in magnitude Co-authored-by: Jody Klymak --- .../examples/subplots_axes_and_figures/secondary_axis.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galleries/examples/subplots_axes_and_figures/secondary_axis.py b/galleries/examples/subplots_axes_and_figures/secondary_axis.py index 676bee8c1ec3..2bd705829c0c 100644 --- a/galleries/examples/subplots_axes_and_figures/secondary_axis.py +++ b/galleries/examples/subplots_axes_and_figures/secondary_axis.py @@ -122,8 +122,8 @@ def one_over(x): # need to define mapped values outside of plotted range to ensure the secondary # axis is plotted correctly -x1n = np.concatenate(([0.0], x1_vals, [20])) -x2n = np.concatenate(([0.0], x2_vals, [20**2])) +x1n = np.concatenate(([-1e10, 0], x1_vals, [20, 1e10])) +x2n = np.concatenate(([-1e10, 0], x2_vals, [20**2, 1e10**2])) def forward(x): From 132c8383ea19327ba5ae9617dbc12032c46309b3 Mon Sep 17 00:00:00 2001 From: Daniel Weiss <32396142+dkweiss31@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:10:26 -0500 Subject: [PATCH 3/5] Update galleries/examples/subplots_axes_and_figures/secondary_axis.py explicitly label x2 = x1**2 Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- galleries/examples/subplots_axes_and_figures/secondary_axis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galleries/examples/subplots_axes_and_figures/secondary_axis.py b/galleries/examples/subplots_axes_and_figures/secondary_axis.py index 2bd705829c0c..ed5281d57a9f 100644 --- a/galleries/examples/subplots_axes_and_figures/secondary_axis.py +++ b/galleries/examples/subplots_axes_and_figures/secondary_axis.py @@ -116,7 +116,7 @@ def one_over(x): x2_vals = x1_vals ** 2 ydata = 50.0 + 20 * np.random.randn(len(x1_vals)) ax.plot(x1_vals, ydata, label='Plotted data') -ax.plot(x1_vals, x2_vals, label=r'$x_2(x_1)$') +ax.plot(x1_vals, x2_vals, label=r'$x_2 = x_1^2$') ax.set_xlabel(r'$x_1$') ax.legend() From 724cd889ea58d749093db0983a046e2418a269f7 Mon Sep 17 00:00:00 2001 From: Daniel Weiss <32396142+dkweiss31@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:14:58 -0500 Subject: [PATCH 4/5] Update galleries/examples/subplots_axes_and_figures/secondary_axis.py simplify interpolation Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- .../examples/subplots_axes_and_figures/secondary_axis.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/galleries/examples/subplots_axes_and_figures/secondary_axis.py b/galleries/examples/subplots_axes_and_figures/secondary_axis.py index ed5281d57a9f..aae4c8d3fcc8 100644 --- a/galleries/examples/subplots_axes_and_figures/secondary_axis.py +++ b/galleries/examples/subplots_axes_and_figures/secondary_axis.py @@ -120,10 +120,9 @@ def one_over(x): ax.set_xlabel(r'$x_1$') ax.legend() -# need to define mapped values outside of plotted range to ensure the secondary -# axis is plotted correctly -x1n = np.concatenate(([-1e10, 0], x1_vals, [20, 1e10])) -x2n = np.concatenate(([-1e10, 0], x2_vals, [20**2, 1e10**2])) +# the forward and inverse functions must be defined on the complete visible axis range +x1n = np.linspace(0, 20, 201) +x2n = x1n**2 def forward(x): From 9f3e17a02c8f4d590d62d0de353e9d2127921a28 Mon Sep 17 00:00:00 2001 From: Daniel Weiss <32396142+dkweiss31@users.noreply.github.com> Date: Wed, 20 Nov 2024 20:42:22 -0500 Subject: [PATCH 5/5] Update galleries/examples/subplots_axes_and_figures/secondary_axis.py Kill unhelpful comment Co-authored-by: Jody Klymak --- galleries/examples/subplots_axes_and_figures/secondary_axis.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/galleries/examples/subplots_axes_and_figures/secondary_axis.py b/galleries/examples/subplots_axes_and_figures/secondary_axis.py index aae4c8d3fcc8..842b296f78cf 100644 --- a/galleries/examples/subplots_axes_and_figures/secondary_axis.py +++ b/galleries/examples/subplots_axes_and_figures/secondary_axis.py @@ -111,8 +111,6 @@ def one_over(x): fig, ax = plt.subplots(layout='constrained') x1_vals = np.arange(2, 11, 0.4) # second independent variable is a nonlinear function of the other. -# this simple example can be more easily handled without interpolation, and is done -# this way only for pedagogical purposes. x2_vals = x1_vals ** 2 ydata = 50.0 + 20 * np.random.randn(len(x1_vals)) ax.plot(x1_vals, ydata, label='Plotted data')