Two y-axes plot for multiple data set in Matlab - matlab

I am trying to create two y-axes plot in Matlab.
I have two groups of data, with each group having three plots of similar type. When I am trying to plot it, the scaling on right hand side y-axis get messed up. I would appreciate some help.
X = [50, 100, 200, 400];
YSKL_Temporal_WOFAE = [3.2000 2.3354 1.9428 1.7658];
YSKL_Spatial_WOFAE = [0.9225 0.9724 1.0986 1.1770];
YSKL_Spatial_WithFAE = [0.2635 0.1653 0.1513 0.1618];
YMSRE_Temporal_WOFAE = [0.3559 0.3027 0.2733 0.2636];
YMSRE_Spatial_WOFAE = [.3151 .2689 .2551 0.2524];
YMSRE_Spatial_WithFAE = [.0933 .0648 0.0663 0.0640];
figure(1);
[AX, p1, p2] = plotyy(X, YSKL_Temporal_WOFAE, X, YMSRE_Temporal_WOFAE);
set(AX,'XTick', X); % This fixes X-axis tick mark (same as data axis)
set(get(AX(1),'Ylabel'),'String','SKL Score')
set(get(AX(2),'Ylabel'),'String','Norm. Residuals')
xlabel('Time (\musec)')
title('SKL and Norm. Residual plotted on different y-axes')
set(p1,'LineStyle','--')
set(p2,'LineStyle',':')
axes(AX(1))
hold on
plot(X, YSKL_Spatial_WOFAE);
hold on
plot(X, YSKL_Spatial_WithFAE);
ylim([0 4])
hold off
axes(AX(2))
hold on
plot(X, YMSRE_Spatial_WOFAE);
hold on
plot(X, YMSRE_Spatial_WithFAE);
ylim([0.0 0.4])
hold off
Plot looks like this:
Please notice the scale on right y-axes
Regards,
Dushyant

The second (right hand side) y-axis tick labels are "frozen" after the call to plotyy. When adjusting the ylim on AX(2) this has no effect on the labels.
Therefore, the axes appearance has to be reset to auto.
Using the following code with the example from the question:
axes(AX(2))
hold on
plot(X, YMSRE_Spatial_WOFAE);
hold on
plot(X, YMSRE_Spatial_WithFAE);
ylim([0.0 0.4])
% include the following statement to allow
% the second y-axis to reset the ticks:
set(AX(2), 'YTickMode', 'auto', 'YTickLabelMode', 'auto')
hold off
Will yield this plot:

Related

Two y-axis in Matlab: Setting different ranges and color

