Distance between axis label and axis in MATLAB figure - matlab

I'm plotting some data with MATLAB and I'd like to adjust the distance between axis label and the axis itself. However, simply adding a bit to the "Position" property of the label makes the label move out of the figure window. Is there a "margin" property or something similar?
In the above figure, I'd like to increase the distance between the numbers and the label "Time (s)" while automatically extending the figures size so that the label does not move out of bounds.
This is how I set up the figure / axis.
figure;
set(gca, ...
'Box' , 'off' , ...
'LooseInset' , get(gca, 'TightInset') * 1.5 , ...
'TickDir' , 'in' , ...
'XMinorTick' , 'off' , ...
'YMinorTick' , 'off' , ...
'TickLength' , [.02 .02] , ...
'LineWidth' , 1 , ...
'XGrid' , 'off' , ...
'YGrid' , 'off' , ...
'FontSize' , 18 );

I wrote a function that should do exactly what you want. It keeps the axes at the exact same size and position, it moves the x-label down and increases the figure size to be large enough to show the label:
function moveLabel(ax,offset,hFig,hAxes)
% get figure position
posFig = get(hFig,'Position');
% get axes position in pixels
set(hAxes,'Units','pixels')
posAx = get(hAxes,'Position');
% get label position in pixels
if ax=='x'
set(get(hAxes,'XLabel'),'Units','pixels')
posLabel = get(get(hAxes,'XLabel'),'Position');
else
set(get(hAxes,'YLabel'),'Units','pixels')
posLabel = get(get(hAxes,'YLabel'),'Position');
end
% resize figure
if ax=='x'
posFigNew = posFig + [0 -offset 0 offset];
else
posFigNew = posFig + [-offset 0 offset 0];
end
set(hFig,'Position',posFigNew)
% move axes
if ax=='x'
set(hAxes,'Position',posAx+[0 offset 0 0])
else
set(hAxes,'Position',posAx+[offset 0 0 0])
end
% move label
if ax=='x'
set(get(hAxes,'XLabel'),'Position',posLabel+[0 -offset 0])
else
set(get(hAxes,'YLabel'),'Position',posLabel+[-offset 0 0])
end
% set units back to 'normalized' and 'data'
set(hAxes,'Units','normalized')
if ax=='x'
set(get(hAxes,'XLabel'),'Units','data')
else
set(get(hAxes,'YLabel'),'Units','data')
end
end
In this case offset should be the absolute offset in pixels. If you want relative offsets, I think this function could easily be rewritten. hFig is the figure handle and hAxes the axes handle.
EDIT: create the figure using hFig = figure; and the axes by hAxes = axes; (then set up the axes like you did in the question: set(hAxes,...)) before calling the function.
EDIT2: added the lines where the 'Units' of hAxes and the XLabel are changed back to 'normalized' and 'data' respectively. That way the figure stays the way you want it after resizing.
EDIT3: modified the function to work for both X and Y labels. Additional input ax should be 'x' or 'y'.

You can accomplish this by adjusting the position of the axis an xlabel. I also suggest using "normalized" units so your positioning does not depend on the data range. Here's an example:
figure
plot(rand(1,10))
set(gca, 'Units', 'Normalized');
pos = get(gca, 'Position');
offset = 0.1;
set(gca, ...
'Box' , 'off' , ...
'LooseInset' , get(gca, 'TightInset') * 1.5 , ...
'TickDir' , 'in' , ...
'XMinorTick' , 'off' , ...
'YMinorTick' , 'off' , ...
'TickLength' , [.02 .02] , ...
'LineWidth' , 1 , ...
'XGrid' , 'off' , ...
'YGrid' , 'off' , ...
'FontSize' , 18 , ...
'Position' , pos + [0, offset, 0, -offset]);
h = xlabel('Time (s)');
set(h, 'Units', 'Normalized');
pos = get(h, 'Position');
set(h, 'Position', pos + [0, -offset, 0]);

