From 8e3ad7fc4b128cfbf67b58cf76051ecb5cb6f40d Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Wed, 31 Dec 2025 20:06:54 +1000 Subject: [PATCH 1/2] Apply dual-axis transform in data space --- ultraplot/scale.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ultraplot/scale.py b/ultraplot/scale.py index d83d8f449..8fc2a05b8 100644 --- a/ultraplot/scale.py +++ b/ultraplot/scale.py @@ -11,8 +11,12 @@ import numpy.ma as ma from . import ticker as pticker -from .internals import ic # noqa: F401 -from .internals import _not_none, _version_mpl, warnings +from .internals import ( + _not_none, + _version_mpl, + ic, # noqa: F401 + warnings, +) __all__ = [ "CutoffScale", @@ -370,7 +374,9 @@ def __init__(self, transform=None, invert=False, parent_scale=None, **kwargs): kwsym["linthresh"] = inverse(kwsym["linthresh"]) parent_scale = SymmetricalLogScale(**kwsym) self.functions = (forward, inverse) - self._transform = parent_scale.get_transform() + FuncTransform(forward, inverse) + # Apply the function in data space, then parent scale (e.g., log). + # This ensures dual axes behave correctly when the parent is non-linear. + self._transform = FuncTransform(forward, inverse) + parent_scale.get_transform() # Apply default locators and formatters # NOTE: We pass these through contructor functions From 0ac6dc46d4c06a7c23f4760e545a4ee8389454ef Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Wed, 31 Dec 2025 20:09:13 +1000 Subject: [PATCH 2/2] Add regression test for dualx on log axes --- ultraplot/tests/test_axes.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ultraplot/tests/test_axes.py b/ultraplot/tests/test_axes.py index 370f2c520..27b621c9f 100644 --- a/ultraplot/tests/test_axes.py +++ b/ultraplot/tests/test_axes.py @@ -4,6 +4,7 @@ """ import numpy as np import pytest + import ultraplot as uplt from ultraplot.internals.warnings import UltraPlotWarning @@ -130,6 +131,23 @@ def test_cartesian_format_all_units_types(): ax.format(**kwargs) +def test_dualx_log_transform_is_finite(): + """ + Ensure dualx transforms remain finite on log axes. + """ + fig, ax = uplt.subplots() + ax.set_xscale("log") + ax.set_xlim(0.1, 10) + sec = ax.dualx(lambda x: 1 / x) + fig.canvas.draw() + + ticks = sec.get_xticks() + assert ticks.size > 0 + xy = np.column_stack([ticks, np.zeros_like(ticks)]) + transformed = sec.transData.transform(xy) + assert np.isfinite(transformed).all() + + def test_axis_access(): # attempt to access the ax object 2d and linearly fig, ax = uplt.subplots(ncols=2, nrows=2)