datetick does not set x-ticks accurately
16 views (last 30 days)
Show older comments
Dear all,
I am experiencing a problem with the datetick function. I am working on Matlab R2014a and the problem is the following.
I have some time series data, which I want to plot and I would like to have the x-ticks in yyyy-qq format. For this purpose I am using the functions datenum and datetick. However, dateticks generates the x-ticks sometimes inaccurately; it misses sometimes certain quarters and jumps directly to the next (e.g. the ticks are 2015-Q4 2016-Q1 2016-Q2 2016-Q3 2017-Q1), so 2016-Q4 is apparently missing. However, the space between the ticks is equal, so this must be an error.
This code reproduces the problem:
%%Problem with x-ticks using datetick
data_cpi=0.2+randn(229,1);
startDate = datenum(1998,12,1);
endDate = datenum(2017,12,1);
month = linspace(startDate,endDate,size(data_cpi,1))';
figure
plot(month,data_cpi)
xlim([month(end-36) month(end)])
datetick('x','yyyy-qq','keepticks','keeplimits')
Is this a bug and how could I fix this problem?
Thanks for the help in advance!
Best,
Diego
0 Comments
Accepted Answer
dpb
on 17 Sep 2015
Edited: dpb
on 17 Sep 2015
Kirby got the root cause; there's one other issue I'd warn about...I recommend strongly against using linspace or other floating point differences in computing date numbers owing to rounding issues--they may not match the precise dates desired. Instead, use the internal ability of datenum to "roll over" higher granularity time periods accounting for them internally so that the differences are integral. That is, compute your month vector as
month=datenum(1998,12+[0:12*(2017-1998)].',1);
rather than as did. I didn't test whether that may have an effect here but it definitely can if you do lookup on datenumbers in not finding a specific date that should owing to rounding in the last one or two significant bits whereas the comparisons are exact.
Anyway, on to the specifics for your case--
set(gca,'xtick',month(end-35:3:end)) % set ticks to quarters
will solve you problem; your xlim is position end-36 at December, ergo, end-35 is the Jan 1 date and the :3 delta between provides every quarter thereafter to the end point. Then you can use both 'keeplimits' and 'keepticks'.
Note that when you change xlim in HG, the number of ticks is consistent with those actually shown in that range, not just a subset with those values of the full range of values in the data vectors. That's how you can have arbitrary values of tick labels independent of the actual data values; they're not tied to each other excepting by where they're placed on the axis horizontally in relation to the axes.
1 Comment
dpb
on 17 Sep 2015
Edited: dpb
on 17 Sep 2015
Actually, hadn't thought about it specifically, but in this case the difference is marked owing to the difference between computing on a monthly basis vis a vis a uniform interval over a number of days--
Consider
>> month1=datenum(1998,12+[0:12*(2017-1998)].',1);
>> month2=linspace(startDate,endDate,length(month1)),';
>> all(month2==month1)
ans =
0
>> sum(month2==month1)
ans =
4
>> find(month2==month1)
ans =
1
58
115
229
>> d=(month2-month1);d(20:30)
ans =
0.3333
-0.2281
-0.7895
-0.3509
-0.9123
-0.4737
-1.0351
-1.5965
0.8421
0.2807
0.7193
>> max(abs(month-month1))
ans =
1.5965
>>
Hence, your times didn't align with the actual quarterly times that closely as they weren't actually even days but a fractional number of days between intervals.
Reinforcing the comment above of using integer periods of the finer time period and letting dateteime take care of the rollovers and computations internally. In the above case, you'll get the first of every month exactly; otherwise it's off by as much as 1.5 days as months aren't uniform in length.
More like what I was thinking of is the following--
>> dn1=datenum(2015,1,1,0,0,[0:3600].');
>> dn2=linspace(dn1(1),dn1(end),length(dn1)).';
>> all(dn1==dn2)
ans =
0
>> sum(dn1==dn2)
ans =
3001
>> max(abs(dn1-dn2))
ans =
1.1642e-10
>> d=(dn1-dn2);
>> plot(d(1:600))
>>
Will show an increasing frequency of number of locations which don't match as get away from the origin; it will be worst at the midpoint and then be nearly mirror image from the end back to the middle.
As noted, this will cause a failure if try to find a specific date if the two ways of computing the date number are mixed for those which are different (and only about 10% are exact).
More Answers (1)
Kirby Fears
on 17 Sep 2015
Edited: Kirby Fears
on 17 Sep 2015
Hi Diego,
When you use the 'keepticks' option in your datetick function call
datetick('x','yyyy-qq','keepticks','keeplimits')
you are telling Matlab to convert the datenumbers previously shown on those ticks to 'yyyy-qq'. Matlab is rounding a specific date to a year and quarter representation, which results in 2016-Q4 getting skipped. Since the kept ticks are (for me) 11 ticks spaced evenly over 37 months, you're not getting 1 tick per quarter at all times. If you had 12 ticks over 36 months, it would work fine.
You can fix this by explicitly choosing the x values & number of xticks before applying datetick with the 'keepticks' option. Be sure to pick good dates that round evenly to yyyy-qq format. Use the link below as a guide for setting the x ticks.
Hope this helps.
0 Comments
See Also
Categories
Find more on Dates and Time in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!