forked from Electromaxim/electricity_load_forecast
-
Notifications
You must be signed in to change notification settings - Fork 1
/
dynamicDateTicks.m
143 lines (123 loc) · 5.25 KB
/
dynamicDateTicks.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
function dynamicDateTicks(axH, link)
% DYNAMICDATETICKS is a wrapper function around DATETICK which creates
% dynamic date tick labels for plots with dates on the X-axis. The date
% ticks intelligently include year/month/day information on specific ticks
% as appropriate. The ticks are dynamic with respect to zooming and
% panning. They update as the timescale changes (from years to seconds).
% Data tips on the plot also show intelligently as dates.
%
% The function may be used with linked axes as well as with multiple
% independent date and non-date axes within a plot.
%
% USAGE:
% dynamicDateTicks()
% makes the current axes a date axes with dynamic properties
%
% dynamicDateTicks(axH)
% makes all the axes handles in vector axH dynamic date axes
%
% dynamicDateTicks(axH, 'link')
% additionally specifies that all the axes in axH are linked. This
% option should be used in conjunction with LINKAXES.
%
% EXAMPLES:
% load integersignal
% dates = datenum('July 1, 2008'):1/24:datenum('May 11, 2009 1:00 PM');
% subplot(2,1,1), plot(dates, Signal1);
% dynamicDateTicks
% subplot(2,1,2), plot(dates, Signal4);
% dynamicDateTicks
%
% figure
% ax1 = subplot(2,1,1); plot(dates, Signal1);
% ax2 = subplot(2,1,2); plot(dates, Signal4);
% linkaxes([ax1 ax2], 'x');
% dynamicDateTicks([ax1 ax2], 'linked')
if nargin < 1 % If no axes is specified, use the current axes
axH = gca;
end
% Apply datetick to all axes in axH, and store any linking information
axesInfo.Type = 'dateaxes'; % Information stored in axes userdata indicating that these are date axes
for i = 1:length(axH)
datetick(axH(i), 'x', 'keeplimits');
if nargin > 1 % If axes are linked,
axesInfo.Linked = axH; % Need to modify all axes at once
else
axesInfo.Linked = axH(i); % Need to modify only 1 axes
end
set(axH(i), 'UserData', axesInfo); % Store the fact that this is a date axes and its link information in userdata
updateDateLabel('', struct('Axes', axH(i)), 0); % Call once to ensure proper formatting
end
% Set the zoom, pan and datacursor callbacks
figH = get(axH, 'Parent');
if iscell(figH)
figH = unique([figH{:}]);
end
if length(figH) > 1
error('Axes should be part of the same plot (have the same figure parent)');
end
z = zoom(figH);
p = pan(figH);
d = datacursormode(figH);
set(z,'ActionPostCallback',@updateDateLabel);
set(p,'ActionPostCallback',@updateDateLabel);
set(d,'UpdateFcn',@dateTip);
% ------------ End of dynamicDateTicks-----------------------
function output_txt = dateTip(gar, ev)
pos = ev.Position;
axHandle = get(ev.Target, 'Parent'); % Which axes is the data cursor on
axesInfo = get(axHandle, 'UserData'); % Get the axes info for that axes
try % If it is a date axes, create a date-friendly data tip
if strcmp(axesInfo.Type, 'dateaxes')
output_txt = sprintf('X: %s\nY: %0.4g', datestr(pos(1)), pos(2));
else
output_txt = sprintf('X: %0.4g\nY: %0.4g', pos(1), pos(2));
end
catch % It's not a date axes, create a generic data tip
output_txt = sprintf('X: %0.4g\nY: %0.4g', pos(1), pos(2));
end
end
function updateDateLabel(obj, ev, varargin)
ax1 = ev.Axes; % On which axes has the zoom/pan occurred
axesInfo = get(ev.Axes, 'UserData');
% Check if this axes is a date axes. If not, do nothing more (return)
try
if ~strcmp(axesInfo.Type, 'dateaxes')
return;
end
catch
return;
end
% Re-apply date ticks, but keep limits (unless called the first time)
if nargin < 3
datetick(ax1, 'x', 'keeplimits');
end
% Get the current axes ticks & labels
ticks = get(ax1, 'XTick');
labels = get(ax1, 'XTickLabel');
% Sometimes the first tick can be outside axes limits. If so, remove it & its label
if all(ticks(1) < get(ax1,'xlim'))
ticks(1) = [];
labels(1,:) = [];
end
[yr, mo, da] = datevec(ticks); % Extract year & day information (necessary for ticks on the boundary)
newlabels = cell(size(labels,1), 1); % Initialize cell array of new tick label information
if regexpi(labels(1,:), '([a-z]{3})|(\d\d/\d\d)', 'once') % Tick format is either mmm or mm/dd
% Add year information to first tick & ticks where the year changes
ind = [1 find(diff(yr))+1];
newlabels(ind) = cellstr(datestr(ticks(ind), '/yy'));
labels = strcat(labels, newlabels);
elseif any(labels(1,:) == ':') % Tick format is HH:MM
% Add month/day/year information to the first tick and month/day to other ticks where the day changes
ind = find(diff(da))+1;
newlabels{1} = datestr(ticks(1), 'mm/dd/yy-'); % Add month/day/year to first tick
newlabels(ind) = cellstr(datestr(ticks(ind), 'mm/dd-')); % Add month/day to ticks where day changes
labels = strcat(newlabels, labels);
end
set(axesInfo.Linked, 'XTick', ticks, 'XTickLabel', labels);
end
end
%#ok<*CTCH>
%#ok<*ASGLU>
%#ok<*INUSL>
%#ok<*INUSD>