How to read year from timeseries?

Hi there,
I have a script that uses "eval" to define a range of yearly environmental values over a large number of sites for a large number of years. I know "eval" is not suggested, but with the number of years, sites, and variables I am dealing with it makes things a whole lot easier.
Anyways, the following snippet of code works well but I would like to automate it even more. In the following, I first load data then create a structure (pars_yr) that defines the variable years I am looking at.
% Download .DAT data matrix, define first column as datetime timeseries
%third column is temp. "Date_all_site" is the entire datetime column for that site.
% Data is recorded every 30min throughout the year
pars_site_yr = {'2014','2015','2016','2017','2018','2019'};
site_yr_start = min(Date_all_site):calyears(1):max(Date_all_site);
site_yrs = years(site_yr_start)
for i = 1:length(pars_site_yr)
eval(['temp_site_',pars_site_yr{i},' = site_',pars_yr{i},'(3,:);'])
end
% more of my code
The problem is, every time I add more data I need to manually change "pars_site_yr". This isn't a huge problem considering I will only need to do it once a year, but I think it would be cool if the code just automatically "read" the new datetime years (especially considering I already defined the years for each site in site_yrs).
"site_yrs" has all the years based off the input "Date_all_site", but it is not in a useable "structure" form like pars_site_yr is. Each site has a different range of years that data was recorded.
I'm pretty new to matlab so hopefully this is easy. Thanks a ton for all your help!
-Devon

5 Comments

Walter Roberson
Walter Roberson on 28 Jan 2020
Edited: Walter Roberson on 28 Jan 2020
Use a struct with dynamic field names instead of eval()
Could you elaborate or send a link to an article about this?
I quite literally have hundreds of different site, probe, variable, and year combinations that I do calculations to. I want to do the "proper" method, but its hard to justify when doing so would require many hours of code writing and several thousand lines.
Thanks for your response!
for i = 1:length(pars_site_yr)
fn = ['y', pars_site_yr{i}];
temp_site.(fn) = site.(fn)(3,:);
end
This would expect site.y2014 site.y2015 and so on, and would produce temp_site.y2014 temp_site.y2015 and so on.
But often better is cell arrays (if the data is different lengths) or multidimensional numeric arrays when practical.
for i = 1:length(pars_site_yr)
fn = ['y', pars_site_yr{i}];
temp_site{i} = site.(fn)(3,:);
end
now you can cellfun over temp_site, and if you want to locate a particular year then ismember() into pars_site_yr and take the second output.
During the time that you are doing the processing, using variable names or struct field names that contain metadata is mostly for presentation purposes. Sometimes it can make sense to use metadata in struct field names inside .mat files but that is the last processing step and can often be handled with cell2struct()
Assuming a datetime variable. you can use year function
yr = year(datetime_var);
yr = unique(yr); % this will give you all the years in your data.
pars_site_yr = arrayfun(@num2str,yr,'UniformOutput',false);
@Mohammad Sami, that works with my existing program, thanks!
@Walter Roberson, that also works, but will require I change quite a bit of my existing code. Because this is the "proper" way to do things, I will try to convert!
Thank you both for your responses!

Sign in to comment.

Answers (0)

Community Treasure Hunt

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

Start Hunting!