diff --git a/plot/plot.pdf b/plot/plot.pdf new file mode 100644 index 0000000000000000000000000000000000000000..437213fa5cf317de17c41e278caf11d6cb3ff965 Binary files /dev/null and b/plot/plot.pdf differ diff --git a/plot/plot_statistic.bat b/plot/plot_statistic.bat index 4b47c4346745aa28a2c442271db02a5c6d0527ce..63bd5039e4eb17fa272793e9a6a380989a6ada65 100644 --- a/plot/plot_statistic.bat +++ b/plot/plot_statistic.bat @@ -1 +1 @@ -matlab -batch "plot; exit" \ No newline at end of file +matlab -batch "plot_statistic('statistic.csv', {'headset_total_latency_0'}, 'plot.pdf'); exit" \ No newline at end of file diff --git a/plot/plot_statistic.m b/plot/plot_statistic.m index 10cf06c01e5dffdd823a6032e2002230ea3c8466..8e057248b25209bda35a14fa82ab3212dc467a26 100644 --- a/plot/plot_statistic.m +++ b/plot/plot_statistic.m @@ -1,13 +1,249 @@ -function plot_statistic(columns, time_start, time_end) - statistic = load_statistic("statistic.csv"); +function plot_statistic(src_file, columns, dst_file, time_start, time_end) + if ~exist("src_file", "var") + disp("No file was specified for plotting!"); + return; + end - test = statistic(:,14); - a = table2array(test); - a(isnan(a))=0; + if ~exist("columns", "var") + disp("No columns were specified for plotting!"); + return; + end - plot(a); + for index=1:size(columns) + if columns{index} == "frame_number" + disp("The frame number should not be plotted and should!") + return; + end + if columns{index} == "transform_id" + disp("The transform id should not be plotted and should!") + return; + end + end + + statistic = load_statistic(src_file); + select = select_columns(statistic, columns); + + if size(select.labels) <= 1 + disp("No columns found!"); + return; + end + + time_end_max = find_time_end(select); + + if ~exist("time_start", "var") + disp("Time start was set to one!"); + time_start = 1; + end + + if ~exist("time_end", "var") + disp("Time end was set to max time end!"); + time_end = time_end_max; + end + + if time_start < 1 + disp("Time start was clamped to one!"); + time_start = 1; + end + + if time_end > time_end_max + disp("Time end was clamped to max end time!"); + time_end = time_end_max; + end + + if time_start > time_end + disp("Time start and time end was reversed!"); + time_temp = time_end; + time_end = time_start; + time_start = time_temp; + end + + figure_handle = plot_columns(select, time_start, time_end); + + if figure_handle == "error" + return; + end + + if ~exist("dst_file", "var") + disp("Showing figure in window mode"); + figure_handle.Visible = "on"; + else + disp("Saving plot to file '" + dst_file + "'"); + save_plot(figure_handle, dst_file); + close(figure_handle); + end end function statistic = load_statistic(file_name) - statistic = readtable(file_name); -end \ No newline at end of file + table = readtable(file_name, 'VariableNamingRule', 'preserve'); + + statistic.table = {}; + statistic.labels = {}; + statistic.display_labels = {}; + statistic.units = {}; + statistic.ordered = {}; + + ordered = true; + + for column_index=1:size(table.Properties.VariableNames, 2) + column = table(:,column_index); + name = table.Properties.VariableNames(column_index); + + if ~all(ismissing(column)) + splits = split(string(name{1})); + + if size(splits, 1) >= 1 + label = splits(1); + display_label = convertStringsToChars(label); + + for index=1:strlength(display_label) + if index == 1 + display_label(index) = upper(display_label(index)); + elseif display_label(index - 1) == '_' + display_label(index - 1) = ' '; + display_label(index) = upper(display_label(index)); + end + end + + display_label = convertCharsToStrings(display_label); + + statistic.labels{end + 1} = label; + statistic.display_labels{end + 1} = display_label; + else + disp("Can't parse label for column '" + name + "'!"); + continue; + end + + if size(splits, 1) >= 2 + uint = extractBetween(splits(2), 2, strlength(splits(2)) - 1); + statistic.units{end + 1} = uint; + else + statistic.units{end + 1} = "undef"; + end + + statistic.table{end + 1} = table2array(column); + statistic.ordered{end + 1} = ordered; + else + ordered = false; + end + end +end + +function select = select_columns(statistic, columns) + select.table = {}; + select.labels = {}; + select.display_labels = {}; + select.units = {}; + select.ordered = {}; + + for column_index=1:size(statistic.labels, 2) + label = statistic.labels{column_index}; + found = false; + + for index=1:size(columns, 2) + if label == columns{index} + found = true; + break; + end + end + + if label == "frame_number" + found = true; + end + + if found + select.table{end + 1} = statistic.table{column_index}; + select.labels{end + 1} = statistic.labels{column_index}; + select.display_labels{end + 1} = statistic.display_labels{column_index}; + select.units{end + 1} = statistic.units{column_index}; + select.ordered{end + 1} = statistic.ordered{column_index}; + end + end +end + +function time_end = find_time_end(statistic) + time_end = 1; + + for index=1:size(statistic.table, 2) + column = statistic.table{index}; + column_end = find(~isnan(column), 1, "last"); + + if statistic.labels{index} == "frame_number" + time_end = max(time_end, column(column_end)); + elseif ~statistic.ordered{index} + time_end = max(time_end, column_end); + end + end +end + +function figure_handle = plot_columns(statistic, time_start, time_end) + ordered_found = false; + frame_numbers_found = false; + frame_numbers = []; + + for index=1:size(statistic.labels, 2) + if statistic.labels{index} == "frame_number" + frame_numbers_found = true; + frame_numbers = statistic.table{index}; + end + + if statistic.ordered{index} + ordered_found = true; + end + end + + if ordered_found && ~frame_numbers_found + disp("Can't find frame numbers even though the statistic contains ordered columns!"); + figure_handle = "error"; + return; + end + + time_line = 1:time_end; + column_samples = {}; + column_labels = {}; + + for column_index=1:size(statistic.table, 2) + if statistic.labels{column_index} == "frame_number" + continue; + end + + column = statistic.table{column_index}; + samples = NaN(time_end, 1); + + if statistic.ordered{column_index} + for row_index=1:size(frame_numbers) + time = frame_numbers(row_index); + + if time_start <= time && time <= time_end + samples(time) = column(row_index); + end + end + else + for row_index=1:size(frame_numbers) + if time_start <= row_index && row_index <= time_end + samples(row_index) = column(row_index); + end + end + end + + column_samples{end + 1} = samples; + column_labels{end + 1} = statistic.display_labels{column_index} + " [" + statistic.units{column_index} + "]"; + end + + figure_handle = figure("Visible", "off"); + + for index=1:size(column_samples, 2) + samples = column_samples{index}; + plot_indices = ~isnan(samples); + + plot_handle = plot(time_line(plot_indices), samples(plot_indices)); + plot_handle.DisplayName = convertCharsToStrings(column_labels{index}); + + hold on + end + + legend_handle = legend(); +end + +function save_plot(figure_handle, dst_file) + saveas(figure_handle, dst_file) +end