Skip to content

Commit 11d70df

Browse files
fix: flow bins xticklabel correction (#502)
* Fixed index issue in drawing flow bin xticks and added support for drawing flow bins on shared x axes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Initialize xticks, xticklabels as empty array and list instead of None * Filter for shared axes in same column * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Removed drawing dashed line on top of axis * Modified xticklabel formatting to truncate trailing zeros and updated reference images. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent bb93c87 commit 11d70df

File tree

5 files changed

+111
-54
lines changed

5 files changed

+111
-54
lines changed

src/mplhep/plot.py

Lines changed: 111 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -550,68 +550,125 @@ def iterable_not_string(arg):
550550
transform=ax.get_xaxis_transform(),
551551
)
552552

553-
elif flow == "show" and (underflow > 0.0 or overflow > 0.0):
554-
xticks = [label.get_text() for label in ax.get_xticklabels()]
553+
elif flow == "show":
554+
underflow_xticklabel = f"<{flow_bins[1]:.2g}"
555+
overflow_xticklabel = f">{flow_bins[-2]:.2g}"
556+
557+
# Loop over shared x axes to get xticks and xticklabels
558+
xticks, xticklabels = np.array([]), []
559+
shared_axes = ax.get_shared_x_axes().get_siblings(ax)
560+
shared_axes = [
561+
_ax for _ax in shared_axes if _ax.get_position().x0 == ax.get_position().x0
562+
]
563+
for _ax in shared_axes:
564+
_xticks = _ax.get_xticks()
565+
_xticklabels = [label.get_text() for label in _ax.get_xticklabels()]
566+
567+
# Check if underflow/overflow xtick already exists
568+
if (
569+
underflow_xticklabel in _xticklabels
570+
or overflow_xticklabel in _xticklabels
571+
):
572+
xticks = _xticks
573+
xticklabels = _xticklabels
574+
break
575+
elif len(_xticklabels) > 0:
576+
xticks = _xticks
577+
xticklabels = _xticklabels
578+
555579
lw = ax.spines["bottom"].get_linewidth()
556580
_edges = plottables[0].edges
557581
_centers = plottables[0].centers
558582
_marker_size = (
559583
20
560584
* ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted()).width
561585
)
562-
if underflow > 0.0:
563-
xticks[0] = ""
564-
xticks[1] = f"<{flow_bins[2]}"
565-
ax.set_xticks(ax.get_xticks())
566-
ax.set_xticklabels(xticks)
567586

568-
ax.plot(
569-
[_edges[0], _edges[1]],
570-
[0, 0],
571-
color="white",
572-
zorder=5,
573-
ls="--",
574-
lw=lw,
575-
transform=ax.get_xaxis_transform(),
576-
clip_on=False,
577-
)
578-
ax.scatter(
579-
_centers[0],
580-
0,
581-
_marker_size,
582-
marker=align_marker("d", valign="center"),
583-
edgecolor="black",
584-
zorder=5,
585-
clip_on=False,
586-
facecolor="white",
587-
transform=ax.get_xaxis_transform(),
588-
)
589-
if overflow > 0.0:
590-
xticks[-1] = ""
591-
xticks[-2] = f">{flow_bins[-3]}"
592-
ax.set_xticks(ax.get_xticks())
593-
ax.set_xticklabels(xticks)
594-
ax.plot(
595-
[_edges[-2], _edges[-1]],
596-
[0, 0],
597-
color="white",
598-
zorder=5,
599-
ls="--",
600-
lw=lw,
601-
transform=ax.get_xaxis_transform(),
602-
clip_on=False,
603-
)
604-
ax.scatter(
605-
_centers[-1],
606-
0,
607-
_marker_size,
608-
marker=align_marker("d", valign="center"),
609-
edgecolor="black",
610-
zorder=5,
611-
clip_on=False,
612-
facecolor="white",
613-
transform=ax.get_xaxis_transform(),
614-
)
587+
if underflow > 0.0 or underflow_xticklabel in xticklabels:
588+
# Replace any existing xticks in underflow region with underflow bin center
589+
_mask = xticks > flow_bins[1]
590+
xticks = np.insert(xticks[_mask], 0, _centers[0])
591+
xticklabels = [underflow_xticklabel] + [
592+
xlab for i, xlab in enumerate(xticklabels) if _mask[i]
593+
]
594+
595+
# Don't draw markers on the top of the top axis
596+
top_axis = max(shared_axes, key=lambda a: a.get_position().y0)
597+
598+
# Draw on all shared axes
599+
for _ax in shared_axes:
600+
_ax.set_xticks(xticks)
601+
_ax.set_xticklabels(xticklabels)
602+
for h in [0, 1]:
603+
# Don't draw marker on the top of the top axis
604+
if _ax == top_axis and h == 1:
605+
continue
606+
607+
_ax.plot(
608+
[_edges[0], _edges[1]],
609+
[h, h],
610+
color="white",
611+
zorder=5,
612+
ls="--",
613+
lw=lw,
614+
transform=_ax.get_xaxis_transform(),
615+
clip_on=False,
616+
)
617+
618+
_ax.scatter(
619+
_centers[0],
620+
h,
621+
_marker_size,
622+
marker=align_marker("d", valign="center"),
623+
edgecolor="black",
624+
zorder=5,
625+
clip_on=False,
626+
facecolor="white",
627+
transform=_ax.get_xaxis_transform(),
628+
)
629+
if overflow > 0.0 or overflow_xticklabel in xticklabels:
630+
# Replace any existing xticks in overflow region with overflow bin center
631+
_mask = xticks < flow_bins[-2]
632+
xticks = np.insert(xticks[_mask], sum(_mask), _centers[-1])
633+
xticklabels = [xlab for i, xlab in enumerate(xticklabels) if _mask[i]] + [
634+
overflow_xticklabel
635+
]
636+
637+
# Don't draw markers on the top of the top axis
638+
top_axis = max(shared_axes, key=lambda a: a.get_position().y0)
639+
640+
# Draw on all shared axes
641+
for _ax in shared_axes:
642+
_ax.set_xticks(xticks)
643+
_ax.set_xticklabels(xticklabels)
644+
645+
for h in [0, 1]:
646+
# Don't draw marker on the top of the top axis
647+
if _ax == top_axis and h == 1:
648+
continue
649+
650+
_ax.plot(
651+
[_edges[-2], _edges[-1]],
652+
[h, h],
653+
color="white",
654+
zorder=5,
655+
ls="--",
656+
lw=lw,
657+
transform=_ax.get_xaxis_transform(),
658+
clip_on=False,
659+
)
660+
661+
_ax.scatter(
662+
_centers[-1],
663+
h,
664+
_marker_size,
665+
marker=align_marker("d", valign="center"),
666+
edgecolor="black",
667+
zorder=5,
668+
clip_on=False,
669+
facecolor="white",
670+
transform=_ax.get_xaxis_transform(),
671+
)
615672

616673
return return_artists
617674

tests/baseline/test_histplot_flow.png

-298 Bytes
Loading
Loading
-513 Bytes
Loading
-495 Bytes
Loading

0 commit comments

Comments
 (0)