How to use retime to get the plot of mean and stdev in continous time series
You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Show older comments
Hello there,
I have a datasets containing y-values in multi-years time series. My intention is getting the plot of monthly mean and its shaded error bars. The datasets contain long span of months which crossing the following year, i.e. in my datasets (attached) there from February, 2020 until December 2022.
But, at first, I want to get the data cleaned by selecting only y-value with a certain range. Here is my first sight code:
T = readtable('datamine');
Tr = table2timetable(T, 'RowTimes','time');
Tx = table(Tr.time,Tr.value_y,'VariableNames',{'time_a','val'});
idx = Tx.val>= 12 & Tx.val< 13.4; % selecting only y-value with a certain range
Tx_mean = retime(Tx(idx,:),'monthly','mean'); % get monthly averaged values ==> Failed
Tx_std = retime(Tx(idx,:),'monthly',@std); % get monthly stdev values ==> Failed
I tried to use directly retime function but it failed. Anyone know to get continous monthly mean and its shaded error bars properly?
More or less, the plot should be like this. The x-axis is continous months, crossing the following years:

Thanks!
Accepted Answer
Star Strider
on 19 Oct 2024
The correct way to express the deviation of cata around the mean is to use the standard error of the mean, given by:
where σ is the standard deviation and N are the number of data used to calculate it.
T1 = readtable('datamine.xlsx')
T1 = 147152x2 table
value_y time
_______ ____________________
12.887 15-Feb-2020 09:50:00
13.136 15-Feb-2020 10:00:00
13.127 15-Feb-2020 10:09:59
12.894 15-Feb-2020 10:20:00
12.816 15-Feb-2020 10:30:00
12.355 15-Feb-2020 10:39:59
12.317 15-Feb-2020 10:50:00
12.922 15-Feb-2020 10:59:59
13.162 15-Feb-2020 11:10:00
13.163 15-Feb-2020 11:19:59
13.109 15-Feb-2020 11:30:00
13.139 15-Feb-2020 11:39:59
13.148 15-Feb-2020 11:50:00
12.937 15-Feb-2020 12:00:00
12.387 15-Feb-2020 12:10:00
12.695 15-Feb-2020 12:20:00
TT1 = table2timetable(T1)
TT1 = 147152x1 timetable
time value_y
____________________ _______
15-Feb-2020 09:50:00 12.887
15-Feb-2020 10:00:00 13.136
15-Feb-2020 10:09:59 13.127
15-Feb-2020 10:20:00 12.894
15-Feb-2020 10:30:00 12.816
15-Feb-2020 10:39:59 12.355
15-Feb-2020 10:50:00 12.317
15-Feb-2020 10:59:59 12.922
15-Feb-2020 11:10:00 13.162
15-Feb-2020 11:19:59 13.163
15-Feb-2020 11:30:00 13.109
15-Feb-2020 11:39:59 13.139
15-Feb-2020 11:50:00 13.148
15-Feb-2020 12:00:00 12.937
15-Feb-2020 12:10:00 12.387
15-Feb-2020 12:20:00 12.695
SEM = @(x) std(x)/sqrt(numel(x));
TT1momean = retime(TT1, 'monthly', 'mean')
TT1momean = 35x1 timetable
time value_y
___________ _______
01-Feb-2020 12.949
01-Mar-2020 12.659
01-Apr-2020 12.587
01-May-2020 12.393
01-Jun-2020 12.535
01-Jul-2020 12.77
01-Aug-2020 12.802
01-Sep-2020 12.6
01-Oct-2020 12.585
01-Nov-2020 13.011
01-Dec-2020 12.637
01-Jan-2021 12.353
01-Feb-2021 12.727
01-Mar-2021 12.884
01-Apr-2021 12.835
01-May-2021 12.701
TT1mosem = retime(TT1, 'monthly', SEM)
TT1mosem = 35x1 timetable
time value_y
___________ _________
01-Feb-2020 0.0093507
01-Mar-2020 0.0067858
01-Apr-2020 0.00657
01-May-2020 0.0067406
01-Jun-2020 0.0038461
01-Jul-2020 0.0050221
01-Aug-2020 0.0055277
01-Sep-2020 0.0039343
01-Oct-2020 0.0054015
01-Nov-2020 0.0074985
01-Dec-2020 0.0082383
01-Jan-2021 0.0049619
01-Feb-2021 0.0080578
01-Mar-2021 0.004472
01-Apr-2021 0.0032843
01-May-2021 0.0033188
TT1monum = retime(TT1, 'monthly', 'count');
[Nmin,Nmax] = bounds(TT1monum{:,1})
Nmin = 331
Nmax = 4464
% TT1Time = TT1mosem.time;
% TT1SEM = TT1mosem{:,1};
figure
plot(TT1momean.time, TT1momean{:,1}, '-k')
hold on
patch([TT1mosem.time; flip(TT1mosem.time)], [TT1momean{:,1}-TT1mosem{:,1}*1.96; flip(TT1momean{:,1}+TT1mosem{:,1}*1.96)], 'r', 'FaceAlpha',0.25, 'EdgeColor','r')
hold off
grid
xlabel('Time')
ylabel('Value')
title('Mean ±95% CI')

