How to overlay single data points on bar graph in MATLAB? - matlab

I am trying to plot a bar graph with means of 9 data points. I want to plot the bar graph with individual data points overlaid on the bar. Here is the code to generate the bar graph. I want to overlay each bar with the individual data points whose average is y. Any suggestions for how to do this would be helpful. Thank you!
x_num = [1:4];
x = categorical({'High PU-High RU','High PU-Low RU', 'Low PU-High RU', 'Low PU-Low RU'});
y = [0.557954545, 0.671394799, 0.543181818, 0.660227273];
figure
bar(x,y,0.4)
title('Economic Performance')
xlabel('Conditions')

You can just hold on and plot the additional points
% Generate some data
x = 1:4;
y = rand(9,4); % note: 4 columns, N rows
ymean = mean(y); % mean of each column for bar
figure();
hold on; % plot multiple things without clearing the axes
bar( x, ymean, 0.4 ); % bar of the means
plot( x, y, 'ok' ); % scatter of the data. 'o' for marker, 'k' for black
hold off
There are loads of options for the plot styling, using 'o', 'x' or '.' as a marker type will make it a scatter rather than a line which is what you want here, other than that you can go crazy with sizing/color/linewidth etc, see the documentation.

Related

How to color multiple lines based on their value?

I produced a plot that contains 50 curves and each of them corresponds to a specific value of a parameter called "Jacobi constant", so I have 50 values of jacobi constant stored in array called jacobi_cst_L1:
3.000900891023230
3.000894276927840
3.000887643313580
3.000881028967010
3.000874419173230
3.000867791975870
3.000861196034850
3.000854592397690
3.000847948043080
3.000841330136040
3.000834723697250
3.000828099771820
3.000821489088600
3.000814922863360
3.000808265737810
3.000801695858850
3.000795067776960
3.000788475204760
3.000781845363950
3.000775192199620
3.000768609354090
3.000761928862980
3.000755335851910
3.000748750854930
3.000742084743060
3.000735532899990
3.000728906460450
3.000722309400740
3.000715644446600
3.000709016645110
3.000702431180730
3.000695791284050
3.000689196186970
3.000682547292110
3.000675958537960
3.000669315388860
3.000662738391370
3.000656116141060
3.000649560630930
3.000642857256680
3.000636330415510
3.000629657944820
3.000623060310100
3.000616425935580
3.000609870077710
3.000603171772120
3.000596554947660
3.000590018845460
3.000583342259840
3.000576748353570
I want to use a colormap to color my curves and then show in a lateral bar the legend that show the numerical values corresponding to each color of orbit.
By considering my example image, I would want to add the array of constants in the lateral bar and then to color each curve according the lateral bar.
% Family of 50 planar Lyapunov orbits around L1 in dimensionless unit
fig = figure;
for k1 = 1:(numel(files_L1_L2_Ly_prop)-2)
plot([Ly_orb_filt(1).prop(k1).orbits.x],[Ly_orb_filt(1).prop(k1).orbits.y],...
"Color",my_green*1.1); hold on %"Color",my_green*1.1
colorbar()
end
axis equal
% Plot L1 point
plot(Ly_orb_filt_sys_data(1).x,Ly_orb_filt_sys_data(1).y,'.',...
'color',[0,0,0],'MarkerFaceColor',my_green,'MarkerSize',10);
text(Ly_orb_filt_sys_data(1).x-0.00015,Ly_orb_filt_sys_data(1).y-0.0008,'L_{1}');
%Primary bodies plots
plot(AstroData.mu_SEM_sys -1,0,'.',...
'color',my_blue,'MarkerFaceColor',my_blue,'MarkerSize',20);
text(AstroData.mu_SEM_sys-1,0-0.001,'$Earth + Moon$','Interpreter',"latex");
grid on;
xlabel('$x$','interpreter','latex','fontsize',12);
ylabel('$y$','interpreter','latex','FontSize',12);
How can I color each line based on its Jacobi constant value?
You can use any colour map to produce a series of RGB-triplets for the plotting routines to read (Or create an m-by-3 matrix with elements between 0 and 1 yourself):
n = 10; % Plot 10 lines
x = 1:15;
colour_map = jet(n); % Get colours. parula, hsv, hot etc.
figure;
hold on
for ii = 1:n
% Plot each line individually
plot(x, x+ii, 'Color', colour_map(ii, :))
end
colorbar % Show the colour bar.
Which on R2007b produces:
Note that indexing into a colour map will produce linearly spaced colours, thus you'll need to either interpolate or calculate a lot to get the specific ones you need. Then you can (need to?) modify the resulting colour bar's labels by hand to reflect your input values. I'd simply use parula(50), treat its indices as linspace(jacobi(1), jacobi(end), 50) and then my_colour = interp1(linspace(jacobi(1), jacobi(end), 50), parula(50), jacobi).
So in your code, rather than using "Color",my_green*1.1 for each line, use "Color",my_colour(kl,:), where my_colour is whatever series of RGB triplets you have defined.

