From 294ed5fa6341fe2284833afb2e3c933dcb3c8467 Mon Sep 17 00:00:00 2001 From: Roberto Moura Date: Sun, 15 Jun 2025 18:21:35 +0100 Subject: [PATCH 1/2] Add support for overriding x tick with non arithmetic progression values --- plotly/matplotlylib/mpltools.py | 15 +++++++++++-- plotly/matplotlylib/tests/test_renderer.py | 25 ++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/plotly/matplotlylib/mpltools.py b/plotly/matplotlylib/mpltools.py index 0a3206998b..6e6d843a8c 100644 --- a/plotly/matplotlylib/mpltools.py +++ b/plotly/matplotlylib/mpltools.py @@ -436,9 +436,9 @@ def prep_ticks(ax, index, ax_type, props): tick0 = tickvalues[0] dticks = [ round(tickvalues[i] - tickvalues[i - 1], 12) - for i in range(1, len(tickvalues) - 1) + for i in range(1, len(tickvalues)) ] - if all([dticks[i] == dticks[i - 1] for i in range(1, len(dticks) - 1)]): + if all([dticks[i] == dticks[i - 1] for i in range(1, len(dticks))]): dtick = tickvalues[1] - tickvalues[0] else: warnings.warn( @@ -448,6 +448,8 @@ def prep_ticks(ax, index, ax_type, props): raise TypeError except (IndexError, TypeError): axis_dict["nticks"] = props["axes"][index]["nticks"] + if props["axes"][index]["tickvalues"] is not None: + axis_dict["tickvals"] = props["axes"][index]["tickvalues"] else: axis_dict["tick0"] = tick0 axis_dict["dtick"] = dtick @@ -496,6 +498,15 @@ def prep_ticks(ax, index, ax_type, props): if formatter == "LogFormatterMathtext": axis_dict["exponentformat"] = "e" + elif ( + formatter == "FuncFormatter" and props["axes"][index]["tickformat"] is not None + ): + to_remove = ["dticktickmode"] + for key in to_remove: + if key in axis_dict: + axis_dict.pop(key) + axis_dict["ticktext"] = props["axes"][index]["tickformat"] + axis_dict["tickvals"] = props["axes"][index]["tickvalues"] return axis_dict diff --git a/plotly/matplotlylib/tests/test_renderer.py b/plotly/matplotlylib/tests/test_renderer.py index f56d830917..5991c16bbb 100644 --- a/plotly/matplotlylib/tests/test_renderer.py +++ b/plotly/matplotlylib/tests/test_renderer.py @@ -199,3 +199,28 @@ def test_filled_path_collection_date_xaxis(): filled = [t for t in plotly_fig.data if t.fill == "toself"] assert len(filled) >= 1 assert all(isinstance(x, str) for x in filled[0].x) + + + +def test_non_arithmetic_progression_xtickvals(): + xticks = [0.01, 0.53, 0.75] + plt.figure() + plt.plot([0, 1], [0, 1]) + plt.xticks(xticks) + + plotly_fig = tls.mpl_to_plotly(plt.gcf()) + + assert plotly_fig.layout.xaxis.tickvals == tuple(xticks) + + +def test_non_arithmetic_progression_xticktext(): + xtickvals = [0.01, 0.53, 0.75] + xticktext = ["Baseline", "param = 1", "param = 2"] + plt.figure() + plt.plot([0, 1], [0, 1]) + plt.xticks(xtickvals, xticktext) + + plotly_fig = tls.mpl_to_plotly(plt.gcf()) + + assert plotly_fig.layout.xaxis.tickvals == tuple(xtickvals) + assert plotly_fig.layout.xaxis.ticktext == tuple(xticktext) From 1ea1d904c948229c057eb3a69136b0dc526e938c Mon Sep 17 00:00:00 2001 From: Roberto Moura Date: Mon, 10 Aug 2026 13:56:21 +0100 Subject: [PATCH 2/2] Run ruff format --- plotly/matplotlylib/tests/test_renderer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plotly/matplotlylib/tests/test_renderer.py b/plotly/matplotlylib/tests/test_renderer.py index 5991c16bbb..21d0fb8393 100644 --- a/plotly/matplotlylib/tests/test_renderer.py +++ b/plotly/matplotlylib/tests/test_renderer.py @@ -201,7 +201,6 @@ def test_filled_path_collection_date_xaxis(): assert all(isinstance(x, str) for x in filled[0].x) - def test_non_arithmetic_progression_xtickvals(): xticks = [0.01, 0.53, 0.75] plt.figure()