plot_histogram.py
1 #!/usr/bin/env python 2 # /// script 3 # requires-python = ">=3.10" 4 # dependencies = [ 5 # "matplotlib", 6 # "pyqt6", 7 # "numpy", 8 # ] 9 # /// 10 11 """This program shows `hyperfine` benchmark results as a histogram.""" 12 13 import argparse 14 import json 15 16 import matplotlib.pyplot as plt 17 import numpy as np 18 19 parser = argparse.ArgumentParser(description=__doc__) 20 parser.add_argument("file", help="JSON file with benchmark results") 21 parser.add_argument("--title", help="Plot title") 22 parser.add_argument( 23 "--labels", help="Comma-separated list of entries for the plot legend" 24 ) 25 parser.add_argument("--bins", help="Number of bins (default: auto)") 26 parser.add_argument( 27 "--legend-location", 28 help="Location of the legend on plot (default: upper center)", 29 choices=[ 30 "upper center", 31 "lower center", 32 "right", 33 "left", 34 "best", 35 "upper left", 36 "upper right", 37 "lower left", 38 "lower right", 39 "center left", 40 "center right", 41 "center", 42 ], 43 default="upper center", 44 ) 45 parser.add_argument( 46 "--type", help="Type of histogram (*bar*, barstacked, step, stepfilled)" 47 ) 48 parser.add_argument("-o", "--output", help="Save image to the given filename.") 49 parser.add_argument( 50 "--t-min", metavar="T", help="Minimum time to be displayed (seconds)" 51 ) 52 parser.add_argument( 53 "--t-max", metavar="T", help="Maximum time to be displayed (seconds)" 54 ) 55 parser.add_argument( 56 "--log-count", 57 help="Use a logarithmic y-axis for the event count", 58 action="store_true", 59 ) 60 61 args = parser.parse_args() 62 63 with open(args.file) as f: 64 results = json.load(f)["results"] 65 66 if args.labels: 67 labels = args.labels.split(",") 68 else: 69 labels = [b["command"] for b in results] 70 all_times = [b["times"] for b in results] 71 72 t_min = float(args.t_min) if args.t_min else np.min(list(map(np.min, all_times))) 73 t_max = float(args.t_max) if args.t_max else np.max(list(map(np.max, all_times))) 74 75 bins = int(args.bins) if args.bins else "auto" 76 histtype = args.type if args.type else "bar" 77 78 plt.figure(figsize=(10, 5)) 79 plt.hist( 80 all_times, 81 label=labels, 82 bins=bins, 83 histtype=histtype, 84 range=(t_min, t_max), 85 ) 86 plt.legend( 87 loc=args.legend_location, 88 fancybox=True, 89 shadow=True, 90 prop={"size": 10, "family": ["Source Code Pro", "Fira Mono", "Courier New"]}, 91 ) 92 93 plt.xlabel("Time [s]") 94 if args.title: 95 plt.title(args.title) 96 97 if args.log_count: 98 plt.yscale("log") 99 else: 100 plt.ylim(0, None) 101 102 if args.output: 103 plt.savefig(args.output, dpi=600) 104 else: 105 plt.show()