Plotting timeseries data in MATLAB - matlab

I have a matrix that contains two columns of data. The first column has timestamps given in UNIX time and the second column has a corresponding data set.
I'm trying to plot this DATA with human-readable times on the bottom axis.
I've plotted the raw data, like so:
plot(DATA(:,1), DATA(:,2));
I know there is a timeseries() function in MATLAB, but I can't seem to get it working correctly. I should be able to plot the data, following the MATLAB documentation.
I've tried declaring the first column as a time series:
TS = timeseries(DATA(:,1));
Then I tried plotting the data, like so:
plot(TS, DATA(:,1));
Although this approach seems to make rational sense, I get the following error:
Error using plot
Data must be a single matrix Y or a list of pairs X,Y
I also tried to use the addsample() function to append the data to the time series and then plot it.
K = addsample(TS, DATA(:,2));
plot(K);
But doing this produced the following error:
A new sample must be specified either as a structure or by Property-Value pairs.
So how do I plot this time data correctly? Thank you!

I work quite often with posix time (i.e. unixtime) with other programs, but in matlab the easiest format to deal with time and date is the Matlab time serial number format.
To convert from Unix to Matlab I use a small conversion function extensively:
function matlabtime = unix2matlabtime(unixtime)
%// function matlabtime = unix2matlabtime(unixtime)
%//
%// input : ** unixtime ** : time vector in the UNIX time serial number
%// representation (seconds since 01-jan-1970)
%//
%// output : ** matlabtime ** : time vector in the Matlab time serial number
%// representation (days since 01-jan-0000)
pivot = datenum([1970 01 01 00 00 00]) ;
matlabtime = ( unixtime / 24 / 3600 ) + pivot ;
with this function saved somewhere on your path, you can plot your data like so:
%// Generate sample data
sampleunixtime = linspace( 1427205640 , 1427205900 ).' ; %'// ignore this comment
DATA = [sampleunixtime , sin(sampleunixtime./10) ] ;
%// get a time vector in Matlab time serial format, then plot
time = unix2matlabtime( DATA(:,1) ) ;
plot( time, DATA(:,2) )
%// Adjust X-Ticks in human readable format
set( gca , 'XTickLabel' , datestr( get(gca,'XTick'),'HH:MM:SS' ) )
To obtain:
look at the datenum and datestr documentation to see how to handle these. There are many predefined output format for the date/time or you can even build your own to refine to the precision you need (add millisecond, remove seconds, add the date etc ...).
Just be aware that the XTickLabel are now overriden, so they will not be updated automatically. So if you zoom or pan on your figure you'll have to re-run the last line of code to refresh the XTicks values.
(personally, I put this last line of code in a Matlab toolbar shortcut to have quick access to it at any time).

Related

For a time series plot, how to set the x axis to calendar time without weekends

I want to plot a time series (pricing data for a forex future contract). Time is given in yyyymmdd HH:MM:SS string format. Price is in double.
The time series spans over a week. However, the timestamp for the data points are always on weekdays. Is there a built-in method to display the appropriate x-axis labels and scaling but without weekends?
I can currently display the time series by converting the timestamp in string to datenum and arrange x-axis automatically with datetick. But I would like to know how to exclude weekends on the x-axis. Or exclude any extended interval of time from the grid where there is no data.
For a visual, please see example at the end. If one can exclude the large empty space due to including the weekend (Apr 10 was a US holiday), the plot can become more legible by focusing on where there is actually data.
The data points themselves are exclusive to weekdays. But between plot and datetick, grid points on weekends are created whenever the time series spans over a week. datetick is helpful because it detects the appropriate scaling for x-axis grid and applies the corresponding grid labels all in one go. If you see datetick as a part of the solution, is there a way to remove particular grid points after using datetick?
Example:
T=[7.378903958333334e+05;7.378967076388889e+05]; % converted from "20200409 09:30:00" and "20200415 16:59:00"
C=[0.7166;0.7090];
grid on
plot(T,C,'.')
xlim([min(T),max(T)])
datetick
If you are interested in tinkering with the same plot, please retrieve the data by c&p into Matlab cmd from pastebin. The same lines above will produce the following plot.
There is no such features. Probably, because this essentially makes the x-axis discontinuous, which is (usually) not desirable.
You will have to create a synthetic x-axis to achieve this by sorting out the the weekends (or rather the not business days).
This is the standard plot (the business days are blue)
% create data
T = 7.3789e+05+(0:5:100)/10.';
C = rand(size(T));
% is a busniess day?
lg = isbusday(T);
% standard date plot
plot(T(lg),C(lg),'o', T(~lg),C(~lg),'o')
datetick('x','ddd')
Now let us get rid of the other days and set the xTickLabel manually:
T = T(lg);
C = C(lg);
% plot without time-axis
plot(C,'o')
% --- get ticks
xTick = get(gca,'XTick');
% get which ticks are integers
lg = isreal(xTick) & rem(xTick,1)==0;
XTick_new = xTick(lg);
% --- create new tick label
xTickLbl_new_num = NaN(size(XTick_new));
% make sure they are within the limits
lg = XTick_new >= 1 & XTick_new <= length(T);
xTickLbl_new_num(lg) = T(XTick_new(lg));
% convert to string (arbitrary format)
xTickLbl_new_str = strings(size(xTickLbl_new_num));
xTickLbl_new_str(lg) = datestr(xTickLbl_new_num(lg),'ddd');
% set new label
set(gca,'XTick',XTick_new,'XTickLabel',xTickLbl_new_str);
Have a look on the results: left the standard version and on the right the version with manually set tick-labels.

