From 3d2d3f4d4798ff18de35f2c17693dbb204da68b4 Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Tue, 27 Jan 2026 19:18:35 +1000 Subject: [PATCH 1/7] Fix ternary tripcolor delegation Delegate tri* plotting calls to external axes and add the ternary tripcolor example. --- docs/examples/plot_types/08_ternary.py | 36 ++++++++++++++++++++++++++ ultraplot/axes/container.py | 28 ++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 docs/examples/plot_types/08_ternary.py diff --git a/docs/examples/plot_types/08_ternary.py b/docs/examples/plot_types/08_ternary.py new file mode 100644 index 000000000..f121e8e4d --- /dev/null +++ b/docs/examples/plot_types/08_ternary.py @@ -0,0 +1,36 @@ +""" +Ternary Plots +============= +Ternary plots are a type of plot that displays the proportions of three variables that sum to a constant. They are commonly used in fields such as geology, chemistry, and materials science to represent the composition of mixtures. UltraPlot makes it easy to create publication-quality ternary plots using the `mpltern` library as a backend. + +Why UltraPlot here? +------------------- +UltraPlot offers seamless integration with `mpltern`, allowing users to create and customize ternary plots with minimal effort. UltraPlot's high-level API simplifies the process of setting up ternary plots, adding data, and formatting the axes and labels. + +See also +-------- +* :doc:`2D plot types ` +* :doc:`External axes containers ` +""" +# %% +import mpltern + + +from mpltern.datasets import get_shanon_entropies, get_spiral +import ultraplot as uplt, numpy as np + +t, l, r, v = get_shanon_entropies() + +fig, ax = uplt.subplots(projection = "ternary") +vmin = 0.0 +vmax = 1.2 +levels = np.linspace(vmin, vmax, 7) + +cs = ax.tripcolor(t, l, r, v, shading='flat', vmin=vmin, vmax=vmax) +ax.set_title("Ternary Plot of Shannon Entropies") +ax.plot(*get_spiral(), color='black', lw=0.5) +colorbar = ax.colorbar(cs) +colorbar.set_label('Entropy', rotation=270, va='baseline') + +fig.show() +uplt.show(block=1) diff --git a/ultraplot/axes/container.py b/ultraplot/axes/container.py index fdad0e01b..b7a38fcab 100644 --- a/ultraplot/axes/container.py +++ b/ultraplot/axes/container.py @@ -602,6 +602,34 @@ def pcolormesh(self, *args, **kwargs): return self._external_axes.pcolormesh(*args, **kwargs) return super().pcolormesh(*args, **kwargs) + def tripcolor(self, *args, **kwargs): + """Delegate tripcolor to external axes.""" + if self._external_axes is not None: + self._external_stale = True # Mark for redraw + return self._external_axes.tripcolor(*args, **kwargs) + return super().tripcolor(*args, **kwargs) + + def tricontour(self, *args, **kwargs): + """Delegate tricontour to external axes.""" + if self._external_axes is not None: + self._external_stale = True # Mark for redraw + return self._external_axes.tricontour(*args, **kwargs) + return super().tricontour(*args, **kwargs) + + def tricontourf(self, *args, **kwargs): + """Delegate tricontourf to external axes.""" + if self._external_axes is not None: + self._external_stale = True # Mark for redraw + return self._external_axes.tricontourf(*args, **kwargs) + return super().tricontourf(*args, **kwargs) + + def triplot(self, *args, **kwargs): + """Delegate triplot to external axes.""" + if self._external_axes is not None: + self._external_stale = True # Mark for redraw + return self._external_axes.triplot(*args, **kwargs) + return super().triplot(*args, **kwargs) + def imshow(self, *args, **kwargs): """Delegate imshow to external axes.""" if self._external_axes is not None: From f709dd49ce8f3353b3af3660a45fa2ce2685494b Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Tue, 27 Jan 2026 19:19:53 +1000 Subject: [PATCH 2/7] Update usage docs --- docs/usage.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/usage.rst b/docs/usage.rst index 7ca540138..1a3f24b9b 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -161,6 +161,8 @@ UltraPlot can be used without installing any of these packages. External axes containers (mpltern, others) ------------------------------------------ +.. _ug_external_axes: + UltraPlot can wrap third-party Matplotlib projections (e.g., ``mpltern``'s ``"ternary"`` projection) in a lightweight container. The container keeps UltraPlot's figure/labeling behaviors while delegating plotting calls to the From e0bdba0379e561fbd10ee5214404b429febc90fe Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Tue, 27 Jan 2026 19:22:51 +1000 Subject: [PATCH 3/7] Correct the link reference --- docs/examples/plot_types/08_ternary.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/examples/plot_types/08_ternary.py b/docs/examples/plot_types/08_ternary.py index f121e8e4d..ef1636acd 100644 --- a/docs/examples/plot_types/08_ternary.py +++ b/docs/examples/plot_types/08_ternary.py @@ -9,8 +9,7 @@ See also -------- -* :doc:`2D plot types ` -* :doc:`External axes containers ` +* :doc:`External axes containers ` """ # %% import mpltern @@ -33,4 +32,3 @@ colorbar.set_label('Entropy', rotation=270, va='baseline') fig.show() -uplt.show(block=1) From b0cf30bceb5cc8da45fe16ae479d440fd8384364 Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Tue, 27 Jan 2026 19:26:40 +1000 Subject: [PATCH 4/7] Jazz up example --- docs/examples/plot_types/08_ternary.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/examples/plot_types/08_ternary.py b/docs/examples/plot_types/08_ternary.py index ef1636acd..de8c3909e 100644 --- a/docs/examples/plot_types/08_ternary.py +++ b/docs/examples/plot_types/08_ternary.py @@ -25,10 +25,11 @@ vmax = 1.2 levels = np.linspace(vmin, vmax, 7) -cs = ax.tripcolor(t, l, r, v, shading='flat', vmin=vmin, vmax=vmax) +cs = ax.tripcolor(t, l, r, v, cmap = "lapaz_r", shading='flat', vmin=vmin, vmax=vmax) ax.set_title("Ternary Plot of Shannon Entropies") -ax.plot(*get_spiral(), color='black', lw=0.5) +ax.plot(*get_spiral(), color='white', lw=1.25) colorbar = ax.colorbar(cs) colorbar.set_label('Entropy', rotation=270, va='baseline') fig.show() +uplt.show(block = 1) From 94d75afb72afc2365eb64ada69462bd7bcc663ea Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Tue, 27 Jan 2026 19:29:09 +1000 Subject: [PATCH 5/7] update workflow --- docs/examples/plot_types/08_ternary.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/examples/plot_types/08_ternary.py b/docs/examples/plot_types/08_ternary.py index de8c3909e..67c5be708 100644 --- a/docs/examples/plot_types/08_ternary.py +++ b/docs/examples/plot_types/08_ternary.py @@ -22,14 +22,13 @@ fig, ax = uplt.subplots(projection = "ternary") vmin = 0.0 -vmax = 1.2 +vmax = 1.0 levels = np.linspace(vmin, vmax, 7) cs = ax.tripcolor(t, l, r, v, cmap = "lapaz_r", shading='flat', vmin=vmin, vmax=vmax) ax.set_title("Ternary Plot of Shannon Entropies") ax.plot(*get_spiral(), color='white', lw=1.25) -colorbar = ax.colorbar(cs) -colorbar.set_label('Entropy', rotation=270, va='baseline') +colorbar = ax.colorbar(cs, loc = "b", align = 'c', title = "Entropy", length = 0.33,) fig.show() uplt.show(block = 1) From 39a137f70d110bd848222c4aad8c86a616726e8b Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Tue, 27 Jan 2026 20:13:17 +1000 Subject: [PATCH 6/7] Docs: fix ternary external axes link --- docs/examples/plot_types/08_ternary.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/examples/plot_types/08_ternary.py b/docs/examples/plot_types/08_ternary.py index 67c5be708..f84eb3384 100644 --- a/docs/examples/plot_types/08_ternary.py +++ b/docs/examples/plot_types/08_ternary.py @@ -9,8 +9,9 @@ See also -------- -* :doc:`External axes containers ` +* :ref:`External axes containers ` """ + # %% import mpltern @@ -20,15 +21,20 @@ t, l, r, v = get_shanon_entropies() -fig, ax = uplt.subplots(projection = "ternary") +fig, ax = uplt.subplots(projection="ternary") vmin = 0.0 vmax = 1.0 levels = np.linspace(vmin, vmax, 7) -cs = ax.tripcolor(t, l, r, v, cmap = "lapaz_r", shading='flat', vmin=vmin, vmax=vmax) +cs = ax.tripcolor(t, l, r, v, cmap="lapaz_r", shading="flat", vmin=vmin, vmax=vmax) ax.set_title("Ternary Plot of Shannon Entropies") -ax.plot(*get_spiral(), color='white', lw=1.25) -colorbar = ax.colorbar(cs, loc = "b", align = 'c', title = "Entropy", length = 0.33,) +ax.plot(*get_spiral(), color="white", lw=1.25) +colorbar = ax.colorbar( + cs, + loc="b", + align="c", + title="Entropy", + length=0.33, +) fig.show() -uplt.show(block = 1) From a78c01afbeadcfef1caa8e1827aa9f92deec9bf9 Mon Sep 17 00:00:00 2001 From: cvanelteren Date: Tue, 27 Jan 2026 20:21:55 +1000 Subject: [PATCH 7/7] fix: link to docs --- docs/usage.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index 1a3f24b9b..f70d90a6f 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -158,11 +158,11 @@ plotting packages. Since these features are optional, UltraPlot can be used without installing any of these packages. +.. _ug_external_axes: + External axes containers (mpltern, others) ------------------------------------------ -.. _ug_external_axes: - UltraPlot can wrap third-party Matplotlib projections (e.g., ``mpltern``'s ``"ternary"`` projection) in a lightweight container. The container keeps UltraPlot's figure/labeling behaviors while delegating plotting calls to the