formatting plotyy with two vectors for each y axis - matlab

I have a plotyy figure in MATLAB with 2 vectors in on each y axis.
plotyy(x1,[y1(:),y2(:)], x1,[y3(:),y4(:)])
I need to format each of the lines separately, but can not find the documentation about how to do this. Can someone please me show an example?

Does the following example code help?
%# Generate some data
N = 20;
X = (1:N)';
Y1 = randn(N, 1);
Y2 = randn(N, 1);
Y3 = randn(N, 1) - 50;
Y4 = randn(N, 1) - 50;
%# Perform the plotyy, returning an axes handle, and a handle for both figures
[Axes, fig1, fig2] = plotyy(X, [Y1 Y2], X, [Y3 Y4]);
%# Change the format of Y1 and Y2 (separately)
set(fig1(1), 'LineStyle', ':');
set(fig1(2), 'LineStyle', '--');
%# Change the format of Y3
set(fig2(1), 'LineStyle', '-.');
In the above code, the figure handle fig1 corresponds to the first y-plot, ie Y1 and Y2, and I can access the individual lines by indexing fig1 with 1 and 2.
Similarly, the figure handle fig2 corresponds to the second y-plot, ie Y3 and Y4, and I access Y3 by indexing this handle with 1. I could also access Y4 with fig2(2), if I so desired.

Related

Correctly aligning labels for subgroups within a tiledlayout

I want to put 5 plots in a figure using tiledlayout, 2x2 plots at the top then a plot at the bottom that spans two columns. There should be two sets of axis labels: one for the 2x2 plot and another for the bottom plot. My MWE is
x = linspace(-2,2,100);
y1 = sin(x);
y2 = cos(x);
y3 = sin(x).*cos(2*x);
y4 = sin(2*x).*cos(x);
y5 = y3 + y4;
figure('PaperUnits', 'inches', 'PaperSize', [4 6], 'PaperPosition', [0 0 4 6]);
t = tiledlayout(3,2,'TileSpacing','compact','Padding','compact');
nexttile; plot(x,y1); title('y_1');
nexttile; plot(x,y2); title('y_2');
nexttile; plot(x,y3); title('y_3');
nexttile; plot(x,y4); title('y_4');
xlabel(t,'time t_\alpha')
ylabel(t,'amplitude \alpha')
nexttile([1 2]); plot(x,y5); title('y_5');
xlabel('time t_\beta')
ylabel('amplitude \beta')
saveas(gcf,'myfig.jpg')
This gives me the following figure:
I want the amplitude \alpha ylabel and the time t_alpha xlabel to be aligned correctly for the 2x2 plots (as indicated by my red annotations). Is there a way to do this?
I'm using MATLAB R2020a. Note that the tiledlayout function was introduced in R2019b.
An approximation of what you wanted can be achieved by the approach I mentioned in my comment (using a "nested" tiledlayout). The steps necessary to make it work are:
Creating an external vertical layout.
Reserving the first two rows for the nested tiledlayout, by asking a 2-by-1 nexttile, making the resulting axes hidden, and creating a uipanel in its place. Calling uipanel is necessary because the parent of a tiledlayout cannot be another tiledlayout, but it can be a Panel.
Plotting everything in the appropriate panels, and applying the labels accordingly.
x = linspace(-2,2,100);
y1 = sin(x);
y2 = cos(x);
y3 = sin(x).*cos(2*x);
y4 = sin(2*x).*cos(x);
y5 = y3 + y4;
hF = figure('PaperUnits', 'inches', 'PaperSize', [4 6], 'PaperPosition', [0 0 4 6]);
tOut = tiledlayout(hF,3,1);
hAx = nexttile(tOut, [2,1]); hAx.Visible = 'off';
hP = uipanel(hF, 'Position', hAx.OuterPosition, 'BorderWidth', 0);
tIn = tiledlayout(hP,2,2,'TileSpacing','compact','Padding','compact');
nexttile(tIn); plot(x,y1); title('y_1');
nexttile(tIn); plot(x,y2); title('y_2');
nexttile(tIn); plot(x,y3); title('y_3');
nexttile(tIn); plot(x,y4); title('y_4');
xlabel(tIn,'time t_\alpha')
ylabel(tIn,'amplitude \alpha')
hAx = nexttile(tOut); plot(x,y5); title('y_5');
xlabel(hAx, 'time t_\beta')
ylabel(hAx, 'amplitude \beta')
Resulting in:
From here you can try tweaking the individual GUI elements (layouts, axes, panel) to get a result closer to what you wanted.
A completely different route I can suggest is starting with your code and adding the labels for the top 4 plots using the annotation function (instead of xlabel and ylabel).

How to make a matlab legend recognize multiple scatter plots?

