Vertical line between two stacked x-axes - matlab

I followed the solution to the question "How to insert two X axis in a Matlab plot" to create a graph with two x-axes, one on top of the other.
I am now trying to create a vertical line between the two x-axes at specific x values. For example, let's say I have a figure like the one in the linked question. How would I draw a vertical line at the value x = 2 m/s between the two x-axes?
Here is an image of what I am looking for. The red line is what I am trying to draw in MATLAB. The two x-axes both have the same scale.

this is doable, but tricky. I used annotation but you need to map from the figure units to the axes units. here goes:
% experimental data
M(:,1) = [ 0, 1, 2, 3, 4, 5];
M(:,3) = [12, 10, 15, 12, 11, 13];
% get bounds
xmaxa = max(M(:,1))*3.6; % km/h
xmaxb = max(M(:,1)); % m/s
figure;
% axis for m/s
b=axes('Position',[.1 .1 .8 eps]);
set(b,'Units','normalized');
set(b,'Color','none');
% axis for km/h with stem-plot
a=axes('Position',[.1 .2 .8 .7]);
set(a,'Units','normalized');
stem(a,M(:,1).*3.6, M(:,3));
% set limits and labels
set(a,'xlim',[0 xmaxa]);
set(b,'xlim',[0 xmaxb]);
xlabel(a,'Speed (km/h)')
xlabel(b,'Speed (m/s)')
ylabel(a,'Samples');
title(a,'Double x-axis plot');
% this where the trick happens
pos = get(b, 'Position') ;
x_normalized = #(x0) (x0 - min(b.XLim))/diff(b.XLim) * pos(3) + pos(1);
xl = [x_normalized(2) x_normalized(2)]; % because you wanted x=2 m/s
yl = [0.1 0.2];
annotation('line',xl,yl,'Color',[1 0 0])

Related

How to create three Y-axis in one graph? [duplicate]

