Expand Plot Area of Matlab Figure - matlab

I'm making a plot and using the legendflex function off of the File Exchange and I keep running into a problem where I have an element of the figure expanding off one side. Is there a way to expand the figure window so I can see everything being plotted?
A trivial example would be as follows:
bar(rand(10, 2))
legendflex({'First Series', 'Second Series'}, 'anchor', [4 8])
I've noticed that there's a section to the documentation in legendflex that talks about a resize function callback, but when I set that as empty and resize the figure, the legend ends up in the middle of the plot. I've tried altering the Position and OuterPosition properties but the plot always expands within the figure and the legend moves with it and continues off the edge of the figure (or doesn't move at all if I mess with the resize function).
Does anyone have a way to expand the size of a figure or "zoom out" without altering the underlying plots?

While not exactly answering the original question, the following code does produce the desired effect:
bar(rand(10, 2));
ax = gca;
ax.Position = [ax.Position(1:2) ax.Position(3)*.75 ax.Position(4)];
legendflex({'First Series', 'Second Series'}, 'anchor', [4 8]);
This resizes the axes before adding the legend so that when it is added there's space to the right of the figure.

Related

How do you fix the size of an axes graphic object?

I'm creating a simple GUI in MATLAB and I'm trying to create a figure that contains a 2d plot on an axes, all is working well, but I have a rough time trying to figure out how to fix the position of the axes/plot.
The axes seems to scale with the figure window size. If I maximize the figure on my screen, the axes is maximized within, etc. What I want to accomplish is to have a row of buttons beneath the plot on the same figure as the plot, basically an area of 50 (ish) pixels tall that the plot does not encroach on. I know how to do this in HTML, but I can't figure out a good way in MATLAB.
Any alternative approaches would also be greatly appreciated.
Change the units of the axes to anything other than 'normalized', like 'pixels'. Then it won't automatically resize with the figure. From this documentation page:
When you create a graph, MATLAB® creates an axes to display the graph. The axes is sized to fit in the figure and automatically resizes as you resize the figure. MATLAB applies the automatic resize behavior only when the axes Units property is set to normalized (the default).
Use set(gca,'Position',pos) where pos = [x y w h] to set the position and size of the axes in the units you chose.
See this answer for an example and a function for holding an axis size once you have it in place.

Expand (maximise) subplot figure temporarily — then collapse it back

Often in Matlab we would plot a figure with many subplot axes, but they are all tiny.
In the prevalent UX paradigm, you would expect to be able to double-click such a small plot to have a closer look using the entire screen space.
Typically this is the reason I avoid using subplot, but plot many individual figures instead — so I can move them around on the screen and double-click on their titlebars which (on Windows) maximises the figure to full screen. (Double-click again, and it returns to its normal size.)
However, the advantage of subplot is that the set of plots is grouped in one panel. When I'm plotting many such groups (each with a dozen separate subplot axes), having that many individual figures becomes hard to work with.
So, is there a way to enable this functionality in Matlab already?
Combining parts of these three posts, here's what I have so far:
h = subplot(2,2,1);
line(1:10, rand(1,10));
set(h, 'buttondownfcn', ['h=gca; hc = copyobj(h, gcf);' ...
'set(hc, ''Units'', ''normal'',' ...
' ''Position'', [0.05 0.1 0.8 0.85],' ...
' ''buttondownfcn'', ''delete(gca)'');']);
It's not perfect, but it works.
Click on the axes:
Click on the expanded axes, and it disappears:
Note that this still allows you to pan, zoom, and "rotate 3D" the resulting axes. Selecting the arrow tool actually enters "Edit Mode", so it's better to unselect the tool you are using instead. For example: if you were zooming in, click on the zoom-in icon again to deselect the tool. Clicking will then "collapse" the blow-up of the axes.
The limitation so far is that you can sometimes see parts of the underlying little subplot axes underneath. If someone can recommend an elegant way to hide them, that would be a nice improvement.
EDIT Learning from this answer (using a uipanel to prevent other contents from showing through), I now have turned the solution into this:
gcaExpand.m:
function gcaExpand
set(copyobj(gca, uipanel('Position', [0 0 1 1])), ...
'Units', 'normal', 'OuterPosition', [0 0 1 1], ...
'ButtonDownFcn', 'delete(get(gca, ''Parent''))');
end
gcaExpandable.m:
function gcaExpandable
set(gca, 'ButtonDownFcn', [...
'set(copyobj(gca, uipanel(''Position'', [0 0 1 1])), ' ...
' ''Units'', ''normal'', ''OuterPosition'', [0 0 1 1], ' ...
' ''ButtonDownFcn'', ''delete(get(gca, ''''Parent''''))''); ']);
end
The first one expands the current plot immediately. The second one adds the functionality where clicking onto the plot expands it. In both cases clicking again returns things back to normal.
I've placed them into the directory with all my other custom Matlab functions that I'm using on a day-to-day basis. The above can also be included in functions to be sent out.
Initially, I was going to write a custom version of subplot that applied gcaExpandable automatically, but that didn't work, because commands like plot erase the ButtonDownFcn property (as well as all other properties, except the position). According to this answer, we can avoid resetting those properties by changing the NextPlot to 'replacechildren', but that has side-effects. For example, plot no longer automatically rescales the axes. Therefore, the cleanest solution so far seems to be as above.

