diff --git a/scripts/parse.nu b/scripts/parse.nu index 3fb4b86990fe33ba3e0065c2f0acb79190584365..62ebc49debb9c5006e0c3867069f2a0354b30fbb 100644 --- a/scripts/parse.nu +++ b/scripts/parse.nu @@ -2,9 +2,10 @@ export def read-atomic-ops [ --include: list<string> = [], --exclude: list<string> = [] ]: list -> record { let raw = $in - | insert t {|it| $it.times |math avg} + | insert t {|it| $it.times | math avg} + | insert s {|it| $it.times | into int | into float | math stddev | into int | into duration} | reject times - | rename --column { label: "group", name: "species", t: "measurement" } + | rename --column { label: "group", name: "species", t: "measurement", s: "variance" } let included = if $include != [] { $raw | where group in $include @@ -16,7 +17,9 @@ export def read-atomic-ops [ | where group not-in $exclude | group-by group --to-table | reject items.group - | update items { transpose -r | into record } + | update items { + each {|it| {$it.species: ($it | reject species)}} | into record | flatten | into record + } | transpose -r | into record } diff --git a/scripts/plot/multi_bar.py b/scripts/plot/multi_bar.py index de24c7c6bfb1ebc87db1cf9f6988e44e4afd85ee..eaa47b904dce3f4e7674496bbc6af69039ffbf76 100644 --- a/scripts/plot/multi_bar.py +++ b/scripts/plot/multi_bar.py @@ -15,19 +15,19 @@ import argparse # ```json # { # "age": { -# "alice": 31, -# "bob": 28, -# "charlie": 44 +# "alice": { "measurement": 31, "variance": 0.1 }, +# "bob": { "measurement": 28, "variance": 0.2 }, +# "charlie": { "measurement": 44, "variance": 0.3 } # }, # "height": { -# "alice": 1.50, -# "bob": 1.82, -# "charlie": 1.65 +# "alice": { "measurement": 1.50, "variance": 0.4 }, +# "bob": { "measurement": 1.82, "variance": 0.5 }, +# "charlie": { "measurement": 1.65, "variance": 0.6 } # }, # "weight": { -# "alice": 65.3, -# "bob": 98.1, -# "charlie": 68.7 +# "alice": { "measurement": 65.3, "variance": 0.7 }, +# "bob": { "measurement": 98.1, "variance": 0.8 }, +# "charlie": { "measurement": 68.7, "variance": 0.9 } # } # } # ``` @@ -40,15 +40,22 @@ import argparse # "bob": [1.82, 28, 98.1], # "charlie": [1.65, 44, 68.7] # } +# variances = { +# "alice": [0.1, 0.4, 0.7], +# "bob": [0.2, 0.5, 0.8], +# "charlie": [0.3, 0.6, 0.9] +# } # ``` -def extract(data: Dict[str, Dict[str, float]]) -> (List[str], Dict[str, List[float]]): +def extract(data: Dict[str, Dict[str, float]]) -> (List[str], Dict[str, List[float]], Dict[str, List[float]]): groups = list(data.keys()) measurements = {} + variances = {} for x in data[groups[0]].keys(): - measurements[x] = [data[g][x] for g in groups] + measurements[x] = [data[g][x]["measurement"] for g in groups] + variances[x] = [data[g][x]["variance"] for g in groups] - return (groups, measurements) + return (groups, measurements, variances) # plot multi bars @@ -58,6 +65,7 @@ def extract(data: Dict[str, Dict[str, float]]) -> (List[str], Dict[str, List[flo def plot_multi_bar( groups: List[str], measurements: Dict[str, List[float]], + variances: Dict[str, List[float]], title: str, y_label: str, labels_locations: List[float] = None, @@ -73,16 +81,19 @@ def plot_multi_bar( fig, ax = plt.subplots(layout=plot_layout) multiplier = 0 - for attribute, measurement in measurements.items(): + for (attribute, measurement), variance in zip(measurements.items(), variances.values()): offset = width * multiplier rects = ax.bar(labels_locations + offset, measurement, width, label=attribute) ax.bar_label(rects, padding=3) + for (x, y, e) in zip(labels_locations + offset, measurement, variance): + ax.errorbar(x, y, yerr=e, fmt='-o', color="black") multiplier += 1 ax.set_ylabel(y_label) ax.set_title(title) ax.set_xticks(labels_locations + width, groups) ax.legend(loc=legend_loc, ncols=nb_legend_cols) + ax.set_ylim([0, None]) if save is not None: fig.set_size_inches((16, 9), forward=False) @@ -99,19 +110,19 @@ if __name__ == "__main__": the actual data to show in a multibar plot, here is an example: { "age": { - "alice": 31, - "bob": 28, - "charlie": 44 + "alice": { "measurement": 31, "variance": 0.1 }, + "bob": { "measurement": 28, "variance": 0.2 }, + "charlie": { "measurement": 44, "variance": 0.3 } }, "height": { - "alice": 1.50, - "bob": 1.82, - "charlie": 1.65 + "alice": { "measurement": 1.50, "variance": 0.4 }, + "bob": { "measurement": 1.82, "variance": 0.5 }, + "charlie": { "measurement": 1.65, "variance": 0.6 } }, "weight": { - "alice": 65.3, - "bob": 98.1, - "charlie": 68.7 + "alice": { "measurement": 65.3, "variance": 0.7 }, + "bob": { "measurement": 98.1, "variance": 0.8 }, + "charlie": { "measurement": 68.7, "variance": 0.9 } } } """) @@ -121,10 +132,16 @@ if __name__ == "__main__": parser.add_argument("--save", "-s", type=str, help="a path to save the figure to") args = parser.parse_args() - groups, measurements = extract(json.loads(args.data)) + groups, measurements, variances = extract(json.loads(args.data)) plot_layout = "constrained" if args.fullscreen else None plot_multi_bar( - groups, measurements, args.title, args.label, save=args.save, plot_layout=plot_layout + groups, + measurements, + variances, + args.title, + args.label, + save=args.save, + plot_layout=plot_layout )