@@ -70,6 +70,7 @@ def histplot(
70
70
edges = True ,
71
71
binticks = False ,
72
72
ax = None ,
73
+ flow = None ,
73
74
** kwargs ,
74
75
):
75
76
"""
@@ -130,6 +131,8 @@ def histplot(
130
131
Attempts to draw x-axis ticks coinciding with bin boundaries if feasible.
131
132
ax : matplotlib.axes.Axes, optional
132
133
Axes object (if None, last one is fetched or one is created)
134
+ flow : str, optional {None, "show", "sum", "hint"}
135
+ Whether plot the under/overflow bin. If "show", add additional under/overflow bin. If "sum", add the under/overflow bin content to first/last bin.
133
136
**kwargs :
134
137
Keyword arguments passed to underlying matplotlib functions -
135
138
{'step', 'fill_between', 'errorbar'}.
@@ -171,6 +174,42 @@ def histplot(
171
174
plottables = [
172
175
Plottable (h .values (), edges = final_bins , variances = h .variances ()) for h in hists
173
176
]
177
+ # Show under/overflow bins
178
+ # "show": Add additional bin with 5 times bin width
179
+ if flow == "show" :
180
+ plottables = []
181
+ final_bins = np .array (
182
+ [
183
+ final_bins [0 ] - (final_bins [- 1 ] - final_bins [0 ]) * 0.08 ,
184
+ final_bins [0 ] - (final_bins [- 1 ] - final_bins [0 ]) * 0.03 ,
185
+ * final_bins ,
186
+ final_bins [- 1 ] + (final_bins [- 1 ] - final_bins [0 ]) * 0.03 ,
187
+ final_bins [- 1 ] + (final_bins [- 1 ] - final_bins [0 ]) * 0.08 ,
188
+ ]
189
+ )
190
+ for h in hists :
191
+ value , variance = h .view (flow = True )["value" ], h .view (flow = True )["variance" ]
192
+ value , variance = np .insert (value , - 1 , np .nan ), np .insert (
193
+ variance , - 1 , np .nan
194
+ )
195
+ value , variance = np .insert (value , 1 , np .nan ), np .insert (
196
+ variance , 1 , np .nan
197
+ )
198
+ plottables .append (Plottable (value , edges = final_bins , variances = variance ))
199
+ # "sum": Add under/overflow bin to first/last bin
200
+ elif flow == "sum" :
201
+ plottables = []
202
+ for h in hists :
203
+ value , variance = h .view ()["value" ], h .view ()["variance" ]
204
+ value [0 ], value [- 1 ] = (
205
+ value [0 ] + h .view (flow = True )["value" ][0 ],
206
+ value [- 1 ] + h .view (flow = True )["value" ][- 1 ],
207
+ )
208
+ variance [0 ], variance [- 1 ] = (
209
+ variance [0 ] + h .view (flow = True )["variance" ][0 ],
210
+ variance [- 1 ] + h .view (flow = True )["variance" ][- 1 ],
211
+ )
212
+ plottables .append (Plottable (value , edges = final_bins , variances = variance ))
174
213
175
214
if w2 is not None :
176
215
for _w2 , _plottable in zip (
@@ -397,12 +436,73 @@ def iterable_not_string(arg):
397
436
if binticks :
398
437
_slice = int (round (float (len (final_bins )) / len (ax .get_xticks ()))) + 1
399
438
ax .set_xticks (final_bins [::_slice ])
439
+ elif flow == "show" :
440
+ if binticks :
441
+ _slice = int (round (float (len (final_bins )) / len (ax .get_xticks ()))) + 1
442
+ ax .set_xticks (final_bins [::_slice ])
400
443
else :
401
444
ax .set_xticks (_bin_centers )
402
445
ax .set_xticklabels (xtick_labels )
403
446
404
447
if x_axes_label :
405
448
ax .set_xlabel (x_axes_label )
449
+ if flow == "hint" or flow == "show" :
450
+ underflow , overflow = 0.0 , 0.0
451
+ for h in hists :
452
+ underflow = underflow + h .view (flow = True )["value" ][0 ]
453
+ overflow = overflow + h .view (flow = True )["value" ][- 1 ]
454
+ d = 0.9 # proportion of vertical to horizontal extent of the slanted line
455
+ trans = mpl .transforms .blended_transform_factory (ax .transData , ax .transAxes )
456
+ kwargs = dict (
457
+ marker = [(- 0.5 , - d ), (0.5 , d )],
458
+ markersize = 15 ,
459
+ linestyle = "none" ,
460
+ color = "k" ,
461
+ mec = "k" ,
462
+ mew = 1 ,
463
+ clip_on = False ,
464
+ transform = trans ,
465
+ )
466
+ xticks = ax .get_xticks ().tolist ()
467
+ if underflow > 0.0 :
468
+ if flow == "hint" :
469
+ ax .plot (
470
+ [
471
+ final_bins [0 ] - (final_bins [- 3 ] - final_bins [2 ]) * 0.03 ,
472
+ final_bins [0 ],
473
+ ],
474
+ [0 , 0 ],
475
+ ** kwargs ,
476
+ )
477
+ if flow == "show" :
478
+ ax .plot (
479
+ [final_bins [1 ], final_bins [2 ]],
480
+ [0 , 0 ],
481
+ ** kwargs ,
482
+ )
483
+ xticks [0 ] = ""
484
+ xticks [1 ] = f"<{ final_bins [2 ]} "
485
+
486
+ ax .set_xticklabels (xticks )
487
+ if overflow > 0.0 :
488
+ if flow == "hint" :
489
+ ax .plot (
490
+ [
491
+ final_bins [- 1 ],
492
+ final_bins [- 1 ] + (final_bins [- 3 ] - final_bins [2 ]) * 0.03 ,
493
+ ],
494
+ [0 , 0 ],
495
+ ** kwargs ,
496
+ )
497
+ if flow == "show" :
498
+ ax .plot (
499
+ [final_bins [- 3 ], final_bins [- 2 ]],
500
+ [0 , 0 ],
501
+ ** kwargs ,
502
+ )
503
+ xticks [- 1 ] = ""
504
+ xticks [- 2 ] = f">{ final_bins [- 3 ]} "
505
+ ax .set_xticklabels (xticks )
406
506
407
507
return return_artists
408
508
@@ -420,6 +520,7 @@ def hist2dplot(
420
520
cmin = None ,
421
521
cmax = None ,
422
522
ax = None ,
523
+ flow = None ,
423
524
** kwargs ,
424
525
):
425
526
"""
@@ -460,6 +561,8 @@ def hist2dplot(
460
561
Colorbar maximum.
461
562
ax : matplotlib.axes.Axes, optional
462
563
Axes object (if None, last one is fetched or one is created)
564
+ flow : str, optional {None, "show", "sum","hint"}
565
+ Whether plot the under/overflow bin. If "show", add additional under/overflow bin. If "sum", add the under/overflow bin content to first/last bin. "hint" would highlight the bins with under/overflow contents
463
566
**kwargs :
464
567
Keyword arguments passed to underlying matplotlib function - pcolormesh.
465
568
@@ -482,6 +585,39 @@ def hist2dplot(
482
585
H = hist .values ()
483
586
xbins , xtick_labels = get_plottable_protocol_bins (hist .axes [0 ])
484
587
ybins , ytick_labels = get_plottable_protocol_bins (hist .axes [1 ])
588
+ # Show under/overflow bins
589
+ # "show": Add additional bin with 2 times bin width
590
+ if flow == "show" :
591
+ H = hist .view (flow = True )["value" ]
592
+
593
+ xbins = np .array (
594
+ [
595
+ xbins [0 ] - (xbins [- 1 ] - xbins [0 ]) * 0.08 ,
596
+ xbins [0 ] - (xbins [- 1 ] - xbins [0 ]) * 0.03 ,
597
+ * xbins ,
598
+ xbins [- 1 ] + (xbins [- 1 ] - xbins [0 ]) * 0.03 ,
599
+ xbins [- 1 ] + (xbins [- 1 ] - xbins [0 ]) * 0.08 ,
600
+ ]
601
+ )
602
+ ybins = np .array (
603
+ [
604
+ ybins [0 ] - (ybins [- 1 ] - ybins [0 ]) * 0.08 ,
605
+ ybins [0 ] - (ybins [- 1 ] - ybins [0 ]) * 0.03 ,
606
+ * ybins ,
607
+ ybins [- 1 ] + (ybins [- 1 ] - ybins [0 ]) * 0.03 ,
608
+ ybins [- 1 ] + (ybins [- 1 ] - ybins [0 ]) * 0.08 ,
609
+ ]
610
+ )
611
+ H = np .insert (H , (1 , - 1 ), np .nan , axis = - 1 )
612
+ H = np .insert (H , (1 , - 1 ), np .full (np .shape (H )[1 ], np .nan ), axis = 0 )
613
+
614
+ if flow == "sum" :
615
+ H [0 , 0 ], H [- 1 , - 1 ], H [0 , - 1 ], H [- 1 , 0 ] = (
616
+ hist .view (flow = True )["value" ][0 , 0 ] + H [0 , 0 ],
617
+ hist .view (flow = True )["value" ][- 1 , - 1 ] + H [- 1 , - 1 ],
618
+ hist .view (flow = True )["value" ][0 , - 1 ] + H [0 , - 1 ],
619
+ hist .view (flow = True )["value" ][- 1 , 0 ] + H [- 1 , 0 ],
620
+ )
485
621
xbin_centers = xbins [1 :] - np .diff (xbins ) / float (2 )
486
622
ybin_centers = ybins [1 :] - np .diff (ybins ) / float (2 )
487
623
@@ -536,6 +672,76 @@ def hist2dplot(
536
672
cb_obj = None
537
673
538
674
plt .sca (ax )
675
+ if flow == "hint" or flow == "show" :
676
+ d = 0.9 # proportion of vertical to horizontal extent of the slanted line
677
+ trans = mpl .transforms .blended_transform_factory (ax .transData , ax .transAxes )
678
+ kwargs = dict (
679
+ marker = [(- 0.5 , - d ), (0.5 , d )],
680
+ markersize = 15 ,
681
+ linestyle = "none" ,
682
+ color = "k" ,
683
+ mec = "k" ,
684
+ mew = 1 ,
685
+ clip_on = False ,
686
+ )
687
+ xticks = ax .get_xticks ().tolist ()
688
+ yticks = ax .get_yticks ().tolist ()
689
+ if hist .view (flow = True )["value" ][0 , 0 ] > 0.0 :
690
+ if flow == "hint" :
691
+ ax .plot (
692
+ [xbins [0 ] - (xbins [- 3 ] - xbins [2 ]) * 0.03 , xbins [0 ]],
693
+ [0 , 0 ],
694
+ transform = trans ,
695
+ ** kwargs ,
696
+ )
697
+ if flow == "show" :
698
+ ax .plot ([xbins [1 ], xbins [2 ]], [0 , 0 ], transform = trans , ** kwargs )
699
+ ax .plot ([xbins [0 ], xbins [0 ]], [ybins [1 ], ybins [2 ]], ** kwargs )
700
+ xticks [0 ] = ""
701
+ xticks [1 ] = f"<{ xbins [1 ]} "
702
+ ax .set_xticklabels (xticks )
703
+ if hist .view (flow = True )["value" ][- 1 , 0 ] > 0.0 :
704
+ if flow == "hint" :
705
+ ax .plot (
706
+ [xbins [- 1 ] + (xbins [- 3 ] - xbins [2 ]) * 0.03 , xbins [- 1 ]],
707
+ [0 , 0 ],
708
+ transform = trans ,
709
+ ** kwargs ,
710
+ )
711
+ if flow == "show" :
712
+ ax .plot ([xbins [- 3 ], xbins [- 2 ]], [0 , 0 ], transform = trans , ** kwargs )
713
+ ax .plot ([xbins [- 1 ], xbins [- 1 ]], [ybins [1 ], ybins [2 ]], ** kwargs )
714
+ xticks [- 1 ] = ""
715
+ xticks [- 2 ] = f">{ xbins [- 2 ]} "
716
+ ax .set_xticklabels (xticks )
717
+ if hist .view (flow = True )["value" ][0 , - 1 ] > 0.0 :
718
+ if flow == "hint" :
719
+ ax .plot (
720
+ [xbins [0 ], xbins [0 ] - (xbins [- 3 ] - xbins [2 ]) * 0.03 ],
721
+ [1 , 1 ],
722
+ transform = trans ,
723
+ ** kwargs ,
724
+ )
725
+ if flow == "show" :
726
+ ax .plot ([xbins [1 ], xbins [2 ]], [1 , 1 ], transform = trans , ** kwargs )
727
+ ax .plot ([xbins [0 ], xbins [0 ]], [ybins [- 3 ], ybins [- 2 ]], ** kwargs )
728
+ yticks [0 ] = ""
729
+ yticks [1 ] = f"<{ ybins [1 ]} "
730
+ ax .set_yticklabels (yticks )
731
+ if hist .view (flow = True )["value" ][- 1 , - 1 ] > 0.0 :
732
+ if flow == "hint" :
733
+ ax .plot (
734
+ [xbins [- 1 ] + (xbins [- 3 ] - xbins [2 ]) * 0.03 , xbins [- 1 ]],
735
+ [1 , 1 ],
736
+ transform = trans ,
737
+ ** kwargs ,
738
+ )
739
+ if flow == "show" :
740
+ ax .plot ([xbins [- 3 ], xbins [- 2 ]], [1 , 1 ], transform = trans , ** kwargs )
741
+ ax .plot ([xbins [- 1 ], xbins [- 1 ]], [ybins [- 3 ], ybins [- 2 ]], ** kwargs )
742
+ yticks [- 1 ] = ""
743
+ yticks [- 2 ] = f">{ ybins [- 2 ]} "
744
+ ax .set_yticklabels (yticks )
539
745
540
746
_labels : np .ndarray | None = None
541
747
if isinstance (labels , bool ):
0 commit comments