I know this has been answered and all, but this is (to some extent) a simpler way:
relative_offset = 1.5;
close all;
figure(99);clf
plot(rand(1,10))
xlabel('The x-axis')
xh = get(gca,'XLabel'); % Handle of the x label
pause(0.2)
set(xh, 'Units', 'Normalized')
pause(0.2)
pos = get(xh, 'Position');
set(xh, 'Position',pos.*[1,relative_offset,1])
I have included the pause commands, since my system will get ahead of itself in some weird way otherwise.
/Niels

Related

Error in MATLAB colorbar tick labeling?

I am plotting 9 subplots as shown in figure below with one color bar for three subplots.
Here I want to show the highest value in color bar as > value, surprisingly when I manually edit the tick label as h.TickLabels{end} = ['>' h.TickLabels{end}]; the color bar starts repeating the value.
When I remove h.TickLabels{end} = ['>' h.TickLabels{end}]; the color bar show no problem. When I change the figure size in set(gcf, 'PaperUnits', 'inches', 'PaperPosition', [0 0 8 8]) as [0 0 5 5] colorbar labeling again changes.
How to resolve this error?
Below are my working example and output image:
data = [1 2 3; 5 7 3; 12 29 14; 1 7 3; 2 8 3; 5 4 1; 2 2 1; 2 3 1; 1 5 2];
for i=1:9
subplot(3, 3, i)
plot(data(i,:));
if ismember(i, [1:3])
caxis([0 20])
if i==3
h = colorbar('Fontsize', 6, 'LineWidth', 0.15, 'TickDirection', 'out',...
'TickLength', 0.02);
set(h, 'Position', [.935 .6867 .01 .2533])
h.TickLabels{end} = ['>' h.TickLabels{end}];
end
end
if ismember(i, [4:6])
caxis([0 6])
if i==6
h = colorbar('Fontsize', 6, 'LineWidth', 0.15, 'TickDirection', 'out',...
'TickLength', 0.02);
set(h, 'Position', [.935 .3733 .01 .2533])
h.TickLabels{end} = ['>' h.TickLabels{end}];
end
end
if ismember(i, [7:9])
caxis([0 4])
if i==9
h = colorbar('Fontsize',6, 'LineWidth', 0.15, 'TickDirection', 'out',...
'TickLength', 0.02);
set(h, 'Position', [.936 .06 .01 .2533])
h.TickLabels{end} = ['>' h.TickLabels{end}];
end
end
end
set(gcf, 'PaperUnits', 'inches', 'PaperPosition', [0 0 8 8])
print('test', '-djpeg', '-r300')
close all
Why is this happening?
Manually changing the TickLabels changes the TickLabelsMode property to manual and the control gets lost for zooming/panning/resizing the figure window.
How can this be fixed?
Use a listener that will adjust the ticks itself. It may require undocumented features. You can take ideas on implementing a listener for colorbar from Yair Altman's this utility. This is for ticklabels of axes and would require some tweaking to work for colorbar.
or a relatively simpler approach would be to:
Change the 'TicksMode' to manual i.e.:
Before this line h.TickLabels{end} = ['>' h.TickLabels{end}];, include
this line:
set(h, 'Ticks', get(h,'Ticks')); %or h.Ticks = h.Ticks; for >= R2014b
This ensures that the ticks remain the same and hence the number of ticks also remains the same and therefore ticklabels will not malfunction on zooming/panning/resizing the figure window.
If you want to have more or less ticks than you originally get then set them as:
%Adjust the increment as desired. I set it as 1 (default)
set(h, 'Ticks', in1:1:in2); %or h.Ticks = in1:1:in2; for >= R2014b
%where in1 and in2 are the 1st and 2nd input args you used for caxis respectively
or if you're only concerned with the output jpeg file and your ticklabels are malfunctioned in the output image file then:
Set the PaperUnits / PaperPosition at the beginning of the plotting instead of doing that at the end. This will not automate the ticklabels but will only make the temporary adjustment.
As Sardar wrote, the only option to solve this automatically, and not lose the auto-scaling of the ticks when the figure window size is changed is to add a listener. This is how to do it:
Copy the following function to an m-file, and save it in the folder you work on this figure (i.e. your current path):
function set_cb_lables
% add '>' to the last tick label in all colorbars
h = findobj(gcf,'Type','Colorbar'); % get all colorbars handels
set(h,{'TickLabelsMode'},{'auto'}); % change thier mode to 'auto'
tiklbl = get(h,{'TickLabels'}); % get all tick labels after the change
for k = 1:numel(tiklbl)
tiklbl{k}{end} = ['>' tiklbl{k}{end}]; % add '>' to the last tick
end
set(h,{'TickLabels'},tiklbl); % replace the current ticklabels with tiklbl
end
Then, in your code, add this line after the loop:
set(gcf,'SizeChangedFcn','set_cb_lables'); % aplly the function 'set_cb_lables' upon any size change
This will add '>' automatically to the last tick label upon any resizing of the figure.
This solution is better than just getting the ticks before adding the '>' because now if the window gets bigger, the colorbar is populated automatically with more ticks.

