diff --git a/ultraplot/axes/base.py b/ultraplot/axes/base.py index dc61d8cc5..31e185ab3 100644 --- a/ultraplot/axes/base.py +++ b/ultraplot/axes/base.py @@ -3824,7 +3824,7 @@ def text( bordercolor="w", borderwidth=2, borderinvert=False, - borderstyle="miter", + borderstyle=None, bboxcolor="w", bboxstyle="round", bboxalpha=0.5, @@ -3854,7 +3854,7 @@ def text( The color of the text border. borderinvert : bool, optional If ``True``, the text and border colors are swapped. - borderstyle : {'miter', 'round', 'bevel'}, optional + borderstyle : {'miter', 'round', 'bevel'}, default: :rc:`text.borderstyle` The `line join style \\ `__ used for the border. @@ -3901,6 +3901,7 @@ def text( kwargs.update(_pop_props(kwargs, "text")) # Update the text object using a monkey patch + borderstyle = _not_none(borderstyle, rc["text.borderstyle"]) obj = func(*args, transform=transform, **kwargs) obj.update = labels._update_label.__get__(obj) obj.update( diff --git a/ultraplot/internals/labels.py b/ultraplot/internals/labels.py index a6d05e4df..c7af81452 100644 --- a/ultraplot/internals/labels.py +++ b/ultraplot/internals/labels.py @@ -7,6 +7,7 @@ import matplotlib.text as mtext from matplotlib.font_manager import FontProperties +from ..config import rc from . import ic # noqa: F401 @@ -65,7 +66,7 @@ def _update_label(text, props=None, **kwargs): bordercolor = props.pop("bordercolor", "w") borderinvert = props.pop("borderinvert", False) borderwidth = props.pop("borderwidth", 2) - borderstyle = props.pop("borderstyle", "miter") + borderstyle = props.pop("borderstyle", rc["text.borderstyle"]) if border: facecolor, bgcolor = text.get_color(), bordercolor diff --git a/ultraplot/internals/rcsetup.py b/ultraplot/internals/rcsetup.py index dcb79037b..9c1889a36 100644 --- a/ultraplot/internals/rcsetup.py +++ b/ultraplot/internals/rcsetup.py @@ -707,6 +707,7 @@ def copy(self): "sawtooth", "roundtooth", ) +_validate_joinstyle = _validate_belongs("miter", "round", "bevel") if hasattr(msetup, "_validate_linestyle"): # fancy validation including dashes _validate_linestyle = msetup._validate_linestyle else: # no dashes allowed then but no big deal @@ -1044,6 +1045,12 @@ def copy(self): _validate_pt, "Width of the white border around a-b-c labels.", ), + "text.borderstyle": ( + "bevel", + _validate_joinstyle, + "Join style for text border strokes. Must be one of " + "``'miter'``, ``'round'``, or ``'bevel'``.", + ), "abc.bbox": ( False, _validate_bool, diff --git a/ultraplot/tests/test_axes.py b/ultraplot/tests/test_axes.py index 27ed331c2..5e0e0e9d6 100644 --- a/ultraplot/tests/test_axes.py +++ b/ultraplot/tests/test_axes.py @@ -5,6 +5,7 @@ import numpy as np import pytest +import matplotlib.patheffects as mpatheffects import ultraplot as uplt from ultraplot.internals.warnings import UltraPlotWarning @@ -132,6 +133,31 @@ def test_cartesian_format_all_units_types(): ax.format(**kwargs) +def _get_text_stroke_joinstyle(text): + for effect in text.get_path_effects(): + if isinstance(effect, mpatheffects.Stroke): + for attr in ("joinstyle", "_joinstyle"): + if hasattr(effect, attr): + return getattr(effect, attr) + if hasattr(effect, "_gc"): + return effect._gc.get("joinstyle") + return None + + +def test_text_borderstyle_rc_default(): + fig, ax = uplt.subplots() + with uplt.rc.context({"text.borderstyle": "round"}): + txt = ax.text(0.5, 0.5, "A", border=True) + assert _get_text_stroke_joinstyle(txt) == "round" + + +def test_text_borderstyle_overrides_rc(): + fig, ax = uplt.subplots() + with uplt.rc.context({"text.borderstyle": "round"}): + txt = ax.text(0.5, 0.5, "A", border=True, borderstyle="bevel") + assert _get_text_stroke_joinstyle(txt) == "bevel" + + def test_dualx_log_transform_is_finite(): """ Ensure dualx transforms remain finite on log axes.