Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 23 additions & 7 deletions ultraplot/axes/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -3509,7 +3509,9 @@ def _fix_sticky_edges(self, objs, axis, *args, only=None):
edges.extend(convert((min_, max_)))

@staticmethod
def _fix_patch_edges(obj, edgefix=None, **kwargs):
def _fix_patch_edges(
obj, edgefix=None, default_linewidth: float | None = None, **kwargs
):
"""
Fix white lines between between filled patches and fix issues
with colormaps that are transparent. If keyword args passed by user
Expand All @@ -3520,7 +3522,11 @@ def _fix_patch_edges(obj, edgefix=None, **kwargs):
# See: https://github.com/jklymak/contourfIssues
# See: https://stackoverflow.com/q/15003353/4970632
edgefix = _not_none(edgefix, rc.edgefix, True)
linewidth = EDGEWIDTH if edgefix is True else 0 if edgefix is False else edgefix
linewidth = (
_not_none(default_linewidth, EDGEWIDTH)
if edgefix is True
else 0 if edgefix is False else edgefix
)
if not linewidth:
return
keys = ("linewidth", "linestyle", "edgecolor") # patches and collections
Expand Down Expand Up @@ -3557,7 +3563,9 @@ def _fix_patch_edges(obj, edgefix=None, **kwargs):
obj.set_edgecolor(obj.get_facecolor())
elif np.iterable(obj): # e.g. silent_list of BarContainer
for element in obj:
PlotAxes._fix_patch_edges(element, edgefix=edgefix)
PlotAxes._fix_patch_edges(
element, edgefix=edgefix, default_linewidth=default_linewidth
)
else:
warnings._warn_ultraplot(
f"Unexpected obj {obj} passed to _fix_patch_edges."
Expand Down Expand Up @@ -5756,7 +5764,9 @@ def _apply_fill(
# No synthetic tagging or seaborn-based label overrides

# Patch edge fixes
self._fix_patch_edges(obj, **edgefix_kw, **kw)
self._fix_patch_edges(
obj, default_linewidth=rc["patch.linewidth"], **edgefix_kw, **kw
)

# Track sides for sticky edges
xsides.append(x)
Expand Down Expand Up @@ -6039,7 +6049,9 @@ def _apply_bar(
if isinstance(obj, mcontainer.BarContainer):
self._add_bar_labels(obj, orientation=orientation, **bar_labels_kw)

self._fix_patch_edges(obj, **edgefix_kw, **kw)
self._fix_patch_edges(
obj, default_linewidth=rc["patch.linewidth"], **edgefix_kw, **kw
)
for y in (b, b + h):
self._inbounds_xylim(extents, x, y, orientation=orientation)

Expand Down Expand Up @@ -6162,7 +6174,9 @@ def pie(self, x, explode, *, labelpad=None, labeldistance=None, **kwargs):
**kw,
)
objs = tuple(cbook.silent_list(type(seq[0]).__name__, seq) for seq in objs)
self._fix_patch_edges(objs[0], **edgefix_kw, **wedge_kw)
self._fix_patch_edges(
objs[0], default_linewidth=rc["patch.linewidth"], **edgefix_kw, **wedge_kw
)
return objs

@staticmethod
Expand Down Expand Up @@ -7074,7 +7088,9 @@ def _apply_hist(
kw = self._parse_cycle(n, **kw)
obj = self._call_native("hist", xs, orientation=orientation, **kw)
if histtype.startswith("bar"):
self._fix_patch_edges(obj[2], **edgefix_kw, **kw)
self._fix_patch_edges(
obj[2], default_linewidth=rc["patch.linewidth"], **edgefix_kw, **kw
)
# Revert to mpl < 3.3 behavior where silent_list was always returned for
# non-bar-type histograms. Because consistency.
res = obj[2]
Expand Down
39 changes: 39 additions & 0 deletions ultraplot/tests/test_plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,45 @@ def test_error_shading_explicit_label_external():
assert "Band" in labels


def test_patch_linewidth_rc_controls_patch_edgefix() -> None:
"""
Patch-style artists should honor rc patch linewidth even when edge-fix is active.
"""
expected = 3.5
with uplt.rc.context({"patch.linewidth": expected}):
fig, axs = uplt.subplots(ncols=4)

bar = axs[0].bar([1, 2], [3, 4])
fill = axs[1].fill_between([0, 1, 2], [1, 2, 1])
hist = axs[2].hist(np.arange(5))
pie = axs[3].pie([1, 2, 3])

assert [patch.get_linewidth() for patch in bar.patches] == pytest.approx(
[expected, expected]
)
assert np.atleast_1d(fill.get_linewidths()) == pytest.approx([expected])
assert [patch.get_linewidth() for patch in hist[2]] == pytest.approx(
[expected] * len(hist[2])
)
assert [wedge.get_linewidth() for wedge in pie[0]] == pytest.approx(
[expected] * len(pie[0])
)

uplt.close(fig)


def test_patch_linewidth_rc_does_not_override_collection_edgefix() -> None:
"""
Collection-style 2D artists keep their dedicated edge-fix linewidth.
"""
with uplt.rc.context({"patch.linewidth": 3.5}):
fig, ax = uplt.subplots()
mesh = ax.pcolormesh(np.arange(9).reshape(3, 3))
assert np.atleast_1d(mesh.get_linewidth()) == pytest.approx([0.3])

uplt.close(fig)


def test_graph_nodes_kw():
"""Test the graph method by setting keywords for nodes"""
import networkx as nx
Expand Down
Loading