The SEM values are quite small when compared to the mean values (on the order of
) so they are barely visible. I did a separate accumulation for the number of values in each month, and since they were all above 330, using the 95% confidence intervals from the normal distribution is a safe estimate. It is not necessary to use the t-distribution, since it will closely approximate the normal distribution with this many degrees-of-freedom.
) so they are barely visible. I did a separate accumulation for the number of values in each month, and since they were all above 330, using the 95% confidence intervals from the normal distribution is a safe estimate. It is not necessary to use the t-distribution, since it will closely approximate the normal distribution with this many degrees-of-freedom. .
12 Comments
Adi Purwandana
on 19 Oct 2024
Edited: Adi Purwandana
on 19 Oct 2024
Thank you @Star Strider! Anyway, where should I put my line below as I need to focus on a certain range of values?
OK, I can put it after the first line. Done.
idx = Tx.val>= 12 & Tx.val< 13.4; % selecting only y-value with a certain range
Adi Purwandana
on 19 Oct 2024
I have one more question please @Star Strider if you don't mind... Is it possible to get the boxchat plot for those continous monthly retime mean? Thank you
As always, my pleasure!
My apologies — I forgot about the restriction.
I included it and the boxchart here —
T1 = readtable('datamine.xlsx')
T1 = 147152x2 table
value_y time
_______ ____________________
12.887 15-Feb-2020 09:50:00
13.136 15-Feb-2020 10:00:00
13.127 15-Feb-2020 10:09:59
12.894 15-Feb-2020 10:20:00
12.816 15-Feb-2020 10:30:00
12.355 15-Feb-2020 10:39:59
12.317 15-Feb-2020 10:50:00
12.922 15-Feb-2020 10:59:59
13.162 15-Feb-2020 11:10:00
13.163 15-Feb-2020 11:19:59
13.109 15-Feb-2020 11:30:00
13.139 15-Feb-2020 11:39:59
13.148 15-Feb-2020 11:50:00
12.937 15-Feb-2020 12:00:00
12.387 15-Feb-2020 12:10:00
12.695 15-Feb-2020 12:20:00
idx = (T1.value_y >= 12) & (T1.value_y < 13.4); % selecting only y-value with a certain range
T1 = T1(idx,:)
T1 = 121962x2 table
value_y time
_______ ____________________
12.887 15-Feb-2020 09:50:00
13.136 15-Feb-2020 10:00:00
13.127 15-Feb-2020 10:09:59
12.894 15-Feb-2020 10:20:00
12.816 15-Feb-2020 10:30:00
12.355 15-Feb-2020 10:39:59
12.317 15-Feb-2020 10:50:00
12.922 15-Feb-2020 10:59:59
13.162 15-Feb-2020 11:10:00
13.163 15-Feb-2020 11:19:59
13.109 15-Feb-2020 11:30:00
13.139 15-Feb-2020 11:39:59
13.148 15-Feb-2020 11:50:00
12.937 15-Feb-2020 12:00:00
12.387 15-Feb-2020 12:10:00
12.695 15-Feb-2020 12:20:00
TT1 = table2timetable(T1);
SEM = @(x) std(x)/sqrt(numel(x));
TT1momean = retime(TT1, 'monthly', 'mean');
TT1mosem = retime(TT1, 'monthly', SEM);
TT1monum = retime(TT1, 'monthly', 'count');
[Nmin,Nmax] = bounds(TT1monum{:,1})
Nmin = 256
Nmax = 4443
% TT1Time = TT1mosem.time;
% TT1SEM = TT1mosem{:,1};
figure
plot(TT1momean.time, TT1momean{:,1}, '-k')
hold on
patch([TT1mosem.time; flip(TT1mosem.time)], [TT1momean{:,1}-TT1mosem{:,1}*1.96; flip(TT1momean{:,1}+TT1mosem{:,1}*1.96)], 'r', 'FaceAlpha',0.375, 'EdgeColor','r', 'EdgeAlpha',0.5)
hold off
grid
xlabel('Time')
ylabel('Value')
title('Mean ±95% CI')

