Increasing the line width of box plot whiskers
112 views (last 30 days)
Show older comments
I have written some code to produce 2 boxplots side by side using tiledlayout. I would like to increase the line weight of the boxes and the whiskers and have written the code to do so as follows:
figure()
t = tiledlayout(1,2,'tilespacing','none');
nexttile
boxplot(T_toPlot,'BoxStyle','outline','Color', 'b', 'Symbol','xk', 'OutlierSize',8,'Labels', labels);
bx1 = findobj('Tag','boxplot');
set(bx1.Children,'LineWidth',2)
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),get(h(j),'Color'),'FaceAlpha',.5);
end
clear h j
nexttile
boxplot(S_toPlot,'BoxStyle','outline','Color', 'b', 'Symbol','xk', 'OutlierSize',8,'Labels', labels);
bx2 = findobj('Tag','boxplot');
set(bx2.Children,'LineWidth',2)
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),get(h(j),'Color'),'FaceAlpha',.5);
end
clear h j
The first time I run this code, the first tile runs successfully and I get the following error message for the second tile:
Error using matlab.graphics.primitive.Line/set
Invalid parameter/value pair arguments.
Error in Filename (line XXX)
set(bx2.Children,'LineWidth',2)
If I then do nothing, just hit enter again to re-run the cell, it then fails with the same error, but now for the first tile - and does not reach the second tile. Even if I clear the workspace and re-run the data processing from scratch, subsequent re-runs will fail for the first tile unless I restart the program. How can I increase the line weight of the boxplots (particularly the whiskers) without running into this problem? Thanks!
0 Comments
Accepted Answer
Voss
on 29 Aug 2024
findobj('Tag','boxplot') finds all* objects whose Tag is 'boxplot'. This includes any object whose Tag is 'boxplot' anywhere in the current figure as well as in other figures created previously. Therefore, assuming that initially there are no objects whose Tag is 'boxplot', after the first boxplot is created here, findobj finds one object. Then, after the second boxplot is created, findobj finds both boxplots. In subsequent runs, assuming the figure hasn't been closed, findobj finds all existing boxplots.
The problem is, when there is more than one boxplot found, the returned value from findobj is a non-scalar array, on which dot indexing (as in the syntax "bx2.Children") produces a non-scalar comma-separated list, so
set(bx2.Children,'LineWidth',2)
is the same as saying
set(bx2(1).Children,bx2(2).Children,'LineWidth',2)
when bx2 is an array of two objects. The set function doesn't know what to do when you give it an object as each of the first two inputs. That's what the error message is complaining about.
One way to avoid this problem is to constrain findobj only to find the boxplot you're interested in modifying. In this case, you can use findobj(gca,'Tag','boxplot') to find only objects in the current axes whose Tag is 'boxplot', and that should work fine.
Another approach would be to use the (undocumented) return value from the boxplot() function, which is the lines created by the boxplot() function. These are equivalent to the Children of the boxplot group object, so
boxplot(...)
bx2 = findobj(gca,'Tag','boxplot');
set(bx2.Children,'LineWidth',2)
is equivalent (in this case) to
bx2 = boxplot(...)
set(bx2,'LineWidth',2)
Here I'll use each approach one time:
% random data
T_toPlot = rand(10,2);
S_toPlot = rand(10,2);
labels = {'A','B'};
figure()
t = tiledlayout(1,2,'tilespacing','none');
nexttile
boxplot(T_toPlot,'BoxStyle','outline','Color', 'b', 'Symbol','xk', 'OutlierSize',8,'Labels', labels);
bx1 = findobj(gca,'Tag','boxplot');
set(bx1.Children,'LineWidth',2)
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),get(h(j),'Color'),'FaceAlpha',.5);
end
nexttile
bx2 = boxplot(S_toPlot,'BoxStyle','outline','Color', 'b', 'Symbol','xk', 'OutlierSize',8,'Labels', labels);
set(bx2,'LineWidth',2)
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),get(h(j),'Color'),'FaceAlpha',.5);
end
*Actually, it finds all objects whose HandleVisibility is 'on' and whose Tag is 'boxplot'.
0 Comments
More Answers (1)
dpb
on 29 Aug 2024
...
hBx=findobj('Tag','boxplot'); % the boxplot group handle
hBx=find(hBx.Children,'-not','Tag','Outliers'); % the group lines less outliers
set(hBx,'LineWidth',2)
...
should work ok; the problem is the outliers are also line objects which may be different sizes. The above returns the handles only for the other lines. If you also want the outlier markers heavier, you need to retrieve those handles separately and either loop or use the expanded version of set() with cell arguments to handle the different data by handle.
Without your specific data we can't duplicate exact code here.
I'd recommend considering the alternate boxchart if you want to modify things; it exposes most of the properties without the grief of having to search for them. Why on earth Mathworks thought hiding stuff inside boxplot was a good idea simply boggles the mind, though...although that goes for all the specialized plots; just some are more egregious than others.
0 Comments
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!