Categorical histogram labels - matlab

I've created a categorical histogram :
h = histogram( categorical( emotions{startIndex:endIndex,:} ) )
h.Categories
ans =
1×5 cell array
{'ANGER'} {'CONTEMPT'} {'DISGUST'} {'JOY'} {'SADNESS'}
>> h.Values
ans =
164 26 18 191 1
But there doesn't seem to be a way to display labels (i.e.h.Values) on the histogram bars.
Following this post, I tried this:
text(h.Values, h.Categories, num2str(h.Values'), 'HorizontalAlignment', 'Center', 'VerticalAlignment', 'Bottom' );
but I just get:
Error using text First two or three arguments must be numeric doubles.
but the problem is my x values are never going to be numeric, they're categorical. How to fix it?
For a reproducible example, this would do:
emotions = { 'JOY','JOY','JOY','JOY','JOY','JOY','JOY','JOY','JOY','JOY','ANGER','ANGER','CONTEMPT','CONTEMPT','CONTEMPT','JOY','ANGER','ANGER','ANGER','ANGER'}
emotions = emotions.';
t = cell2table(emotions)
histogram(categorical(emotions))

You have interchanged the first two input arguments of text and h.Categories is not numeric double which it needs to be (as the error message is suggesting you).
So the solution is:
emotions = {'JOY','JOY','JOY','JOY','JOY','JOY','JOY','JOY','JOY', ...
'JOY','ANGER','ANGER','CONTEMPT','CONTEMPT','CONTEMPT','JOY', ...
'ANGER','ANGER','ANGER','ANGER'};
% emotions = emotions.'; %No need of this line
% t = cell2table(emotions); %No need of this line
h = histogram(categorical(emotions));
text(1:numel(h.Values), h.Values, num2str(h.Values.'), ...
'HorizontalAlignment', 'Center', 'VerticalAlignment', 'Bottom');
Result:

Related

How to align xlabels and ylabels in subplot in MATLAB

I have the following code:
mean_h =[11.9877,13.3937,16.1717];
std_h = [12.5379,10.2732,10.8000];
subplot(2,1,1)
hold on
h = bar(1:3,mean_h,0.2);
errorbar(1:3,mean_h,std_h,'s','MarkerSize',10,...
'MarkerEdgeColor','red','MarkerFaceColor','red');
name = {'4 mics','9 mics','24 mics'};
set(gca,'XTick',[1 2 3],'XTickLabel',{'4 mics','9 mics','24 mics'});
set(gca,'fontsize', 21);
legend({'mean_{hor}', 'std_{hor}'});
grid on
xlabel(' 3 different subsets of horizontal microphone pair combinations of
microphone array 3');
ylabel('Mean/stds rmse`s [°]');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Mean and standard devaiation for vertical rmse's of microphone array 3
mean_v =[7.3022,11.3737,16.2675];
std_v =[6.2369,9.9813,10.3599];
subplot(2,1,2)
hold on
h = bar(1:3,mean_v,0.2);
errorbar(1:3,mean_v,std_v,'s','MarkerSize',10,...
'MarkerEdgeColor','red','MarkerFaceColor','red');
name = {'4 mics','9 mics','24 mics'};
set(gca,'XTick',[1 2 3],'XTickLabel',{'4 mics','9 mics','24 mics'});
set(gca,'fontsize', 21);
legend({'mean_{ver}', 'std_{ver}'});
grid on
xlabel('3 different subsets of vertical microphone pair combinations of
microphone array 3');
ylabel('Mean/stds rmse`s [°]');
Now when i plot these two subplots i am facing an alignment problem in xlabels and ylabels . They are not aligned. Can anybody help me how can i fix this problem. Thanks
They don't align if the graphs are different. In your case the numbers are different.
You can either do it by hand or use a text(my_x, my_y,'mylabel') and set it up properly. I wrote an example below.
a=1:10;
b=a.^2;
subplot(4,1,1)
plot(a,b)
ylabel(' long text')
subplot(4,1,2)
plot(a,a)
ylabel('long even long text')
subplot(4,1,3)
hold
plot(a,b)
text(0,50,'long text','HorizontalAlignment','center','VerticalAlignment','middle', ...
'FontSize',12,'Rotation',90)
subplot(4,1,4)
hold
plot(a,a)
text(0,5,'long even long text','HorizontalAlignment','center','VerticalAlignment','middle', ...
'FontSize',12,'Rotation',90)
giving the graph below
Notice the last two are aligned, but it was necessary to input the coordinates by hand as i did.
As a tip, you often ca use your data and move it by a fixed percentage (e.g., the minimum -10% graph total length), making it possible to 'automate' your script.
Another way is to use the Position property of the ylabel. But this is similar to the method described above. To do so use
t=ylabel('long text')
t =
Text ( long text) with properties:
String: ' long text'
FontSize: 11
FontWeight: 'normal'
FontName: 'Helvetica'
Color: [0.15 0.15 0.15]
HorizontalAlignment: 'center'
Position: [0.3333 50 -1]
%other things here too
%overwrite the property
% Here you have to put [X_position Y_position Z_position]
t.Position= [0.2 50 -1];
For that to work, every x/ylabel need its own name, or same name, but update the position before you call the command again.

How to set the custom marker in MATLAB figure legend

I have an image as follows.
In this images you can see 3 lines, these are actually 6 lines, one line in invisible just for showing markers and other line is smoothened version of original data points. Now the issue is that how do I get the markers in legend. In this case, you can see the figure legend consists of just line, not the markers. My code is as follows.
clc; clear all ;
colour_green = [12 195 82] ./ 255;
colour_lightgreen = [94 250 81] ./ 255;
colour_lightblue = [8 180 238] ./ 255;
colour_darkblue = [1 17 181] ./ 255;
colour_peach = [251 111 66] ./ 255;
figure('DefaultAxesFontSize',30);
set(0,'DefaultAxesFontName',' Times ');
hold on
time_window = xlsread('pattern_data.xlsx', 'effect_of_count', 'A2:A12');
count1plus = xlsread('pattern_data.xlsx', 'effect_of_count', 'B2:B12');
count10plus = xlsread('pattern_data.xlsx', 'effect_of_count', 'C2:C12');
count1to5 = xlsread('pattern_data.xlsx', 'effect_of_count', 'D2:D12');
x1 = 50:1:99;
% x1 = .01:.01:.5;
x2 = interp1(time_window,count1plus,x1, 'pchip') ;
x3 = interp1(time_window,count10plus,x1, 'pchip') ;
x4 = interp1(time_window,count1to5,x1, 'pchip') ;
% count 1+
plot(x1,x2,'b--','DisplayName', 'Count_{A} = 1: and Count_{B} = 1:','LineWidth',3)
plot(time_window,count1plus,'bs', 'HandleVisibility','off','LineWidth',5)
% count 1:5
plot(x1,x4,'-','DisplayName', 'Count_{A} = 1: and Count_{B} = 5:','LineWidth',3 , 'Color', colour_green)
plot(time_window,count1to5,'^', 'HandleVisibility','off','LineWidth',5 , 'Color', colour_green)
% count 10+
plot(x1,x3,'r--','DisplayName', 'Count_{A} = 1: and Count_{B} = 10:','LineWidth',3)
plot(time_window,count10plus,'ro', 'HandleVisibility','off','LineWidth',5)
hold off
xlabel('Th_{B} ')
ylabel('L (milliseconds)')
legend('Location','north')
legend show
set(gcf, 'PaperUnits', 'normalized');
set(gcf, 'PaperPosition', [0 0 1 1]);
set(gcf,'PaperOrientation','l');
print -dpng graphs/p1_effect_of_count_and_selB;
Please help. What I want is to have a marker(circle, square etc.) in the respective legend.
Edit# 1
The solution provided here did not solve my problem as it did not illustrates how to add a marker. An animation shows how to customize the position of a marker, but here I want to add a new marker not re-position the original existing one.
As explained in this answer to a very similar question, since R2014b onward the legend object is kind of opaque and cannot be easily changed. However, that answer also shows that there is a syntax to the legend function with four output arguments, which creates the legend in a different way such that it can be modified. The answer also shows how to modify the legend. We'll follow their lead.
The documentation says about this syntax:
This syntax is not recommended. It creates a legend that does not support some functionality, such as adding a legend title. Also, the legend does not automatically update when you add or remove data series from the axes.
But in this case these issues don't bother us, so we'll continue along.
In the case of the graph in the question, we'll replace
legend('Location','north')
with
[lgd,icons,plots,txt] = legend('Location','north');
Now, icons contains handles to the objects that form the legend:
>> icons
icons =
9×1 graphics array:
Text (Count_{A} = 1: and Count_{B} = 1:)
Text (Count_{A} = 1: and Count_{B} = 5:)
Text (Count_{A} = 1: and Count_{B} = 10:)
Line (Count_{A} = 1: and Count_{B} = 1:)
Line (Count_{A} = 1: and Count_{B} = 1:)
Line (Count_{A} = 1: and Count_{B} = 5:)
Line (Count_{A} = 1: and Count_{B} = 5:)
Line (Count_{A} = 1: and Count_{B} = 10:)
Line (Count_{A} = 1: and Count_{B} = 10:)
The display even helpfully shows which elements belong to which item. The first three are text objects, the last 6 are line objects. These line objects are what we need to modify.
Why are there two line objects for each of the items shown in the legend? That is because there is one line object (the first one) that is the rendered line (it has two data points):
>> icons(4)
ans =
Line (Count_{A} = 1: and Count_{B} = 1:) with properties:
Color: [0 0 1]
LineStyle: '--'
LineWidth: 3
Marker: 'none'
MarkerSize: 6
MarkerFaceColor: 'none'
XData: [0.0108 0.0919]
YData: [0.8246 0.8246]
ZData: [1×0 double]
and the other that is the marker (currently not visible, it has one data point):
>> icons(5)
ans =
Line (Count_{A} = 1: and Count_{B} = 1:) with properties:
Color: [0 0 1]
LineStyle: 'none'
LineWidth: 3
Marker: 'o'
MarkerSize: 6
MarkerFaceColor: 'none'
XData: 0.0514
YData: 0.8246
ZData: [1×0 double]
So, what we need to do is set these marker objects:
icons(5).Marker = 's';
icons(7).Marker = '^';
icons(9).Marker = 'o';
Now the plot looks like you wanted.
I hope that the description above is clear enough that you can now change the legend in other ways too.

PCA with colorbar

I have this data of which I want to make a principal component analysis.
In particular for each data point I want to associate a color.
This is my code:
for ii=1:size(SBF_ens,1)
SBF(ii) = SBF_ens(ii, max(find(SBF_ens(ii,:)~=0)) ); %value at the moment of the measurement
end
%matrix of data
toPCA =[
wind_trend_72h_ens-nanmean(wind_trend_72h_ens);
wind_trend_24h_ens-nanmean(wind_trend_24h_ens);
wind_trend_12to18h_ens-nanmean(wind_trend_12to18h_ens);
wind_trend_0to12h_ens-nanmean(wind_trend_0to12h_ens);
wind_trend_last6h_ens-nanmean(wind_trend_last6h_ens);
Mwind12h_ens-nanmean(Mwind12h_ens);
Mwind24h_ens-nanmean(Mwind24h_ens);
SBF-nanmean(SBF)]';
variables = { 'wt72h','wt24h','wt12to18h','wt0to12h','wtLast6h','Mw12h', 'Mw24h', 'SBF'}; %labels
%PCA algorithm
C = corr(toPCA,toPCA);
w = 1./var(toPCA);
[wcoeff,score,latent,tsquared,explained] = pca(toPCA,'VariableWeights',w);
coefforth = diag(sqrt(w))*wcoeff;
metric=decstd_ens; %metric for colorbar
hbi=biplot(coefforth(:,1:2),'scores',score(:,1:2),'varlabels',...
variables,'ObsLabels', num2str([1:length(toPCA)]'),...
'markersize', 15);
%plotting
cm = autumn;
colormap(cm);
for ii = length(hbi)-length(toPCA):length(hbi)
userdata = get(hbi(ii), 'UserData');
if ~isempty(userdata)
indCol = ceil( size(cm,1) * abs(metric(userdata))/max(abs(metric)) );%maps decstd between 0 and 1 and find the colormap index
if indCol==0 %just avoid 0
indCol=1;
end
col = cm(indCol,:); %color corresponding to the index
set(hbi(ii), 'Color', col); %modify the dot's color
end
end
for ii = 1:length(hbi)-length(toPCA)-1 %dots corresponding to the original dimensions are in black
set(hbi(ii), 'Color', 'k');
end
c=colorbar;
ylabel(c,'decstd') %is this true?
xlabel(['1^{st} PCA component ', num2str(explained(1)), ' of variance explained'])
ylabel(['2^{nd} PCA component ', num2str(explained(2)), ' of variance explained'])
The resulting figure is the following:
Everything is fine except for the colorbar range. In fact decstd has values between 0 and 2. Actually I do not understand at all what the values on the colorbar are.
Does anyone understand it?
Is it possible to rethrive the data in the colorbar? So to understand what they are?
size(autumn)
shows you that the default length of the autumn colourmap (actually of all the colourmaps) is 64. When you call colorbar, by default it will use tick labels from 1 to n where n is the length of your colourmap, in this case 64.
If you want the mapping of the colourbar ticklabels to match the mapping that you used to get your data to fit between 1 and 64 (i.e. this line of yours indCol = ceil( size(cm,1) * abs(metric(userdata))/max(abs(metric)) );), then you will need to set that yourself like this
numTicks = 6;
cAxisTicks = linspace(min(metric), max(metric), numTicks); % or whatever the correct limits are for your data
caxis([min(metric), max(metric)]);
set(c,'YTick', cAxisTicks );

Matlab plot legend automation

I am solving a pde that depends on x and t and would like to show the solution over all x for a few values of t. I am trying to write code that will automatically generate a legend for this plot. For example, if I am plotting the solution at t = 0, 1, 5, and 9, I want the legend to show "t=0", "t=1", and so on.
Let's say my solution is held in matrix u. My times are held in vector t. The index of the times I am sampling would be in vector tsampled. Note this is not the same as the time I want on the plot. If I take the time at index 6 of vector t, this value is not 6, but could be anything.
I am currently attempting to do this by:
tlen = max(size(t));
tsampled = [2, floor(tlen/5), floor(2*tlen/5), floor(3*tlen/5), floor(4*tlen/5), floor(tlen)];
t(tsampled)
legnd = {'', '', '', '', '', ''};
hold on
for i = 1:1:size(tsampled)
plot(x,u(tsampled(i),:))
legnd(i) = sprintf('t = %0.2f s \n', t(tsampled(i)));
end
title('my PDE solution');
legend(legnd, 0);
xlabel('x')
ylabel('u')
hold off
But this is producing the error "Conversion to cell from char is not possible."
When I instead try using the line:
legend (sprintf('t = %0.2f s \n', t(tsampled)))
I get the correct "strings" on the graph, but they are formatted like this:
I would like this to show "t=10.20 s" next to a blue line, "t = 91.84 s" next to an orange line, and so on. How do I get the result I want?
Because you predefined legnd as a cell array, you need to use {} instead of () to get the correct index. Try:
legnd{i} = sprintf('t = %0.2f s \n', t(tsampled(i)));

Add legend to graph created iteratively

I am creating a graph iteratively from various data sets, and I try to add legend to it, but it fails.
colors = {'g','b','m','k','c'};
subplot(2,3,iii);
hold all;
for jjj=1:length(aggregation_methods),
aggregate = all_aggregate{jjj};
std_agg = all_std_agg{jjj};
plot(coverages, aggregate, colors{jjj});
h1 = errorbar(coverages,aggregate,std_agg,colors{jjj});
set(h1,'linestyle','none')
end
plot(coverages, regular, 'r');
h1 = errorbar(coverages,regular,std_reg,'r');
set(h1,'linestyle','none')
title(datasets{iii});
xlabel('coverage');
ylabel('MSE');
legend('enhanced with clustering(k=4)','enhanced random split', 'regular we');
The graph seems to be generated just fine, it's just the legend that is failing.
I expect the colors of the legend to be (top-down): green, blue, red.
P.S. I also tried (and it didn't work):
legend({'enhanced with clustering(k=4)','enhanced random split', 'regular we'});
EDIT:
Inspired by this thread, I changed the code to use the 'DisplayName' property for each plot:
colors = {'g','b','m','k','c'};
names = {'enhanced with clustering(k=4)','enhanced random split', 'regular we'};
subplot(2,3,iii);
hold all;
for jjj=1:length(aggregation_methods),
aggregate = all_aggregate{jjj};
std_agg = all_std_agg{jjj};
plot(coverages, aggregate, colors{jjj}, 'DisplayName', names{jjj});
h1 = errorbar(coverages,aggregate,std_agg,colors{jjj});
set(h1,'linestyle','none')
end
%plot(coverages,aggregate,'g',coverages ,regular,'r');
%h1 = errorbar(coverages,aggregate,std_agg,'g');
%set(h1,'linestyle','none')
plot(coverages, regular, 'r', 'DisplayName', names{length(aggregation_methods) + 1});
h1 = errorbar(coverages,regular,std_reg,'r');
set(h1,'linestyle','none')
%axis([0 1 0 max(mean(rc{iii}))]);
title(datasets{iii});
xlabel('coverage');
ylabel('MSE');
legend('show');
However, it yields the following legend, but I'd like to get rid of these 'dataX' strings.
a=[
1 2 3
4 5 6
7 8 9
];
clist={'g','b','m'};
for i=1:3
pt(i)=plot(a(i,:),'Color',clist{i});
hold on;
end
b=[5 6 7];
pt(4)=plot(b,'Color','r');
legend([pt(1:2) pt(4)],{'line1','line2','line4'});