I want to place three scatter plots in the same figure window and have a legend that describes them. The scatter plots all load in the same window just fine, but the legend only recognizes the last series. In other words, the legend shows a red marker (the color for the last series) for each of its entries.
How do I make the legend recognize each scatter and not just the last one? I've tried a bunch of different things, and none of them seem to work. Thanks!
The picture is the plot for one of my datasets, note the legend.
s10 = scatter3(x1, y1, z1, 'b'); hold on;
s1 = scatter3(x2, y2, z2, 'g'); hold on;
s01 = scatter3(x3, y3, z3, 'r'); hold on;
legend([s10,s1,s01], {'10ms', '1ms', '0.1ms'})
% Every legend entry is red (pertains to the last series)
I can't reproduce the problem. Using your code above with random data seems to work (I did fix a typo, you need a comma after the first argument to legend):
x1 = rand(10, 1); y1 = rand(10, 1); z1 = rand(10, 1);
x2 = rand(10, 1); y2 = rand(10, 1); z2 = rand(10, 1);
x3 = rand(10, 1); y3 = rand(10, 1); z3 = rand(10, 1);
s10 = scatter3(x1, y1, z1, 'b'); hold on;
s1 = scatter3(x2, y2, z2, 'g'); hold on;
s01 = scatter3(x3, y3, z3, 'r'); hold on;
legend([s10,s1,s01], {'Series 10', 'Series 1', 'Series 01'})
For me this seems to be associated with the recent version of Matlab (R2015b); in this version I get the same problem as you with the legend entries showing only one color (in contrast to the other answers that can't reproduce the problem). But if I roll back to a previous version (R2010b), the problem goes away. I'm not sure if you have that option, but it might help diagnose the precise issue.
If the previous answer doesn't work, you can also exploit dynamic legends. This answer is what is inspiring this post: Dynamic Legend (Updates in every recursion). This is a rather undocumented feature but it does work very well. Basically, after each plot, you are able to dynamically update what the legend looks like without having to make one call to legend that has all of them together.
As such, try something like this. I'll borrow some of the previous answer's code to get me started:
x1 = rand(10, 1); y1 = rand(10, 1); z1 = rand(10, 1);
x2 = rand(10, 1); y2 = rand(10, 1); z2 = rand(10, 1);
x3 = rand(10, 1); y3 = rand(10, 1); z3 = rand(10, 1);
scatter3(x1, y1, z1, 'b', 'DisplayName', '10ms'); hold on;
legend('-DynamicLegend');
scatter3(x2, y2, z2, 'g', 'DisplayName', '1ms'); hold on;
legend('-DynamicLegend');
scatter3(x3, y3, z3, 'r','DisplayName', '0.1ms'); hold on;
legend('-DynamicLegend');
Call scatter3, then make sure that you use the 'DisplayName' flag and place what you would normally put in the appropriate legend spot. After each call to scatter3 after, you use the legend('-DynamicLegend'); command to signal to MATLAB that the legend entries will be forthcoming... you're going to specify them in the 'DisplayName' flag.
When you do that, this is the figure I get:
As a minor note, I can't reproduce your plot either. I get the same plot as the previous answer.
This issue is caused by a Matlab bug affecting version R2015b. It was fixed in R2016a. There is a bugreport here, which contains a patch and 3 alternative workarounds.
Here are the workarounds in case the link goes dead:
If you are unable to install the patch, there are three alternative workarounds:
If the CData of each scatter plot is an RGB triplet, then assign the MarkerEdgeColor or MarkerFaceColor of each scatter plot to the value of the CData:
s1 = scatter(1:10,1:10);
hold on
s2 = scatter(2:11,1:10);
s1.MarkerEdgeColor = s1.CData;
s2.MarkerEdgeColor = s2.CData;
legend('show');
Assign an RGB triplet to the MarkerEdgeColor or MarkerFaceColor of each scatter plot:
s1 = scatter(1:10,1:10);
hold on
s2 = scatter(2:11,1:10);
s1.MarkerEdgeColor = [0 0.4470 0.7410];
s2.MarkerEdgeColor = [0.8500 0.3250 0.0980];
legend('show');
Use this workaround when all the points within each scatter plot are the same color.
Call the legend function with two or more output arguments:
s1 = scatter(1:10,1:10,[],1:10);
hold on
s2 = scatter(2:11,1:10,[],26:35);
[h, ~] = legend('show');
Use this workaround when the points within each scatter plot are different colors.

Only plotting two of four diagrams in yyaxes

I am trying to use a plotyy and hold on to plot four diagrams in two y axes and it did not work.
Can anybody see where is the problem?
It only plots the first two diagrams:
load dexpan2Cp;
x1=dexpan2Cp(:,2);
x1=x1/3600;
y1=((dexpan2Cp(:,3)+dexpan2Cp(:,4))/2000)*32.5;
load Dexpan2_2C;
x2=Dexpan2_2C(:,1);
x2=x2/3600;
y2=Dexpan2_2C(:,2);
A = importdata('Scan Session94-Dexpan19.txt','\t',5);
Dexpan19p=A.data;
save('Dexpan19p.mat','Dexpan19p');
x3=Dexpan19p(:,2);
x3=x3/3600;
y3=((Dexpan19p(:,3)+Dexpan19p(:,4))/2000)*32.5;
load Dexpan19C;
x4=Dexpan19C(:,1);
x4=x4/3600;
y4=Dexpan19C(:,2)+3.3;
x1 = x1(x1<115.7); y1 = y1(1: length(x1) , :);
x2 = x2(x2<115.7); y2 = y2(1: length(x2), :);
x3 = x3(x3<115.7); y3 = y3(1: length(x3), :);
x4 = x4(x4<115.7); y4 = y4(1: length(x4), :);
hold off;
figure;
[ax, h1, h2] = plotyy(x1,y1,x2,y2);
set(h1,'g',y1,'DisplayName','1');
set(h2,'b',y2,'DisplayName','2e');
hold(ax(1),'on');
plot(ax(1),x3,y3,'r',y3,'DisplayName','3');
hold(ax(2),'on');
plot(ax(2),x4,y4,'k',y4,'DisplayName','4');
xlabel('Time (h)');
ylabel(ax(1),' Pressure (MPa)');
ylabel(ax(2),'Tempereture (°C)');
legend('show');
You seem to be using invalid syntax, and not telling us what errors you are receiving when executing your code. In particular, your code errors out after plotting the first two lines -- hence why you are only getting 2 lines plotted.
To make it work, four of your lines should be changed to,
set(h1,'Color','g','DisplayName','1');
set(h2,'Color','b','DisplayName','2e');
plot(ax(1),x3,y3,'Color','r','DisplayName','3');
plot(ax(2),x4,y4,'Color','k','DisplayName','4');

Multiple Data Sets on the Same Scatter

I know this question may sound a bit easy, but I couldn't find what I wanted in the documentation. Basically, I would like to know if a function exists in matlab which allows me to plot data sets y1, y2, ..., yn against the same x-axis in the same scatter diagram.
Any suggestions?
Thanks
You can just use scatter + hold on. For example,
x = rand(1,10);
y1 = rand(1,10);
y2 = rand(1,10);
y3 = rand(1,10);
figure; grid on;
hold on;
scatter(x, y1);
scatter(x, y2);
scatter(x, y3);
Gives:

Show the intersection of two curves

If I have two plots defined by two different equations:
x = 0:0.01:30;
y1 = x .^2 + 2;
y2 = x .^3 ;
and I plot them as
plot(x, y1, x, y2);
How do I get a small ring around the point of intersection programatically (as in the following plot)?
You'll have to find the point of intersection (px, py) manually:
idx = find(y1 - y2 < eps, 1); %// Index of coordinate in array
px = x(idx);
py = y1(idx);
Remember that we're comparing two numbers in floating point representation, so instead of y1 == y2 we must set a tolerance. I've chosen it as eps, but it's up to you to decide.
To draw a circle around this point, you can compute its points and then plot them, but a better approach would be to plot one point with a blown-up circle marker (credit to Jonas for this suggestion):
plot(px, py, 'ro', 'MarkerSize', 18)
This way the dimensions of the circle are not affected by the axes and the aspect ratio of the plot.
Example
x = 0:0.01:30;
y1 = x .^ 2 + 2;
y2 = x .^ 3;
%// Find point of intersection
idx = find(y1 - y2 < eps, 1);
px = x(idx);
py = y1(idx);
figure
plot(x, y1, x, y2, px, py, 'ro', 'MarkerSize', 18)
axis([0 10 0 10])
This should produce the following plot:
In your example, when you have x, y1 and y2
What you can do is
idx = find(abs(y1 - y2) == min(abs(y1 - y2)));
xInter = x(idx)
yInter = y1(idx) % or y2(idx)
If you have x1, y1 and x2, y2, where x1 ~= x2
you could first do 1D interpolation using
yy2 = interp1(x2, y2, x1);
then apply
idx = find(abs(y1 - yy2) == min(abs(y1 - yy2)));
xInter = x1(idx)
yInter = y1(idx) % or yy2(idx)
Excellent post by #EitanT, however I would like to complement this with a different (automated) way to find the intersection (Assuming there is one and the graphs behave nicely).
Here is our starting point:
x = 0:0.01:30;
y1 = x .^2 + 2;
y2 = x .^3 ;
First of all we check whether these values are exactly equal, for non-floating point non-discrete situations this should be sufficient:
idx = find(y1==y2)
If they are never recorded to be exactly equal, an intersection occurs if one surpasses the other, hence we look at the difference:
if isempty(idx)
d = y1-y2;
% At the moment of crossing, the sign will change:
s = diff(sign(d));
% Now just find the point where it changes
f = find(s,1);
end
To summarize this in compact form without additional variables, I would recommend using:
idx = find(y1==y2)
if isempty(idx)
idx = find(diff(sign(y1-y2)),1)
end
Especially when knowing the functions, the symbolic math toolbox can be used.
y1 = x .^2 + 2;
y2 = x .^3 ;
syms x real
intersection=simplify(solve(y1==y2))
Use vpa(intersection) to convert it to a number or double(intersection) to convert it to a floating point value.
Last but not least, perhaps the cleanest way to do this is the command polyxpoly:
[xi,yi] = polyxpoly(x,y1,x,y2)
xi = 1.69560153754948
yi = 4.87508921229275
Good luck!