How tick labels on one of the plot's axis can be multiplied in MATLAB?

I am currently trying to make 'nice looking' axis on my plot in Matlab. The values are samples where each is taken every 20ms. So on X axis I'd like to have time in ms. My general code for plotting data is very simple:
plot(1:size( data.matrix,1), data.matrix(:,1),'b');
So far I've been able to correctly display sample numbers on this axis:
Code:
set(gca,'XTick',(1:size(data.matrix,1))*20);
Result (a):
In the given example the number of samples equals 184, that makes:
time = 184 * 20ms = 3680ms
Because changing the XTick value didn't do much of a change, I've tested XTickLabel property:
Code:
set(gca,'XTickLabel',ceil(linspace(0,size(data.matrix,1)*20,10)));
Result (b):
Code:
set(gca,'XTickLabel',0:ceil((size(data.matrix,1)*20)/10):size(data.matrix,1)*20);
Result (c):
As you may see, the results aren't the worst one. But this is not what I am trying to achieve. My goal is to have values like this:
So it simply first plot's (result a) X axis multiplied by 20.
Can someone please tell me how to achieve this?
when you use :
plot(1:size( data.matrix,1), data.matrix(:,1),'b');
The first parameter 1:size( data.matrix,1) create a vector of consecutive integers representing the indices of your data points. Two things are wrong with that:
1) You do not need to specify it. Matlab plot function called with only the Y data will create this vector automatically and use it to plot the data.
2) These indices represent the position of your data in an array, they have no physical meaning (like "time" for your case).
The solution is to create a proper 'time' vector and send it as the first parameter to the plot function. This way Matlab will take care of the tick management and you don't have to temper with the manual xtick settings.
Look at the two ways of doing it in the example below and everything will be clear:
%// build a simple index "X" vector (as you were doing)
x_index = 1:size(data.matrix,1) ;
%// build a properly scaled time vector
timeInterval = 20 ; % in milliseconds
x_time = ( 0:size(data.matrix,1)-1 ) * timeInterval ;
plot( x_index , data.matrix(:,1) ) %// this will do like in your example
plot( x_time , data.matrix(:,1) ) %// this will do what you want
Can you not just do?
set(gca,'XTickLabel',(1:size(data.matrix,1))*20*20);

Plotting in matlab time in secs as HH:MM:SS.FFF

I have a 356*2 array lets call him tmp
When the (:,1) is in milisecs
Now i am looking to make a plot of X over y when i want the X be showed in HH:MM:SS.FFF secs
I have converted the secs to that format by
datestr(tmp(:,1)*0.001/24/3600,'HH:MM:SS.FFF')
But this is a string, how can i use it in my plot function
You can apply what are called date format strings to the axes of plots with built-in function datetick. For example, with your first column being time, you could call
plot(tmp(:, 1), tmp(:, 2))
to plot the data. Then call:
datetick('x', 'HH:MM:SS.FFF')
to format the values assigned to ticks on the x-axis based on the second input argument. NOTE that, in order to perform this conversion, the function assumes that the time data is in units of DAYS, so if your data is in milliseconds, you should divide your time data by (24*60*60*1000). Note also that when you zoom on this graph, the new labels will not be re-written at each scale as numeric ones would have been. To get around this, I thoroughly recommend datetickzoom from the MATLAB file exchange.
Use your original value of tmp(:,1) for the plot function and then use your datestr(tmp(:,1)*0.001/24/3600,'HH:MM:SS.FFF') as the label?

Selecting certain time range in Matlab