[GV, ID1, ID2] = findgroups(year(T1.time), month(T1.time)); % Grouping Variable For ‘boxchart’
% [b1,b2] = bounds(ID1)
xtl = compose("%s",datetime(ID1,ID2,ones(size(ID1)), Format="MMM yyyy")); % Cell Array Of Time Values
% disp(xtl)
figure
hb = boxchart(GV, T1.value_y);
hb.JitterOutliers = "on";
hb.MarkerStyle = ".";
hb.Notch = "on";
hb.BoxMedianLineColor = "r";
Ax = gca;
xt = Ax.XTick;
Ax.XTick = [1 xt];
Ax.XTickLabel = xtl(Ax.XTick);
Ax.XTickLabelRotation = 45;
xlabel("Time")
ylabel("Value")
title("T1: Boxchart")
axis("padded")

% get(hb)
The boxchart took a bit of time because I do not use it frequently. It uses the original ‘T1’ with the ‘idx’ constraint, not any of the derived timetable arrays.
I defined the XTick locations as:
Ax.XTick = [1 xt];
to include thee first element. It needs to be integers from 1 to 35, within that constraint you can define it however you want. You can change the XTickLabel format by changing the Format string in the ‘xtl’ assignment. (That is the easiest way to do it in this instance.)
.
Great! But, I don't know it didn't work on my 2022a:
- the Xtick label shown as integer instead of MMM yyy
- the BoxMedianLineColor red doesn't show

