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
14 changes: 8 additions & 6 deletions python/xy/_figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1075,16 +1075,18 @@ def _zero_baseline_anchor(self, axis_id: str) -> Optional[str]:
continue
base = t.x0.values if axis == "x" else t.y0.values
value = t.x1.values if axis == "x" else t.y1.values
# Ask the questions as masked predicates rather than compacting
# `base`/`value` down to their finite rows first: the compaction
# allocates and copies two full columns per axis per build, and
# every question here is a single "does any row violate this?".
finite = np.isfinite(base) & np.isfinite(value)
if not np.any(finite):
if not finite.any():
continue
base = base[finite]
value = value[finite]
if not np.all(base == 0.0):
if (finite & (base != 0.0)).any():
continue
if np.all(value >= 0.0):
if not (finite & (value < 0.0)).any():
return "lo"
if np.all(value <= 0.0):
if not (finite & (value > 0.0)).any():
return "hi"
return None

Expand Down
15 changes: 14 additions & 1 deletion python/xy/marks.py
Original file line number Diff line number Diff line change
Expand Up @@ -1001,8 +1001,21 @@ def _auto_cap_size(positions: np.ndarray) -> float:

0.25x the median adjacent spacing of the distinct finite positions along
the cap's axis; 0.4 when fewer than two are distinct (no spacing exists).

The positions an error bar carries are usually an ordered independent
variable, and `np.unique` sorts unconditionally — an O(N log N) pass over
the whole column to answer a question about adjacent gaps. One O(N) diff
both proves the column is already non-decreasing and yields those gaps
directly; only an out-of-order column pays for the sort. Same distinct
values in the same order either way, so the median is identical.
"""
distinct = np.unique(positions[np.isfinite(positions)])
finite = positions[np.isfinite(positions)]
if len(finite) >= 2:
gaps = np.diff(finite)
if (gaps >= 0.0).all():
positive = gaps[gaps != 0.0]
return 0.25 * float(np.median(positive)) if len(positive) else 0.4
distinct = np.unique(finite)
if len(distinct) < 2:
return 0.4
return 0.25 * float(np.median(np.diff(distinct)))
Expand Down
Loading