Plotting data from files [duplicate] - matlab

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Calculations of files
Day price1 price2
2/2/2000 10 15
3/2/2000 12 18
4/2/2000 14 19
How could I plot x=day and y=price1?
file = xlsread('example.xls');
x = file(:,1);
y = file(:,2);
plot(x,y);
It doesn't give the days in x line it gives numbers 0, 1, 2 insted of 2/2/2000

The neatest method for getting the x-axis to display dates is via the datetick function. I used to do it manually, as the other answers to this question suggest doing, until I discovered this wonderful function.
Cut and paste the following example into a Matlab script and run it line-by-line:
y = randn(4, 1); %# Simulate random observations
Dates = {'1/1/2000', '2/1/2000', '3/1/2000', '4/1/2000'}; %# Build a vector of date strings
DatesNum = datenum(Dates, 'dd/mm/yyyy'); %# Convert date strings to date numbers
plot(DatesNum, y); %# Plot the data
datetick('x', 'dd/mm/yyyy'); %# Convert date numbers on plot to string format
The last line essentially says "on the x axis of the current plot, display the numbers in date-time format, using the format string dd/mm/yyyy".
Once you are familiar with how this example works, you should be able to adapt this example to your code.

You can use date strings to label your xtick marks in the plot. First we need to convert the date number to a date sting, using datestr.
[file, text] = xlsread('example.xls');
x = file(:, 1);
y = file(:, 2);
x0 = datenum(2000, 2, 2);
cal = cellstr(datestr(x + x0));
Then we can plot and label the tickmarks.
plot(x, y);
set(gca(), 'xtick', 1 : length(y), 'xticklabel', cal);;

If you do not have an Excel COM server available (likely the case if you are running on unix/linux), the dates will appear as Excel serial date numbers (an integer). These are different from MATLAB date serial numbers. They can be converted using x2mdate():
file = xlsread('example.xls')
file(:,1) = x2mdate(file(:,1))
set(gca,'Xtick',file(:,1),'XTickLabel',datestr(file(:,1)))
Here I am assuming that the dates in your date column are formatted as dates by Excel/LibreOffice and not as strings.

Related

How to generate a date-time array in MATLAB?

How do I generate this 480x1 array of date-times in Matlab?
1982-01-01
1982-02-01
1982-03-01
1982-03-01
1982-04-01
.
.
.
2015-12-01
This is made easy with the datetime function (introduced in R2014b) and following the documentation to Generate Sequence of Dates and Time.
% MATLAB 2019a
t1 = datetime(1982,1,1);
t2 = datetime(2015,12,1);
t = t1:t2;
t = t(:); % Force column
Alternatively, you can specify the number of linearly-spaced points between two dates using the linspace command.
t_alt = linspace(t1,t2,480).';
You can convert to the y-M-d format you specified with datetime as well.
t_format = datetime(t,'Format','y-M-d')
References:
1. Dates and Time (in MATLAB)
2. Represent Dates and Times in MATLAB
3. Set Date and Time Display Format
4. Generate Sequence of Dates and Time

How do I grab only June, July, August daily data in Matlab from multi-year data using a for loop?

