How to add error bars to a timeseries plot using datetime values

Hi all,
Please can someone help me figure out how to add error bars to my timeseries! I am gaving a problem figuring out what the x axis values should be. Would be much appreciated. (I'm new to Matlab!)
Context
I have a timeseries plot that runs Dec 17th - May 30th (alternate days). This is the code for my timeseries plot:
ts1 = timeseries(SSS_SGeast_anom_av_series, 1:2:166);
ts1.Name = ('Average salinity anomaly (psu)');
ts1.TimeInfo.Units = 'days';
ts1.TimeInfo.StartDate = '17-Dec-2020'; % Set start date.
ts1.TimeInfo.Format = 'dd mmm yy'; % Set format for display on x-axis.
ts.TimeInfo.Increment = '2';
ts1.Time = ts1.Time - ts1.Time(1); % Express time relative to the start date.
plot(ts1, '- k .', 'MarkerSize', 10, 'Linewidth', 2);
hold on
My standard deviation vector is a double numeric vector, size 83 x 1. I want to add this data as error bars on to my timeseries plot, using the command:
I have set y to by the timeseries y values (SSS_SGeast_anom_av_series), and err to be the standard deviation vector mentioned above.
Problem
I can't figure out what x values I need to suit the errorbar command above?
I think I need to somehow extract the datetime values from my original timeseries and then use these, but I can't figure out how to get those values.
Either that or make a new vector of the date values, and convert this to datetime. I'm not sure.
Please help if you can! Or let me know if I've been unclear.

 Accepted Answer

Wouldn't your X be ts1.Time? See the Plot Datetime Values with Error Bars example for more.
I have formatted errorbar to not draw a line connecting the data points. Technically, the marker isn't necessary either, but I wanted to keep this example simple.
% Create a data set
y = randn(83,10);
SSS_SGeast_anom_av_series = mean(y,2);
ts1 = timeseries(SSS_SGeast_anom_av_series, 1:2:166);
ts1.Name = ('Average salinity anomaly (psu)');
ts1.TimeInfo.Units = 'days';
ts1.TimeInfo.StartDate = '17-Dec-2020'; % Set start date.
ts1.TimeInfo.Format = 'dd mmm yy'; % Set format for display on x-axis.
ts.TimeInfo.Increment = '2';
ts1.Time = ts1.Time - ts1.Time(1); % Express time relative to the start date.
plot(ts1, '- k .', 'MarkerSize', 10, 'Linewidth', 2);
hold on
errorbar(ts1.Time,ts1.Data,std(y,[],2),'k.')
hold off

7 Comments

Thanks so much Cris, this works!
I had to tweak the std(y,[],2) bit slightly as I didn't have this variable in this format, but since I already had the err vector I just swapped that in and it worked.
I really appreciate your help!! I have lots more error bars to add but hopefully now I've figured it out (with your help) once I can add all the others now without too much trouble.
:)
My use of std was just a way for me to create errorbars here since I had to create my own data. You should replace anything I created to get this example to work with your actual data.
Hi Cris,
Yep sure - I can see why you had it this way. It's more efficient I guess calculating the std dev within the errorbar command anyway. Unfortunately though, I have tried what I feel like is this exact way of doing it with another dataset and it no longer works?
ts = timeseries(Pos_anom_series, 1:5);
ts.Name = 'Average chlorophyll anomaly';
ts.TimeInfo.Units = 'months';
ts.TimeInfo.StartDate = 'Dec-2020'; % Set start date.
ts.TimeInfo.Format = 'mmm yy'; % Set format for display on x-axis.
ts.Time = ts.Time - ts.Time(1); % Express time relative to the start date.
plot(ts, '-- r o')
errorbar(ts.Time, ts.Data, Pos_anom_std_dev);
hold on
grid on
Pos_anom_series is a 1x5 vector =
[ -0.123895243023677 , 0.0516582570769676 , 0.443403815055329 , 1.84363664335436 , 0.514591415320431 ]
Pos_anom_std_dev is also a 1x5 vector =
[ 0.866800000000000 , 0.564300000000000 , 0.749800000000000 , 1.58430000000000 , 0.921700000000000]
I feel like this should work, but the error message I am getting says...
Error using errorbar>checkSingleInput (line 270)
XData must be the same size as YData.
Error in errorbar (line 94)
x = checkSingleInput(x, sz, 'XData');
Error in CODE_Plot_monthly_anomaly_timeseries (line 54)
errorbar(ts1.Time, ts1.Data, Pos_anom_std_dev);
There are a couple issues to point out. First, ts.TimeInfo.StartDate must be one of the accepted character vector formats. Click here for a list of valid character vector formats.
While there, I also noticed that timeseries objects do not officially support 'months' as a unit. The code does appear to work with it set to months, but that's something to be aware of. Your Time values may not be what you expect.
Time Data:1
'01-Dec-2020 00:00:00' -0.123895243023677
'31-Dec-2020 10:30:00' 0.0516582570769676
'30-Jan-2021 21:00:00' 0.443403815055329
'02-Mar-2021 07:30:00' 1.84363664335436
'01-Apr-2021 18:00:00' 0.514591415320431
I also appear to have mispoken about extracting time. ts.Time returns the values that were entered for the timevals input (here that is 1:5). That works when your unit was days, but not when it is months. Use getabstime and datetime to extract time as formatted in the timeseries object.
Finally, errorbar appears to only like column vectors. Transpose your data and it should work.
Pos_anom_series = [-0.123895243023677, 0.0516582570769676, 0.443403815055329, 1.84363664335436, 0.514591415320431]';
Pos_anom_std_dev = [0.866800000000000, 0.564300000000000, 0.749800000000000, 1.58430000000000, 0.921700000000000]';
ts = timeseries(Pos_anom_series, 1:5);
ts.Name = 'Average chlorophyll anomaly';
ts.TimeInfo.Units = 'months';
ts.TimeInfo.StartDate = '01-Dec-2020'; % Set start date.
ts.TimeInfo.Format = 'mmm yy'; % Set format for display on x-axis.
ts.Time = ts.Time - ts.Time(1); % Express time relative to the start date.
plot(ts, '--ro')
grid on
hold on
e = errorbar(datetime(getabstime(ts)), ts.Data, Pos_anom_std_dev);
e.LineStyle = 'none';
hold off
Remember your hold on must come before your second plotting command. Also, it is best practice to always have a matching hold off.
Given all the issues mentioned above, I wonder if it wouldn't make more sense to update your code to use a timetable. I'm not sure the reasons you elected to use a timeseries object, but you'll find timetables offer many of the same benefits. The equivalent code could be the following:
Pos_anom_series = [-0.123895243023677, 0.0516582570769676, 0.443403815055329, 1.84363664335436, 0.514591415320431]';
Pos_anom_std_dev = [0.866800000000000, 0.564300000000000, 0.749800000000000, 1.58430000000000, 0.921700000000000]';
% Create data
Time = datetime(2020,12,01) + calmonths(1:5)';
Data = Pos_anom_series;
stdev = Pos_anom_std_dev;
% create timetable
dataTT = timetable(Time,Data,stdev)
dataTT = 5×2 timetable
Time Data stdev ___________ ________ ______ 01-Jan-2021 -0.1239 0.8668 01-Feb-2021 0.051658 0.5643 01-Mar-2021 0.4434 0.7498 01-Apr-2021 1.8436 1.5843 01-May-2021 0.51459 0.9217
% create plot
errorbar(dataTT.Time, dataTT.Data, dataTT.stdev,'--ro')
grid on
title('Average chlorophyll anomaly')
ylabel('Average chlorophyll')
xtickformat('MMM yy')
Thanks so much Cris, this is really helpful (and useful in helping me improve in general).
However it's still not working for me - still getting errors related to the errorbar command line.
Is there any chance something is different in the version I am using?? I'm using R2020a.
I will keep trying tomorrow and maybe I'll spot something I'm missing with a fresh eye.
Thanks again.
Possibly, but without knowing what the error message is, I wouldn't want to say. What happens if you copy and paste the code I've shared? Does that run without error?
Consider saving your variables to a mat file and attaching it to your post using the paperclip icon. Also copy/paste the code you are running (all the code needed to reproduce the error), as well as the full error message (all the red text).

