1313# limitations under the License.
1414import argparse
1515from pathlib import Path
16+ from typing import Any , Optional
1617
1718import matplotlib .pyplot as plt
1819import numpy as np
1920import pandas as pd
21+ from matplotlib .axes import Axes
22+
23+ from .stats import Stats
24+
25+ NDArray = Any
2026
2127
2228def plot (output_dir : Path ) -> None :
2329 result_dfs = [pd .read_csv (f ) for f in output_dir .glob ("results_*.csv" )]
2430 results_df = pd .concat (result_dfs , axis = "index" , ignore_index = True )
2531
26- n_columns = 2
32+ n_columns = 3
2733 n_rows = len (results_df .name .unique ())
2834 width = 6 * n_columns
2935 height = 4 * n_rows
@@ -37,74 +43,46 @@ def plot(output_dir: Path) -> None:
3743
3844 for i , (ax_name , ax_df ) in enumerate (results_df .groupby ("name" )):
3945 line_xs = []
40- line_y_with_means = []
41- line_y_with_uppers = []
42- line_y_with_lowers = []
43- line_y_without_means = []
44- line_y_without_uppers = []
45- line_y_without_lowers = []
46- line_y_overhead_means = []
47- line_y_overhead_uppers = []
48- line_y_overhead_lowers = []
46+ line_ys = []
4947
5048 for timestamp , timestamp_df in ax_df .groupby ("timestamp" ):
51- by_cs = timestamp_df .groupby ("check_shapes" )
52- mean_by_cs = by_cs .time_s .mean ()
53- std_by_cs = by_cs .time_s .std ().fillna (0.0 )
54- var_by_cs = by_cs .time_s .var ().fillna (0.0 )
55-
56- with_mean = mean_by_cs [True ]
57- with_mean_sq = with_mean ** 2
58- with_std = std_by_cs [True ]
59- with_var = var_by_cs [True ]
60- without_mean = mean_by_cs [False ]
61- without_mean_sq = without_mean ** 2
62- without_std = std_by_cs [False ]
63- without_var = var_by_cs [False ]
64-
65- overhead_mean = (with_mean / without_mean ) - 1
66- # https://en.wikipedia.org/wiki/Ratio_distribution#Uncorrelated_noncentral_normal_ratio
67- overhead_var = (with_mean_sq / without_mean_sq ) * (
68- (with_var / with_mean_sq ) + (without_var / without_mean_sq )
69- )
70- overhead_std = np .sqrt (overhead_var )
71-
7249 line_xs .append (timestamp )
73- line_y_with_means .append (with_mean )
74- line_y_with_uppers .append (with_mean + 1.96 * with_std )
75- line_y_with_lowers .append (with_mean - 1.96 * with_std )
76- line_y_without_means .append (without_mean )
77- line_y_without_uppers .append (without_mean + 1.96 * without_std )
78- line_y_without_lowers .append (without_mean - 1.96 * without_std )
79- line_y_overhead_means .append (100 * overhead_mean )
80- line_y_overhead_uppers .append (100 * (overhead_mean + 1.96 * overhead_std ))
81- line_y_overhead_lowers .append (100 * (overhead_mean - 1.96 * overhead_std ))
50+ line_ys .append (Stats .new (timestamp_df ))
51+
52+ def plot_mean_and_std (
53+ ax : Axes , prefix : str , * , label : Optional [str ] = None , scale : float = 1.0
54+ ) -> None :
55+ mean_name = f"{ prefix } _mean"
56+ std_name = f"{ prefix } _std"
57+
58+ # pylint: disable=cell-var-from-loop
59+ mean : NDArray = np .array ([getattr (y , mean_name ) for y in line_ys ]) * scale
60+ std : NDArray = np .array ([getattr (y , std_name ) for y in line_ys ]) * scale
61+ lower : NDArray = mean - 1.96 * std
62+ upper : NDArray = mean + 1.96 * std
63+
64+ (mean_line ,) = ax .plot (line_xs , mean , label = label )
65+ color = mean_line .get_color ()
66+ ax .fill_between (line_xs , lower , upper , color = color , alpha = 0.3 )
67+
68+ ax .set_title (ax_name )
69+ ax .tick_params (axis = "x" , labelrotation = 30 )
70+ if np .min (lower ) > 0 :
71+ ax .set_ylim (bottom = 0.0 )
8272
8373 ax = axes [i ][0 ]
84- (mean_line ,) = ax .plot (line_xs , line_y_with_means , label = "with check_shapes" )
85- color = mean_line .get_color ()
86- ax .fill_between (line_xs , line_y_with_lowers , line_y_with_uppers , color = color , alpha = 0.3 )
87- (mean_line ,) = ax .plot (line_xs , line_y_without_means , label = "without check_shapes" )
88- color = mean_line .get_color ()
89- ax .fill_between (
90- line_xs , line_y_without_lowers , line_y_without_uppers , color = color , alpha = 0.3
91- )
92- ax .set_title (ax_name )
74+ plot_mean_and_std (ax , "with" , label = "with check_shapes" )
75+ plot_mean_and_std (ax , "without" , label = "without check_shapes" )
9376 ax .set_ylabel ("time / s" )
94- ax .tick_params (axis = "x" , labelrotation = 30 )
9577 ax .legend ()
9678
9779 ax = axes [i ][1 ]
98- (mean_line ,) = ax .plot (line_xs , line_y_overhead_means )
99- color = mean_line .get_color ()
100- ax .fill_between (
101- line_xs , line_y_overhead_lowers , line_y_overhead_uppers , color = color , alpha = 0.3
102- )
103- ax .set_title (ax_name )
80+ plot_mean_and_std (ax , "abs_overhead" )
81+ ax .set_ylabel ("overhead / s" )
82+
83+ ax = axes [i ][2 ]
84+ plot_mean_and_std (ax , "rel_overhead" , scale = 100.0 )
10485 ax .set_ylabel ("% overhead" )
105- if np .min (line_y_overhead_lowers ) >= 0 :
106- ax .set_ylim (bottom = 0.0 )
107- ax .tick_params (axis = "x" , labelrotation = 30 )
10886
10987 fig .tight_layout ()
11088 fig .savefig (output_dir / "overhead.png" )
0 commit comments