Finding x position of color-grouped boxchart boxes for overlaying jittered errorbar plot

19 visualizzazioni (ultimi 30 giorni)
I'm writing a GUI that creates a boxchart from the results of a fitting operation. Each data point has an x and color category and a confidence interval associated with it. I'd like to create a boxchart that groups data points categorically on x and color, and then overlay an errorbar plot that shows each individual data point data point and its confidence interval. There could be any number of color and x categories.
My issue is that I can't figure out how to calculate or find the x position of each of the boxes, which I need to ensure the errorbar plots line up. It seems like this should be a property of the BoxChart object, but I can't find it.
For example, if I create the following data set, which uses either a two or three color categories:
% Generate some data
xcat = categorical({'a', 'b', 'c'});
ccat = categorical({'c1'; 'c2'; 'c3'}); % 3 color categories
%ccat = categorical({'c1'; 'c2'; 'c2'}); % 2 color categories
xdata = reshape(repmat(xcat, 12, 1), [], 1);
cdata = reshape(repmat(ccat, 4, 3), [], 1);
ydata = reshape([normrnd(10, 1, 12, 1), normrnd(11, 1, 12, 1), normrnd(8, 1, 12, 1)], [], 1);
cfdata = reshape(normrnd(0, 0.5, 12, 3), [], 1);
And I create a boxchart from it like this:
% Convert from categorical to numerical for plot
xcat_names = categories(xdata);
xdata_num = double(xdata);
% Create boxchart
figure
b = boxchart(xdata_num, ydata, 'GroupByColor', cdata);
set(gca, "XTick", unique(xdata_num), "XTickLabel", xcat_names);
legend
The following error bar code works perfectly when there's three colors, but doesn't align properly if there's two:
% Estimate errorbar positions
ccat_names = categories(cdata);
cgroupwidth = 1-1/length(ccat_names);
xspacing = cgroupwidth/length(ccat_names);
xcoloroffset = (0:length(ccat_names)-1) * xspacing - cgroupwidth/2 + xspacing/2;
% Add some jitter for readability
xjitteroffset = zeros(size(xdata)); % Zeros for testing alignment with no jitter
%xjitteroffset = randn(size(xdata))*cgroupwidth/length(ccat_names)/4;
% Overlay jittered errorbars on boxchart
cmap_c = lines(length(categories(cdata))); % match color of boxchart
hold on
for ix = 1:length(xcat_names)
for ic = 1:length(ccat_names)
ibox = xdata == xcat(ix) & cdata == ccat(ic); % find data that fits criteria
errorbar(xdata_num(ibox) + xcoloroffset(ic) + xjitteroffset(ibox),...
ydata(ibox), cfdata(ibox), '.', 'Color', cmap_c(ic,:),...
'HandleVisibility','off')
end
end
grid on
This code results in the following graphs depending on which ccat definition is commented out. You can see that the errorbars don't align in the 2 Color scenario.
So in summary, I'm interested if anyone knows:
  • A way to get the x position of the boxes from the BoxChart object
  • A way to calculate the x position of the boxes reliably with varying numbers of color and x categories.
  2 Commenti
Theo Husby
Theo Husby il 1 Ott 2025 alle 15:04
Thanks! This is helpful. I missed some of these.
I've got a solution now. I'm just writing it up as an answer.

Accedi per commentare.

Risposta accettata

Theo Husby
Theo Husby il 1 Ott 2025 alle 15:23
I figured out a solution based on this answer given for bar graphs in this answer.
The box position can be calculated reliably, and I was close with my position estimate, but had the wrong definition of cgroupwidth. In my original question, the line should be:
cgroupwidth = min(0.8, length(ccat_names)/(length(ccat_names) + 1.5));
Here is the implementation written out as a function in case it's useful to anyone who encounters the same problem in the future:
function xboxpos = get_boxchart_x_position(xdata_num, nc)
% Return the x position of each individual box in a boxchart that uses 'GroupByColor'.
% xdata_num is a numerical vector. Same as the first input to boxchart.
% nc is the number of color categories
xgroup = unique(xdata_num);
nx = length(xgroup);
% Calculate offset for colors
cgroupwidth = min(0.8, nc/(nc + 1.5));
xspacing = cgroupwidth/nc;
xcoloroffset = (0:nc-1) * xspacing - cgroupwidth/2 + xspacing/2;
% Calculate x positions of each boxchart box assuming the same number
% of colors for each x position.
xboxpos = zeros(nx * nc, 1);
for ix = 1:nx
for ic = 1:nc
xboxpos((ix-1)*nc + ic) = xgroup(ix) + xcoloroffset(ic);
end
end
end
Example usage:
% Create a boxchart
boxchart(xdata_num, ydata, 'GroupByColor', cdata);
% Get number of color categories. cdata is categorical in my case.
nc = length(categories(cdata));
% Call function to get x position of each box in the chart.
xboxpos = get_boxchart_x_position(xdata_num, nc);
If anyone knows a cleaner solution, please let me know.

Più risposte (0)

Categorie

Scopri di più su Errorbars in Help Center e File Exchange

Prodotti


Release

R2025a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by