Related
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]');
I'm trying to individually link both y-axes in an yyaxis subplot. So far I'm only linking the right y-axes in the given code by calling linkaxes(g), where g are the axes handles. How can I also get the left y-axes linked to one another?
Thanks.
g(1) = subplot(2,1,1);
hold on;
yyaxis left;
plot(rand(10,1));
yyaxis right;
plot(2*rand(10,1));
hold off;
g(2) = subplot(2,1,2);
hold on;
yyaxis left;
plot(2*rand(10,1));
yyaxis right;
linkaxes(g);
plot(rand(10,1));
hold off;
An Axes object has the read-only property YAxisLocation that is set upon every call to yyaxis and remembers the last axis that was in use. When you type linkaxes(g) it simply takes the right axis because that the last one you set. To see that you can run this code for the first axes:
g(1) = subplot(2,1,1);
hold on;
yyaxis right;
plot(2*rand(10,1));
yyaxis left;
plot(rand(10,1));
hold off;
and see how this time the left top axis is linked to the right bottom axis.
If you want to link both axes you just need to add this lines at the end of your code to refer again to the left axis:
yyaxis(g(1),'left')
yyaxis(g(2),'left')
linkaxes(g);
Alternatively, you could grab the handles to the numeric rulers, and use linkprop (without any call to linkaxes):
Y = get(g,'YAxis');
Y = [Y{:}];
linkprop(Y(1,:),'Limits')
linkprop(Y(2,:),'Limits')
You should add this after all axis are created, so all the handles will be assigned already.
Is there a way to remove only the axis lines in the Matlab figure, without affecting ticks and tick labels.
I know that box toggles the upper and right axes lines and ticks and that works perfectly for me.
But my problem is that I want eliminate the bottom and left lines (only lines!) but keeping the ticks and tick labels.
Any tricks?
Yair Altman's Undocumented Matlab demonstrates a cleaner way to do this using the undocumented axes rulers:
plot(x,y);
ax1 = gca;
yruler = ax1.YRuler;
yruler.Axle.Visible = 'off';
xruler = ax1.XRuler;
xruler.Axle.Visible = 'off'; %// note you can do different formatting too such as xruler.Axle.LineWidth = 1.5;
A nice feature of this approach is that you can separately format the x and y axis lines.
Solution for Matlab versions prior to R2014b
You can introduce a new white bounding box and put it on top.
// example data
x = linspace(-4,4,100);
y = 16 - x.^2;
plot(x,y); hold on
ax1 = gca;
set(ax1,'box','off') %// here you can basically decide whether you like ticks on
%// top and on the right side or not
%// new white bounding box on top
ax2 = axes('Position', get(ax1, 'Position'),'Color','none');
set(ax2,'XTick',[],'YTick',[],'XColor','w','YColor','w','box','on','layer','top')
%// you can plot more afterwards and it doesn't effect the white box.
plot(ax1,x,-y); hold on
ylim(ax1,[-30,30])
Important is to deactivate the ticks of the second axes, to keep the ticks of the f rist one.
In Luis Mendo's solution, the plotted lines are fixed and stay at their initial position if you change the axes properties afterwards. That won't happen here, they get adjusted to the new limits. Use the correct handle for every command and there won't be much problems.
Dan's solution is easier, but does not apply for Matlab versions before R2014b.
There is another undocumented way (applicable to MATLAB R2014b and later versions) of removing the lines by changing the 'LineStyle' of rulers to 'none'.
Example:
figure;
plot(1:4,'o-'); %Plotting some data
pause(0.1); %Just to make sure that the plot is made before the next step
hAxes = gca; %Axis handle
%Changing 'LineStyle' to 'none'
hAxes.XRuler.Axle.LineStyle = 'none';
hAxes.YRuler.Axle.LineStyle = 'none';
%Default 'LineStyle': 'solid', Other possibilities: 'dashed', 'dotted', 'dashdot'
This is different from Dan's answer which uses the 'visible' property of rulers.
You could "erase" the axis lines by plotting a white line over them:
plot(1:4,1:4) %// example plot
box off %// remove outer border
hold on
a = axis; %// get axis size
plot([a(1) a(2)],[a(3) a(3)],'w'); %// plot white line over x axis
plot([a(1) a(1)],[a(3) a(4)],'w'); %// plot white line over y axis
Result:
As noted by #SardarUsama, in recent Matlab versions you may need to adjust the line width to cover the axes:
plot(1:4,1:4) %// example plot
box off %// remove outer border
hold on
a = axis; %// get axis size
plot([a(1) a(2)],[a(3) a(3)],'w', 'linewidth', 1.5); %// plot white line over x axis.
%// Set width manually
plot([a(1) a(1)],[a(3) a(4)],'w', 'linewidth', 1.5);
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!
I can add 2 y-axis to a octave/matlab plot but when I try and add the x-axis at the bottom of the plot with xlabel('Frequency in Hz') it doesn't show up
[ax h1 h2]=plotyy(xx,yy,xx,yy2); %plot two y axes and 1 x-axis
axes(ax(1)); ylabel('Phase Angle in degrees');
axes(ax(2)); ylabel('Amplitude');
Anybody know how to fix this so the x-axis will also show up
I'm using octave 3.2.4 / matlab
Make sure to call xlabel() after referencing one of the specific axes on the plot. You just need to do it once, but because of the double axis, invoking x-label outside of a specific axis context won't work. The following works for me just fine in Octave 3.2.4.
xx = [1,2,3];
yy = [10,11,12];
yy2 = [-10,-11,-12];
[ax h1 h2]=plotyy(xx,yy,xx,yy2);
axes(ax(1)); xlabel('Frequency in Hz'); ylabel('Phase Angle in degrees');
axes(ax(2)); ylabel('Amplitude');
In order to add a label (either xlabel or ylabel) to certain axes you can also pass this axes reference as first argument of the command call. This way you will also guarantee that you are on the right context as #EMS pointed out.
xx = [1,2,3];
yy = [10,11,12];
yy2 = [-10,-11,-12];
[ax h1 h2]=plotyy(xx,yy,xx,yy2);
xlabel(ax(1),'Frequency in Hz'); ylabel(ax(1),'Phase Angle in degrees');
ylabel(ax(2),'Amplitude');
This is also better in terms of performance, as in case you call axes several times, you will see how everything slows considerably down.