Showing images on same axes

I have a basic question about MATLAB. How I can show two images on same axes? I don't want it to be in same figure (as the following code shows) but the same axes.
subplot(1,2,1), subimage(X)
subplot(1,2,2), subimage(X2)
You need hold on to plot two graphs on the same axes:
figure
subimage(X)
hold on
subimage(X2)
If you want to display two images side-by-side in the same axes you'll want to modify the XData property of the second image to shift it to the right of the first image
X = rand(10);
X2 = rand(10);
figure
subimage(X)
hold on
him2 = subimage(X2);
set(him2, 'XData', get(him2, 'XData') + size(X, 2))

MATLAB: combining and normalizing histograms with different sample sizes

I have four sets of data, the distribution of which I would like to represent in MATLAB in one figure. Current code is:
[n1,x1]=hist([dataset1{:}]);
[n2,x2]=hist([dataset2{:}]);
[n3,x3]=hist([dataset3{:}]);
[n4,x4]=hist([dataset4{:}]);
bar(x1,n1,'hist');
hold on; h1=bar(x1,n1,'hist'); set(h1,'facecolor','g')
hold on; h2=bar(x2,n2,'hist'); set(h2,'facecolor','g')
hold on; h3=bar(x3,n3,'hist'); set(h3,'facecolor','g')
hold on; h4=bar(x4,n4,'hist'); set(h4,'facecolor','g')
hold off
My issue is that I have different sampling sizes for each group, dataset1 has an n of 69, dataset2 has an n of 23, dataset3 and dataset4 have n's of 10. So how do I normalize the distributions when representing these three groups together?
Is there some way to..for example..divide the instances in each bin by the sampling for that group?
You can normalize your histograms by dividing by the total number of elements:
[n1,x1] = histcounts(randn(69,1));
[n2,x2] = histcounts(randn(23,1));
[n3,x3] = histcounts(randn(10,1));
[n4,x4] = histcounts(randn(10,1));
hold on
bar(x4(1:end-1),n4./sum(n4),'histc');
bar(x3(1:end-1),n3./sum(n3),'histc');
bar(x2(1:end-1),n2./sum(n2),'histc');
bar(x1(1:end-1),n1./sum(n1),'histc');
hold off
ax = gca;
set(ax.Children,{'FaceColor'},mat2cell(lines(4),ones(4,1),3))
set(ax.Children,{'FaceAlpha'},repmat({0.7},4,1))
However, as you can see above, you can do some more things to make your code more simple and short:
You only need to hold on once.
Instead of collecting all the bar handles, use the axes handle.
Plot the bar in ascending order of the number of elements in the dataset, so all histograms will be clearly visible.
With the axes handle set all properties at one command.
and as a side note - it's better to use histcounts.
Here is the result:
EDIT:
If you want to also plot the pdf line from histfit, then you can save it first, and then plot it normalized:
dataset = {randn(69,1),randn(23,1),randn(10,1),randn(10,1)};
fits = zeros(100,2,numel(dataset));
hold on
for k = numel(dataset):-1:1
total = numel(dataset{k}); % for normalizing
f = histfit(dataset{k}); % draw the histogram and fit
% collect the curve data and normalize it:
fits(:,:,k) = [f(2).XData; f(2).YData./total].';
x = f(1).XData; % collect the bar positions
n = f(1).YData; % collect the bar counts
f.delete % delete the histogram and the fit
bar(x,n./total,'histc'); % plot the bar
end
ax = gca; % get the axis handle
% set all color and transparency for the bars:
set(ax.Children,{'FaceColor'},mat2cell(lines(4),ones(4,1),3))
set(ax.Children,{'FaceAlpha'},repmat({0.7},4,1))
% plot all the curves:
plot(squeeze(fits(:,1,:)),squeeze(fits(:,2,:)),'LineWidth',3)
hold off
Again, there are some other improvements you can introduce to your code:
Put everything in a loop to make thigs more easily changed later.
Collect all the curves data to one variable so you can plot them all together very easily.
The new result is:

2-d graph with two different axis showing different min and max MATLAB

I have the graph below I need to create two different x-axis. The unique part of this problem is where the min and max values need to be located. The range for is 0-100 for both, however the 100% value on the second x-axis needs to be where the 50% value is on the first. See the picture for clarification. The red is what I need to add using MATLAB.
I did a lot of looking and while it's very simple to put two different axis on one graph, I couldn't find a solution for this particular problem. I'd like this to be done in the code and not plot tools.
How about this
% dummy data
y = 1:80;
x1 = 100*sin( 4*pi*y/80 ).^2 ;
x2 = 100*cos( 5*pi*y/80).^2;
Plot the first line
figure;
line( x1, y, 'Color', 'b', 'LineWidth', 2 );
Get position and size of first plot
haxes1 = gca;
haxes1_pos = get(haxes1,'Position');
set the 100% of second plot to 50% of first ("tweaking" the width of the axis)
haxes1_pos(3) = haxes1_pos(3)/2;
haxes2 = axes('Position',haxes1_pos,'XAxisLocation','top','Color','none','XColor','r');
Plot the second line
line( x2, y, 'Color', 'k', 'LineWidth',2,'Parent',haxes2);
And this is what you get

How do I reach first and second plots from bode()

I know how to create the Bode plots with bode() function. If I want to overlap two or more systems frequency responses, I use
bode(sys1,sys2,...)
or
hold on
When I want to reach the plot in order to put a legend with text(), for instance, is easy to reach the second plot. Something like the figure pointer always returns to the second plot (phase graph).
i.e., if try these lines:
G = tf([1],[1 6]); figure(1); bode(G); text(10,-20,'text');
G = tf([1],[1 6]); figure(2); bode(G); text(10,-20,'text');
when I return to the first figure, with figure(1), and try
figure(1); text(10,-20,'text')
legend is displayed in the second plot (Phase plot)
I try these other lines:
P = bodeoptions; % Set phase visiblity to off
P.PhaseVisible = 'off';
G = tf([1],[1 6]);
figure(1); bode(G,P); text(10,-20,'text');
figure(1); text(10,-20,'text');
As you can see, even I turn off the phase plot visiblity, the legend is not displayed.
Essentialy, my question is, how do I reach first and second plots, one by one? I tried with subplot(), but it is pretty clear this is not the way Matlab traces these plots.
Thanks in advance.
It all comes to getting into upper plot, since after bodeplot command the lower one is active. Intuitively one would want to call subplot(2,1,1), but this just creates new blank plot on top of if. Therefore we should do something like this:
% First, define arbitrary transfer function G(s), domain ww
% and function we want to plot on magnitude plot.
s = tf('s');
G = 50 / ( s*(1.6*s+1)*(0.23*s+1) );
ww = logspace(0,3,5000);
y = 10.^(-2*log10(ww)+log10(150));
hand = figure; % create a handle to new figure
h = bodeplot(G,ww);
hold on;
children = get(hand, 'Children') % use this handle to obtain list of figure's children
% We see that children has 3 objects:
% 1) Context Menu 2) Axis object to Phase Plot 3) Axis object to Magnitude Plot
magChild = children(3); % Pick a handle to axes of magnitude in bode diagram.
% magChild = childern(2) % This way you can add data to Phase Plot.
axes(magChild) % Make those axes current
loglog(ww,y,'r');
legend('transfer function','added curve')
you can get magnitude and phase data separately for each system using:
[mag,phase] = bode(sys,w)
now you can use subplot or plot to plot the diagram you want.
The only solution I was able to perform is taking into account axis position. It is not very clean but it works.
Here is the code to select mag plot:
ejes=findobj(get(gcf,'children'),'Type','axes','visible','on');
posicion=get(ejes,'pos');
tam=length(posicion);
for ii=1:tam
a=posicion{ii}(2);
vectorPos(ii)=a;
end
[valorMax,ind]=max(vectorPos); % min for choosing the phase plot
axes(ejes(ind))