Axis commands changes TightInset property to zero

I use some things from this question get-rid-of-the-white-space-around-matlab-figures-pdf-output to get rid of the white space when saving figure plots and images. This works fine, but my problem is when I use commands like "axis square" or "axis image". Ivt sets TightInset property of corresponding axes to 0 in "y" direction. I mean when I use this:
inset=get(a,'TightInset');
second and fourth numbers in "inset" are always zero, even if I set title and x-label. So in the end I don't see plot titles and x-labels.
Can I fix it somehow? So far I do it manually by adding some suitable number, but it is not convenient.
EDIT: Some more code for example. It displays two histograms.
h=figure;
subplot(121)
bar(bins,histogram1,'hist');
axis square
title('Historgram 1');
xlabel('Intensity');
ylabel('Pixel count');
set(gca,'xlim',[0 1])
subplot(122)
bar(bins,histogram_out,'hist');
axis square
title('Histogram 2');
set(gca,'xlim',[0 1])
xlabel('Intensity');
ylabel('Pixel count');
and if I call
a=get(h,'Children');
for i=1:length(a)
inset=get(a(i),'TightInset');
%...some stuff here
end
those y-related numbers in inset are zeros. If I comment axis square and do this, then inset are correct and it does what I need.
As far as I know when you use 'TightInset' you'll get only the graph or image, axis will be removed. I downloaded a function from mathworks file exchange 'saveTightfigure.m' to solve a similar problem. But I did not needed axes. If you need axes may be you can edit limits set inside the function. I mean you can give a little more space at left and bottom for keeping the axes.

Problem or bug in xticklabel_rotate while drawing heatmap and rotating xtick labels in Matlab

