I am having a small issue with printing Matlab figure into the size I preferred. The current figure I can get is shown on the top and I want to get the figure as the bottom. I used the code from Matlab help to minimize the white space.
Thank You.
Your kindness help is appreciated.
ax = gca;
outerpos = ax.OuterPosition;
ti = ax.TightInset;
left = outerpos(1) + ti(1);
bottom = outerpos(2) + ti(2);
ax_width = outerpos(3) - ti(1) - ti(3);
ax_height = outerpos(4) - ti(2) - ti(4);
ax.Position = [left bottom ax_width ax_height];
set(gca,'YTick',[0:1:4])
set(gca,'XTick',[0:2:20])
set(gca,'XMinorTick','on','YMinorTick','on')
set(gca,'TickLength',[0.015 0.01])
set(gca,'FontSize',12)
set(gca,'FontName','Times New Roman')
set(gca,'layer','top')
set(gcf,'renderer','zbuffer');
There is a function in the MATLAB file exchange which may satisfy your needs: tightfig. It automatically reduces the maximum of whitespace possible.
Compare this (just running your code):
to this (just running your code with tightfig
% Your code example from above (all but last two lines skipped) ...
set(gca,'layer','top')
set(gcf,'renderer','zbuffer');
tightfig; % Calling tightfig function
(right click the figures and "open in new tab" to see the difference)
Related
Is there a (manual or automatic) way of cutting out several parts of the y-axis for certain x-values in a Matlab plot? I found solutions in other programming languages (see 2 links below), but not for Matlab, except for BreakAxis and BreakYaxis on File Exchange, but this only works for one break.
I am also posting my code below, for which I would like to implement it. I would like to have a y-axis break for each yNegData and yPosData, i.e. two breaks, each at [0.3*min(yNegData) 0.7*min(yNegData] and [0.3*max(yPosData) 0.7*max(yPosData].
If you could write it in a way that I could use it for different kinds of plots (not only bar, but also line, for example), that would be very useful.
http://lagrange.univ-lyon1.fr/docs/matplotlib/examples/pylab_examples/broken_axis.html
Using gnuplot, how to 'cut out' usused y-axis regions of the graph
The code:
revenue = ones(100,1);
opex = -1*ones(100,1);
opex(10:15,1) = 3;
data{1} = revenue;
data{2} = opex;
colors = parula(numel(data));
labels = {'Revenue','Opex'};
for i = 1:numel(data)
dataNeg{i} = data{i};
dataNeg{i}(data{i}>0) = 0;
dataPos{i} = data{i};
dataPos{i}(data{i}<0) = 0;
mdata(i) = nnz(dataPos{i}); % was: mean(data{i});
end
[~,posOrder] = sort(mdata,'ascend');
[~,negOrder] = sort(mdata,'descend');
yDataPos = [dataPos{posOrder}];
yDataNeg = [dataNeg{negOrder}];
hold on;
bNeg = bar(yDataNeg,'stack');
bPos = bar(yDataPos,'stack');
for i= 1:numel(data)
set(bNeg(i),'FaceColor',colors(negOrder(i),:))
set(bPos(i),'FaceColor',colors(posOrder(i),:))
end
legend(labels{:});
hold off;
There is this package
https://nl.mathworks.com/matlabcentral/fileexchange/45760-break-y-axis
which works for lines; it has a little example
a=20*rand(21,1)+10;
figure;hold on;
plot(a);
breakyaxis([14 21]);
% hold off %% I guess, inserted by me
However, it does not seem to work as well for bar plots -- if you replace plot(a) by bar(a) in the example above the split stripe does not cover the width of the axes. It could be tweaked I'm sure but that might not be worth the effort.
If you're OK with switching to R you can use gap.barplot() from the plotrix package (see this example) and you can also still switch to gnuplot (see this example).
I am trying to put a legend in Matlab figures that include a symbol in Latex. When I plot the figure, the legend looks fine. However, when I export the figure as a PDF, the legend gets spaces put into it. I don't know why this is happening. Sample code is as follows:
set(groot,'defaultLineLineWidth',2,'defaultAxesFontSize',...
12,'defaultAxesFontName','timesnewroman',...
'defaulttextinterpreter','latex')
x0 = 8;
y0 = 5;
width = 5;
height = 4;
kappa1 = 0.1;
kappa2 = 0.5;
f = linspace(0,2*pi,1000);
y1 = sin(f+kappa1*f.^2);
y2 = sin(f+kappa2*f.^2);
figure(1)
hold on
plot(f,y1,'k')
plot(f,y2,'b')
xlabel('Frequency (MHz)')
ylabel('Amplitude')
legend(strcat('\kappa = 0.1 MHz/','\mu','s'),...
strcat('\kappa = 0.5 MHz/','\mu','s'))
grid on;
set(gcf,'units','inches','Position',[x0,y0,width,height],...
'PaperPositionMode','Auto','PaperUnits','Inches',...
'PaperSize',[width, height]);
saveas(gcf,'legendtest.pdf')
It seems like the error happens when I save the file as a PDF. It saves as a JPG just fine. Below are the two images I get. The jpg is:
But the PDF I get is:
I am using Matlab version R2017a on a Mac running OS 10.12.5. Thanks in advance for any help!
This is a known bug. See the bug report according to which it affects the versions from R2014b to R2017a. A workaround is suggested in that bug report as well which is to generate the pdf file by setting the Renderer to opengl i.e.
set(gcf,'Renderer','opengl');
But then the generated pdf file contains a pixel graphic instead of a vector graphic.
Better thing would be to use the respective unicode values which will produce a vector graphic. i.e.
legend([char(954), ' = 0.1 MHz/',char(956),'s'],...
[char(954), ' = 15 MHz/',char(956),'s']); %char(954) equals 'κ', char(956) equals 'μ'
If you want to use italic characters, it is also possible with unicode characters.
legend([char([55349,57093]), ' = 0.1 MHz/',char([55349,57095]),'s'],...
[char([55349,57093]), ' = 15 MHz/',char([55349,57095]),'s']);
%char([55349,57093]) equals '𝜅' (italic κ), char([55349,57095]) equals '𝜇' (italic μ)
Another workaround is to just interpret the whole legend text with Latex:
h = legend(strcat('$\kappa$ = 0.1 MHz/','$\mu$','s'),...
strcat('$\kappa$ = 0.5 MHz/','$\mu$','s'))
set(h,'Interpreter','latex')
It requires some basic Latex knowledge, e.g. you have to wrap all math signs (kappa, mu) with $ and beware if you want to use any special non-english characters. Changes the look of the legend a bit, but arguably for the better.
Btw, you can skip strcat, it does not serve any purpose.
h = legend('$\kappa$ = 0.1 MHz/$\mu$s',...
'$\kappa$ = 0.5 MHz/$\mu$s')
set(h,'Interpreter','latex')
Works just as well, the same goes for the non latex version.
When creating a GUI using OOP in MATLAB, I am having troubles understanding how to control which Axis of which Tab I want to plot my data in. I attach sample code to aid with my questions
First of all, when the GUI is loaded, only Axis 2 under Tab 2 is titled (Axis 2), the code title('Axis 1'); does not seem to get through. Why is this?
When the code is run, by default there are no plots in Tab1 or Tab2. If you click "Plot Data" while Tab1 is open, then switch to Tab2, you can see the sine curve is plot in Tab2. But according to my code, or at leaste what I am trying to do, is that the sine curve should appear in Axis1 of Tab1.
But when you click on Tab2, and click 'Plot Data', the curve changes to the exponential, which is what I am expecting.
I am still quite new at OOP GUI with MATLA so there might be some simple stuff I am missing. Thanks for any help and comments.
classdef example < handle
properties
Figure;
TabGroupAxis;
TabsAxis;
Axis1;
Axis2;
ButtonPlotData;
DataToPlot;
end
methods
function obj = example()
create(obj)
makeUpData(obj);
end
function create(obj)
obj.Figure = figure('Position',[300 300 640 640]);
obj.TabGroupAxis = uitabgroup(obj.Figure,'Units','pixels','Position',[100 20 600 600]);
obj.TabsAxis(1) = uitab(obj.TabGroupAxis,'Title','Tab1');
obj.TabsAxis(2) = uitab(obj.TabGroupAxis,'Title','Tab2');
obj.Axis1 = axes('Parent',obj.TabsAxis(1),'Units','pixels','Position',[30 20 500 500]);
obj.Axis2 = axes('Parent',obj.TabsAxis(2),'Units','pixels','Position',[30 20 500 500]);
obj.ButtonPlotData = uicontrol(obj.Figure,'Style','pushbutton','String','Plot Data',...
'Callback',#obj.buttonPlotDataCallback);
axis(obj.Axis1);
title('Axis 1');
axis(obj.Axis2);
title('Axis 2');
end
function makeUpData(obj)
obj.DataToPlot(1).x = linspace(0,2*pi);
obj.DataToPlot(1).y = sin(obj.DataToPlot(1).x);
obj.DataToPlot(2).x = linspace(0,2*pi);
obj.DataToPlot(2).y = exp(obj.DataToPlot(1).x);
end
function buttonPlotDataCallback(obj,hObject,eventdata)
activeTab = obj.TabGroupAxis.SelectedTab.Title;
switch activeTab
case 'Tab1'
axis(obj.Axis1);
plot(obj.DataToPlot(1).x,obj.DataToPlot(1).y);
case 'Tab2'
axis(obj.Axis2);
plot(obj.DataToPlot(2).x,obj.DataToPlot(2).y);
end
end
end
end
Long Answer
Excellent question, your example made it really easy for me to understand the problem. I put a break point in the buttonPlotDataCallback and saw that the switch case is operation correctly, the problem was that axis(obj.Axis1) didn't change the focus. Looking at the documentation, that's because that isn't the correct use of axis.
An alternative way to plot the function is to use an overloaded method of plot
case 'Tab1'
plot(obj.Axis1,obj.DataToPlot(1).x,obj.DataToPlot(1).y);
Now we realize that the reason that axis1 is not getting titled is that the call to axis on line 34 is not working either. This can also be fixed by overloading, this time title.
title(obj.Axis1,'Axis 1');
Shorter Answer
Turns out axes does exactly what you are using axis for. You have a typo that didn't get caught because axis is a valid function. change axis(< handle >) to axes(< handle >) and you'll be good to go.
I've been trying to plot some inequalities in Matlab.
When it shows in Matlab figure, it looks right:
But when I save the figure, I get this annoying yellow line (both when saved manually and when saved in code):
The code which produces the plot is:
function [ ] = plotInequalities( ~ )
pRange = linspace(1/2,1,1000);
cRange = linspace(0,1,1000);
[P, C] = meshgrid(pRange,cRange);
ineq1 = P >= 2/3;
ineq2 = C.*P.*(3-4.*P)./(2.*P+C.*(2-4.*P)) >= 1-P;
ineq3 = C <= 3.*P.*(1-P)./(2.*(-6.*P.^2+6.*P-1));
rest = ~ineq1 & ~ineq2 & ~ineq3;
pl = figure
hold on
c = 2:5;
contourf(pRange, cRange, c(2) * ineq2, [c(2), c(2)], 'c')
contourf(pRange, cRange, c(3) * ineq3, [c(3), c(3)], 'y')
contourf(pRange, cRange, c(4) * rest, [c(4), c(4)], 'r')
contourf(pRange, cRange, c(1) * ineq1, [c(1), c(1)], 'b')
legend('\{A,AB\}', '\{A,B\}', '\{A,AB, B\}', '\{A\}')
xlabel('P')
ylabel('C')
saveas(pl, 'out.png','png');
end
I'm using Matlab R2014a on Windows 8.
Any idea as to why this happens?
This is because there is an overlap between your domain ineq1 and ineq3.
If you set the renderer of the figure to anything else than painter (e.g. opengl or zbuffer) you will see the line which represent the border of your domain ineq3 (which should be hidden under ineq1)
When the figure is printed with the Matlab engine (for png,jpg,tiff etc ...), I couldn't force the print command to use the painter renderer. If you use one of the format rendered with the gostscript engine (pdf, bmp,pcx,pcm,...) then the proper output is produced.
If you want to stick to png output, the simple way around is to ensure there is no overlap between your domains before you send them to the contourf function. So in your case just add the line:
ineq3(ineq3==ineq1) = false ;
just before you call the different contourf, and the ouput will be OK in the figure and in the image saved (because there will be no ghost line to confuse the rendering engine).
Of course with this method, the order of overlap is important. This solution assume you want to see the full domain ineq1 and it has priority over the domain ineq3. If you want a different priority you have to change which domain override the other.
PS: and if you want the border of all domains to be visible, consider using patches and transparency so the overlaps will be more obvious.
I don't know how to accomplish the following in MATLAB. I have a figure which looks like this:
In the figure, I have a panel with many subplots and a scrollbar that allows me to view a portion of the panel.
I want to save the whole contents of the panel to a PNG image file (not just the visible portion), i.e. I want to have a file which is a tall rectangle, and doesn't require scrolling.
The code for generating the figure is as follows:
function draw(obj)
figure;
panel1 = uipanel('Parent',1);
panel2 = uipanel('Parent',panel1);
panelheight = obj.nIterations / 2;
set(panel1,'Position',[0 0 0.97 1]);
set(panel2,'Position',[0 1-panelheight 1 panelheight]); %%
nPlot = 1;
for i=1:obj.nIterations
models = obj.iterations{i};
for nModel=1:length(models)
subplot(obj.nIterations,length(models)*2,nPlot);
nPlot = nPlot + 1;
drawTransitions(models{nModel});
set(gca,'Parent',panel2);
subplot(obj.nIterations,length(models)*2,nPlot);
nPlot = nPlot + 1;
drawRewards(models{nModel});
set(gca,'Parent',panel2);
end
end
s = uicontrol('Style','Slider','Parent',1,...
'Units','normalized','Position',[0.97 0 0.03 1],...
'Value',1,'Callback',{#slider_callback1,panel2,panelheight});
end
I have tried the following, without success.
The saveas funstion saves the whole figure, not just the panel. Also, it clips the invisible portion of the panel.
export_fig(panel2.'file.png') gives just a solid gray image.
Why don't you just scroll your panel and grab the frames and concatenate them all together? Here's some code that will basically do that. I would have posted am image, but I guess I don't have enough points for that. You may need to fiddle with the scrolling, and maybe making the slider invisible, but it works.
function printPanel(pnl,filename)
fig = figure(ancestor(pnl,'figure'));
pnl_units = get(pnl,'units');
fig_units = get(fig,'units');
set(pnl,'units','pixels')
set(fig,'units','pixels')
pnl_rect = getpixelposition(pnl);
fig_rect = getpixelposition(fig);
pnl_height = pnl_rect(4);
fig_height = fig_rect(4);
pnl_rect(2) = -pnl_height;
set(pnl,'position',pnl_rect)
N = ceil(pnl_height/fig_height);
CDATA = cell(N,1);
for i = 1:N
F = getframe(fig);
CDATA{i} = F.cdata;
pnl_rect(2) = pnl_rect(2)+fig_height;
set(pnl,'position',pnl_rect)
drawnow
end
set(pnl,'units',pnl_units)
set(fig,'units',fig_units)
imwrite(cat(1,CDATA{:}),filename)
end
You could get rid of the ui elements and just make a figure with all the subplots, and then export that one, using e.g. print -dpng ....
saveas takes a handle as a first argument. Maybe this does not have to be a figure or model handle, but could be a reference to the contents of the panel.