MATLAB slice functionality without using meshgrid

I have a 3D big matrix of size 2001 , 2001 , 30. I want to show its 30 slices in a 3D plot. I try to do it using matlab 'slice' command. However, since 'slice' needs to get the X Y Z locations as 3D arrays from the 'meshgrid' command, I get an 'out of memory error'.
My code is presented below.
How can I get over the 'Out of Memory' error without having to shrink
my 3D matrix, and with using my x,y,z locations of the matrix data ??
function presentFig4_ver4
close all; clc;
%im3 is of size of im3 = 201 201 30
load('img3D_shrinked.mat' , 'im3' , 'y_n_mm' , 'x_n_mm')
% next code until the mesh grid is in order to have the axes arranged
% so that the slices are shown one after the other in the depth
% direction of the figure and not from the bottom of the figure to the top of the figure
x_len=length(x_n_mm);
y_len=length(y_n_mm);
im3_reshaped=zeros(y_len , x_len , y_len);
for (ind_slice=1:30)
im3_reshaped(:,ind_slice,:)=im3(:,:,ind_slice);
end
[X,Y,Z]=meshgrid(x_n_mm,y_n_mm,y_n_mm);
slices=x_n_mm %= 0.23:0.1:(0.23+((30-1)*0.1)); %This is the same as x_n_mm
shownSlices=[1:30];
h=slice(X,Y,Z, im3_reshaped, [slices(shownSlices)],[],[]);
set(h,'EdgeColor','none','FaceColor','interp');
set( h , 'FaceAlpha', 'interp','AlphaData',im3*10^3)
dcm_obj = datacursormode(gcf); %datacursor mode on
set(dcm_obj,'enable','on','updatefcn',{#updateMe X Y Z im3_reshaped}) %update, need X,Y,Z, im3-values
set(gca,'FontName', 'Arial' ,'FontSize',14)
set(gca,'Position',[.32 .19 .41 0.9]) % [horizontal distance, vertical distance, width, height]
hold on
%camproj perspective
c_h=colorbar('horiz');
set( c_h, 'XDir', 'reverse' , 'Position' , [0.2 0.2 0.7 0.04],'FontSize',12);
opengl software
daspect([ 1 10 10])
axis tight
view(-49,16)
maxAxisLim=2; %mm
ylim([-maxAxisLim maxAxisLim])
zlim([-maxAxisLim maxAxisLim])
xlim([0.23 3.13])
camzoom(2)
xlabel('X [mm]','FontName', 'Arial' , 'FontSize',14)
ylabel('Y[mm]','FontName', 'Arial' ,'FontSize',14)
zlabel('Z [mm]','FontName', 'Arial' , 'FontSize',14)
x_h=get(gca,'XLabel');
y_h=get(gca,'YLabel');
z_h=get(gca,'ZLabel');
set(y_h, 'Units','normalized','Position', [0.03 -0.08 ] );
set(x_h, 'Units','normalized','Position', [0.6 0.12] );
set(z_h, 'Units','normalized','Position', [-0.08 0.27] );
set(get(gca,'YLabel'),'Rotation',-20);
set(get(gca,'XLabel'),'Rotation',12);
set(gca,'XTick',[0.23 0.5:0.5:3 3.13])
set(gca,'XTickLabel',{'0.23' '0.5' '1' '1.5' '2' '2.5' '3' '3.1' })
end % of presentFig4_ver4 function
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function msg = updateMe(src,evt,X,Y,Z,f)
evt = get(evt); %what's happenin'?
pos = evt.Position; %position
fval = f(X==pos(1)&Y==pos(2)&Z==pos(3)); %where?
msg = num2str(fval); %create msg
end

Matlab print -dpdf produces fuzzy lines

I have a problem when printing a 2D plot to pdf in matlab. I'm trying to print the following plot to a file (pdf, eps, svg, doesn't matter):
The problem is that at some points the line is very "jiggly" (sorry for the lack of a better word). I zoomed in on the upper part so you can see what I mean:
This is obviously not a problem for the matlab figure window. But when I print it to pdf, this is what it looks like:
The result is identical for pdf, svg and eps. I guess the problem is that matlab is creating a vectorized path (that is good!) but the path line is too thick and then every little spike can be seen.
Here's the code I'm using to produce the pdf:
sTitle = 'trajectory';
sFile = 'Data/trajectory.mat';
sPdfFile = 'pdfs/trajectory.pdf';
linewidth = 1;
fontsize1 = 18;
fig = figure;
% Adjust figure window size
set(fig, 'Position', [100 100 1400 800]);
% Set title
title(sTitle);
% Get states
[s, t] = load_data(some_data);
% Draw trajectory
plot(s(1,:), s(2,:), 'linewidth', linewidth);
% Labels and stuff
xlabel('x^W [m]', 'fontsize', fontsize1);
ylabel('y^W [m]', 'fontsize', fontsize1);
set(gca, 'fontsize', fontsize1)
% Axis font
set( gca , ...
'FontName' , 'Helvetica' );
set(gca, ...
'Box' , 'on' , ...
'TickDir' , 'out' , ...
'TickLength' , [.02 .02] , ...
'XMinorTick' , 'on' , ...
'XGrid' , 'on' , ...
'XMinorGrid' , 'off' , ...
'YMinorTick' , 'on' , ...
'YGrid' , 'on' , ...
'XColor' , [.3 .3 .3], ...
'YColor' , [.3 .3 .3], ...
'XTick' , -5:1:5, ...
'XTickLabelMode', 'auto', ...
'YTick' , -5:1:5, ...
'LineWidth' , 1 );
% Adjust view
axis([-2.5 2.5, -2.7 0.5]);
% Correct data aspect ratio
daspect([1,1,1])
% Print to PDF
width = 10;
height = 5;
set(gcf, 'PaperPosition', [0 0 width height]); %Position plot at left hand corner with width 5 and height 5.
set(gcf, 'PaperSize', [width height]); %Set the paper to have width 5 and height 5.
print('-dpdf', '-r600', sPdfFile);
According to this answer, this is an acknowledged bug, and the answerer provided a function to correct the issue for EPS files.
Since you are creating a PDF, I'd suggest using export_fig (requires a Ghostscript install) which, on the test script below, creates a smooth line in the produced PDF.
clc();
clear();
figure(1);
% Get states
n = 800;
x = linspace(0,2*pi,n);
s = [x.*cos(x);x.*sin(x)] + 0.3*exp(-0.3*[x;x]).*(rand(2,n)-0.5) ;
% Draw trajectory
plot(s(1,:), s(2,:), 'linewidth', 1);
axis([-20,20,-20,20]);
daspect([1,1,1])
% Print to PDF
print('traj.pdf','-dpdf', '-r600');
export_fig('traj2.pdf','-dpdf','-r600');
print PDF output:
export_fig PDF output:

How to make xTicks fit into all the plot window?

In the plot below how can I make the xTicks fit into all the x axis? I can not understand where the problem is and I will appreciate any advice as a new MATLAB user.
here is the part of code where I plot this graph :
f=figure();
plot(time, C, 'b*');
hold on
plot(time, L_Tilde, 'g-.');
plot(time, U_Tilde, 'g-.');
tickStep = 1 ;
tickDates = datenum( 1996:tickStep:2007 ,1,1) ;
set(gca, 'XTick' , tickDates , 'XTickLabel' , datestr(tickDates,'yyyy') )
Try
axis tight
This will will set the limits of both axes to exactly the limits of the data.
Just define the ylimit:
set(gca,'Xlim',[1996,2007])
set(gca, 'XTick' , tickDates , 'XTickLabel' , datestr(tickDates,'yyyy') )
Danny's suggestion is the automized way. To ge the 1996 back, you can add some days of margin to both sides:
%// example data
time = datenum( linspace(1996,2007),1,1);
L_Tilde = randi(10,[1,numel(time)]);
figure(1);
plot(time, L_Tilde, 'g-.');
tickStep = 1 ;
tickDates = datenum( 1996:tickStep:2007 ,1,1) ;
xlimms = get(gca,'Xlim');
axis tight
set(gca, 'XLim', get(gca,'XLim')+[-100,+100])
set(gca, 'XTick' , tickDates , 'XTickLabel' , datestr(tickDates,'yyyy') )
Adjust the 100 according to your needs.

Adding text to a figure - MATLAB

I wrote a code that shows a figure devided to 2 parts;
the first one showing the main image, and the second one is a slider showing the rest of the images.
Now I need to add text to the main part (Like "Help" or "guide" text).
How can I do it?
This is my main sub-code:
%# design GUI
numSubs = 10; % Num of sub-images.
mx = numImgs-numSubs+1;
hFig = figure('Menubar','none');
% The Main Image:
hAx = axes('Position',[0 0.3 1 0.8], 'Parent',hFig);
hMainImg = imshow(img, 'Parent',hAx);
% the slider
hPanel = uipanel('Position',[0 0.04 1 0.26], 'Parent',hFig);
uicontrol('Style','slider', 'Parent',hFig, ...
'Callback',#slider_callback, ...
'Units','normalized', 'Position',[0 0 1 0.04], ...
'Value',1, 'Min',1, 'Max',mx, 'SliderStep',[1 10]./mx);
subImg = zeros(numSubs,1);
for i=1:numSubs
%# create axis, show frame, hookup click callback
hAx = axes('Parent',hPanel, ...
'Position',[(i-1)/numSubs 0 1/numSubs 1]);
% Load img number i
name=frames(i).name;
img=imread(name,'jpg');
subImg(i) = imshow(img, 'Parent',hAx);
value = i;
set(subImg(i), 'ButtonDownFcn',{#click_callback value})
axis(hAx, 'normal')
hold off;
end
Any suggestions?
Thanks in advance.
Use this construction:
hT = uicontrol('style', 'text', 'string', 'HELLO WORLD', 'position', [...])
It will create static text in the figure at position position. You can use all the regular options for uicontrols like 'parent' or 'units'.
However, since your image is in an axis, the better/easier way to do it is using
hT = text(X, Y, 'HELLO WORLD')
with X and Y the desired coordinates of the text in the axes.
You can set additional options via set:
set(hT, 'color', 'r', 'backgroundcolor', 'k', 'fontsize', 10, ...)
You can get a list of all options by issuing set(hT) on a mock text object.