function varargout = setaxes(varargin)
%SETAXES fixes common problems with MATLAB figures.
%
% SETAXES(AX, ...) applies to the axes AX which, when not supplied, defaults to the current axes.
%
%
% SETAXES('xoffset') [2-D view only] adjusts the axes position in the
% horizontal direction to make up for any clipped (left or right) part
% of the axes based on some default settings.
%
% SETAXES('yoffset') [2-D view only] adjusts the axes position in the
% vertical direction to make up for any clipped (lower or upper) part
% of the axes based on some default settings.
%
% SETAXES('axesmoveresize', [L B R T]) adds the array [L B -R -T] to the
% 'OuterPosition' property of the axes.
%
%
% SETAXES('xtick2text', OFFSET) [2-D view only] replaces the tick labels
% on the X-Axis by text objects where OFFSET is the factor of the axis
% height used as the vertical margin from the X-Axis.
%
% When not supplied, OFFSET defaults to 0.03.
%
% SETAXES('xtick2text',..., PROP1, VALUE1, PROP2, VALUE2, ...)
% sets the values of the specified properties of the text objects.
%
% HT = SETAXES('xtick2text',...) returns in HT the handles of the text objects.
%
%
% SETAXES('ytick2text', OFFSET) [2-D view only] replaces the tick labels
% on the Y-Axis by text objects where OFFSET is the factor of the axis
% width used as the horizontal margin from the Y-Axis.
%
% When not supplied, OFFSET defaults to 0.02.
%
% SETAXES('ytick2text',..., PROP1, VALUE1, PROP2, VALUE2, ...)
% sets the values of the specified properties of the text objects.
%
% HT = SETAXES('ytick2text',...) returns in HT the handles of the text objects.
%
%
% SETAXES('xlabelcorner') [2-D view only] places the XLABEL in an
% appropriate corner. The most common corner is the right-bottom when
% the X-Axis is to the bottom and the ticks are increasing from left to
% right. The corner changes accordingly for other combinations of axes properties.
%
% SETAXES('xlabelcorner', PROP1, VALUE1, PROP2, VALUE2, ...)
% sets the values of the specified properties of the XLabel object.
%
%
% SETAXES('ylabelcorner') [2-D view only] places the YLABEL in an
% appropriate corner. The most common corner is the top-left when the
% Y-Axis is to the left and the ticks are increasing upward. The corner
% changes accordingly for other combinations of axes properties.
%
% SETAXES('ylabelcorner', PROP1, VALUE1, PROP2, VALUE2, ...)
% sets the values of the specified properties of the YLabel object.
%
%
% SETAXES('axesarrows') [2-D view only] adds arrow annotation objects to
% X- and Y-Axis. The default 'HeadLength' and 'HeadWidth' are both 5.
% Line width and Color are inherited from the the corresponfing axis line.
%
% SETAXES('axesarrows','xx') adds arrow annotation objects to X-Axis only.
% SETAXES('axesarrows','yy') adds arrow annotation objects to Y-Axis only.
%
% SETAXES('axesarrows',..., PROP1, VALUE1, PROP2, VALUE2, ...)
% sets the values of the specified properties of the arrow objects.
%
% HA = SETAXES('axesarrows',...) returns in HA the handles of the arrow objects.
%
% Note that since SETAXES('axesarrows',...) changes the axes position property, any
% annotation objects should be added after SETAXES('axesarrows',...).
%
%=======================================================================
% EXAMPLE trying to cover a few features:
%-----------------------------------------------------------------------
%
% figure('Units', 'centimeters', ...
% 'Position', [2 2 8 6], ...
% 'PaperUnits', 'centimeters', ...
% 'PaperSize', [8 6], ...
% 'PaperPositionMode', 'auto')
%
% ax = axes('FontSize', 8, ...
% 'LineWidth', 0.4, ...
% 'Box', 'off', ...
% 'TickDir', 'out' );
%
% hold all
%
% t = linspace(0,5,51);
% n = 1:49;
% rand('state', sum(100*clock));
% W = [0 cumsum(-log(rand(size(n)))./n)];
% hPlot(1) = stairs(W, [n 50], '-b');
% hPlot(2) = line(t, exp(t), 'LineStyle', '--', 'Color', 'r');
% axis([0 5 0 50])
%
% xlabel('$T=\mathrm{Exp}(\frac{1}{X})$', 'Interpreter','LaTeX');
% ylabel('$X$', 'Interpreter','LaTeX');
% legend(hPlot, {'sample $n$'; 'mean $\mu(T)$'}, 'Interpreter','LaTeX')
% set(ax, 'XTickLabel', {'$0$';'$\tau_1$';'$\tau_2$'; ...
% '$\tau_3$';'$\tau_4$';'$\tau_5$'}, ...
% 'YTickLabel', {'$0$';'$X_1$';'$X_2$';'$X_3$';'$X_4$';'$X_5$'} )
%
% setaxes('xtick2text')
% setaxes('ytick2text')
% setaxes('ylabelcorner')
% setaxes('yoffset')
% setaxes('axesarrows')
%
% [xfig,yfig] = dsxy2figxy([1 2], [45 45]);
% har = annotation('doublearrow', xfig , yfig);
% set(har, 'LineWidth', .25, 'Color', 'k', ...
% 'Head1Length', 3.5, 'Head2Length', 3.5, ...
% 'Head1Width', 3.5, 'Head2Width', 3.5, ...
% 'Head1Style', 'vback3', 'Head2Style', 'vback3')
%
% text(1.5, 48, '$\Delta \tau$', ...
% 'VerticalAlignment', 'bottom', ...
% 'HorizontalAlignment', 'center', 'Interpreter','LaTeX');
% print -dpdf setaxes_example.pdf
%
%
%=========================================================================
% Mukhtar Ullah
% mukhtar.ullah@informatik.uni-rostock.de
% First created: Sep 18, 2008
% Last modified: Oct 18, 2010
%
%=========================================================================
persistent SetAxes_CurrentAxes SetAxes_Functions SetAxes_ValidNames
[ax,argsmain,nIn] = axescheck(varargin{:});
error(nargchk(1, inf, nIn));
if isempty(ax)
ax = gca;
else
assert(~strcmp(get(ax,'Tag'),'legend'), 'Legend Axes not supported')
end
% Bring to focus
figure(get(ax, 'Parent'))
set(gcf, 'CurrentAxes', ax)
% first time run or a successive run for a different axes
if isempty(SetAxes_CurrentAxes) || ax~=SetAxes_CurrentAxes
SetAxes_CurrentAxes = ax;
SetAxes_Functions = {};
end
if isempty(SetAxes_Functions)
oldaxunits = get(ax, 'Units');
set(ax, 'Units', 'normalized')
axprop = get(ax, {'Position', ...
'OuterPosition', ...
'LooseInset', ...
'XTick', ...
'YTick', ...
'XLim', ...
'YLim', ...
'Xlabel', ...
'Ylabel', ...
'Title'} );
set(ax, 'Units', oldaxunits)
numvar = numel(axprop);
axprop = [axprop, get(ax, {'XAxisLocation', ...
'YAxisLocation', ...
'XDir', ...
'YDir', ...
'XScale', ...
'YScale', ...
'XTickLabelMode', ...
'YTickLabelMode'} )];
[axpos, outpos, looseinset, xtick, ytick, axlim(1:2), axlim(3:4), ...
hxlab, hylab, htitle, xxloc, yyloc] = axprop{1:numvar+2};
proptf = num2cell(strcmp(axprop(numvar+1:end), ...
{'bottom', 'left', 'normal', 'normal', 'log', 'log', 'auto', 'auto'}));
[isxxbottom, isyyleft, isxdirnormal, isydirnormal, ...
isxxlog, isyylog, autoxticklab, autoyticklab] = proptf{:};
[dxt, dyt, dxtfig, dytfig, xtickroom, ytickroom] = deal(0);
isxlabelcorner = false;
isylabelcorner = false;
notxxloc = setdiff({'top', 'bottom'}, xxloc);
notyyloc = setdiff({'left', 'right'}, yyloc);
set([hxlab, hylab, htitle], {'Tag'}, {'XLabel'; 'YLabel'; 'Title'})
xlabpos = get(hxlab, 'Position');
ylabpos = get(hylab, 'Position');
[axwidth, axheight, ...
xlabhalign, ylabhalign, xlabvalign, ylabvalign] = falign();
%----------------------------------------------------------------------
SetAxes_ValidNames = {'axesmoveresize', 'legendmoveresize'};
[az,el]=view(ax);
camUp = get(ax,'CameraUpVector');
if (az==0) && (el==90) && isequal(abs(camUp),[0 1 0]) % Is2D
SetAxes_ValidNames = [ SetAxes_ValidNames, ...
{ 'xoffset', 'yoffset', ...
'xtick2text', 'ytick2text', ...
'xlabelcorner', 'ylabelcorner', 'axesarrows' } ];
end
SetAxes_Functions = cellfun(@(s) eval(['@', s]), SetAxes_ValidNames, 'UniformOutput', false);
end
funstr = validatestring(argsmain{1}, SetAxes_ValidNames);
fh = SetAxes_Functions{strcmp(funstr, SetAxes_ValidNames)};
nOut = nargout;
switch sprintf('%d',[nIn-1 nOut]>0)
case '00'
fh();
case '10'
fh(argsmain{2:end});
case '01'
[varargout{1:nOut}] = fh();
otherwise
[varargout{1:nOut}] = fh(argsmain{2:end});
end
%==========================================================================
function xoffset()
if ~isylabelcorner && get(hylab, 'Rotation')==0
set(hylab, 'HorizontalAlignment', ylabhalign)
end
tightinset = get(ax, 'TightInset');
set(ax, 'LooseInset', max(looseinset, tightinset))
restoreleftright(hylab)
end
%--------------------------------------------------------------------------
function yoffset()
tightinset = get(ax, 'TightInset');
set(ax, 'LooseInset', max(looseinset, tightinset))
restoreupdown(hxlab)
restoreupdown(htitle)
end
%--------------------------------------------------------------------------
function axesmoveresize(offset)
if nargin == 0
disp('Drag a rectangle in the axes to define OuterPosition:')
k = waitforbuttonpress;
if k == 1
return
end
% fig = gcf; if the figure is already in focus
fig = get(ax, 'Parent');
oldunits = get(fig, 'Units');
set(fig, 'Units', 'normalized')
outpos = rbbox;
set(fig, 'Units', oldunits)
else
outpos = outpos + [1 1 -1 -1].*offset;
end
set(ax, 'OuterPosition', outpos)
drawnow
axpos = get(ax, 'Position');
end
%--------------------------------------------------------------------------
function hxt = xtick2text(varargin)
[xtickoffset, pvpairs] = extractoffset(.03, varargin{:});
hxt = [];
xticklab = cellstr(get(ax, 'XTickLabel'));
xticklab = matchticks(xtick, xticklab);
if ~isempty(xticklab)
set(ax, 'XTickLabel', []);
if xor(isxxbottom,isydirnormal)
yloc = axlim(4) + xtickoffset*axheight;
else
yloc = axlim(3) - xtickoffset*axheight;
end
yloc = yloc(ones(size(xtick)));
if isyylog
yloc = 10.^yloc;
xticklab = append10(xticklab, autoxticklab, pvpairs);
end
hxt = text(xtick, yloc, xticklab);
set(hxt(strncmp('$', xticklab, 1)), 'Interpreter', 'latex')
% mathtick = ~cellfun(@isempty, ...
% regexp(xticklab, '\${1,2}[^\$]*\${1,2}', 'match', 'once'));
% set(hxt(strncmp(mathtick), 'Interpreter', 'latex')
set(hxt, 'HorizontalAlignment', 'center', ...
'VerticalALignment', xlabvalign, pvpairs{:});
%--------------------------------------------------------------
oldunits = get(hxt(1), 'Units');
set(hxt, 'Units', 'normalized')
xtickext = get(hxt, 'Extent');
xtickroom = max(cellfun(@(x) x(4), xtickext));
set(hxt, 'Units', oldunits)
xtickext = get(hxt, 'Extent');
xlabposnow = get(hxlab, 'Position');
if isxxbottom
xlabposnow(2) = ...
min(cellfun(@(x) x(2), xtickext)) + xtickoffset;
else
xlabposnow(2) = ...
max(cellfun(@(x) x(2)+x(4), xtickext)) + xtickoffset;
end
set(hxlab, 'Position', xlabposnow)
end
end
%--------------------------------------------------------------------------
function hyt = ytick2text(varargin)
[ytickoffset, pvpairs] = extractoffset(.02, varargin{:});
hyt = [];
yticklab = cellstr(get(ax, 'YTickLabel'));
yticklab = matchticks(ytick, yticklab);
if ~isempty(yticklab)
set(ax, 'YTickLabel', []);
if xor(isyyleft,isxdirnormal)
xloc = axlim(2) + ytickoffset*axwidth;
else
xloc = axlim(1) - ytickoffset*axwidth;
end
xloc = xloc(ones(size(ytick)));
if isxxlog
xloc = 10.^xloc;
yticklab = append10(yticklab, autoyticklab, pvpairs);
end
hyt = text(xloc, ytick, yticklab);
set(hyt(strncmp('$', yticklab, 1)), 'Interpreter', 'latex')
% mathtick = ~cellfun(@isempty, ...
% regexp(yticklab, '\${1,2}[^\$]*\${1,2}', 'match', 'once'));
% set(hyt(strncmp(mathtick), 'Interpreter', 'latex')
set(hyt, 'VerticalAlignment', 'middle', ...
'HorizontalALignment', ylabhalign, pvpairs{:})
%--------------------------------------------------------------
oldunits = get(hyt(1), 'Units');
set(hyt, 'Units', 'normalized')
ytickext = get(hyt, 'Extent');
ytickroom = max(cellfun(@(x) x(3), ytickext));
set(hyt, 'Units', oldunits)
ytickext = get(hyt, 'Extent');
ylabposnow = get(hylab, 'Position');
if isyyleft
ylabposnow(1) = min(cellfun(@(x) x(1), ytickext));
else
ylabposnow(1) = max(cellfun(@(x) x(1)+x(3), ytickext));
end
set(hylab, 'Position', ylabposnow)
end
end
%--------------------------------------------------------------------------
function xlabelcorner(varargin)
if isxxlog
xlabpos(1:2) = 10.^xlabpos(1:2);
end
set(hxlab, ...
'Position', xlabpos, ...
'VerticalALignment', 'middle', ...
'HorizontalALignment', xlabhalign, varargin{:});
isxlabelcorner = true;
axpos = get(ax, 'Position');
restoreleftright(hxlab)
end
%--------------------------------------------------------------------------
function ylabelcorner(varargin)
if isyylog
ylabpos(1:2) = 10.^ylabpos(1:2);
end
set(hylab, ...
'Position', ylabpos, ...
'Rotation', 0, ...
'VerticalALignment', ylabvalign, ...
'HorizontalALignment', 'center', varargin{:});
isylabelcorner = true;
axpos = get(ax, 'Position');
restoreupdown(hylab)
end
%--------------------------------------------------------------------------
function h = axesarrows(varargin)
args = varargin;
xxarrow = true;
yyarrow = true;
if nargin>0
switch args{1}
case 'xx'
yyarrow = false;
args(1) = [];
case 'yy'
xxarrow = false;
args(1) = [];
otherwise
error('Unknown option')
end
end
[left, bottom, right, top] = deal(0);
if xxarrow && ~isxlabelcorner
if isyyleft
right = dxtfig;
else
left = dxtfig;
end
end
if yyarrow && ~isylabelcorner
if isxxbottom
top = dytfig;
else
bottom = dytfig;
end
end
axesmoveresize([left, bottom, right, top])
if isyyleft
xxarx = axpos(1)+axpos(3)+[0 dxtfig];
yyarx = axpos([1 1]);
else
xxarx = axpos(1)+[axpos(3) -dxtfig];
yyarx = axpos([1 1]) + axpos([3 3]);
end
if isxxbottom
yyary = axpos(2)+axpos(4)+[0 dytfig];
xxary = axpos([2 2]);
else
yyary = axpos(2)+[axpos(4) -dytfig];
xxary = axpos([2 2]) + axpos([4 4]);
end
if xxarrow
h(1) = annotation('arrow', xxarx, xxary, ...
'Color', get(ax, 'XColor'));
end
if yyarrow
h(2) = annotation('arrow', yyarx, yyary, ...
'Color', get(ax, 'YColor'));
end
set(nonzeros(h), 'HeadLength', 5, 'HeadWidth', 5, ...
'LineWidth', get(ax, 'LineWidth'), args{:})
end
%==========================================================================
function restoreupdown(lab)
withlab = ~isempty(get(lab, 'String')) && ...
strcmp(get(lab, 'Visible'), 'on');
if withlab
oldunits = get(lab, 'Units');
set(lab, 'Units', 'normalized')
labext = get(lab, 'Extent');
if strcmpi(get(lab, 'Tag'), 'YLabel')
labext = labext.*axpos([3 4 4 3]);
else
labext = labext.*axpos([3 4 3 4]);
end
extroom = labext(4);
if strcmpi(get(lab, 'Tag'), 'XLabel')
set(lab, 'Visible', 'off')
keyword = xxloc;
% extroom = 1.05*max(extroom, xtickroom*axpos(4));
extroom = max(extroom, xtickroom*axpos(4));
else
keyword = notxxloc;
end
tightinset = get(ax, 'TightInset');
set(lab, 'Visible', 'on', 'Units', oldunits)
if strcmp(keyword, 'bottom')
looseinset(2) = max(looseinset(2), tightinset(2) + extroom);
else
% looseinset(4) = max(looseinset(4), labext(2)+labext(4)-axpos(4));
looseinset(4) = max(looseinset(4), tightinset(4) + extroom);
end
set(ax, 'LooseInset', looseinset)
axpos = get(ax, 'Position');
end
end
%--------------------------------------------------------------------------
function restoreleftright(lab)
withlab = ~isempty(get(lab, 'String')) && ...
strcmp(get(lab, 'Visible'), 'on');
if withlab
oldunits = get(lab, 'Units');
set(lab, 'Units', 'normalized')
labext = get(lab, 'Extent');
if strcmpi(get(lab, 'Tag'), 'YLabel')
set(lab, 'Visible', 'off')
labext = labext.*axpos([3 4 4 3]);
if get(lab, 'Rotation')==90
extroom = labext(4);
else
extroom = labext(3);
end
extroom = max(extroom, ytickroom*axpos(3));
keyword = yyloc;
else
labext = labext.*axpos([3 4 3 4]);
extroom = labext(3);
keyword = notyyloc;
end
% extroom = 1.05*extroom;
tightinset = get(ax, 'TightInset');
set(lab, 'Visible', 'on', 'Units', oldunits)
if strcmp(keyword, 'left')
looseinset(1) = max(looseinset(1), tightinset(1) + extroom);
else
% looseinset(3) = max(looseinset(3), labext(1)+labext(3)-axpos(3));
looseinset(3) = max(looseinset(3), tightinset(3) + extroom);
end
set(ax, 'LooseInset', looseinset)
axpos = get(ax, 'Position');
end
end
%--------------------------------------------------------------------------
function [ axwidth, axheight, xlabhalign, ylabhalign, ...
xlabvalign, ylabvalign ] = falign()
if isxxlog
axlim(1:2) = log10(axlim(1:2));
xlabpos(1) = log10(xlabpos(1));
end
if isyylog
axlim(3:4) = log10(axlim(3:4));
ylabpos(2) = log10(ylabpos(2));
end
axwidth = diff(axlim(1:2));
axheight = diff(axlim(3:4));
dxtfig = .02;
dxt = max(0.05*axwidth, dxtfig*axwidth/axpos(3));
dxtfig = dxt*axpos(3)/axwidth;
dytfig = .02;
dyt = max(0.05*axheight, dytfig*axheight/axpos(4));
dytfig = dyt*axpos(4)/axheight;
if isyyleft
xlabhalign = 'left';
ylabhalign = 'right';
if isxdirnormal
xlabpos(1) = axlim(2) + 1.5*dxt;
ylabpos(1) = axlim(1);
else
xlabpos(1) = axlim(1) + 1.5*dxt;
ylabpos(1) = axlim(2);
end
else
xlabhalign = 'right';
ylabhalign = 'left';
if isxdirnormal
xlabpos(1) = axlim(1) - 1.5*dxt;
ylabpos(1) = axlim(2);
else
xlabpos(1) = axlim(2) - 1.5*dxt;
ylabpos(1) = axlim(1);
end
end
if isxxbottom
xlabvalign = 'top';
ylabvalign = 'bottom';
if isydirnormal
ylabpos(2) = axlim(4) + 1.5*dyt;
xlabpos(2) = axlim(3);
else
ylabpos(2) = axlim(3) + 1.5*dyt;
xlabpos(2) = axlim(4);
end
else
xlabvalign = 'bottom';
ylabvalign = 'top';
if isydirnormal
ylabpos(2) = axlim(3) - 1.5*dyt;
xlabpos(2) = axlim(4);
else
ylabpos(2) = axlim(4) - 1.5*dyt;
xlabpos(2) = axlim(3);
end
end
end
%--------------------------------------------------------------------------
function [tickoffset, pvpairs] = extractoffset(tickoffset, varargin)
pvpairs = varargin;
npv = nargin - 1;
if npv>0 && isnumeric(pvpairs{1})
tickoffset = pvpairs{1};
pvpairs(1) = [];
npv = npv - 1;
end
% validateattributes(npv, {'numeric'}, {'even'})
%
% assert((rem(npv,2) == 0), 'Incorrect number of input arguments')
textpropnames = {'FontAngle', 'FontName', ...
'FontUnits', 'FontSize', 'FontWeight'};
textpv = [textpropnames; get(ax, textpropnames)];
pvpairs = [textpv(:)' pvpairs];
end
%--------------------------------------------------------------------------
function ticklab = matchticks(tick, ticklab)
ntick = numel(tick);
nticklab = numel(ticklab);
q = floor(ntick/nticklab);
r = rem(ntick,nticklab);
ticklab = ticklab([repmat(1:nticklab, 1, q) 1:r]);
end
%--------------------------------------------------------------------------
function ticklab = append10(ticklab, autoticklab, pvpairs)
if autoticklab
interpreter = get(0, 'DefaultTextInterpreter');
if ~isempty(pvpairs)
tparams = pvpairs(1:2:end-1);
tvals = pvpairs(2:2:end);
k = strcmpi('interpreter', tparams);
if any(k), interpreter = tvals{k}; end
end
if strcmpi(interpreter, 'tex')
d = '';
else
d = '$';
end
ticklab = cellfun(@(x) [d '10^{' x '}' d], ticklab, 'UniformOutput', false);
end
end
end