Matlab Horizontal Bar Double Graph - matlab

I made in Matlab a horizontal bar plot, with a bar coming from left to right:
Horizontal Single Bar Plot
I would like to add an additional horizontal bar, on the same horizontal plan of the previous bar, this time coming from right to left. The bar is supposed to stop at the white dot (with its error bars). Both horizontal bars should be present at the same time.
Does anybody have any idea on how to do that? If I use the reverse function everything is reversed, but I need to reverse only the new specific bar without changing anything else.
Here is my script:
figure
Data = [19 26; 1.7 2; 1.8 2]; % 1 Means 2 Error Bars1 3 Errors Bars2
%% Horizontal Bar Graph
barh(Data(1,1),'FaceColor',[0,0.5,0.5],'EdgeColor',[0,0,0],'LineWidth',2);
hold on
x = Data(1,1); %mean Bar 1
e = Data(2,1); %err Bar 1
f = Data(3,1); %err Bar 2
h = herrorbar(x,1,e,f);
set(h(1),'linewidth',6,'Color',[0 0 0]);
%% Point for other bar graph coming from other side
hold on;
plot(Data(1,2),1,'o','LineWidth',2,'MarkerSize',20,'MarkerEdgeColor','k','MarkerFaceColor',[1 1 1])
%% Axis limits etc etc
set(gca,'fontsize',20)
set(gca,'linewidth',3)
axis([10 30 0.5 1.5])

