make patch white where there are NaNs
12 views (last 30 days)
Show older comments
Hi All,
I would like to use patch to make uncertainty bounds around timeseries data, but the data has NaNs. I can remove the NaNs from the patch datasets, but then I get nasty straight lines where it interpolates between the missing data. Since I am dealing with timeseries data the gaps in time with no data should remain. I thought of somehow making another white patch that goes only where there are NaNs but this would require dealing with every gap seperately, and finding their indices, which seems quite a pain given that there are many gaps. Any suggestons welcome!
Here's a simple example:
figure();
DT = datetime(2000,1,1):datetime(2000,12,31); DT=DT'; sizeDT = size(DT,1);
X_data = rand(sizeDT,1);
X_data(5:40)=NaN; X_data(100:120)=NaN; %make some NaN
idnans = isnan(X_data);
lb = X_data - (X_data.*0.3);
ub = X_data + (X_data.*0.3);
DTnn = DT; DTnn(idnans)=[]; lbnn = lb; lbnn(idnans)=[]; ubnn=ub; ubnn(idnans)=[];
patch([DTnn' fliplr(DTnn')],[lbnn' flipud(ubnn)'],'b','FaceAlpha',.2, 'EdgeColor','none'); hold on;
%modelled
plot(DT,X_data,'Color','b','LineStyle','-'); hold on;
legend('uncertainty','data');
Thanks!!
2 Comments
dpb
on 5 Mar 2025
figure();
DT = datetime(2000,1,1):datetime(2000,12,31); DT=DT'; sizeDT = size(DT,1);
X_data = rand(sizeDT,1);
X_data(5:40)=NaN; X_data(100:120)=NaN; %make some NaN
idnans = isnan(X_data);
lb = X_data - (X_data.*0.3);
ub = X_data + (X_data.*0.3);
DTnn = DT; DTnn(idnans)=[]; lbnn = lb; lbnn(idnans)=[]; ubnn=ub; ubnn(idnans)=[];
patch([DTnn' fliplr(DTnn')],[lbnn' flipud(ubnn)'],'b','FaceAlpha',.2, 'EdgeColor','none'); hold on;
%modelled
plot(DT,X_data,'Color','b','LineStyle','-'); hold on;
legend('uncertainty','data');
It's not clear what you want the end result to be??? With a white background a white patch is/will be unseen, so what's the point?
As for dealing with the missing data sections, patch can create multiple polygons in a single call, where each is specificed by the corner coordinates in X,Y arrays; each column in X and Y defines a separate area. But, you will indeed have to locate the ends of the missing sections. How much trouble that may be will probably depend upon the sampling scheme; if it is a uniformly sampled time history, then any gap other than the sample time is missing and easy to find. Turning the data into a timetable would probably make things easier with retime.
Accepted Answer
Voss
on 5 Mar 2025
Edited: Voss
on 5 Mar 2025
In this case, the patch's EdgeColor is 'none', so wherever the upper and lower patch bounds coincide, no edge is rendered and the patch does not appear at all in those regions. Therefore, rather than removing the elements of DTnn, lbnn, and ubnn where X_data is NaN, you can merely set those elements of lbnn and ubnn to the same value so that the upper and lower bounds of the patch coincide. [To get the patch to look right at the gap edges, I use fillmissing(_,'linear') to fill the NaNs in lbnn and ubnn with their own respective line segments and then take the mean of the two to get a single line segment for each gap.]
figure();
DT = (datetime(2000,1,1):datetime(2000,12,31)).';
X_data = rand(size(DT));
X_data([5:40 100:120])=NaN; %make some NaN
idnans = isnan(X_data);
lb = 0.7*X_data;
ub = 1.3*X_data;
DTnn = DT;
lbnn = lb;
ubnn = ub;
tmp = mean(fillmissing([lbnn ubnn],'linear'),2);
lbnn(idnans)=tmp(idnans);
ubnn(idnans)=tmp(idnans);
patch([DTnn; flipud(DTnn)],[lbnn; flipud(ubnn)],'b','FaceAlpha',0.2, 'EdgeColor','none');
hold on;
plot(DT,X_data,'Color','b','LineStyle','-');
legend('uncertainty','data');
% zoomed-in copy to show a gap
copyobj([gca() gca().Legend],figure())
xlim(DT([80 140]))
More Answers (0)
See Also
Categories
Find more on Polygons 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!