24
24
25
25
import matplotlib .pyplot as plt
26
26
27
+ from typing import Optional
28
+
27
29
# https://cduvallet.github.io/posts/2018/03/boxplots-in-python
28
30
plt .rcdefaults ()
29
31
@@ -54,7 +56,7 @@ def get_stats(results_path, stats_keys):
54
56
stats_dict = {stats_key : {"mean" : [], "stddev" : []} for stats_key in stats_keys .keys ()}
55
57
56
58
keys = list (stats_keys .keys ())
57
- print (f"Statis dict { stats_dict } " )
59
+ # print(f"Statis dict {stats_dict}")
58
60
59
61
for folder in sub_folders :
60
62
if eval_files .check_if_results_folder (folder ):
@@ -69,34 +71,50 @@ def get_stats(results_path, stats_keys):
69
71
70
72
return stats_dict
71
73
72
- def main (results_path , details ):
74
+
75
+ def plot (results_path , details_list ):
76
+
77
+ num_details = len (details_list )
78
+ fig , axes = plt .subplots (nrows = num_details , ncols = 1 , constrained_layout = True )
79
+
80
+ from string import ascii_lowercase
81
+
82
+ alphabet = iter (ascii_lowercase )
83
+
84
+ for ax , details in zip (axes , details_list ):
85
+ letter = next (alphabet )
86
+ title = f"({ letter } )"
87
+
88
+ detail_name = details .get ("name" , None )
89
+ if detail_name is not None :
90
+ title += f" { detail_name } "
91
+
92
+ main (results_path , ax , details , title = title )
93
+
94
+ fig .tight_layout ()
95
+ plt .show ()
96
+
97
+ def main (results_path :str , ax : plt .Axes , details : dict , title : Optional [str ] = None ):
73
98
stats_keys = details ["keys" ]
74
99
log_scale = details .get ("log_scale" , False )
75
100
stats_dict = get_stats (results_path , stats_keys )
76
101
means = {}
77
- stddev = {}
78
- print (log_scale )
79
102
for key , stats in stats_dict .items ():
80
103
81
104
label = stats_keys [key ]["label" ]
82
-
83
105
data = stats ["mean" ]
84
106
85
107
# label could be in twice if we want to map a stats key to the same label
86
108
if label in means :
87
- means [label ].extends (data )
109
+ means [label ].extend (data )
88
110
else :
89
111
means [label ] = data
90
- # stddev[label] = stats["stddev"]
91
112
92
- # df = pd.DataFrame({k: pd.Series(v) for k, v in means.items()})
93
113
# Convert the dictionary into a DataFrame with varying lengths (introducing NaNs)
94
114
df = pd .DataFrame (dict ([(k , pd .Series (v )) for k , v in means .items ()]))
115
+ for series_name , series in df .items ():
116
+ print (f"{ series_name } : max { series .mean ()} min { series .min ()} max { series .max ()} " )
95
117
96
- # Prepare the data as a list of arrays (each array can have different length)
97
- data_for_boxplot = [df [col ].dropna ().values for col in df .columns ]
98
- fig = plt .figure (figsize = (13 ,5 ))
99
- ax = fig .gca ()
100
118
101
119
102
120
boxprops = { 'linewidth' : 2 , 'facecolor' : 'w' }
@@ -111,7 +129,14 @@ def main(results_path, details):
111
129
112
130
# boxplot = ax.boxplot(data_for_boxplot, labels=df.columns,patch_artist=True)
113
131
# ax.set_yscale("log")
114
- sns .boxplot (data = df ,ax = ax ,fliersize = 0 , saturation = 0.6 ,log_scale = log_scale ,patch_artist = True )
132
+ sns .boxplot (
133
+ data = df ,
134
+ ax = ax ,
135
+ fliersize = 0 ,
136
+ saturation = 0.6 ,
137
+ log_scale = log_scale ,
138
+ patch_artist = True ,
139
+ width = 0.8 )
115
140
116
141
colour_iter = itertools .cycle (formatting .prop_cycle ())
117
142
sns .stripplot (data = df ,
@@ -141,24 +166,21 @@ def main(results_path, details):
141
166
ax .grid (True , alpha = 0.5 )
142
167
ax .yaxis .grid (True )
143
168
ax .xaxis .grid (False ) # Show the vertical gridlines
144
- # ax.grid(True)
145
- # # ax.set_yscale("log")
146
- fig .tight_layout ()
147
169
170
+ if title is not None :
171
+ ax .set_title (title , loc = "left" , pad = 10 )
148
172
149
173
150
- plt .show ()
151
174
152
175
def get_all_stats (results_folder , stats_dict , stats_key ):
153
176
154
- print (f"Starting results folder { results_folder } " )
155
- print (f"Stats keys { stats_key } " )
177
+ # print(f"Starting results folder {results_folder}")
178
+ # print(f"Stats keys {stats_key}")
156
179
157
180
sub_files = [os .path .join (results_folder , name ) for name in os .listdir (results_folder )]
158
181
# from all the logging files in the results folder, get those prefixed by stats
159
182
stats_files = list (filter (lambda file : Path (file ).name .startswith ("stats_" ) and Path (file ).name .endswith ("csv" ), sub_files ))
160
183
161
- print (stats_key )
162
184
for stats_file in stats_files :
163
185
164
186
@@ -171,98 +193,28 @@ def get_all_stats(results_folder, stats_dict, stats_key):
171
193
stats_dict ["stddev" ].append (float (row ["stddev" ]))
172
194
173
195
174
- # def make_batch_plots()
175
-
176
-
177
- # def make_POM_plots(results_path):
178
- # print(f"Iterating over parent results path {results_path}")
179
- # sub_folders = [os.path.join(results_path, name) for name in os.listdir(results_path) if os.path.isdir(os.path.join(results_path, name))]
180
-
181
- # timing_results = {}
182
-
183
- # for folder in sub_folders:
184
- # if not eval_files.check_if_results_folder(folder):
185
- # continue
186
-
187
- # # ignore the frontend-testing ones
188
- # if not "_POM" in Path(folder).name:
189
- # continue
190
-
191
- # print(f"Processing POM for {folder}")
192
-
193
- # folder = Path(folder)
194
- # stats_file = folder / "statistics_samples.csv"
195
- # if not os.path.exists(stats_file):
196
- # continue
197
196
198
- # reader = eval_files.read_csv(stats_file, ["label", "samples"])
199
197
200
- # for row in reader:
201
- # label = row["label"]
202
- # samples = list(row["samples"])
203
- # samples = [float(i) for i in samples if i !=' ']
204
-
205
-
206
-
207
- # if "joint_of_pose" in label:
208
- # if "joint_of_pose" not in timing_results:
209
- # timing_results["joint_of_pose"] = {"ms": [], "all": [], "inliers":[]}
210
-
211
- # elif "object_nlo_refinement" in label:
212
- # if "object_nlo_refinement" not in timing_results:
213
- # timing_results["object_nlo_refinement"] = {"ms": [], "all": [], "inliers":[]}
214
- # else:
215
- # continue
216
-
217
- # print(label)
218
- # print(len(samples))
219
-
220
- # if label.endswith("joint_of_pose [ms]"):
221
- # timing_results["joint_of_pose"]["ms"].extend(samples)
222
- # elif label.endswith("joint_of_pose_num_vars_all"):
223
- # timing_results["joint_of_pose"]["all"].extend(samples)
224
- # elif label.endswith("joint_of_pose_num_vars_inliers"):
225
- # timing_results["joint_of_pose"]["inliers"].extend(samples)
226
- # # elif label.endswith("object_nlo_refinement [ms]"):
227
- # # timing_results["object_nlo_refinement"]["ms"].extend(samples)
228
- # # elif label.endswith("object_nlo_refinement_num_vars_all"):
229
- # # timing_results["object_nlo_refinement"]["all"].extend(samples)
230
- # # elif label.endswith("object_nlo_refinement_num_vars_inliers"):
231
- # # timing_results["object_nlo_refinement"]["inliers"].extend(samples)
232
- # # else:
233
- # # continue
234
-
235
- # fig = plt.figure(figsize=(8,8))
236
- # joint_of_ax = fig.add_subplot(211)
237
-
238
- # def plot_result(ax, result, label):
239
- # timing = result["ms"]
240
- # all = result["all"]
241
-
242
- # ax.plot(timing, all, label=label)
243
- # ax.set_ylabel(r"Num Vars")
244
- # ax.set_xlabel(r"[ms]")
245
-
246
- # plot_result(joint_of_ax, timing_results["joint_of_pose"], "joint_of_pose")
247
-
248
- # plt.show()
249
-
250
-
251
- # KEYS = [{"frontend.feature_tracker"}]
252
-
253
-
254
- TRACKING_STATS_KEYS = {"name" : "Tracking" ,
198
+ TRACKING_STATS_KEYS = {"name" : "Feature Tracking" ,
255
199
"log_scale" :False ,
256
200
"keys" :{"frontend.feature_tracker" : {"label" :"Feature Tracker" },
201
+ "tracking_timer" : {"label" :"Feature Tracker" },
257
202
"static_feature" : {"label" : "Static Features" },
258
203
"dynamic_feature" : {"label" : "Dynamic Features" }}
259
204
}
260
205
261
- REFINEMENT_STATS_KEYS = {"name" : "Refinement" ,
206
+
207
+ BACKEND_STATS_KEYS = {"name" : "Back-end" ,
208
+ "log_scale" :False ,
209
+ "keys" :{
210
+ "full_batch_opt" : {"label" :"Feature Tracker" }}
211
+ }
212
+
213
+ REFINEMENT_STATS_KEYS = {"name" : "Motion Estimation" ,
262
214
"log_scale" :True ,
263
215
"keys" :{"motion_solver.solve_3d2d" : {"label" :"PnP Solve" },
264
- "joint_of_pose [ms]" : {"label" : "Joint Optical Flow" },
265
- "object_nlo_refinement [ms]" : {"label" : "3D Motion Refinement" }}
216
+ "joint_of_pose [ms]" : {"label" : "Optical Flow Refinement " },
217
+ "object_nlo_refinement [ms]" : {"label" : "Motion Refinement" }}
266
218
}
267
219
268
220
# hardcoded key to search for
@@ -271,20 +223,14 @@ def get_all_stats(results_folder, stats_dict, stats_key):
271
223
# OPT_STATS_KEYS=["batch_opt [ms]", "sliding_window_optimise [ms]"]
272
224
# OPT_STATS_KEYS=["batch_opt_num_vars", "sliding_window_optimise_num_vars"]
273
225
274
- STATS_KEYS = TRACKING_STATS_KEYS
226
+ STATS_KEYS = REFINEMENT_STATS_KEYS
275
227
276
228
277
229
if __name__ == "__main__" :
278
230
parser = parser ()
279
231
argcomplete .autocomplete (parser )
280
232
args = parser .parse_args ()
281
- if main (args .dynosam_results_path , STATS_KEYS ):
233
+ if plot (args .dynosam_results_path , [ TRACKING_STATS_KEYS , REFINEMENT_STATS_KEYS , BACKEND_STATS_KEYS ] ):
282
234
sys .exit (os .EX_OK )
283
235
else :
284
236
sys .exit (os .EX_IOERR )
285
-
286
-
287
- # if make_POM_plots(args.dynosam_results_path):
288
- # sys.exit(os.EX_OK)
289
- # else:
290
- # sys.exit(os.EX_IOERR)
0 commit comments