A possible solution could be to add a new axes to the figure, in the same position and of the same size of the firt one.
You can then plot the second horizontal bar in the new axes.
In order to have the second bar aligned to the right, you have to set the XDir property of the second axes to reverse
Setting the color property of the second axes to `none" allows you not to mask the first bar.
In order to plot the second bar from right to left up to the circle, you can evalaute the distance from the right limit of the first axex (i. e. the max of its XLim) from the position of the circle.
I'm not sure how you want to evalaute the errorbar, so, in the following code I've used the same settings of the first one, you can easily adapt it.
In the following you can find a possible implementation of the proposed solution.
figure
Data = [19 26; 1.7 2; 1.8 2]; % 1 Means 2 Error Bars1 3 Errors Bars2
% Horizontal Bar Graph
barh(Data(1,1),'FaceColor',[0,0.5,0.5],'EdgeColor',[0,0,0],'LineWidth',2);
hold on
x = Data(1,1); %mean Bar 1
e = Data(2,1); %err Bar 1
f = Data(3,1); %err Bar 2
h = herrorbar(x,1,e,f);
set(h(1),'linewidth',6,'Color',[0 0 0]);
% Point for other bar graph coming from other side
hold on;
plot(Data(1,2),1,'o','LineWidth',2,'MarkerSize',20,'MarkerEdgeColor','k','MarkerFaceColor',[1 1 1])
% Axis limits etc etc
set(gca,'fontsize',20)
set(gca,'linewidth',3)
axis([10 30 0.5 1.5])
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ADD THE SECOND AXES AND %
% PLOT THE SECOND BAR %
%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Get first axes position
xp=get(gca,'position')
% Get first axes X Limits
first_ax_lim=get(gca,'xlim')
% Get first axes X span
first_ax_span=first_ax_lim(2)-first_ax_lim(1)
% Create the second axes in the same position of the first one
new_ax=axes('position',xp)
% Get the data for the second bar
new_bar_data=first_ax_lim(2)-Data(1,2)
% Plot the second bar in the second axes
barh(new_bar_data,'FaceColor',[0,0.5,0.5],'EdgeColor',[0,0,0],'LineWidth',2);
% Set the properties of the second axes
set(new_ax,'xdir','reverse','color','none')
% Set the limits of the second axes
axis([0 first_ax_span 0.5 1.5])
% Remove the XTick from the second axes
new_ax.XTick=[]
new_ax.YTick=[]
% Add the error bar on the second axes
hold on
new_h = herrorbar(new_bar_data,1,e,f);
% Set the properties of the second error bar
set(new_h,'linewidth',6,'Color',[0 0 0]);

Related

How to overlay single data points on bar graph in 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.

Having groups of the same color in a bar graph and having the legend elements in the bars

I have a bar graph as given below and x is a 8x3 matrix. My codes are as
x=[0.2193 0.2281 0;
0.193 0.1404 0;
0.2045 0.1875 0.159;
0.0625 0.0568 0;
0.1993 0.1554 0.1318;
0.0878 0.0034 0;
0.1369 0.1103 0.1027;
0.0951 0.076 0];
x0=10;
y0=10;
width=1200;
height=500;
set(gcf,'position',[x0,y0,width,height])
a=bar(x,'BarWidth',0.9);
a(1).FaceColor=[0.9290, 0.6940, 0.1250];
a(2).FaceColor=[0, 0.4470, 0.7410];
a(3).FaceColor=[0.4660, 0.6740, 0.1880];
lgd=legend('Method 1','Method 2','Method 3');
title('False Negative Rates')
xlabel('Clusters')
ylabel('False Negative Rate')
xticklabels({'Cl1 - PRed','Cl1 - PYellow','Cl2 - PRed','Cl2 - PYellow', 'Cl3 - PRed','Cl3 - PYellow', 'Cl4 - PRed','Cl4 - PYellow'})
saveas(gcf,'False Negatives.png')
As you can see there are 8 groups in the chart.
I need to do three things with this graph:
1st, 3rd, 5th and 7th groups should be colored red, and others yellow.
I need to write the legend elements inside every bar. If it doesn't fit inside, then above it in a vertical fashion. Red bars will have white font, yellow bars will have black font.
If the value is 0, then show it by a line on the horizontal axis.
I went through this but couldn't apply similarly.
How to make groups of horizontal bars have the same color?
How can I achieve any or all of these?
You need to follow the following algorithm to correctly get the graph as per requirements.
Loop for each element individually in the x matrix.
And for each element plot the respective bar graph and hold on.
Check each column number in a switch-case and accordingly put the legends vertically above the bars.
Next, check if the row number is odd, if yes then change the bar color to red and legend color to white. Within this step fix the position of legends inside/outside the bars, based on the bar length.
If, row is an even number then change the bar color to yellow and change the legend color to black and fix the legend position accordingly as per bar length.
Finally, check whether the x bar length is 0, if yes then increase the Line-Width and slide up the bar's legend.
Increment the bar's gap variable and close the inner loop.
Increment again the bar's gap variable and close the outer loop.
Hold off and Put the title, ticks and labels.
The code to do is given below.
clc
close all
% declare the points, for the bars
x=[0.2193 0.2281 0;
0.193 0.1404 0;
0.2045 0.1875 0.159;
0.0625 0.0568 0;
0.1993 0.1554 0.1318;
0.0878 0.0034 0;
0.1369 0.1103 0.1027;
0.0951 0.076 0];
% declare the figure width and height
x0=10;
y0=10;
width=1200;
height=500;
% create the figure
set(gcf,'position',[x0,y0,width,height]);
% get the number of rows and column in x points
[row, col] = size(x);
% variable to decide the gap between the bars
p = 1;
%%%%%% Loop for Rows %%%%%%%%
for r = 1:row
%%%%%%%%%% loop for each elements in each row %%%%%%%
% loop for columns %
for c = 1:col
% draw the individual bar
a = bar(p, x(r,c), 'BarWidth',0.9); hold on
% switch the column value
switch(c)
% if column is 1 then create bar legend as "Method 1"
% vertically just above the bar
case 1
t1 = text(p,x(r,c),'Method 1','rotation',90);
% if column is 2 then create bar legend as "Method 2"
% vertically just above the bar
case 2
t1 = text(p,x(r,c),'Method 2','rotation',90);
% if column is 3 then create bar legend as "Method 3"
% vertically just above the bar
case 3
t1 = text(p,x(r,c),'Method 3','rotation',90);
end
% Now check whether the row is odd
% if yes then change the bar color to Red
if(rem(r, 2) ~= 0)
set(a, 'FaceColor', 'r')
% Change the legend color to white in red bars
t1.Color = 'White';
% check if x value is equals or greaten than
% 0.05, it means the legend fit inside the bars
if(x(r,c) >= 0.05)
% slide down the legend into the bars
t1.Position = [p, x(r,c)-0.04];
else
% else change the color of the
% legend to black and keep the
% position unchanged, because if the
% position remains outside the red bars
% then the legend would not be visible due
% to the color white and hence change it to black
t1.Color = 'black';
end
else
% else, it means row is even then
% change the bar color to yellow
set(a, 'FaceColor', 'y')
% if bar color is yellow then change the legend
% color to black
t1.Color = 'black';
% check if length of bar is greater than 0.05
% if yes slide the legend position inside the bar
if(x(r,c) >= 0.05)
t1.Position = [p, x(r,c)-0.04];
end
end
% finally, check if x is equal to 0
% then make the line width of bar to
% 2 points, to make it more visible
% and slide up the legend above the bar
% to few fractional points to make it more ligible
if(x(r,c) == 0)
a.LineWidth = 2;
t1.Position = [p, x(r,c)+0.002];
end
% increment the legend gap as y-axis
p = p+1;
end
%%%%% END the Column loop %%%%%%%%%
% on each row end increment the gap of bars to
% make it categorized as each row.
p = p+1;
end
%%%%%%%%% END the Row loop %%%%%%%%%%%
hold off
% set the title
title('False Negative Rates')
% set the labels
xlabel('Clusters')
ylabel('False Negative Rate')
% mark the xticks to put the xticklables
% in next line
xticks([2:4:32])
% change the xtick labels at corresponding xticks
xticklabels({'Cl1 - PRed','Cl1 - PYellow','Cl2 - PRed','Cl2 - PYellow', 'Cl3 - PRed','Cl3 - PYellow', 'Cl4 - PRed','Cl4 - PYellow'})
saveas(gcf,'False Negatives.png')
OUTPUT

matlab - set tick label at origin

In generating plots with Matlab, when both the x and y minimum are zero, I prefer to have only one zero marking the origin rather than denoting it on both axes.
Matlab defaults to the latter, like so
Whereas I want something more like this
This can be done manually, but I'm trying to automate the process. Removing the x and y tick labels for 0 are obviously easy enough. However, I can't seem to access any handle for the position of the axis tick labels to properly position a text box for the 'new origin'. It seems the tick label offsets from the x and y axes may be somewhat constant in a given figure (in physical units, not normalized units), but I don't know if this is a standard across all figures or axes.
Any ideas?
I'm running Matlab 2014b.
Here's a simple way to do that:
% somthing to plot:
x = 0:0.1:2*pi;
y = abs(sin(x)+cos(x));
plot(x,y)
% get the handle for the current axes:
ax = gca;
% get the position of the zero tick on y-axis:
zeroYtick = ax.YAxis.TickValues==0;
% remove it (tick and lable)
ax.YAxis.TickValues(zeroYtick) = [];
The result:
If you want the 0 to be offset a little to the left, so it will be at the corner of the plot, you can use annotation:
% get the position of the zero tick on x-axis:
zeroXtick = ax.XAxis.TickValues==0;
% remove it (tick and lable)
ax.XAxis.TickValues(zeroXtick) = [];
% place a new zero at the origin:
dim = [0.1 0.01 0.1 0.1];
annotation('textbox',dim,'String','0',...
'FitBoxToText','on','LineStyle','none')
And you will get:
The advantage in annotation is that the origin always placed relative to the corner of the axes, and you don't need to know the values of the axes ticks to properly offset it.
EDIT:
For pre 2016a version you can use the following (I wrote it a little more compact):
ax = gca;
% remove the zero tick on y-axis (tick and lable):
ax.YTick(ax.YTick==0) = [];
% remove the zero tick on x-axis (tick and lable):
ax.XTick(ax.XTick==0) = [];
% place a new zero at the origin:
dim = [0.1 0.01 0.1 0.1];
annotation('textbox',dim,'String','0',...
'FitBoxToText','on','LineStyle','none')
EDIT 2:
Another option to keep the 0 in place is to stick it to the axes. this is done by replacing the Parent with the axes handle. First, we need a handle to the annotation (continuing from the last edit):
t = annotation('textbox',dim,'String','0',...
'FitBoxToText','on','LineStyle','none');
then we switch the Parent and set the new position:
t.Parent = ax;
t.Position(1:2) = -[0.2 0.1];
and finally, we super-glue it by converting the Units to pixels:
t.Units = 'Pixels';
The following will exclude the first tick on yaxis without shifting the graph at all. You can ensure that the correct item is being removed by setting the axis limits, ylim([0,upper_limit]) prior to removing the first one, or manually setting your yTicks, set(h,'yTick',my_ticks). Note that yTick changes the position of the ticks, while yTickLabel will change the text appearing at each position of yTick
h = plot([0,1],[0,1]);
yTicks = get(h,'yTick');
set(h,'yTick',yTick(2:end));

Matlab Area Plot: Adjusting box style and tick marks

I am trying to create area plots with 2 y-axis using plotyy by using 'area' function. I don't want to have any tick marks or labels or titles but I just want the outside box. I would also like to save just the plot (not the entire figure window) as a png file.
When I turn off the x and y-axis ticks and labels, the box looks thin on the bottom and left, thick on the top and right. What am I doing wrong?
Also, if I try to make the box 'LineWidth' fat, I see two tick marks at the bottom left and bottom right - which ruin the plot and I am unable to remove. Can someone help?
My test code is below:
x = 1:100;
y1 = rand(size(x));
y2 = 100*rand(size(x));
fig_handle = figure('units','inches','position',[1 1 9 3]);
[a,p1,p2] = plotyy(x,y1,x,y2,'area');
c1 = get(p1,'child');
c2 = get(p2,'child');
set(c1,'facea',0.5,'FaceColor','b','EdgeColor',[0 0 0]);
set(c2,'facea',0.5,'FaceColor','r','EdgeColor',[0 0 0]);
set(c1,'Line','None');
set(c2,'Line','None');
set(a,'Layer','top')
set(a,'XTick',[]);
set(a(1),'YTick',[]);
set(a(2),'YTick',[]);
set(a,'TickDir','in')
set(a,'LineWidth',5);
Also, notice how the left Y-axis has red area on it, while the right Y-axis doesn't. Is this fix-able?
Any help would be appreciated! Also, I am new to StackOverflow - so, if these are too many questions in one post, please pardon me and I will post them as separate requests/questions.
Here is a workaround for the red appearing on the left Y-axis.
Since the axes line is quite thick, the data displayed close to it is drawn over it. To avoid this, you can slightly shift the x limits of the axes to make more room for the data. Do so by changing the XLim property of either axes since they share the same x limit:
XL = get(a,'Xlim');
xl = XL{1}; %// here XL{1} and XL{2} are the same...[1 100]
set(a(:),'Xlim',[xl(1)-.5 xl(2)+.5])
As for the annoying tick marks at the bottom of the plot, I must say that I don't know how to remove them while keeping the axes visible.
As an alternative solution to plotyy, here is a way to obtain a good result (I think) without plotyy. The trick is to superimpose 2 axes and make both of them not visible, then set the figure's color to white and add a black rectangle surrounding the plot.
Here is the code:
clear
clc
close all
x = 1:100;
y1 = rand(size(x));
y2 = 100*rand(size(x));
H1 = area(x,y1);
%// Set the figure color to white
set(gcf,'Color','w')
%// Plot data and set different properties for each axes
A1 = gca;
A2 = axes('Position',get(A1,'Position'));
H2 = area(x,y2);
set(A2,'YAxisLocation','right','Color','none','XTickLabel',[]);
set(A2,'XLim',get(A1,'XLim'),'XTick',[],'YTick',[]);
set(A1,'XTick',[],'YTick',[]);
%// Make both axes not visible.
set(A2,'Visible','off')
set(A1,'Visible','off')
axes(A1)
%// Get axes limits
XL = get(gca,'XLim');
YL= get(gca,'YLim');
%// Create rectangle as a bounding box
rectangle('Position',[XL(1) YL(1) XL(2)-1 YL(2)],'LineWidth',5)
%//===
%// Change the data color/properties
hP = findobj('Type','patch');
set(hP(1),'FaceColor','b','FaceAlpha',.5,'EdgeColor',[0 0 0],'line','none')
set(hP(2),'FaceColor','r','FaceAlpha',.5,'EdgeColor',[0 0 0],'line','none')
And the output:
It's not perfect but hope that helps!

x-axis labels move to top of graph after using

I am using Rotate Tick Label to change the labels on the x-axis to a vertical orientation.
Before using the rotate tick label function the labels on the x-axis are on the bottom of the graph:
After the following command:
TH= rotateTickLabel(gca,90);
the graph looks like this:
How do I get the labels to stay on the bottom of the graph and not move to the top?
The reason why you get this error is because on plots made with 'plot' the YTicks are defined from bottom up. And on image plots (made with 'image') the YTicks are defined from top down. Make the following two changes to rotateticklabel.m:
Edit line 54 so that it looks like this:
th=text(b,repmat(c(end)-.1*(c(end-1)-c(end)),length(b),1),a,'HorizontalAlignment','right','rotation',rot);
Edit line 56 to look like this:
th=text(b,repmat(c(end)-.1*(c(end-1)-c(end)),length(b),1),a,'HorizontalAlignment','left','rotation',rot);
For completion, the entire rotateticklabel.m should look like this:
function th=rotateticklabel(h,rot,demo)
%ROTATETICKLABEL rotates tick labels
% TH=ROTATETICKLABEL(H,ROT) is the calling form where H is a handle to
% the axis that contains the XTickLabels that are to be rotated. ROT is
% an optional parameter that specifies the angle of rotation. The default
% angle is 90. TH is a handle to the text objects created. For long
% strings such as those produced by datetick, you may have to adjust the
% position of the axes so the labels don't get cut off.
%
% Of course, GCA can be substituted for H if desired.
%
% TH=ROTATETICKLABEL([],[],'demo') shows a demo figure.
%
% Known deficiencies: if tick labels are raised to a power, the power
% will be lost after rotation.
%
% See also datetick.
% Written Oct 14, 2005 by Andy Bliss
% Copyright 2005 by Andy Bliss
%DEMO:
if nargin==3
x=[now-.7 now-.3 now];
y=[20 35 15];
figure
plot(x,y,'.-')
datetick('x',0,'keepticks')
h=gca;
set(h,'position',[0.13 0.35 0.775 0.55])
rot=90;
end
%set the default rotation if user doesn't specify
if nargin==1
rot=90;
end
%make sure the rotation is in the range 0:360 (brute force method)
while rot>360
rot=rot-360;
end
while rot<0
rot=rot+360;
end
%get current tick labels
a=get(h,'XTickLabel');
%erase current tick labels from figure
set(h,'XTickLabel',[]);
%get tick label positions
b=get(h,'XTick');
c=get(h,'YTick');
%make new tick labels
if rot<180
th=text(b,repmat(c(end)-.1*(c(end-1)-c(end)),length(b),1),a,'HorizontalAlignment','right','rotation',rot);
else
th=text(b,repmat(c(end)-.1*(c(end-1)-c(end)),length(b),1),a,'HorizontalAlignment','left','rotation',rot);
end
Once you edit rotateticklabel.m you can now successfully use it on plots made with 'image' as in this short example:
A = magic(5);
image(A)
datetick('x',0,'keepticks')
h=gca;
set(h,'position',[0.13 0.35 0.775 0.55])
rot=90;
th = rotateticklabel(h,30)