How to label a plot in Matlab with combine label?

It is hard to explaine here.
For example "peaks" is located second line and combine with "a" and "b".

 Accepted Answer

Option 1: use boxplotGroup()
See boxplotGroup() on the file exchange. If your boxplot data are matrices with the same number of columns, you can use this function to group them and provide primary and secondary labels.
Option 2: Use newline to create two rows of tick labels
Pro: Easy and clean
Con: Less control of the alignment between the upper and lower labels.
ax = axes();
xlim([0,12])
ticks = {'a_peaks','b','a_concat','b','a_F0','b','a_Fs','b'};
ticks = strrep(ticks,'_','\newline'); % replace underscore with \newline
ax.XTick = [1 2 4 5 7 8 10 11];
ax.XTickLabel = ticks;
This variation below controls the alignment between the upper and lower labels but adds an additional tick between the upper labels.
ax = axes();
xlim([0,12])
ticks = {'a','_peaks','b','a','_concat','b','a','_F0','b','a','_Fs','b'};
ticks = strrep(ticks,'_','\newline'); % replace underscore with \newline
ax.XTick = [1 1.5 2 4 4.5 5 7 7.5 8 10 10.5 11];
ax.XTickLabel = ticks;
Option 2.1: Use cell array with justified text
Added to answer 11-Feb-2021
Pro: Intuitive label arrangement & text justification
ax = axes();
xlim([0,12])
ticks = {'a','','b','a','','b','a','','b','a','','b'; ... % 1st row of labels
'','peaks','','','concat','','','F0','','','Fs',''}; % 2nd row of labels
ticksJust = strjust(pad(ticks),'center'); % Justify: 'left'(default)|'right'|'center
% ticksJust =
% 2×9 cell array
% {' a '} {' '} {' b '} {' a '} {' '} {' b '} {' a '} {' '} {' b '}
% {' '} {'peaks'} {' '} {' '} {'peaks'} {' '} {' '} {'peaks'} {' '}
tickLabels = strtrim(sprintf('%s\\newline%s\n', ticksJust{:}));
ax.XTick = [1 1.5 2 4 4.5 5 7 7.5 8 10 10.5 11];
ax.XTickLabel = tickLabels;
Option 3: Use text() to create a second row of tick lables
Pro: More control over the placement of the tick labels.
Con: Axis limits must be set and the lower tick labels will move if the pan feature is used.
ax = axes();
% Set axis limits before labeling
xlim([0,12])
ylim([0,1]);
% Shorten the height of the axes to 90% and shift
% upward to make room for the 2-layers of labels.
upperPosition = sum(ax.Position([2,4]));
ax.Position(4) = ax.Position(4) * .9;
ax.Position(2) = minus(upperPosition, ax.Position(4));
% label the upper row using xtick and xticklabel
ax.XTick = [1 2 4 5 7 8 10 11];
ax.XTickLabel = {'a' 'b'};
% use text() to creat the lower row of tick labels
% The 2nd layer will be 6% of the y axis range below the axis.
lowerLevel = min(ylim(ax))-range(ylim(ax))*.06;
lowerLabels = {'peaks','concat','F0','FS'};
text([1.5, 4.5, 7.5, 10.5], repmat(lowerLevel,1,numel(lowerLabels)), lowerLabels,...
'VerticalAlignment','Top','HorizontalAlignment','Center')

28 Comments

