Finding minimum temperature for a month in a data set - matlab

I have already made a function which extracts all temeperatures from a data set for a certain time for a given month and year.
Which looks like exctractperiod(data, year, month, time)
I now want to find a minimum temperature for a certain month, say January, across many years. For example if I look at the month January between the year 1997 and 2006. Now I want the lowest registered temperatue for January between 1997-2006.
My progress so far (keep in mind this is just a rough idea for what I want)
for i = 1:12
for z = 1:x+1
year=startyear:1:endyear;
year(z)
p = extractperiodtwo(DATA, year, month, time);
end
I want to know how I can write my for loops so that for, say month 1, it goes through the years 1997-2006 and finds the lowest temperatue. Then for the next loop it goes through the years 1997-2006 for month 2. This should then repeat until month 12.
The variable p stores all the temperatures for year YYYY month MM.
Don't take my program all to seriously it was just a rough write-up to give myself a idea for how it should look. Maybe it clarifies my question.

You're probably looking for something like this:
mintemp = inf(1,12); % initialize to infinity for each month
for month = 1:12
for year = 1997:2006
p = extractperiodtwo(DATA, year, month, time);
temp = min(p); % assuming `p` contains multiple temperatures?
mintemp(month) = min(mintemp(month), temp); % update current month's min temp
end
end

Related

How can I convert time from seconds to decimal year in Matlab?

I have a dataset which includes the seconds that have passed since 2000-01-01 00:00:00.0 and I would like them to be converted to decimal years (for example 2013.87).
An example from the dataset:
416554767.293262
416554768.037637
416554768.782013
416554769.526386
416554770.270761
416554771.015136
416554771.759509
416554772.503884
416554773.248258
416554773.992632
416554774.737007
416554775.481381
416554776.225757
416554776.970131
416554777.714504
416554778.458880
Can anyone help me out on this?
Thanks!
You should be able to perform these computations using methods of datetime and duration. A bit like this. I've tried to be careful regarding the number of seconds / year, since of course that varies depending on whether the year in question is a leap year.
% Original data
data = [416554767.293262
416554768.037637
416554768.782013
416554769.526386
416554770.270761
416554771.015136
416554771.759509
416554772.503884
416554773.248258
416554773.992632
416554774.737007
416554775.481381
416554776.225757
416554776.970131
416554777.714504
416554778.458880];
% Original data is seconds since 'base':
base = datetime(2000,1,1);
% Get datetimes corresponding to 'data'
dates = base + seconds(data);
% Extract the year portion from the dates
wholeYears = year(dates);
% Extract the remainder of the dates as seconds
remainderInSeconds = seconds(dates - datetime(wholeYears,1,1));
% Calculate the number of seconds in each of the years
secondsPerYear = seconds(datetime(wholeYears + 1, 1, 1) - datetime(wholeYears, 1, 1));
% Final result is whole years + remainder expressed as years
result = wholeYears + (remainderInSeconds ./ secondsPerYear);
fprintf('%.16f\n', result);

Plots on a calendar background, graphic interface, matlab

I'm using matlab for a project. I have to get a similar result to this:
Is matlab suitable for this kind of plots?
Are there any software that could be more specific for this result?
Thank you
Yes, Matlab could do this, but it will require a lot of coding I think.
I would start with a function that draws the calender in a figure
Then continue with filling the calender with the graphs and high and low values.
To find the first sunday before the start of the month you can use the start of this script. The rest draws a calender with day and date
month = [2011 04];% 2011 april
%month = [1987 02];% 1987 february (had exactly 4 weeks)
%month = [1983 01];% 1983 january (requires 6 weeks to plot)
fig=figure(1);clf;hold on;axis image off
D = datenum([month,01]);
title(datestr(D,'mmmm yyyy'))
D=D-weekday(D)+1; %find sunday
square = [0,0;0,1;1,1;1,0;0,0]; %x and y to draw a square
row=1;
while row~=0
for column = 1:7 %one week per row
plot(square(:,1)+column-1,square(:,2)-row+1,'-k'); %go right each column, go down each row
text(column-0.5,1.8-row,datestr(D,'ddd')); %name of day
text(column-0.5,1.5-row,datestr(D,'DD')); %number of day
mp = mod(D-693961,29.530588853)./29.530588853; %crude approximation of lunar phase (693961 = 31-dec-1899)
text(column-0.5,1.2-row,sprintf('%.2f',mp))
D=D+1;
end
temp=datevec(D); %are we still in the right month?
if temp(2)==month(2)
row=row+1; %new row
else
row=0; %stop the while loop
end
end

matlab: how to find interval of data

