Code covered by the BSD License  

Highlights from
pilabels

image thumbnail
from pilabels by Alan B
Automatically replaces xticklabels with rational multiples of pi.

pilabels
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

Contact us at files@mathworks.com