I have 4 sets of values: y1, y2, y3, y4 and one set x. The y values are of different ranges, and I need to plot them as separate curves with separate sets of values on the y-axis.
To put it simple, I need 3 y-axes with different values (scales) for plotting on the same figure.
Any help appreciated, or tips on where to look.
This is a great chance to introduce you to the File Exchange. Though the organization of late has suffered from some very unfortunately interface design choices, it is still a great resource for pre-packaged solutions to common problems. Though many here have given you the gory details of how to achieve this (#prm!), I had a similar need a few years ago and found that addaxis worked very well. (It was a File Exchange pick of the week at one point!) It has inspired later, probably better mods. Here is some example output:
(source: mathworks.com)
I just searched for "plotyy" at File Exchange.
Though understanding what's going on in important, sometimes you just need to get things done, not do them yourself. Matlab Central is great for that.
One possibility you can try is to create 3 axes stacked one on top of the other with the 'Color' properties of the top two set to 'none' so that all the plots are visible. You would have to adjust the axes width, position, and x-axis limits so that the 3 y axes are side-by-side instead of on top of one another. You would also want to remove the x-axis tick marks and labels from 2 of the axes since they will lie on top of one another.
Here's a general implementation that computes the proper positions for the axes and offsets for the x-axis limits to keep the plots lined up properly:
%# Some sample data:
x = 0:20;
N = numel(x);
y1 = rand(1,N);
y2 = 5.*rand(1,N)+5;
y3 = 50.*rand(1,N)-50;
%# Some initial computations:
axesPosition = [110 40 200 200]; %# Axes position, in pixels
yWidth = 30; %# y axes spacing, in pixels
xLimit = [min(x) max(x)]; %# Range of x values
xOffset = -yWidth*diff(xLimit)/axesPosition(3);
%# Create the figure and axes:
figure('Units','pixels','Position',[200 200 330 260]);
h1 = axes('Units','pixels','Position',axesPosition,...
'Color','w','XColor','k','YColor','r',...
'XLim',xLimit,'YLim',[0 1],'NextPlot','add');
h2 = axes('Units','pixels','Position',axesPosition+yWidth.*[-1 0 1 0],...
'Color','none','XColor','k','YColor','m',...
'XLim',xLimit+[xOffset 0],'YLim',[0 10],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
h3 = axes('Units','pixels','Position',axesPosition+yWidth.*[-2 0 2 0],...
'Color','none','XColor','k','YColor','b',...
'XLim',xLimit+[2*xOffset 0],'YLim',[-50 50],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
xlabel(h1,'time');
ylabel(h3,'values');
%# Plot the data:
plot(h1,x,y1,'r');
plot(h2,x,y2,'m');
plot(h3,x,y3,'b');
and here's the resulting figure:
I know of plotyy that allows you to have two y-axes, but no "plotyyy"!
Perhaps you can normalize the y values to have the same scale (min/max normalization, zscore standardization, etc..), then you can just easily plot them using normal plot, hold sequence.
Here's an example:
%# random data
x=1:20;
y = [randn(20,1)*1 + 0 , randn(20,1)*5 + 10 , randn(20,1)*0.3 + 50];
%# plotyy
plotyy(x,y(:,1), x,y(:,3))
%# orginial
figure
subplot(221), plot(x,y(:,1), x,y(:,2), x,y(:,3))
title('original'), legend({'y1' 'y2' 'y3'})
%# normalize: (y-min)/(max-min) ==> [0,1]
yy = bsxfun(#times, bsxfun(#minus,y,min(y)), 1./range(y));
subplot(222), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('minmax')
%# standarize: (y - mean) / std ==> N(0,1)
yy = zscore(y);
subplot(223), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('zscore')
%# softmax normalization with logistic sigmoid ==> [0,1]
yy = 1 ./ ( 1 + exp( -zscore(y) ) );
subplot(224), plot(x,yy(:,1), x,yy(:,2), x,yy(:,3))
title('softmax')
Multi-scale plots are rare to find beyond two axes... Luckily in Matlab it is possible, but you have to fully overlap axes and play with tickmarks so as not to hide info.
Below is a nice working sample. I hope this is what you are looking for (although colors could be much nicer)!
close all
clear all
display('Generating data');
x = 0:10;
y1 = rand(1,11);
y2 = 10.*rand(1,11);
y3 = 100.*rand(1,11);
y4 = 100.*rand(1,11);
display('Plotting');
figure;
ax1 = gca;
get(ax1,'Position')
set(ax1,'XColor','k',...
'YColor','b',...
'YLim',[0,1],...
'YTick',[0, 0.2, 0.4, 0.6, 0.8, 1.0]);
line(x, y1, 'Color', 'b', 'LineStyle', '-', 'Marker', '.', 'Parent', ax1)
ax2 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','left',...
'Color','none',...
'XColor','k',...
'YColor','r',...
'YLim',[0,10],...
'YTick',[1, 3, 5, 7, 9],...
'XTick',[],'XTickLabel',[]);
line(x, y2, 'Color', 'r', 'LineStyle', '-', 'Marker', '.', 'Parent', ax2)
ax3 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','right',...
'Color','none',...
'XColor','k',...
'YColor','g',...
'YLim',[0,100],...
'YTick',[0, 20, 40, 60, 80, 100],...
'XTick',[],'XTickLabel',[]);
line(x, y3, 'Color', 'g', 'LineStyle', '-', 'Marker', '.', 'Parent', ax3)
ax4 = axes('Position',get(ax1,'Position'),...
'XAxisLocation','bottom',...
'YAxisLocation','right',...
'Color','none',...
'XColor','k',...
'YColor','c',...
'YLim',[0,100],...
'YTick',[10, 30, 50, 70, 90],...
'XTick',[],'XTickLabel',[]);
line(x, y4, 'Color', 'c', 'LineStyle', '-', 'Marker', '.', 'Parent', ax4)
(source: pablorodriguez.info)
PLOTYY allows two different y-axes. Or you might look into LayerPlot from the File Exchange. I guess I should ask if you've considered using HOLD or just rescaling the data and using regular old plot?
OLD, not what the OP was looking for:
SUBPLOT allows you to break a figure window into multiple axes. Then if you want to have only one x-axis showing, or some other customization, you can manipulate each axis independently.
In your case there are 3 extra y axis (4 in total) and the best code that could be used to achieve what you want and deal with other cases is illustrated above:
clear
clc
x = linspace(0,1,10);
N = numel(x);
y = rand(1,N);
y_extra_1 = 5.*rand(1,N)+5;
y_extra_2 = 50.*rand(1,N)+20;
Y = [y;y_extra_1;y_extra_2];
xLimit = [min(x) max(x)];
xWidth = xLimit(2)-xLimit(1);
numberOfExtraPlots = 2;
a = 0.05;
N_ = numberOfExtraPlots+1;
for i=1:N_
L=1-(numberOfExtraPlots*a)-0.2;
axesPosition = [(0.1+(numberOfExtraPlots*a)) 0.1 L 0.8];
if(i==1)
color = [rand(1),rand(1),rand(1)];
figure('Units','pixels','Position',[200 200 1200 600])
axes('Units','normalized','Position',axesPosition,...
'Color','w','XColor','k','YColor',color,...
'XLim',xLimit,'YLim',[min(Y(i,:)) max(Y(i,:))],...
'NextPlot','add');
plot(x,Y(i,:),'Color',color);
xlabel('Time (s)');
ylab = strcat('Values of dataset 0',num2str(i));
ylabel(ylab)
numberOfExtraPlots = numberOfExtraPlots - 1;
else
color = [rand(1),rand(1),rand(1)];
axes('Units','normalized','Position',axesPosition,...
'Color','none','XColor','k','YColor',color,...
'XLim',xLimit,'YLim',[min(Y(i,:)) max(Y(i,:))],...
'XTick',[],'XTickLabel',[],'NextPlot','add');
V = (xWidth*a*(i-1))/L;
b=xLimit+[V 0];
x_=linspace(b(1),b(2),10);
plot(x_,Y(i,:),'Color',color);
ylab = strcat('Values of dataset 0',num2str(i));
ylabel(ylab)
numberOfExtraPlots = numberOfExtraPlots - 1;
end
end
The code above will produce something like this:

Plotting unit circles in matlab and using the hold on to insert individual data points and plotting the intersection with circle

I was trying to produce the following figure:
as similar as possible. I was having difficulties because I wasn't sure how to plot the unit circle. How does one do that? I tried using the polar function but I couldn't then make it also plot the blue crosses and red crosses. Anyone has an idea?
Edited answer
Here is a part of the code:
% --- Plot everything on the same axes
hold on
% --- Plot the unit circle:
theta = linspace(0, 2*pi, 360);
plot(cos(theta), sin(theta), 'k--');
% --- Plot the blue points
x = [0.2 0.4 0.4 0.8];
y = [0.4 0.2 0.8 0.4];
scatter(x, y, 'bs');
% --- Plot the red points:
x = [0.4 0.8];
y = [0.4 0.8];
scatter(x, y, 'ro');
There are still many modifications to do to get the final plots, but at least this is a starting point.
Second edit
To answer your question about the intersection of a line and a circle, you have to start with the maths behind. Line and circle are defined by the following equations:
y = a.x + b % Cartesian definition of a line
(x-x0)² + (y-y0)² = r² % Cartesian definition of a circle
If you combine the two, you realize that finding the intersection is similar to finding the solution of:
(a²+1).x² + 2(a(b-y0)-x0).x + x0²+(b-y0)²-r² = 0
i.e. the roots of a polynom. As this is a trinom, there are 3 possibilities: 0 solution (no intersection), 1 solution (line is tangent to the circle) and 2 solutions (line crossing the circle).
So, in practice you have to:
Get the parameters a, b, x0, y0 and r of your problem
Find the roots of the polynom (for instance, with the function roots)
Decide what to do based on the number of roots.
Hope this helps,
%% Construct polar grid (put inside another function)
range = 0.2:0.2:1;
n = 50;
for i=1:length(range)
ro = ones(1,n);
ro = ro.*range(i);
th = linspace(0,pi*2,n);
[xx,yy] = pol2cart(th,ro);
plot(xx,yy, 'color',[.9 .9 .9]), grid on, hold on
n = round(n * 1.5);
end
%% Plot like normal
x1 = [.2 .4 .4 .8];
y1 = [.4 .2 .8 .4];
x2 = [.4 .8];
y2 = [.4 .8];
plot(x1,y1, 'bx',...
x2,y2, 'ro');
xlim([-.05 1]);
ylim([-.05 1]);

Zoom region within a plot in Matlab

I'm using Matlab to produce figures, and I'm wondering if there is a way to plot a zoomed region in a figure of the overall data?
I have scatter data plotted over one week, with the x-axis in hours, and I want to zoom into the first 3 hours, and display them within the main figure with the x-axis label of minutes.
The plotting code I have so far is as follows:
allvalsx = marabint(:,2)
allvalsy = marabint(:,5)
subvalsx = marabint(1:7,2);
subvalsy = marabint(1:7,2);
%% Plots the scatter chart.
sizemarker = 135
handle = scatter(allvalsx, allvalsy, sizemarker, '.')
figure(1)
axes('Position',[.2 .2 .2 .2])
handle2 = scatter(subvalsx, subvalsy, '.r')
title(plotTitle)
xlabel('Time since treatment (hours)')
ylabel('Contact angle (deg)')
% Axis scales x1, x2, y1, y2
axis([0, marabint(length(marabint),2) + 10, 0, 120]);
% This adds a red horizontal line indicating the untreated angle of the
% sample.
untreatedLine = line('XData', [0 marabint(length(marabint),2) + 10], 'YData', [untreatedAngle untreatedAngle], 'LineStyle', '-', ...
'LineWidth', 1, 'Color','r');
% Adding a legend to the graph
legendInfo = horzcat('Untreated angle of ', untreatedString)
hleg1 = legend(untreatedLine, legendInfo);
% This encases the plot in a box
a = gca;
% set box property to off and remove background color
set(a,'box','off','color','none')
% create new, empty axes with box but without ticks
b = axes('Position',get(a,'Position'),'box','on','xtick',[],'ytick',[]);
% set original axes as active
axes(a)
% link axes in case of zooming
linkaxes([a b])
set(gcf,'PaperUnits','inches');
set(gcf,'PaperSize', [8.267 5.25]);
set(gcf,'PaperPosition',[0 0.2625 8.267 4.75]);
set(gcf,'PaperPositionMode','Manual');
set(handle,'Marker','.');
print(gcf, '-dpdf', '-r150', horzcat('markertest4.pdf'));
This produces the following
Can anyone help me out with this?
yeah, I think I know what you need. Try this:
zoomStart = 0;
zoomStop = 3;
set(gca, 'XLim', [zoomStart zoomStop])
Let me know if that doesn't do what you need, and I'll give you a different way.

Plot Shaded Area Between Two User-Defined Lines and Beneath Preexisting Data

I am trying to add a grey shaded area between two user-defined vertical lines. I need this gray shaded area to appear beneath my already plotted data. I have tried using the fill and area functions, but haven't been able to successfully create a bounded area to appear underneath the Matlab plot. I need the shaded area plot to extend from the x-axis at vertical lines created at 5.5 and 19 and extend up to the y-axis at 900 (left y-axis) and at 1 (right y-axis). See here: https://www.dropbox.com/s/qyzkuhw17yxn8p5/sample.png
I suppose the problem does not lie in generating the shaded area, but in making it appear below other elements of the plot even though it gets plotted later. You can achieve that by locating it "deeper", i.e. at a smaller z-value. Here is an example, building on the code by randomatlabuser:
x = linspace(0, 24, 100);
plot(x, 450 - 400 * cos(x / 12 * pi), 'k.-')
hold all
x = [5.5 5.5 19 19 5.5];
y = [0 900 900 0 0];
patch(x, y, -1 * ones(size(x)), [0.9 0.9 0.9], 'LineStyle', 'none')
patch is essentially the same as fill, but has a version that supports a third coordinate, the z-value.
From what I understand you want to do this:
h1 = plot((0:24), (0:700/24:700), '-b', 'LineWidth', 10); % some function
hold on
h2 = plot((0:24), 1.5 * (0:24) .^2, '-r', 'LineWidth', 10); % some other function
x = [5.5 5.5 19 19 5.5]; y = [0 900 900 0 0]; % define edges of area
h3 = fill(x, y, [0.9 0.9 0.9], 'LineStyle', 'none'); % fill area
set(gca, 'Children', [h1 h2 h3]) % h3 in the background, then h2 and finally h1 upfront
If not, you need to explain better what you are after.
% Add shaded area to plot
% Line 1
hl1 = line(x1,y1,'Color','b');
x = [5.5 5.5 19 19]; y = [0 900 900 0]; % define edges of shaded area
% Locations for 5:30am and 19:00pm with the left y-axis ranging from 0-900
hl2=fill([x(1) x(2) x(3) x(4)], [y(1) y(2) y(3) y(4)],'Color','r','EdgeColor','none','LineStyle','none');
hl1 = line(x1,y1,'Color','b'); % Replot line 1 over shaded area
hold on;
% Continue adding more shaded areas using the fill function or add lines directly...

How to plot a intersection operation on two vectors MatLab

I'm trying to represent a the intersection of two fuzzy sets as a 3d mesh in MatLab.
Here are my sets of vectors:
x = [0.3 0.5 0.7]
y = [0.5 0.7 0.1]
Followed by these statements:
[u,v] = meshgrid(x,y)
w = min(u,v)
mesh(u,v,w)
The x and y ticks seem to be all over the place and do not correlate to the actual index number of each vector i.e. 1 to 3, and the graph should represent the shape of a small triangle/T-norm.
At the moment it looks like this:
Here is an example out of my book I'm following:
Ignore what looks like fractions, they are delimiters. Here is the resulting graph:
After looking up fuzzy sets and intersections, here's what I've come up with. First, let's reproduce the textbook example:
% possible values and associated degrees of truth for F
Fv = 1 : 5;
Ft = [0 0.5 1 0.5 0];
% possible values and associated degrees of truth for D
Dv = 2 : 4;
Dt = [0 1 0];
% determine degrees of truth for fuzzy intersection
It = bsxfun(#min, Ft', Dt);
% plot
h = mesh(Dv, Fv, It);
set(h, 'FaceColor', 'none')
set(h, 'EdgeColor', 'k')
xlim([0 4.5])
ylim([0 5])
xlabel D
ylabel F
view(37.5, 30)
The result is:
Not as pretty as in your book, but the same thing.
Applying the same code to your example yields:
Via the arguments u,v you are telling mesh to use the values in them, i.e. the values from x and y, for the positioning of the data points and corresponding ticks. If you just want positions and ticks at 1, 2, 3, leave these arguments out.
mesh(w)