I am a noob when it comes to Matlab and I would appreciate any help! I need to create a figure with two y axis, and in order to satisfy my tutors I have to use specific ranges for them, and also to make it "more appealing" use colours that make some sense.
So I have two questions:
First, how can I set different ranges for the two y axis? I know I can use ylim([]} easily for 1 y axis but that doesn't seem to work.
Secondly, how can I easily change the color and format of one plot?(preferably they are the same as the color of the y axis they are assigned to, but Matlab automatically chooses them weirdly) Sadly sth like this won't work:
plot(x,y,'r','-','LineWidth',2.0);
It would be perfect if the first and second plot have the same format so '-' and the third and fourth another e.g. '--' but the plots Colors stay the same as their respective axis.
This is my current figure:
The following is my code
clc
A=dlmread('bipsim2_220.txt');
B=dlmread('bipsim2_680.txt');
x=A(:,1);
y=A(:,3);
plot(x,y,'LineWidth',2.0);
yyaxis left
hold on
x2=A(:,1);
y2=A(:,2);
plot(x2,y2,'LineWidth',2.0);
yyaxis right
hold on
x3=B(:,1);
y3=B(:,3);
plot(x3,y3,'LineWidth',2.0);
yyaxis left
hold on
x4=B(:,1);
y4=B(:,2);
plot(x4,y4,'LineWidth',2.0);
yyaxis right
yyaxis left
ylabel('Verstärkung (dB)')
yyaxis right
ylabel('Phase (deg)')
ylabel('Freq (Hz)')
set(gca,'Xscale','log')
set(gca,'fontsize',18)
hold off
grid minor
legend('R48/220 Ω: Phase [deg]','R48/220 Ω: Gain [dB]','R51/680 Ω: Phase [deg]','R51/680 Ω: Gain [dB]')
Thanks in advance for any help!
You can specify colors using RGB tuple with the color keyword agrument
You can specify linewidth using the linewidth keyword argument
You can specify styles as a positional argument after the data.
You can easily get X with logscale using semilogx
twinx will create a secondary Y-axis on with the labels on the right sharing the same X-axis.
import numpy as np
import matplotlib.pyplot as plt
freq = np.logspace(0, 5) # your frequency grid
# I made up a transfer function
H = lambda s: (s**2 - 1e2*s + 1e2) / (s - 1e3)**2
g = H(2j * np.pi * freq); # evaluate the transfer function at the frequency grid
# plot
plt.semilogx(freq, 20 * np.log10(abs(g)), '--k', linewidth=2)
plt.ylabel('Gain [dB]')
plt.xlabel('Frequency [Hz]');
plt.grid()
plt.twinx()
plt.semilogx(freq, 180 * np.angle(g) / np.pi, '-', linewidth=2, color=[0.8, 0.5, 0.3])
plt.ylabel('Phase [degrees]')
you can also specify predefined colors e.g k for black.
A few things to note:
You only need to call hold on once on the figure. Everything plotted after the first hold on will keep in the plot until you clear it with clf.
You can specify color and line style for each of your plots individually in its respective call to plot(...)
You need to set yyaxis left or yyaxis right before the thing you want to appear on that axis. This Matlab "from now on, we're now going to use the left/right axis"
On the same note, once you've set the approriate axis, you can manipulate its color and range.
In your code (untested because I don't have your input text files):
A=dlmread('bipsim2_220.txt');
B=dlmread('bipsim2_680.txt');
% resorted to have data and plotting separate (no need to do this, just easier to read the plotting part)
x1=A(:,1);
y1=A(:,3);
x2=A(:,1);
y2=A(:,2);
x3=B(:,1);
y3=B(:,3);
x4=B(:,1);
y4=B(:,2);
% set colors as a variables to change them easier
colorLeft = 'r'; % red
colorRight = 'k'; % black
% let's just open a clean figure
clf;
% set hold to on
hold on;
%% do stuff for the left y axis (gain)
yyaxis left;
% plot data with respective color and line style
plot(x1,y1,'LineWidth',2.0, 'Color', colorLeft, 'LineStyle', '-');
plot(x3,y3,'LineWidth',2.0, 'Color', colorLeft, 'LineStyle', '--');
% axis formating
ylabel('Verstärkung (dB)');
ylim([-200, 50]); % chose lower and upper limit for left y-axis
ax = gca; % all the formating of the axis is stored in an axis object which we can manipulate
ax.YColor = colorLeft; % set color of current (i.e. left) y-axis
%% now we move to do stuff for the right y axis (phase)
yyaxis right;
% plot data with respective color and line style
plot(x2,y2,'LineWidth',2.0, 'Color', colorRight, 'LineStyle', '-');
plot(x4,y4,'LineWidth',2.0, 'Color', colorRight, 'LineStyle', '--');
% axis formating
ylabel('Phase (deg)');
ylim([-180, 0]); % chose lower and upper limit for right y-axis
ax.YColor = colorRight; % set color of current (i.e. right) y-axis
%% finally, set all the format stuff not related to a particular y-axis
xlabel('Freq (Hz)')
ax.XScale = 'log';
ax.FontSize = 18;
grid minor
% hold off % no need to turn hold off, its only affecting the current figure anyway
%make sure that the order of legend entries fits the order in which you plot the curves
legend('R48/220 Ω: Gain [dB]','R51/680 Ω: Gain [dB]', 'R48/220 Ω: Phase [deg]','R51/680 Ω: Phase [deg]');

How to plot unevenly spaced data on Matlab / Origin?

I want to plot my following data:
x-axis: [0,10,50,100,500,1000,1500]
y-axis: [75.6,78,78.2,81.8,84.7,85.2,86.3]
As seen above, the data on the x-axis are unevenly spaced. When I plot the above data linearly using origin, I get:
I got the similar graph on Matlab too. Notice that most of the Amp data lie for x<500. I want to plot the graph such that the whole output (y-axis) become clearly visible. For this, I tried using the Logarithmic plot. I changed the x-axis into logarithmic in Matlab as follows:
set(gca, 'XScale','log');
In Origin, we can use GUI to change the x-axis to logarithmic. The obtained graphs are as follows:
The obtained graphs are still not good. Any ideas, please!
Thank you very much.
https://www.mathworks.com/help/matlab/ref/semilogx.html
x = [0,10,50,100,500,1000,1500];
y = [75.6,78,78.2,81.8,84.7,85.2,86.3];
semilogx(x,y,'.-', 'markersize', 15);
set(gca,'XTick',x);
set(gca,'XTickLabelRotation',45);
x = [0,10,50,100,500,1000,1500];
y = [75.6,78,78.2,81.8,84.7,85.2,86.3];
y2 = [80,84,85,86,89,90,92];
semilogx(x+1,y,'.-', 'markersize', 15);
set(gca,'XTick',x);
set(gca,'XTickLabelRotation',45);
hold on;
semilogx(x+1,y2,'.-', 'markersize', 15);
hold off;
grid on;
legend('y1','y');

Multiple plots on a logarithmic scale

I'm trying to plot two lines (data and linear fit) in a single graph with logarithmic scale. My code:
Iots = I_An./Temp.^2; % I Over T Squared
Oot = 1./Temp; % One Over T
[p,~] = polyfit(Oot,Iots,1);
linfit = polyval(p,Oot);
figure('color','w','units','normalized','outerposition',[0 0 1 1]);
hold on
loglog(Oot,Iots,'.','LineWidth',2);
loglog(Oot,linfit,':r','LineWidth',2);
The result is not a logarithmic scale graph:
If I run just one of the plot lines, it works on its own. What should I do? Are there any contradicting commands?
You want to call hold on after creating your first loglog plot. Also, you only need to use loglog on the first plot to create the logarithmic axes. After than you can just call normal plot and it will use the logarithmic axes.
x = linspace(0, 100);
loglog(x, x, '.', 'LineWidth', 2);
hold on
plot(x, x.^2, '.r', 'LineWidth',2);

MATLAB: update surface plot and change location of line objects in while loop

So I am encountering a couple errors and am not sure where they're coming from. I won't post the whole code, but I will do my best to explain (fear I will be accused of plagiarism).
The assignment is to create a window with two plots: a surface plot and a contour plot. The surface plot represents elevation of a portion of the map represented by the contour plot. The portion is indicated by a blue box on the contour plot. I've successfully plotted the surface and contour plots and have identified the first area with a blue box. However, now I need to implement a menu system wherein the user enters 1, 2, 3, or 4 to move the box north, south, east or west.
Here is how I instantiated the plots:
fig = figure(1);
[xGrid, yGrid] = meshgrid(xMeters(xStart:xEnd), yMeters(yStart:yEnd));
%surface plot
elevationBox = ELEV(xStart:xEnd, yStart:yEnd);
surface = subplot(2, 1, 1);
surf(xGrid, yGrid, elevationBox);
axis([0 max(xGrid(:)) 0 max(yGrid(:)) min(elevationBox(:)) max(elevationBox(:))]);
axis tight;
%contour plot
elevation = ELEV;
[xMap, yMap] = meshgrid(xMeters(1:335), yMeters(1:230));
map = subplot(2, 1, 2); contour(xMap, yMap, elevation);
axis([0 max(xMeters(:)) 0 max(yMeters(:))]);
axis fill;
set(fig, 'Position', [500 100 600 700]);
right = line(xRight, xLeft);
left = line(xLeft, yLeft);
top = line(xTop, yTop);
bottom = line(xBottom, yBottom);
So all that works fine. Obviously I didn't include the parts where I defined the data and everything. After this comes a switch statement that changes the values of xLeft, yLeft, etc as well as xStart, xEnd etc.
Here is my attempt to update the plots:
[xGrid, yGrid] = meshgrid(xMeters(xStart:xEnd), yMeters(yStart:yEnd));
elevationBox = ELEV(xStart:xEnd, yStart:yEnd);
subplot(2, 1, 1)
set(surface, 'XData', xGrid, 'YData', yGrid, 'ZData', elevationBox);
drawnow;
I can choose an option and there is no error, but the plot doesn't update and when I quit the program I get this error:
Error using matlab.graphics.axis.Axes/set
There is no XData property on the Axes class.
Error in A9 (line 129)
set(surface, 'XData', xGrid);
The setting is inside the while loop but outside the switch statement. I also had a few lines using set on the line objects but those weren't working either so I thought I'd focus here first. I'm figuring whatever I'm doing wrong applies to both object types but if not let me know.
Thanks!
Rather than grab a handle to the axis (which you call surface), you want the data object. So grab a handle at surf_h = surf(...);.
A little example:
% Generate a random surface grid
n = 10;
[x, y] = meshgrid(1:n, 1:n);
z = rand(n);
% Plot
fig_h = figure(1);
axis_h = subplot(2, 1, 1);
surf_h = surf(x,y,z);
% Modify XData
set(surf_h, 'XData', -x);
drawnow;

Overlaying two axes in a Matlab plot

I am looking for a way to overlay an x-y time series, say created with 'plot', on top of a display generated by 'contourf', with different scaling on the y-axes.
It seems that the typical way to do this in the case of two x-y plots is to use the built-in function 'plotyy', which can even be driven by functions other than 'plot' (such as 'loglog') as long as the input arguments remain the same (x,y). However, since in my case contourf requires three input arguments, 'plotyy' seems to not be applicable. Here is some sample code describing what I would like to do:
x1 = 1:1:50;
y1 = 1:1:10;
temp_data = rand(10,50);
y2 = rand(50,1)*20;
figure; hold on;
contourf(x1,y1,temp_data);
colormap('gray');
plot(x1,y2,'r-');
Ideally, I would like the timeseries (x1,y2) to have its own y-axes displayed on the right, and be scaled to the same vertical extent as the contourf plot.
Thanks for your time.
I don't think there's a "clean" way to do this, but you can fake it by overlaying two axes over each other.
x1 = 1:1:50;
y1 = 1:1:10;
temp_data = rand(10,50);
y2 = rand(50,1)*20;
figure;
contourf(x1, y1, temp_data);
colormap('gray');
h_ax = gca;
h_ax_line = axes('position', get(h_ax, 'position')); % Create a new axes in the same position as the first one, overlaid on top
plot(x1,y2,'r-');
set(h_ax_line, 'YAxisLocation', 'right', 'xlim', get(h_ax, 'xlim'), 'color', 'none'); % Put the new axes' y labels on the right, set the x limits the same as the original axes', and make the background transparent
ylabel(h_ax, 'Contour y-values');
ylabel(h_ax_line, 'Line y-values');
In fact, this "plot overlay" is almost definitely what the plotyy function does internally.
Here's example output (I increased the font size for legibility):