Code covered by the BSD License  

Highlights from
Datetick Zoom, Pan & Subplot with Day of Year

image thumbnail
from Datetick Zoom, Pan & Subplot with Day of Year by David
Date formatted tick labels, auto updated when zoomed or panned with Day of Year formats added.

datetick2_doy(varargin)
function datetick2_doy(varargin)
%DATETICK2_DOY Date formatted tick labels, automatically updated when zoomed or panned.
%   Arguments are a super-set to those of DATETICK. Allows 2 or more
%   subplots, keeps all of them synched using LINKPROP.
%
%   For best results with multiple subplots, call datetick2_doy from the axis
%   that has the widest range of dates. This functionality could be
%   included, but would probably needlessly bloat the code.
%
%   Example:
%   figure
%   h(1)=subplot(411);
%   plot(now:1:now+100,randn(101,1))
%   h(2)=subplot(412);
%   plot(now:1:now+10,rand(11,1))
%   h(3)=subplot(413);
%   plot(now+20:1:now+30,rand(11,1))
%   h(4)=subplot(414);
%   plot(now-5:1:now+5,rand(11,1))
%   datetick2_doy
%
%   Written by Andy Bliss June 22, 2008. Based in part on DATETICKZOOM from
%   the file exchange by Christophe Lauwerys.
%
%   datetick2.m (submitted by Andy Bliss above) modified by David Murphy, November 20, 2009
%   Re-targeted to datetick_doy.m to support Day of Year labeling.
%
%   See also DATETICK, DATETICK_DOY, LINKPROP

%the first section of code runs when DATETICK2_DOY is called by the figure
if nargin==2 && isstruct(varargin{2}) && isfield(varargin{2},'Axes') && isscalar(varargin{2}.Axes)
    dtd = getappdata(varargin{2}.Axes,'datetickdata');
    axh = gca; %used to be dtd.axh instead of gca. But after a zoom, we always want the current axes
    if dtd.keep_ticks
        %if we're keeping the ticks
        set(axh,[dtd.ax,'TickMode'],'auto')
        if ~isempty(dtd.dateform)
            datetick_doy(axh,dtd.ax,dtd.dateform,'keeplimits','keepticks')
        else
            datetick_doy(axh,dtd.ax,'keeplimits','keepticks')
        end
    else
        %if we let Matlab choose the best tick positions
        if ~isempty(dtd.dateform)
            datetick_doy(axh,dtd.ax,dtd.dateform,'keeplimits')
        else
            datetick_doy(axh,dtd.ax,'keeplimits')
        end
    end
else
    %this section of code runs the first time DATETICK2_DOY is called

    %initialize dtd
    dtd = [];
    %parse inputs using the datetick parser
    [dtd.axh,dtd.ax,dtd.dateform,dtd.keep_ticks] = parseinputs(varargin);

    %get the handles to other parts of the figure
    dtd.pa=get(dtd.axh,'parent'); %the figure handle
    dtd.kids=get(dtd.pa,'Children'); %all children of the figure
    dtd.axes=[]; %just the axes children of the figure
    for n=1:length(dtd.kids)
        if strcmp(get(dtd.kids(n),'type'),'axes') & ...
                ~strcmp(get(dtd.kids(n),'tag'),'legend')
            dtd.axes=[dtd.axes dtd.kids(n)];
        end
    end
    %link all the axes together
    dtd.hlink=linkprop(dtd.axes,{[dtd.ax 'lim'];[dtd.ax 'tick']});
    dtd.hlink2=linkprop(dtd.axes,[dtd.ax 'ticklabel']); %for some reason this can't be on the line above

    %set application data and callbacks so the dateticks will update after
    %   pan and zoom
    for n=1:length(dtd.axes)
        setappdata(dtd.axes(n),'datetickdata',dtd);
        set(zoom(dtd.axes(n)),'ActionPostCallback',@datetick2_doy)
        set(pan(get(dtd.axes(n),'parent')),'ActionPostCallback',@datetick2_doy)
    end
    %setting datetick on one axis in the figure will set it on all because
    %   of the linkprop
    datetick_doy(varargin{:})
end





function [axh,ax,dateform,keep_ticks] = parseinputs(v)
%Parse Inputs (this is directly from DATETICK)

% Defaults;
nin = length(v);
dateform = [];
keep_ticks = 0;

% check to see if an axes was specified
if nin > 0 & ishandle(v{1}) & isequal(get(v{1},'type'),'axes') %#ok ishandle return is not scalar
    % use the axes passed in
    axh = v{1};
    v(1)=[];
    nin=nin-1;
else
    % use gca
    axh = gca;
end

% check for too many input arguments
error(nargchk(0,4,nin,'struct'));

% check for incorrect arguments
% if the input args is more than two - it should be either
% 'keeplimits' or 'keepticks' or both.
if nin > 2
    for i = nin:-1:3
        if ~(strcmpi(v{i},'keeplimits') || strcmpi(v{i},'keepticks'))
            error('MATLAB:datetick:IncorrectArgs', 'Incorrect arguments');
        end
    end
end

% Look for 'keeplimits'
%   This section is not needed because we always use keeplimits after zoom.
%   But, I'll leave it in for continuity.
%   keeplimits is not passed back out of parseargs.
for i=nin:-1:max(1,nin-2),
    if strcmpi(v{i},'keeplimits'),
        keep_limits = 1;
        v(i) = [];
        nin = nin-1;
    end
end

% Look for 'keepticks'
for i=nin:-1:max(1,nin-1),
    if strcmpi(v{i},'keepticks'),
        keep_ticks = 1;
        v(i) = [];
        nin = nin-1;
    end
end

if nin==0,
    ax = 'x';
else
    switch v{1}
        case {'x','y','z'}
            ax = v{1};
        otherwise
            error('MATLAB:datetick:InvalidAxis', 'The axis must be ''x'',''y'', or ''z''.');
    end
end
if nin > 1
    % The dateform (Date Format) value should be a scalar or string constant
    % check this out
    dateform = v{2};
    if (isnumeric(dateform) && length(dateform) ~= 1) && ~ischar(dateform)
        error('The Date Format value should be a scalar or string');
    end
end

Contact us at files@mathworks.com