Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2bdd15b
add seaborn context processing
cvanelteren Nov 12, 2025
5cae6f0
rm debug
cvanelteren Nov 12, 2025
0786d28
add unittest
cvanelteren Nov 12, 2025
61ae661
resolve iterable
cvanelteren Nov 12, 2025
6dab0f2
relax legend filter
cvanelteren Nov 12, 2025
2887b3f
add seaborn import
cvanelteren Nov 12, 2025
d542103
add more unittests
cvanelteren Nov 12, 2025
4f9c13b
add ctx texts
cvanelteren Nov 12, 2025
7ea041c
implement mark external and context managing
cvanelteren Nov 12, 2025
c12de2b
fix test
cvanelteren Nov 12, 2025
80fef46
refactor classes for clarity
cvanelteren Nov 12, 2025
7d93bb1
update tests
cvanelteren Nov 12, 2025
288e8bb
more fixes
cvanelteren Nov 12, 2025
8ecccdd
more tests
cvanelteren Nov 12, 2025
aaa1cbc
minor fix
cvanelteren Nov 12, 2025
219e611
minor fix
cvanelteren Nov 12, 2025
3b5c90d
fix for mpl 3.9
cvanelteren Nov 13, 2025
9435fda
remove stack frame
cvanelteren Nov 13, 2025
4c44e82
adjust and remove unecessary tests
cvanelteren Nov 13, 2025
c8635c8
more fixes
cvanelteren Nov 13, 2025
3f969bf
add external to pass test
cvanelteren Nov 13, 2025
1b1ddc4
restore test
cvanelteren Nov 16, 2025
82fbb5d
rm dup
cvanelteren Nov 16, 2025
d5b2aa9
finalize docstring
cvanelteren Nov 16, 2025
8d2824c
remove fallback
cvanelteren Nov 17, 2025
8ee3fe3
Merge branch 'main' into add-seaborn-ctx
cvanelteren Nov 18, 2025
e6ba821
Apply suggestion from @beckermr
beckermr Nov 18, 2025
5923cdb
Apply suggestion from @beckermr
beckermr Nov 18, 2025
5287cdb
fix bar and test
cvanelteren Nov 19, 2025
d5df6a2
Merge branch 'main' into add-seaborn-ctx
cvanelteren Nov 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
add seaborn context processing
  • Loading branch information
cvanelteren committed Nov 12, 2025
commit 2bdd15bdbc97f705dc70fb4a4b68f8c04b209e60
72 changes: 64 additions & 8 deletions ultraplot/axes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import copy
import inspect
import re
import sys
import types
from numbers import Integral, Number
from typing import Union, Iterable, MutableMapping, Optional, Tuple
from collections.abc import Iterable as IterableType
from numbers import Integral, Number
from typing import Iterable, MutableMapping, Optional, Tuple, Union

try:
# From python 3.12
Expand All @@ -34,12 +35,39 @@
from matplotlib import cbook
from packaging import version

from .. import legend as plegend

def _inside_seaborn_call():
"""
Detect seaborn internals on the call stack. Used to suppress on-the-fly
guide updates that can cause duplicate legends/colorbars during seaborn calls.
"""
try:
frame = sys._getframe()
except Exception as e:
print(e)
return False
absolute_names = (
"seaborn.distributions",
"seaborn.categorical",
"seaborn.relational",
"seaborn.regression",
"seaborn.lineplot",
)
print(
frame,
)
while frame is not None:
if frame.f_globals.get("__name__", "") in absolute_names:
return True
frame = frame.f_back
return False


from .. import colors as pcolors
from .. import constructor
from .. import legend as plegend
from .. import ticker as pticker
from ..config import rc
from ..internals import ic # noqa: F401
from ..internals import (
_kwargs_to_args,
_not_none,
Expand All @@ -51,6 +79,7 @@
_version_mpl,
docstring,
guides,
ic, # noqa: F401
labels,
rcsetup,
warnings,
Expand Down Expand Up @@ -1739,14 +1768,20 @@ def _get_legend_handles(self, handler_map=None):
handler_map_full = plegend.Legend.get_default_handler_map()
handler_map_full = handler_map_full.copy()
handler_map_full.update(handler_map or {})
# Prefer synthetic tagging to exclude helper artists; see _ultraplot_synthetic flag on artists.
for ax in axs:
for attr in ("lines", "patches", "collections", "containers"):
for handle in getattr(ax, attr, []): # guard against API changes
label = handle.get_label()
handler = plegend.Legend.get_legend_handler(
handler_map_full, handle
) # noqa: E501
if handler and label and label[0] != "_":
if (
handler
and label
and label[0] != "_"
and not getattr(handle, "_ultraplot_synthetic", False)
):
handles.append(handle)
return handles

Expand Down Expand Up @@ -1894,14 +1929,21 @@ def _update_guide(
colorbar_kw = colorbar_kw or {}
guides._cache_guide_kw(objs, "legend", legend_kw)
guides._cache_guide_kw(objs, "colorbar", colorbar_kw)
print("here", legend)
if legend:
align = legend_kw.pop("align", None)
queue = legend_kw.pop("queue", queue_legend)
self.legend(objs, loc=legend, align=align, queue=queue, **legend_kw)
# Avoid immediate legend creation inside seaborn to prevent duplicates
if not _inside_seaborn_call():
self.legend(objs, loc=legend, align=align, queue=queue, **legend_kw)
if colorbar:
align = colorbar_kw.pop("align", None)
queue = colorbar_kw.pop("queue", queue_colorbar)
self.colorbar(objs, loc=colorbar, align=align, queue=queue, **colorbar_kw)
# Avoid immediate colorbar creation inside seaborn to prevent duplicates
if not _inside_seaborn_call():
self.colorbar(
objs, loc=colorbar, align=align, queue=queue, **colorbar_kw
)

@staticmethod
def _parse_frame(guide, fancybox=None, shadow=None, **kwargs):
Expand Down Expand Up @@ -2423,6 +2465,8 @@ def _legend_label(*objs): # noqa: E301
labs = []
for obj in objs:
if hasattr(obj, "get_label"): # e.g. silent list
if getattr(obj, "_ultraplot_synthetic", False):
continue
lab = obj.get_label()
if lab is not None and not str(lab).startswith("_"):
labs.append(lab)
Expand Down Expand Up @@ -2453,10 +2497,21 @@ def _legend_tuple(*objs): # noqa: E306
if hs:
handles.extend(hs)
elif obj: # fallback to first element
handles.append(obj[0])
# Skip synthetic helpers and fill_between collections
if (
not getattr(obj[0], "_ultraplot_synthetic", False)
and type(obj[0]).__name__ != "FillBetweenPolyCollection"
):
handles.append(obj[0])
else:
handles.append(obj)
elif hasattr(obj, "get_label"):
# Skip synthetic helpers and fill_between collections
if (
getattr(obj, "_ultraplot_synthetic", False)
or type(obj).__name__ == "FillBetweenPolyCollection"
):
continue
handles.append(obj)
else:
warnings._warn_ultraplot(f"Ignoring invalid legend handle {obj!r}.")
Expand Down Expand Up @@ -3322,6 +3377,7 @@ def _label_key(self, side: str) -> str:
labelright/labelleft respectively.
"""
from packaging import version

from ..internals import _version_mpl

# TODO: internal deprecation warning when we drop 3.9, we need to remove this
Expand Down
Loading
Loading