1% =========================================================================== %
2%> @brief create a comparison plot
4%>
this function creates a modified bland-altman plot from two vectors. the plot
5%> is saved to a file or displayed.
7%> @param gt_vec vector with the ground truth values
8%> @param meas_vec vector with the measured values
9%> @param i_step vector with the step indices
10%> @param filename filename of the plot
11%> @param options options
for the plot
12%> -
"title" (
default:
"Bland-Altman plot") title of the plot
13%> -
"legend" (
default: false) show a legend
14%> -
"compare_ptps" (default: false) compare the PTPs
15%> -
"ptp_vec" vector with the PTP numbers (only if
"compare_ptps" is true)
17%> @retval mu mean of the differences (cm)
18%> @retval sigma standard deviation of the differences (cm)
19%> @retval mse mean squared error of the differences (cm^2)
21%> @copyright see the file @ref LICENSE in the root directory of the repository
22% =========================================================================== %
23function [mu, sigma, mse] =
comparison_plot(gt_vec, meas_vec, i_step, filename, options)
30 options.title (1,:) char =
"Bland-Altman plot"
31 options.legend (1,1) logical = true
32 options.compare_ptps (1,1) logical = false
33 options.ptp_vec (:,1) categorical = categorical()
36if options.compare_ptps
37 assert(~isempty(options.ptp_vec),
"The PTP vector must be provided")
41assert(all(isnan(gt_vec) == isnan(meas_vec)),
"The vectors must have the same NaN values")
42i_step = i_step(~isnan(gt_vec));
43gt_vec = gt_vec(~isnan(gt_vec));
44meas_vec = meas_vec(~isnan(meas_vec));
45if options.compare_ptps
46 options.ptp_vec = options.ptp_vec(~isnan(gt_vec));
50assert(length(gt_vec) == length(meas_vec),
"The vectors must have the same length")
51assert(length(gt_vec) == length(i_step), "The vectors must have the same length")
52if options.compare_ptps
53 assert(length(gt_vec) == length(options.ptp_vec), "The vectors must have the same length")
58meas_vec = meas_vec * 100;
60% calculate the difference
61diff_vec = gt_vec - meas_vec;
63% calculate accuracy matrics
65mu = mean(diff_vec); % cm
66mse = mean(diff_vec.^2); % cm^2
67sigma = std(diff_vec); % cm
68me = rmse(gt_vec, meas_vec); % cm
69mu_rel = mean(diff_vec ./ gt_vec) * 100; % %
70sigma_rel = std(diff_vec ./ gt_vec) * 100; % %
71me_rel = rmse(gt_vec, meas_vec) / mean(gt_vec) * 100; % %
74fig = figure(Visible="off", InnerPosition=[0,0,1920,1080]);
76% bland altman part (absolute values)
78scatter(gt_vec, diff_vec, "filled", 'SizeData', 5)
80yline(mean(diff_vec), "r", "LineWidth", 1.5)
81yline(mean(diff_vec) + 1.96 * std(diff_vec), "r--", "LineWidth", 1.5)
82yline(mean(diff_vec) - 1.96 * std(diff_vec), "r--", "LineWidth", 1.5)
83xlabel("Ground Truth [cm]")
84ylabel("Difference (VICON - IMU) [cm]")
85title(sprintf("n = %d, \\mu = %.2f cm, \\sigma = %.2f cm, RMSE = %.2f cm", ...
89 legend("VICON - IMU", "Ground Truth", "95% CI", "Location", "best")
92% bland altman part (relative values)
94scatter(gt_vec, diff_vec ./ gt_vec, "filled", 'SizeData', 5)
96yline(mean(diff_vec ./ gt_vec), "r", "LineWidth", 1.5)
97yline(mean(diff_vec ./ gt_vec) + 1.96 * std(diff_vec ./ gt_vec), "r--", "LineWidth", 1.5)
98yline(mean(diff_vec ./ gt_vec) - 1.96 * std(diff_vec ./ gt_vec), "r--", "LineWidth", 1.5)
99xlabel("Ground Truth [cm]")
100ylabel("Relative Difference (VICON - IMU) [%]")
101title(sprintf("n = %d, \\mu_{rel} = %.2f %%, \\sigma_{rel} = %.2f %%, RMSE_{rel} = %.2f %%
", ...
102 n, mu_rel, sigma_rel, me_rel), "Interpreter
","tex
")
105 legend("VICON - IMU
", "Ground Truth
", "95% CI
", "Location
", "best
")
108% Q-Q plot (only if ptp comparison is disabled)
109if ~options.compare_ptps
111 qqplot(gt_vec, diff_vec)
112 xlabel("Ground Truth [cm]
")
113 ylabel("Difference (VICON - IMU) [cm]
")
118% boxplot per PTP (only if ptp comparison is enabled)
119if options.compare_ptps
121 boxplot(diff_vec, options.ptp_vec, 'Notch', true)
123 ylabel("Difference (VICON - IMU) [cm]
")
124 title("Boxplot per PTP
")
128% error vs step (spearman correlation plot between error and step index)
129% calculate the correlation
130r = corr(diff_vec, i_step, Type="Spearman
");
131[p,S] = polyfit(diff_vec, i_step, 1);
132[fit, delta] = polyval(p, diff_vec, S);
135[diff_vec, idx] = sort(diff_vec);
142scatter(diff_vec, i_step, "filled
", 'SizeData', 5)
144plot(diff_vec, fit, 'r', 'LineWidth', 0.75)
145xlabel("Difference (VICON - IMU) [cm]
")
147title(sprintf("Error vs Step Index, r = %.2f
", r))
151sgtitle(options.title)
function comparison_plot(in gt_vec, in meas_vec, in i_step, in filename, in options)
create a comparison plot