Are the date time axis and BoxMedianLineColor working only on 2024b, as what you did?
clear all;
clc
T1 = readtable('datamine.xlsx')
idx = (T1.value_y >= 12) & (T1.value_y < 13.4); % selecting only y-value with a certain range
T1 = T1(idx,:)
TT1 = table2timetable(T1);
SEM = @(x) std(x)/sqrt(numel(x));
TT1momean = retime(TT1, 'monthly', 'mean');
TT1mosem = retime(TT1, 'monthly', SEM);
TT1monum = retime(TT1, 'monthly', 'count');
[Nmin,Nmax] = bounds(TT1monum{:,1})
% TT1Time = TT1mosem.time;
% TT1SEM = TT1mosem{:,1};
figure
plot(TT1momean.time, TT1momean{:,1}, '-k')
hold on
patch([TT1mosem.time; flip(TT1mosem.time)], [TT1momean{:,1}-TT1mosem{:,1}*1.96; flip(TT1momean{:,1}+TT1mosem{:,1}*1.96)], 'r', 'FaceAlpha',0.375, 'EdgeColor','r', 'EdgeAlpha',0.5)
hold off
grid
xlabel('Time')
ylabel('Value')
title('Mean ±95% CI')
[GV, ID1, ID2] = findgroups(year(T1.time), month(T1.time)); % Grouping Variable For ‘boxchart’
% [b1,b2] = bounds(ID1)
xtl = compose("%s",datetime(ID1,ID2,ones(size(ID1)), Format="MMM yyyy")); % Cell Array Of Time Values
% disp(xtl)
figure
hb = boxchart(GV, T1.value_y);
hb.JitterOutliers = "on";
hb.MarkerStyle = ".";
hb.Notch = "on";
hb.BoxMedianLineColor = "r";
Ax = gca;
xt = Ax.XTick;
Ax.XTick = [1 xt];
Ax.XTickLabel = xtl(Ax.XTick);
Ax.XTickLabelRotation = 45;
xlabel("Time")
ylabel("Value")
title("T1: Boxchart")
axis("padded")
% get(hb)
Adi Purwandana
on 19 Oct 2024
Edited: Adi Purwandana
on 19 Oct 2024
Also, if possible... (I tried but still got no solution), can we put a mean value plot connecting the boxplot? There's likely I need groupsummary.
Just like:

Thank you and sorry for so many following questions.
Everything in my previous code should have worked in R2022a. I checked — all those functions existed from at least R2020b, most earlier. Apparently boxchart wasn’t compatible with string arrays then, so we’ll see if a cell array works with it this time. Adding the mean line to the boxchart is straightforward. I added a legend as well to both plots. You can reposition each as desired, or not use it if you don’t want it.
Try this —
T1 = readtable('datamine.xlsx')
T1 = 147152x2 table
value_y time
_______ ____________________
12.887 15-Feb-2020 09:50:00
13.136 15-Feb-2020 10:00:00
13.127 15-Feb-2020 10:09:59
12.894 15-Feb-2020 10:20:00
12.816 15-Feb-2020 10:30:00
12.355 15-Feb-2020 10:39:59
12.317 15-Feb-2020 10:50:00
12.922 15-Feb-2020 10:59:59
13.162 15-Feb-2020 11:10:00
13.163 15-Feb-2020 11:19:59
13.109 15-Feb-2020 11:30:00
13.139 15-Feb-2020 11:39:59
13.148 15-Feb-2020 11:50:00
12.937 15-Feb-2020 12:00:00
12.387 15-Feb-2020 12:10:00
12.695 15-Feb-2020 12:20:00
idx = (T1.value_y >= 12) & (T1.value_y < 13.4); % selecting only y-value with a certain range
T1 = T1(idx,:)
T1 = 121962x2 table
value_y time
_______ ____________________
12.887 15-Feb-2020 09:50:00
13.136 15-Feb-2020 10:00:00
13.127 15-Feb-2020 10:09:59
12.894 15-Feb-2020 10:20:00
12.816 15-Feb-2020 10:30:00
12.355 15-Feb-2020 10:39:59
12.317 15-Feb-2020 10:50:00
12.922 15-Feb-2020 10:59:59
13.162 15-Feb-2020 11:10:00
13.163 15-Feb-2020 11:19:59
13.109 15-Feb-2020 11:30:00
13.139 15-Feb-2020 11:39:59
13.148 15-Feb-2020 11:50:00
12.937 15-Feb-2020 12:00:00
12.387 15-Feb-2020 12:10:00
12.695 15-Feb-2020 12:20:00
TT1 = table2timetable(T1);
SEM = @(x) std(x)/sqrt(numel(x));
TT1momean = retime(TT1, 'monthly', 'mean');
TT1mosem = retime(TT1, 'monthly', SEM);
TT1monum = retime(TT1, 'monthly', 'count');
[Nmin,Nmax] = bounds(TT1monum{:,1})
Nmin = 256
Nmax = 4443
% TT1Time = TT1mosem.time;
% TT1SEM = TT1mosem{:,1};
figure
hplt = plot(TT1momean.time, TT1momean{:,1}, '-k', "DisplayName",'Monthly Mean');
hold on
hpch = patch([TT1mosem.time; flip(TT1mosem.time)], [TT1momean{:,1}-TT1mosem{:,1}*1.96; flip(TT1momean{:,1}+TT1mosem{:,1}*1.96)], 'r', 'FaceAlpha',0.375, 'EdgeColor','r', 'EdgeAlpha',0.5, "DisplayName","±95% Confidence Interval");
hold off
grid
xlabel('Time')
ylabel('Value')
title('Value Mean & ±95% CI')
legend("Location","NE")