Thanks. Can i ask if this applied to boxplot function?
I tried, but it not working well.
If you share the code you tried, I could help fix it.
Thanks for your reply.
I not sure how to add in boxplot function
boxplot(rand(100,2),{'a','b'})
xlabel('Peaks','FontSize',12)
With this syntax, you only need to apply the 2nd row of labels since the first row is provided by the boxplot() function.
For example,
ax = gca();
lowerLevel = min(ylim(ax))-range(ylim(ax))*.06;
lowerLabels = {'peaks'}; % <--- define lower labels here
lowerLabelsX = [1.5]; % <--- define the x-position of each label
text(lowerLabelsX, repmat(lowerLevel,1,numel(lowerLabels)), lowerLabels,...
'VerticalAlignment','Top','HorizontalAlignment','Center')
Note that I've updated my answer with a new Option 1.
See the boxplotGroup() function on the file exchange
Thanks. Your answer very good.
Can I ask how to lable 4 values like below:
boxplot(randn(4),{'a','b','c','d'})
xlabel('Peaks', 'Peaks2','FontSize',12)
To use the boxplotGroup() function, you just need to split the matrix up into a cell array which is demonstrated below.
data = randn(4);
splitData = {data(:,1:2), data(:,3:4)};
% or
% splitData = mat2cell(data, size(data,1), [2,2]);
boxplotGroup(splitData,'primaryLabels', {'a' 'b' 'c' 'd'}, 'SecondaryLabels', {'Peak', 'Peak1'})
If you're rather not have the horizontal space between groups, set "InterGroupSpace" to 0.
Also see this link for more examples.
Thanks, the function you created is brillant!
Between, if I add a y-axis, it seemed overlap with the y-axis label.
I didn't understand that last part about adding a y axis. Can you share a screen shot and a snippet of relevant code?
Sorry for my bad English
data = randn(4);
splitData = {data(:,1:2), data(:,3:4)};
% or
% splitData = mat2cell(data, size(data,1), [2,2]);
boxplotGroup(splitData,'primaryLabels', {'a' 'b' 'c' 'd'}, 'SecondaryLabels', {'Peak11', 'Peak1'})
ylabel('Percentages')
Thanks for bringing that to my attention. I fixed that in the boxplotGroup() function and updated the file on the file exchange (version 1.2.0).
You can download the new version and the problem should be fixed.
I should thanks you.
However, could you check again? I am not sure is my file loaded wrongly.
But the new code, y-axis does not show up.
data = randn(4);
splitData = {data(:,1:2), data(:,3:4)};
% or
% splitData = mat2cell(data, size(data,1), [2,2]);
boxplotGroup(splitData,'primaryLabels', {'a' 'b' 'c' 'd'}, 'SecondaryLabels', {'Peak11', 'Peak1'})
ylabel('Percentages')
It looks fine to me (screen shot below). What version of Matlab are you using? Are you sure you're using the newest version of boxplotGroup()?
Hi, Thanks.
I am usng MATLAB R2017b and also I using the newest version of code.
Is below will give some hints why not working?
>> data = randn(4);
splitData = {data(:,1:2), data(:,3:4)};
% or
% splitData = mat2cell(data, size(data,1), [2,2]);
boxplotGroup(splitData,'primaryLabels', {'a' 'b' 'c' 'd'}, 'SecondaryLabels', {'Peak11', 'Peak1'})
ylabel('Percentages')
ans =
LinkProp with properties:
Enabled: 'on'
PropertyNames: {'Units' 'Position' 'ActivePositionProperty' 'Parent'}
Targets: [1×2 Axes]
No appropriate method, property, or field 'Toolbar' for class 'matlab.graphics.axis.Axes'.
Error in boxplotGroup (line 172)
h.axis2.Toolbar.Visible = 'off';
ah.... there is a version issue between r2017b and r2019b. Thanks again for bringing this to my attention.
I've update the file and you can download the most recent version 1.2.1. I've tested it on r2017b and r2016b.
Thanks, it working very well.
Just one question. Regarding the range of boxplot between the function of "boxplot" and "boxplotGroup".
For example:
Using MALTAB function "boxplot", the y-axis start from 30 to 100.
Using "boxplotGroup" function, the y-axis start from 0 to 100.
%%
y = [33, 44, 67, 78, 80, 90, 99, 47];
boxplot(y,'Labels',{'1'})
%%
boxplotGroup(y)
Error using boxplotGroup
The value of 'x' is invalid. Expected input to be one of these types:
cell
Instead its type was double.
Error in boxplotGroup (line 95)
parse(p,varargin{:})
Error in Boxplot2 (line 129)
boxplotGroup(x)
Thanks.
If you execute
help('boxplotGroup')
you'll notice that the 'x' input should be a cell array.
% boxplotGroup(x) receives a 1xm cell array where each element is a matrix with
% n columns and produced n groups of boxplot boxes with m boxes per group.
Here's the correct way to set that up.
figure()
y = [33, 44, 67, 78, 80, 90, 99, 47];
ax1 = subplot(1,2,1);
boxplot(y);
ax2 = subplot(1,2,2);
boxplotGroup(ax2, {y(:)})
xlim(ax2, xlim(ax1)) % This just equates the scaling
Regarding the difference in the y-axis and x-axis limits between boxplot() and boxplotGroup(), that is expected. The limits are set within the boxplotGroup() function but you can change them as needed after the plots are produced.
Thanks for your reply.
It is still a bit difficult for me. Not sure why still not working with the y-axis limit.
1. Using "boxplotGroup" function
a= [33.3333 100.0000 61.9048 95.2381;
57.1429 80.9524 66.6667 100.0000;
57.1429 85.7143 47.6190 95.2381;
42.8571 90.4762 52.3810 80.9524;
42.8571 95.2381 61.9048 85.7143;
57.1429 100.0000 71.4286 100.0000;
42.8571 100.0000 28.5714 85.7143;
61.9048 95.2381 76.1900 66.6667;
38.1000 100.0000 57.1429 76.1905;
71.4286 90.4762 52.3810 100.0000]
splitData = {a(:,1:2), data(:,3:4)};
boxplotGroup(splitData,'primaryLabels', {'a' 'b' 'c' 'd'}, 'SecondaryLabels', {'Range1', 'Range2'})
ylabel('Percentages')
Output:
2. Using function "boxplot"
a= [33.3333 100.0000 61.9048 95.2381;
57.1429 80.9524 66.6667 100.0000;
57.1429 85.7143 47.6190 95.2381;
42.8571 90.4762 52.3810 80.9524;
42.8571 95.2381 61.9048 85.7143;
57.1429 100.0000 71.4286 100.0000;
42.8571 100.0000 28.5714 85.7143;
61.9048 95.2381 76.1900 66.6667;
38.1000 100.0000 57.1429 76.1905;
71.4286 90.4762 52.3810 100.0000]
boxplot(a,'Labels',{'AM','b','a','c'})
Thanks.
The only significant difference in the figures you shared is the order the boxplots are in. See the inline comments below to produce an exact replication between the two functions.
% Input data
a= [33.3333 100.0000 61.9048 95.2381;
57.1429 80.9524 66.6667 100.0000;
57.1429 85.7143 47.6190 95.2381;
42.8571 90.4762 52.3810 80.9524;
42.8571 95.2381 61.9048 85.7143;
57.1429 100.0000 71.4286 100.0000;
42.8571 100.0000 28.5714 85.7143;
61.9048 95.2381 76.1900 66.6667;
38.1000 100.0000 57.1429 76.1905;
71.4286 90.4762 52.3810 100.0000]
% ******* boxplotGroup setup *******
% Note that the columns of 'a' are rearranged in the line below.
splitData = {a(:,[1,3]), a(:,[2,4])};
% Plot results
figure()
boxplotGroup(splitData,'primaryLabels', {'a' 'b' 'c' 'd'}, ...
'SecondaryLabels', {'Range1', 'Range2'}, 'interGroupSpace', 0)
% this section here ^^^^^^^^^^^^^^^^^^^^
% removes the space between the box groups
ylabel('Percentages')
grid on
ylim([25, 104])
% ******* boxplot setup *******
figure()
boxplot(a,'Labels',{'a' 'b' 'c' 'd'})
grid on
ylim([25, 104])
Thanks. Brillant!
Is there a way to increase the label font size?
With this below, only the first line font increase.
set(gca,'FontSize',13)
Use the outputs
h = boxplotGroup(. . . );
set(h.axis,'FontSize',13)
set(h.axis2,'FontSize',13)
It works well. Thanks.
Glad I could help. Thanks for testing the boxplotGroup function and providing feedback.
my pleasure. I also leave a good comment on your function too.
Will it be possible to make one of the words in tha label in italic font?
From
boxplot(a,'Labels',{'a' 'b' 'c' 'd'})
to
boxplot(a,'Labels',{\it'a' 'b' 'c' 'd'})
ax.XAxis.FontAngle = 'italic';
where ax is your axis handle.
If you want 2 groups with 3 boxplots per group, your input will be a 1x3 cell array.
Each of the 3 cells will should contain 2 columns where column 1 are the data for the first boxplot of each group, column 2 are the data for the 2nd boxplot for each group
splitdata = {c(:,[1,4]),c(:,[2,5]),c(:,[3,6])};
Please let me know if you have any problems or need more clarification.

Sign in to comment.

More Answers (1)

I believe the simple way is to separate the plot for each group and use xlabel to add 'Peaks', 'Concat', etc.
The following is an example:
figure
subplot(1,2,1)
boxplot(rand(100,2),{'a','b'})
xlabel('Peaks','FontSize',12)
subplot(1,2,2)
boxplot(rand(100,2),{'a','b'})
xlabel('Concat','FontSize',12)

1 Comment

Thanks. Is there a away to combine both boxplot together?

Sign in to comment.

Categories

Tags

Asked:

on 6 Mar 2020

Edited:

on 11 Feb 2021

Community Treasure Hunt

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

Start Hunting!