I have a 2 dimensional matrix [date x data]. The date is formatted in Matlab time, and spans 30+ years of data. I want to find only June, July, and August months of data. How do I loop through the date column to find all daily data for JJA months and create a new variable from it? The date column spans an entire year (Jan-Dec) from 1958-2014.
Sample data is as follows:
715290 248.466883960556
715291 283.505916006759
715292 324.290798860324
715293 330.142892431377
715294 267.062371422836
715295 263.568232655174
715296 540.856981589398
715297 1068.81389065867
715298 1174.92651788078
715299 1077.71223624073
715300 940.399428121956
715301 720.323217401065
715302 689.605704068148
715303 777.776178783704
715304 914.330565109213
715305 1069.02532264344
715306 1168.15631281824
715307 1263.47638011252
715308 1309.37995956891
715309 1318.50751550512
715310 1303.83817524424
715311 1273.11884252625
715312 1272.70005316829
715313 1330.08825971279
715314 1391.65459098343
715315 1511.13670010565
715316 1524.18921565080
715317 1451.41725782868
715318 1384.63128177358
715319 1388.90746497726
715320 1423.66479419858
715321 1417.13642861071
I've tried the following, but the indices ('idx' variable) doesn't successfully grab the Matlab date time column from the 'data' matrix:
t = datevec(data(:,1)); % get the date value
[unDates, ~, subs] = unique(t(:,1:2),'rows'); % group by unique month
idx = find(unDates(:,2) == 6 | unDates(:,2) == 7 | unDates(:,2) == 8); %Find JJA months
time_JJA = unDates(idx); %unDates is a 2D matrix [YYYY x M]. Col 1 = year and Col 2 = month (e.g., '6' is June)
I would always prefer to use the matlab datetime format, as i find it quite handy. Then you can use the special date operations and it get quite easy:
%creating datetimes
DataAsDatetime=datetime(data(:,1), 'ConvertFrom', 'datenum');
%getting a vector of month
DataMonth=month(DataAsDatetime);
%creating that logical vector
Logicalvector=(DataMonth==6 | DataMonth==7 | DataMonth==8);
%getting what you want
WhatYouWant=X(Logicalvector,2);
%or all of that in one line
WhatYouWant2=X(month(datetime(data(:,1), 'ConvertFrom', 'datenum'))>=6 & month(datetime(data(:,1), 'ConvertFrom', 'datenum'))<=8,2);
I would reccomend you to transform to datetime right after importing. It that case you can go even more into detail, like looking for weekdays or filtering specific years

Add the year in the x-axis in Matlab

I have a two column data with mmyyyy and SPI (Standardized Precipitation Index) variables. The first two samples have no data (NAN). The file is:
011982 NAN
021982 NAN
031982 -1.348
.
.
.
122013 1.098
I load the time and SPI data into MATLAB, then I would like to plot it but it is not working.
I would like to plot line graph but I really have no idea how to plot time in x-axis and I would like my x-axis to show only the year.
Using the new datetime data type in MATLAB (added in R2014b), this should be easy.
Here is an example. First we load the data into a MATLAB table:
% import data from file
fid = fopen('file.dat', 'rt');
C = textscan(fid, '%{MMyyyy}D %f');
fclose(fid);
% create table
t = table(C{:}, 'VariableNames',{'date','SPI'});
You get something like this:
>> t(1:10,:)
ans =
date SPI
______ ________
011982 NaN
021982 NaN
031982 2.022
041982 1.5689
051982 0.75813
061982 -0.74338
071982 -1.7323
081982 -2.4466
091982 -0.86604
101982 0.085698
Next to plot the data with date and time, it's as easy as calling plot:
plot(t.date, t.SPI)
xlabel('Date'), ylabel('Standardized Precipitation Index')
By default, plot chooses tick mark locations based on the range of data. When you zoom in and out of a plot, the tick labels automatically adjust to the new axis limits.
But if you want, you can also specify a custom format for the datetime tick labels. Note that when you do this, the plot always formats the tick labels according to the specified value, they won't adjust on zoom:
plot(t.date, t.SPI, 'DatetimeTickFormat','yyyy')
I'm adding another answer that works in older MATLAB versions without table or datetime data types.
Like before, we first import the data from file, but this time we read the dates as strings then convert them to serial date numbers using datenum function (defined as the number of days since "January 0, 0000"):
% import data from file
fid = fopen('file.dat', 'rt');
C = textscan(fid, '%s %f');
fclose(fid);
% create matrix
t = [datenum(C{1},'mmyyyy') C{2}];
The data looks like this:
>> format long
>> t(1:10,:)
ans =
1.0e+05 *
7.239120000000000 NaN
7.239430000000000 NaN
7.239710000000000 0.000005606888474
7.240020000000000 0.000009156147863
7.240320000000000 0.000004504804864
7.240630000000000 0.000008359005819
7.240930000000000 0.000007436313932
7.241240000000000 0.000002800134237
7.241550000000000 0.000005261613664
7.241850000000000 0.000001809901372
Next we plot the data like before, but instead we use the datetick function to format the x-axis as dates ('yyyy' for years):
plot(t(:,1), t(:,2))
datetick('x', 'yyyy')
xlabel('Date'), ylabel('Standardized Precipitation Index')
Unfortunately the tick labels will not automatically update when you zoom in and out... The good news, there are solutions on the File Exchange that solve this issue, for example datetickzoom and datetick2.