I have been drawing heatmaps with labels in Matlab, mainly using the functions imagesc to draw the heatmap and xticklabel_rotate to rotate the xtick labels.
(please see here for xticklabel_rotate).
It usually works well. But today I met some problem which appeared to be caused by xticklabel_rotate (or maybe the Matlab text handle used by xticklabel_rotate?)
To illustrate the problem, in the following I print my code and the results generated from the code (basically, what it does is to randomly generate a normally distributed data matrix, draw a heatmap for the data using imagesc, draw its labels on top and right of the axis, and then rotate xticklabels):
function debug_xticklabelRotate(numX, numY, axisFontsize)
data = randn(numY, numX);
imagesc(data);
colormap(jet);
box on
set(gca, 'ticklength', [0,0]);
set(gca, 'xminortick', 'off', 'yminortick', 'off');
set(gca, 'XAxisLocation', 'top');
set(gca, 'YAxisLocation', 'right');
set(gca,'FontSize', axisFontsize);
axis image
set(gca, 'Xtick', 1 : numX);
htext = xticklabel_rotate([],90, [], 'fontsize', axisFontsize);
set(gca, 'YTick', 1 : numY);
end
Problem 1: I called the above function with parameters as
debug_xticklabelRotate(40, 100, .5);
the output image is shown below (to save space here, I cut the image and only show the top few rows):
Please notice that the bug is that, as the result of calling xticklabel_rotate, neither the right side of the figure box nor the yticklabels are drawn.
Problem 2: When I call the above function with parameters as
debug_xticklabelRotate(40, 200, .5); % only numY is changed from 100 to 200
the output image is shown below (again to save space here, I cut the image and only show the top few rows):
http://i55.tinypic.com/317grdd.png
Compared to the call with numY=100, in this figure both the data image and the labels are shown. However, please notice two problems here. First, the fontsize of xticklabel is not the same as that of yticklabel (axisFontsize). Second, the xtick labels are not aligned well with the columns (xticks): some labels are closer and some are further away.
Please note if I remove the function call of xticklable_rotate in my function debug_xticklabelRotate, all these mentioned problems are gone (except that now the xticklabel are not rotated).
I wish my problem is stated clear above. Any suggestion on solving the problem will be highly appreciated. Thank you very much.
As the author of xticklabel_rotate, I have tried to reproduce the errors mentioned with only small success. I have found an issue with the axis position being changed when y-labels are on the right, which I will look into. I do not get such marked misalignements as you have shown when I run the same examples, so I am not sure how to respond. Please verify that these issues exist when you PRINT the figure, and it is not a simple display issue.
The text boxes are created at the tick positions, in data units. They are middle aligned, there is not much more that can be done, but I am open to suggestions.
PS. I agree it would be nice if this function was inherent in MatLab. If it was, I wouldn't have had to work on this.
If you comment out the line:
set(gca, 'YAxisLocation', 'right')
then it should work as expected. It seems that the XTICKLABEL_ROTATE function does not support right y-labels. You should contact the original author and let him know of the possible bug...

In matlab, how can I zoom in on a plot in my script

I'd like to zoom in on a plot using a script. I'm only interested in horizontally constrained zooming. So I'd like to do something like
p = plot(myData);
z = zoom;
set(z, 'ZoomInToPoints' , [50 100]);
or
p = plot(myData);
myZoom([50, 100]);
So either of these functions would zoom into a plot like when you zoom in with the magnifying glass tool. I only specify two points because I only want to zoom horizontally.
Note, I've already tried to use xlim for this. While it works, it doesn't let me use the command text on my plots, which I need.
Calls to text will fix the text at a specific set of coordinates on the graph. Have you tried updating these after calling xlim?
EDIT: You can always adjust the text position:
x=1:.1:10;
y=sin(.1*x);
plot(x,y)
text(6,.8,'test') %#Sample figure
F=get(0,'children'); %#Figure handle
A=get(F,'Children'); %#Axes handle
T=findobj(A,'Type','text'); %# Text handle
oldxlim=xlim; %#grab the original x limits before zoom
oldpos=get(T,'Position'); %#get the old text position
set(A,'xlim',[5 15]); %#Adjust axes
newxlim=xlim;
newpos=[(oldpos(1)-oldxlim(1))*(diff(newxlim))...
/(diff(oldxlim))+newxlim(1) oldpos(2:end)];
%#interpolate to place the text at the same spot in the axes
set(T,'Position',newpos) %#Finally reset the text position
Not pretty, but it should work. If you have more than one annotation per axes or axes per figure, you can always throw the above code in a loop.
What is the problem with text and xlim? Is this not the type of behavior you want?
plot(1:100,randn(100,1))
text(80,1.5,'text')
set(gca,'XLim',[70 100]) % notice that text stays at same point in "data space" but moves in "axis space"
text(80,1,'text2'); % new text appears in axis space as well
If I'm misunderstanding and you want text to appear at a specific point in your axis space (not the data space that text uses) regardless of how zoomed in you are, you can create another set of axes for your text:
inset_h = axes('position',[0.5 0.5 0.2 0.2])
set(inset_h,'Color','none'); axis off
text(0,0,'text')