I have a dataset of trajectories of users: every current location of the traiectories has these fields:_ [userId year month day hour minute second latitude longitude regionId]. Based on the field day, I want to divide trajectories based on daily-scale in interval of different hours: 3 hours, 4 hours, 2 hours. I have realized this code that run for interval of 4 hours
% decomposedTraj is a struct that contains the trajectories based on daily scale
for i=1:size(decomposedTraj,2)
if ~isempty(decomposedTraj(i).dailyScaled)
% find the intervals
% interval [0-4]hours
Interval(i).interval_1=(decomposedTraj(i).dailyScaled(:,5)>=0&decomposedTraj(i).dailyScaled(:,5)<4);
% interval [4-8]hours
Interval(i).interval_2=(decomposedTraj(i).dailyScaled(:,5)>=4&decomposedTraj(i).dailyScaled(:,5)<8);
% interval [8-12]hours
Interval(i).interval_3=(decomposedTraj(i).dailyScaled(:,5)>=8&decomposedTraj(i).dailyScaled(:,5)<12);
% interval [12-16]hours
Interval(i).interval_4=(decomposedTraj(i).dailyScaled(:,5)>=12&decomposedTraj(i).dailyScaled(:,5)<16);
% interval [16-20]hours
Interval(i).interval_5=(decomposedTraj(i).dailyScaled(:,5)>=16&decomposedTraj(i).dailyScaled(:,5)<20);
% interval [20-0]hours
Interval(i).interval_6=(decomposedTraj(i).dailyScaled(:,5)>=20);
end
end
or more easily to understand the logic of the code:
A=[22;19;15;15;0;20;22;19;15;15;0;20;20;0;22;21;17;23;22]';
A(A>=0&A<4)
A(A>=4&A<8)
A(A>=8&A<12)
A(A>=12&A<16)
A(A>=16&A<20)
A(A>=20)
It runs and gives the right answer but it's not smart: if I want to change the interval, I have to change all the code... can you help me to find a smart solution more dinamical of this? thanks
0 Comments
Interval k is defined as [(k-1)*N k*N] where N=4 in your example. Therefore you can do the same using a for loop:
for k=1:floor(24/N)
Interval(k) = A(A>=(k-1)*N & A<k*N);
end
Note that in this example A(A>=(k-1)*N & A<k*N) is not necessarily the same size for each k so Interval should be a cell array.

Checking if a given date hour is within a predefined interval with datenum()

I have a table with dates (and other things), which I have extracted from a CSV file. In order to do some processing of my data (including plotting) I decided to convert all my date-strings to date-numbers (below for simplicity reasons I will exclude all the rest of the data and concentrate on the dates only so don't mind the step from dates to timetable and the fact that it can be omitted):
dates = [7.330249777777778e+05;7.330249291666667e+05;7.330246729166667;7.330245256944444;7.330246763888889;7.330245284722222;7.330245326388889;7.330246625000000];
timetable = table(dates);
timetable
_________
7.330249777777778e+05
7.330249291666667e+05
7.330246729166667
7.330245256944444
7.330246763888889
7.330245284722222
7.330245326388889
7.330246625000000
I'm facing the following issue - based on the time during the day I want to tell the user if a date is in the morning (24-hours scale: 5-12h), noon (12-13h), afternoon (13-18h), evening (18-21h), night (21-5h) based on the date I have stored in my table. In case I had a date-vector (with elements: year,month,day,hour,minute,second) it would be pretty straight forward:
for date = 1:size(timetable)
switch timetable(date).hour
case {5,12}
'morning'
case {12,13}
'noon'
case {13,18}
'afternoon'
case {18,21}
'evening'
otherwise
'night'
end
end
With 7.330246729166667 and the rest this is not that obvious at least to me. Any idea how to avoid converting to some other date-format just for this step and at the same time avoid some complex formula for extracting the required data (not necessarily hour only but I'm interested in the rest too)?
One unit in Matlab serial dates is equivalent to 1 day, i.e. 24 hours. Knowing this, you can bin the fractional part of the the dates within the intraday buckets you defined (note that your switch will only work for values exactly equal to the case lists):
bins = {'morning', 'noon', 'afternoon', 'evening', 'night'};
edges = [5,12,13,18,21,25]./24; % As fraction of a day
% Take fractional part
time = mod(dates,1);
% Bin with lb <= x < ub, where e.g. lb = 5/25 and is ub = 12/24
[counts,~,pos] = histcounts(time, edges);
% Make sure unbinned x in [0,5) are assigned 'night'
pos(pos==0) = 5;
bins(pos)'
ans =
'night'
'night'
'morning'
'morning'
'morning'
'morning'
'morning'
'morning'

How to construct moving time average with different weights for different months?

So I want to construct a moving time average with different weights for different months. E.g. see the filter function at http://www.mathworks.com/help/matlab/data_analysis/filtering-data.html, where b = # of days in each month and a = # of days in a year.
The issue is, though, that the time-series is a series of temperatures for every month (and I want to construct a yearly average temperature for each set of possible years, where a year could be from March to February, for example). Using this approach, the first month in each window would be weighted as 31/365, irrespective of whether the first month is January or June.
In that case, the standard filter algorithm wouldn't work. Is there an alternative?
A solution that incorporates leap years would also be nice, but is not necessary for an initial solution.
A weighted average is defined as sum(x .* weights) / sum(weights). If you want to calculate this in a moving average kind of way, I guess you could do (untested):
moving_sum = #(n, x) filter(ones(1,n), 1, x);
moving_weighted_avg = moving_sum(12, temperature .* days_per_month) ...
./ moving_sum(12, days_per_month);
If temperature is a vector of monthly temperatures and days_per_month contains the actual number of days of the corresponding months, this should even work in case of leap years.
Edit to answer comment
You can reconstruct days_per_month like so:
start_year = 2003;
start_month = 10;
nmonth = 130;
month_offset = 0:nmonth - 1;
month = mod(start_month + month_offset - 1, 12) + 1;
year = start_year + floor((start_month + month_offset - 1) / 12);
days_in_month = eomday(year, month);
disp([month_offset; year; month; days_in_month]') %print table to check