I have a project to do and im facing some problems. Please help me. Im not so good at matlab yet.
Basically, I have a set of movement data (data.mat) which were recorded for 3 days non stop. And I need to:
1. select only certain certain moments (time range) of this whole set of data
2. divide these moments into small 2.56 seconds parts
3. make FFT of each small parts , to see the movement in frequency domain, and select only 5-25 Hz
4. find a few biggest frequency peaks
I wrote a code for making FFT and peaks for whole my data "Data.mat" and it is working.
This is my code:
load('Data.mat');
P=data1(,2); %
Fs=100
Ts=1/Fs
L=length(P)
t = (0:L-1)*Ts;
nfft = 256
figure(1) % raw signal plotting
plot(t,P);
y = fft(P,nfft)/L; % FFT
ymag = abs(y(1:length(y)/2+1));
ft = Fs/2*linspace(0,1,nfft/2+1);
figure(2) % FFT plotting
plot(ft,2*abs(y(1:nfft/2+1)))
indx=ft>= 5 & ft<= 25; % only 5-25Hz
ftsub=ft(indx);
ymagsub=ymag(indx);
% highest peaks
[pks,locs] = findpeaks(ymagsub,'MinPeakHeight',0.02)
plot(ftsub,ymagsub,ftsub(locs),pks,'rv','MarkerFaceColor','r')
Now Im trying to select only certain moments of the data but I have problems with it.
E.g. lets say, I want select only time range: 13-03-2013 9:20:00-9:45:00 AM
I have tried:
t_start =datenum('13-03-2013 9:20:00 AM', 'dd-mm-yyyy HH:MM:SS AM');
t_end = datenum('13-03-2013 9:45:00 AM', 'dd-mm-yyyy HH:MM:SS AM');
rows=find(P>= t_start & P<= t_end);
but I get answer:
rows=
Empty matrix: 0-by-1
Whats wrong? If this code is wrong, how to select certain time range then?
And how to select into 2.56 seconds ?
Please help me, Ive been trying to find the solution since weeks, im really depressed now.
For this line to work properly:
rows=find(P>= t_start & P<= t_end); P must be a series of times in MATLAB datenum format.
I'm guessing P is your actual data - so it doesn't work because find simply compares the numeric values in P against the numeric date values - your "P" values aren't date-tagged in MATLAB. The important things to remember is that the output of datenum is simply a number, so MATLAB will allow you to compare it against other numbers even if the result doesn't make real-world sense.
Your options are:
If your data contains a timestamp, load that, check that it is in the correct format (convert back with datestr for a sanity check). This may be the first column of your data. Perform the find on the time values and then use that to plot/extract the appropriate parts of P.
Construct a time vector - using what you know about the time of the first data point + the sampling rate, and do the same. Similar to your t but in datenums. This will also work if your data acquisition means you only have the times in time-since-start-of-file plus a start time.
Then it's just something like:
r=find(t>= t_start & t<= t_end);
plot(t(r),P(r);

Plotting data on time (date) axis

I have data like this:
22.10.1980. 100
25.10.1980. 120
26.10.1980. 12
(only much more of it, and for each date, several independent measurements on the right).
Now, this is probably trivial, but I've never done anything like it in MATLAB, and am having problems finding similar examples online. I need to plot the data on a time/showing dates axis (x axis), with all dates inside (so, 23. and 24. as well ... for which I don't have measurements).
How can I get dates to show up on a plot axis?
It seems like it might be the best to use datetick.
Usage: datetick('x') or datetick('x', dateformat) with the available formats as explained in the documentation.
Assuming your data file has the format given above, you could use textscan to read the data:
fid = fopen('data.txt','rt');
C = textscan(fid,'%s %s %s %d','Delimiter','.','CollectOutput',1);
fclose(fid);
The first cell of C will contain an N-by-3 cell array of strings (the parts of the date) and the second cell of C will contain an N-by-1 vector of the data measurements. You can create a date number for each measurement by first concatenating the 3 smaller strings into one date string and then using the datenum function:
t = datenum(strcat(C{1}(:,3),'-',C{1}(:,2),'-',C{1}(:,1)));
data = C{2};
Once you have a vector of date numbers t to go with your vector of measurements data, you can then plot them:
plot(t,data,'*'); %# Plot the points as asterisks
Now, you can change the x-axis labels to show the actual dates. One option is to use the function datetick, an easy and elegant solution given in steven's answer. Another option is to use the function datestr to create the labels yourself, then modify the XTick and XTickLabel properties of the current axes:
xpts = min(t):max(t); %# Make a full vector, filling in missing dates
set(gca,'XTick',xpts,'XTickLabel',datestr(xpts)); %# Set axes properties
NOTE: Whichever option you choose for changing the x-axis labels to date strings, you may run into trouble with the labels overlapping each other if the tick marks are too close together. You could fix this by reducing or repositioning the tick marks along the x-axis (by changing the XTick property) or by adjusting the axes FontSize property. If you wanted to rotate the labels to make them fit, you would have to erase the labels and create new rotated text objects for them. The following submission on The MathWorks File Exchange does just that:
Rotate Tick Label by Andrew Bliss
With datenum you can convert any string date into numerical format based on the date format symbols (see help datestr).
For example all this leads to the same numerical date representation:
datenum('15/05/2009 21:22','dd/mm/yyyy HH:MM');
datenum('15.05.2009 21:22','dd.mm.yyyy HH:MM');
datenum('21-22 15.05.2009','HH-MM dd.mm.yyyy');
datenum('21-22 05/15.2009','HH-MM mm/dd.yyyy');
...
The nice thing is that you can pass cell array (output from textscan) or char array directly to datenum and it will output numeric date array.
Datetick is a good option, as well as datetick2, which can be found here: MATLAB Central
Datetick2 allows panning and zooming, with adjustments to the time labels, depending on how far you're zoomed in.
I'm not sure about the dd.mm.yyyy format - you could use regexp or strrep to change the decimals to dashes if neccessary.
You can use datenum to convert the dates to a numbers, and plot the data as usual. lets say you put your dates vector in the variable called x.
Now, you can use
set(gca, 'xtick',x(1:10:end));
set(gca, 'xticklabel',datestr(x(1:10:end));
to set the ticks on the x axis.