For command + interpolation: need some tips

I have a matrix A with three columns: daily dates, prices, and hours - all same size vector - there are multiple prices associated to hours in a day.
sample data below:
A_dates = A_hours= A_prices=
[20080902 [9.698 [24.09
20080902 9.891 24.59
200080902 10.251 24.60
20080903 9.584 25.63
200080903 10.45 24.96
200080903 12.12 24.78
200080904 12.95 26.98
20080904 13.569 26.78
20080904] 14.589] 25.41]
Keep in my mind that I have about two years of daily data with about 10 000 prices per day that covers almost every minutes in a day from 9:30am to 16:00pm. Actually my initial dataset time was in milliseconds. I then converted my milliseconds in hours. I have some hours like 14.589 repeated three times with 3 different prices. Hence I did the following:
time=[A_dates,A_hours,A_prices];
[timeinhr,price]=consolidator(time,A_prices,'mean'); where timeinhr is both vector A_dates and A_hours
to take an average price at each say 14.589hours.
then for any missing hours with .25 .50 .75 and integer hours - I wish to interpolate.
For each date, hours repeat and I need to interpolate linearly prices that I don't have for some "wanted" hours. But of course I can't use the command interp1 if my hours repeats in my column because I have multiple days. So say:
%# here I want hours in 0.25unit increments (like 9.5hrs)
new_timeinhr = 0:0.25:max(A_hours));
day_hour = rem(new_timeinhour, 24);
%# Here I want only prices between 9.5hours and 16hours
new_timeinhr( day_hour <= 9.2 | day_hour >= 16.1 ) = [];
I then create a unique vectors of day and want to use a for and if command to interpolate daily and then stack my new prices in a vector one after the other:
days = unique(A_dates);
for j = 1:length(days);
if A_dates == days(j)
int_prices(j) = interp1(A_hours, A_prices, new_timeinhr);
end;
end;
My error is:
In an assignment A(I) = B, the number of elements in B and I must be the same.
How can I write the int_prices(j) to the stack?
I recommend converting your input to a single monotonic time value. Use the MATLAB datenum format, which represents one day as 1. There are plenty of advantages to this: You get the builtin MATLAB time/date functions, you get plot labels formatted nicely as date/time via datetick, and interpolation just works. Without test data, I can't test this code, but here's the general idea.
Based on your new information that dates are stored as 20080902 (I assume yyyymmdd), I've updated the initial conversion code. Also, since the layout of A is causing confusion, I'm going to refer to the columns of A as the vectors A_prices, A_hours, and A_dates.
% This datenum vector matches A. I'm assuming they're already sorted by date and time
At = datenum(num2str(A_dates), 'yyyymmdd') + datenum(0, 0, 0, A_hours, 0, 0);
incr = datenum(0, 0, 0, 0.25, 0, 0); % 0.25 hour
t = (At(1):incr:At(end)).'; % Full timespan of dataset, in 0.25 hour increments
frac_hours = 24*(t - floor(t)); % Fractional hours into the day
t_business_day = t((frac_hours > 9.4) & (frac_hours < 16.1)); % Time vector only where you want it
P = interp1(At, A_prices, t_business_day);
I repeat, since there's no test data, I can't test the code. I highly recommend testing the date conversion code by using datestr to convert back from the datenum to readable dates.
Converting days/hours to serial date numbers, as suggested by #Peter, is definitely the way to go. Based on his code (which I already upvoted), I present below a simple example.
First I start by creating some fake data resembling what you described (with some missing parts as well):
%# three days in increments of 1 hour
dt = datenum(num2str((0:23)','2012-06-01 %02d:00'), 'yyyy-mm-dd HH:MM'); %#'
dt = [dt; dt+1; dt+2];
%# price data corresponding to each hour
p = cumsum(rand(size(dt))-0.5);
%# show plot
plot(dt, p, '.-'), datetick('x')
grid on, xlabel('Date/Time'), ylabel('Prices')
%# lets remove some rows as missing
idx = ( rand(size(dt)) < 0.1 );
hold on, plot(dt(idx), p(idx), 'ro'), hold off
legend({'prices','missing'})
dt(idx) = [];
p(idx) = [];
%# matrix same as yours: days,prices,hours
ymd = str2double( cellstr(datestr(dt,'yyyymmdd')) );
hr = str2double( cellstr(datestr(dt,'HH')) );
A = [ymd p hr];
%# let clear all variables except the data matrix A
clearvars -except A
Next we interpolate the price data across the entire range in 15 minutes increments:
%# convert days/hours to serial date number
dt = datenum(num2str(A(:,[1 3]),'%d %d'), 'yyyymmdd HH');
%# create a vector of 15 min increments
t_15min = (0:0.25:(24-0.25))'; %#'
tt = datenum(0,0,0, t_15min,0,0);
%# offset serial date across all days
ymd = datenum(num2str(unique(A(:,1))), 'yyyymmdd');
tt = bsxfun(#plus, ymd', tt); %#'
tt = tt(:);
%# interpolate data at new datetimes
pp = interp1(dt, A(:,2), tt);
%# extract desired period of time from each day
idx = (9.5 <= t_15min & t_15min <= 16);
idx2 = bsxfun(#plus, find(idx), (0:numel(ymd)-1)*numel(t_15min));
P = pp(idx2(:));
%# plot interpolated data, and show extracted periods
figure, plot(tt, pp, '.-'), datetick('x'), hold on
plot([tt(idx2);nan(1,numel(ymd))], [pp(idx2);nan(1,numel(ymd))], 'r.-')
hold off, grid on, xlabel('Date/Time'), ylabel('Prices')
legend({'interpolated prices','period of 9:30 - 16:00'})
and here are the two plots showing the original and interpolated data:
I think I might have solved it this way:
new_timeinhr = 0:0.25:max(A(:,2));
day_hour = rem(new_timeinhr, 24);
new_timeinhr( day_hour <= 9.4 | day_hour >= 16.1 ) = [];
days=unique(data(:,1));
P=[];
for j=1:length(days);
condition=A(:,1)==days(j);
intprices = interp1(A(condition,2), A(condition,3), new_timeinhr);
P=vertcat(P,intprices');
end;

plot extending several years

In the following example I have two years worth of data denoted by data_2007 and data_2008 which have a corresponding array of dates:
clear all
DateTime_2007 = datestr(datenum('2007-01-01 00:00','yyyy-mm-dd HH:MM'):1/24:...
datenum('2007-12-31 23:57','yyyy-mm-dd HH:MM'),...
'yyyy-mm-dd HH:MM');
DateTime_2007 = cellstr(DateTime_2007);
DateTime_2008 = datestr(datenum('2008-01-01 00:00','yyyy-mm-dd HH:MM'):1/24:...
datenum('2008-12-31 23:57','yyyy-mm-dd HH:MM'),...
'yyyy-mm-dd HH:MM');
DateTime_2008 = cellstr(DateTime_2008);
data_2007 = 1 + (20-1).*rand(8760,1);
data_2008 = 1 + (20-1).*rand(8784,1);
I would like to plot the data on one graph, showing how the data has varied over the 2 years, so basically a plot extending over 2 years. How can this be achieved, considering that I need the dates to be shown along the xaxis, and possible only the month name (mmm) to be given (not yyyy-mm-dd HH:MM).
Have you tried the datetick command to label the axes?
plot(datenum(DateTime_2007),data_2007)
hold on
plot(datenum(DateTime_2008),data_2008,'g')
datetick('x','mmm')
It might be easier if you didn't convert your dates to date strings, and then have to convert them back for plotting.
Use datetick. Your dates should just be datenum:
DateTime_2008 = datenum('2008-01-01 00:00','yyyy-mm-dd HH:MM'):1/24:...
datenum('2008-12-31 23:57','yyyy-mm-dd HH:MM');
and you can plot it like:
plot([DateTime_2007 DateTime_2008], [data_2007; data_2008]);
datetick('x');
If you want a different format for the ticks, try:
datetick('x', 'yyyy-mm');
and if you want to choose the location of the ticks yourself (to actually specify the ticks, you might need to use set(gca, 'XTick', ...), see axes properties):
datetick('x', 'keepticks');