function pilabels
%PILABELS draw xticklabels as pi fractions
% assumes x-axis
% automatically picks reasonable limits and ticks
% automatically uses latex for pretty fractions if necessary
% automatically replaces old labels produced by PILABELS
% does NOT autocorrect on zoom/pan/resize
% algorithm:
% choose limits as smallest n such that pi/n < x_data_range
% optional: increase n to next smallest "round" number
% round can be d*b^n with d<b, 2^a*3^b, etc
% choose step size as smallest d that ensures at least L tick marks
%
%
% plot good example function
if isempty(findobj(gca,'type','line'))
% x=-9:.01:9; % for tex
x = 1:.01:3; % for latex
clf, plot(x,sin(x)); axis tight
end
% parameters
FONT_SIZE=10; % only applies to latex labels
MIN_TICKS=6; % minimum total number of xticks
Y_PIX_OFFSET=-5; % xlabel yposition offset in pixels
SIMPLIFY=1; % algebraic simplification FLAG
SET_AXES=1; % change xlim to integer rational multiples of pi FLAG
USE_POW2_DENOM=1; % whether to use a power of 2 as the base denominator FLAG
USE_POW2_DENOM2=0; % whether to use a power of 2 as the true denominator FLAG
% remove old labels
a = allchild(gca);
for n=length(a):-1:1
if strcmp(get(a(n),'type'),'text') && ...
~isempty(strfind(get(a(n),'tag'),'_pilabel'))
delete(a(n))
end
end
% determine new limits
xl=get(gca,'xlim');
DD=ceil(pi/diff(xl)); % minimum denom required to resolve current xlim
DD=2^nextpow2(DD);
if USE_POW2_DENOM, DD=2^nextpow2(DD); end
xl2=round(xl*DD/pi)*pi/DD; % set xlim to integer multiples of pi/DD
xl2 = xl2+sign(xl2)*eps; % ensures stable iterated calls
% determine new tick vector
D = 1; % denominator multiplier
while diff(xl2)*D*DD/pi+1 < MIN_TICKS % ensure >MIN_TICKS labels
D=D+1;
if D>20
fprintf('this case is not handled well... please debug\n')
xl2
keyboard
end
end
D = D*DD;
if USE_POW2_DENOM2, D=2^nextpow2(D); end
xtk2 = xl2(1):pi/D:xl2(end);
% set limits, ticks; remove ticklabels
if SET_AXES
set(gca,'xlim',xl2)
end
set(gca,'xtick',xtk2)
set(gca,'xticklabel','')
% figure out y-offset for latex labels
yl=get(gca,'ylim');
u=get(gca,'units'); set(gca,'units','pixels');
pos=get(gca,'position');
yoffs = diff(yl)*Y_PIX_OFFSET/pos(4);
% draw manual text()-based ticklabels
set(gca,'units',u)
interp='tex';
if D~=1, interp='latex'; end
for n=1:length(xtk2)
% simplify fraction algebraically
den=D;
num = round(xtk2(n)*D/pi);
if SIMPLIFY
gd = gcd(num,den);
num=num/gd; den=den/gd;
end
% simplify string lexically
sgn=''; if sign(num)<0, sgn='-'; end % separate sign and value
num=int2str(abs(num));
if strcmp(num,'1'), num=''; end % remove 1's
if den==1 % dont use a fraction if simplified denom=1
lbl = sprintf('%s%s\\pi',sgn,num);
sz=FONT_SIZE;
else % use a fraction if simplified denom>1 (this forces latex)
lbl = sprintf('%s\\frac{%s\\pi}{%d}',sgn,num,den);
sz=FONT_SIZE*11/8; % seems to be an approximately correct ratio
end
if strcmp(num,'0'), lbl='0'; end % replace '0pi' with '0'
% draw the label
opts = {'vert','top','horiz','center','tag',sprintf('_pilabel%0d',n)};
if strcmp(interp,'tex')
text(xtk2(n),yl(1),lbl,'interpreter','tex',opts{:});
else
text(xtk2(n),yl(1)+yoffs,['$' lbl '$'],'interpreter','latex','fontsize',sz,opts{:})
end
end