[GV, ID1, ID2] = findgroups(year(T1.time), month(T1.time)); % Grouping Variable For ‘boxchart’
% [b1,b2] = bounds(ID1)
xtl = compose('%s',datetime(ID1,ID2,ones(size(ID1)), Format="MMM yyyy")); % Cell Array Of Time Values
% disp(xtl)
figure
hb = boxchart(GV, T1.value_y, "DisplayName","Boxchart of Monthly Data");
hold on
plot((1:height(TT1momean)), TT1momean{:,1}, '.-r', "DisplayName","Monthly Mean")
hold off
hb.JitterOutliers = "on";
hb.MarkerStyle = ".";
hb.Notch = "on";
hb.BoxMedianLineColor = "r";
Ax = gca;
xt = Ax.XTick;
Ax.XTick = [1 xt];
Ax.XTickLabel = xtl(Ax.XTick);
Ax.XTickLabelRotation = 45;
xlabel("Time")
ylabel("Value")
title("Boxchart of Monthly Data")
hlgnd = legend("Location","northoutside", "Orientation","horizontal");
axis("padded")

% get(hb)
That should work.
.
Adi Purwandana
on 20 Oct 2024
I really appreciate your help. FYI, I just installed 2024b and it works fine, but not for the 2022a.

It is mostlikely those (adjustable BoxMedianLineColor and date format syntax) are not available in 2022a. I don't know. Anyway, thank you for such very helpful solution. The best as always!
Star Strider
on 20 Oct 2024
As always, my pleasure!
I did not consider that the other options for boxchart could have been the problem. The ‘Version History’ in the boxchart documentation did not mention any changes.
Adi Purwandana
on 21 Oct 2024
Sorry @Star Strider, is it possible to adjust the time increment of the x-axis for this latest boxchart plot? For example with regular space every 3 months or 6 months. Thanks!
Yes.
Create a vector using the colon, : operator, with the second (‘increment’ or ‘step’) value being whatever integer value you want. Here, it needs to be an integer since it will be used as a subscript, however that is the only constraint:
Ax.XTick = [1 : 3 : xt(end)]; % Every 3 Months
Ax.XTick = [1 : 6 : xt(end)]; % Every 6 Months
In this code, I commented the every 6 month line so it would not run.
It can also be whatever months you want to display, for example:
Ax.XTick = [2 3 4 7 10 17 22 28 33]; % Specific Months
The only constraint is that they be integers from 1 to 35 (in this instance).
Try this —
T1 = readtable('datamine.xlsx')
T1 = 147152x2 table
value_y time
_______ ____________________
12.887 15-Feb-2020 09:50:00
13.136 15-Feb-2020 10:00:00
13.127 15-Feb-2020 10:09:59
12.894 15-Feb-2020 10:20:00
12.816 15-Feb-2020 10:30:00
12.355 15-Feb-2020 10:39:59
12.317 15-Feb-2020 10:50:00
12.922 15-Feb-2020 10:59:59
13.162 15-Feb-2020 11:10:00
13.163 15-Feb-2020 11:19:59
13.109 15-Feb-2020 11:30:00
13.139 15-Feb-2020 11:39:59
13.148 15-Feb-2020 11:50:00
12.937 15-Feb-2020 12:00:00
12.387 15-Feb-2020 12:10:00
12.695 15-Feb-2020 12:20:00
idx = (T1.value_y >= 12) & (T1.value_y < 13.4); % selecting only y-value with a certain range
T1 = T1(idx,:)
T1 = 121962x2 table
value_y time
_______ ____________________
12.887 15-Feb-2020 09:50:00
13.136 15-Feb-2020 10:00:00
13.127 15-Feb-2020 10:09:59
12.894 15-Feb-2020 10:20:00
12.816 15-Feb-2020 10:30:00
12.355 15-Feb-2020 10:39:59
12.317 15-Feb-2020 10:50:00
12.922 15-Feb-2020 10:59:59
13.162 15-Feb-2020 11:10:00
13.163 15-Feb-2020 11:19:59
13.109 15-Feb-2020 11:30:00
13.139 15-Feb-2020 11:39:59
13.148 15-Feb-2020 11:50:00
12.937 15-Feb-2020 12:00:00
12.387 15-Feb-2020 12:10:00
12.695 15-Feb-2020 12:20:00
TT1 = table2timetable(T1);
SEM = @(x) std(x)/sqrt(numel(x));
TT1momean = retime(TT1, 'monthly', 'mean');
TT1mosem = retime(TT1, 'monthly', SEM);
TT1monum = retime(TT1, 'monthly', 'count');
[Nmin,Nmax] = bounds(TT1monum{:,1})
Nmin = 256
Nmax = 4443
% TT1Time = TT1mosem.time;
% TT1SEM = TT1mosem{:,1};
figure
hplt = plot(TT1momean.time, TT1momean{:,1}, '-k', "DisplayName",'Monthly Mean');
hold on
hpch = patch([TT1mosem.time; flip(TT1mosem.time)], [TT1momean{:,1}-TT1mosem{:,1}*1.96; flip(TT1momean{:,1}+TT1mosem{:,1}*1.96)], 'r', 'FaceAlpha',0.375, 'EdgeColor','r', 'EdgeAlpha',0.5, "DisplayName","±95% Confidence Interval");
hold off
grid
xlabel('Time')
ylabel('Value')
title('Value Mean & ±95% CI')
legend("Location","NE")