Sign in to comment.

More Answers (1)

Maybe you should try to employ datenum(), e.g.:
x= datenum(ts1); % See help doc how to get datenum()
errorbar(x,y,ERR);
How to use datenum(): https://www.mathworks.com/help/matlab/ref/datenum.html#d123e278633

2 Comments

Thanks for the answer! Unfortunately that didn't seem to work though. It gave me this error message:
Error in CODE_Calculate_SGeast_SSSanom_std_dev (line 107)
x3 = datenum(ts1); % See help doc how to get datenum()
Caused by:
Error using datevec (line 109)
The input to DATEVEC was not an array of character vectors or strings.
Error using datenum (line 188)
DATENUM failed.
However, I have now managed to create the datetime variable that I need: an 83 x 1 datetime vector that basically matches the x axis in my timeseries plot exactly. It's in the same datetime format, here is an extract:
'17-Dec-2020'
'19-Dec-2020'
'21-Dec-2020'
'23-Dec-2020'
'25-Dec-2020'
But it still doesn't accept this within the errorbar command! This is the error message I see when I run the command e = errorbar(x, SSS_SGeast_anom_av_series, err);
Error using errorbar (line 76)
Input arguments must be numeric or objects which can be converted to double.
Error in CODE_Calculate_SGeast_SSSanom_std_dev (line 119)
e = errorbar(x,SSS_SGeast_anom_av_series, err);
So I tried converting the datetime vector into a double precision numerical array (following these instructions https://www.mathworks.com/help/matlab/matlab_prog/convert-between-datetime-arrays-numbers-and-strings.html) and it still didn't accept it. This is the error message I saw that time:
Warning: Error updating ErrorBar.
Undefined function 'double' for input arguments of type 'datetime'. To convert from datetimes to numeric, first subtract off a datetime origin, then convert to numeric using the SECONDS,
MINUTES, HOURS, DAYS, or YEARS functions.
I have no idea if it wants double, or datetime, or what!?

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!