# Finding Number of Events with Values Consectively Greater Than a Threshold

4 views (last 30 days)
Claire Hollow on 22 Jun 2020
Commented: Image Analyst on 24 Jun 2020
I have temperature data called tmax (2650x1 double) that is basically just temperatures every single day in a row. Im trying to find the number of events in which the temperature was 90 degrees or above for 2 or more consecutive days. I've tried a few things with no luck, please help me with how to go about this. Thank you in advance for the help!

Michael Soskind on 22 Jun 2020
Hi Claire,
I would use the findpeaks function, a very useful function I like to use for finding peaks of particular width without going through a loop. I showcase how you might be interested in using this function below, with a sample array A. I convert it to a binary sequence that is either larger than or smaller than the threshold of 90 degrees, and then I find the location of the start of the increased temperature, and the extent of this increased temperature.
% Generating fake temperature data
A = floor(100*rand(2650,1));
% Creating a binary array of when the value is greater than 90 degrees F
B = ones(size(A));
B(A < 90) = 0;
% finding the number of times the temperature is larger than 90 degrees F
% at least 2 times in a row
findpeaks(B, 'MinPeakWidth', 2)
[pks,locs,w,p] = findpeaks(B, 'MinPeakWidth', 2);
% pks provides the peak values, the locs provides the peak locations, the w
% provides the width of the peak, and the p provides the prominence of the
% peaks. w should provide some useful information to you.
Hope this code helps, you learned the function, and it proves useful for your application!
Michael

Michael Soskind on 23 Jun 2020
Nice Point Image Analyst! You are right that my code only works for heatwaves that are not at the edges of the timeseries. I believe that my answer may have been accepted simply because I had respondend quite early to the question, provided relatively working code, albeit with edge problems that I had not considered initially, and it looks as though your response may have simply been after Claire had logged in to accept her answer based on the timestamps I see of the thread. Hopefully this change can be made, but thank you for your very robust solution! Of course, as you mention, there are ways to work around this edge case challenge with a some more preprocessing.
Walter Roberson on 23 Jun 2020
The stfind() solution I presented does not need any additional toolboxes, and takes leading / trailing patterns into account.
Image Analyst on 24 Jun 2020
Yes, it was very clever. Many people don't know the trick of using strfind() on numerical arrays. It's not just for character arrays.

Walter Roberson on 22 Jun 2020
Hint:
T = [0 0 0 0 1 0 0 0 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1]
strfind(T, [0 1 1])

Claire Hollow on 22 Jun 2020
I've somehow never used the strfind function, did some more looking into it and tried this out and it worked perfect, thank you!
tmax01=tmax01';
idx=tmax01>90;
ii1=strfind([0 idx 0],[0 1]);
ii2=strfind([0 idx 0],[1 0])-1;
ii=(ii2-ii1+1)>=2;
out=arrayfun(@(x,y) tmax01(x:y),ii1(ii),ii2(ii),'un',0);
celldisp(out)
Walter Roberson on 22 Jun 2020
Using [0 idx is correct when you are looking for the beginning of patterns: it avoids problems if the part being searched begins with an appropriate pattern. Well done for discovering that.
Using idx 0] is not needed when searching for the beginning of a pattern: the extra 0 you are putting on can never match the 1 of your [0 1] pattern, and if the data to be searched happens to end in [0 1] then you would want that to be found when using [0 1] as the pattern. Adding the 0 does not do anything for you compared to using strfind properly.
Using idx 0] is, however, proper if you are looking for the end of a pattern.
ii=(ii2-ii1+1)>=2;
You do not need that. Consider
idx = tmax01(:).' > 90; %force row
N = 2; %number to find
ii1 = strfind([0 idx], [0 ones(1,N)]);
then ii1 will only match the beginning of locations that have a minimum of N 1's in a row. And for your purposes here, knowing the number of events, length(ii1) is all you need.
It is common to want to know the start and end of patterns, though. Instead of subtracting and comparing to a threshold, you can work more directly:
idx = tmax01(:).' > 90; %force row
N = 2; %number to find
ii1 = strfind([0 idx], [0, ones(1,N)]);
ii2 = strfind([idx 0], [ones(1,N), 0]) + N - 1;
Then you already know that ii1 and ii2 only match if the appropriate length was found, and ii1 and ii2 are direct indices to the beginning and end:
out = arrayfun(@(x,y) tmax0(x:y), ii1, ii2, 'uniform', 0)

Image Analyst on 22 Jun 2020
Yet another way is to use regionprops() to measure all the stretches of days above 90:
% Generate 2650 random temperatures, and plot them in a bar chart.
numPoints = 2650;
dailyTemperatures = 80 + 12 * rand(numPoints,1);
bar(dailyTemperatures);
ylim([80, 100]);
grid on;
yline(90, 'Color', 'r', 'LineWidth', 2); % Display the threshold.
% Measure lengths of stretches above 90:
props = regionprops(dailyTemperatures > 90, 'Area')
allLengths = [props.Area]
% Count how events are 2 days or longer.
numEvents = sum(allLengths >= 2);
fprintf('There are %d heatwaves of more than 90 Degrees for 2 days or longer.\n', numEvents);
Doing it this way would also let you see the longest heat wave:
fprintf('The longest heatwave lasted %d days.\n', max(allLengths));