[GV, ID1, ID2] = findgroups(year(T1.time), month(T1.time)); % Grouping Variable For ‘boxchart’
% [b1,b2] = bounds(ID1)
xtl = compose('%s',datetime(ID1,ID2,ones(size(ID1)), Format="MMM yyyy")); % Cell Array Of Time Values
% disp(xtl)
figure
hb = boxchart(GV, T1.value_y, "DisplayName","Boxchart of Monthly Data");
hold on
plot((1:height(TT1momean)), TT1momean{:,1}, '.-r', "DisplayName","Monthly Mean")
hold off
hb.JitterOutliers = "on";
hb.MarkerStyle = ".";
hb.Notch = "on";
hb.BoxMedianLineColor = "r";
Ax = gca;
xt = Ax.XTick;
xt = 1×7
5 10 15 20 25 30 35
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Ax.XTick = [1 : 3 : xt(end)]; % Every 3 Months
% Ax.XTick = [1 : 6 : xt(end)]; % Every 6 Months
Ax.XTickLabel = xtl(Ax.XTick);
Ax.XTickLabelRotation = 45;
xlabel("Time")
ylabel("Value")
title("Boxchart of Monthly Data")
hlgnd = legend("Location","northoutside", "Orientation","horizontal");
axis("padded")

% get(hb)
.
Adi Purwandana
on 21 Oct 2024
Ah, yes. Add ":" for the spacing. Thank you very much!
Star Strider
on 21 Oct 2024
As always, my pleasure!
More Answers (0)
Categories
Find more on Time Series Events in Help Center and File Exchange
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)