How to plot observations against season and time of day?
5 ビュー (過去 30 日間)
古いコメントを表示
Hello every one,
DayMonth = datetime('12/06/2004');
T = {'19:04 - 19:51:02'};
%T = {'10:10 - 10:30:02'};
%DayMonth = datetime('15/06/2004');
%T = {'03:20 - 03:45:06'};
%DayMonth = datetime('15/07/2005');
%T = {'07:10 - 07:50:07'};
% split to start and end times
startEndTimes = cellfun(@(str) strsplit(str,' - '),T,'UniformOutput',0);
startTimes = cellfun(@(c) c{1},startEndTimes,'UniformOutput',0);
endTimes = cellfun(@(c) c{2},startEndTimes,'UniformOutput',0);
% % add seconds where missing
missingSecondsIdx = cellfun(@length,startTimes) == 5;
startTimes(missingSecondsIdx) = cellfun(@(str) [str ':00'],startTimes(missingSecondsIdx),'UniformOutput',0);
missingSecondsIdx = cellfun(@length,endTimes) == 5;
endTimes(missingSecondsIdx) = cellfun(@(str) [str ':00'],endTimes(missingSecondsIdx),'UniformOutput',0);
% % convert time strings to numbers
startTimeNums = datenum(startTimes,'HH:MM:SS');
EPS = 1e-4;
endTimeNums = datenum(endTimes,'HH:MM:SS') - EPS;
contTime = linspace(startTimeNums(1),endTimeNums(end),200);
repDayMonth = repmat(DayMonth,[2 1]);
repDayMonth = repDayMonth(:);
allTimes = [startTimeNums';endTimeNums'];
allTimes = allTimes(:);
contDayMonth = interp1(allTimes,repDayMonth,contTime);
p=plot([DayMonth(1),DayMonth(1)],[startTimeNums(1),endTimeNums(1)],'b-','Markersize',5,'LineWidth',1);
datetick('x','dd/mm')
datetick('y','HH:MM')
This code gives me the plot given below
Now the plot gives me the correct information's (time and day of month). Now the question is that how to plot the other observations on the same figure?. I tried hold on, but i did not work. I want to get the plot as:
Any help will be appreciated.
Thanks
6 件のコメント
dpb
2018 年 3 月 25 日
Well, to date (so to speak :) ) that code is all there's been to look at so what else were we to do?
This is a start; we do finally have the datapoints of interest in front of us. Now where's your code that reads those data and tries to create the plot from them? As recommended earlier, I'd suggest to start by normalizing that set of data so can read it conveniently into an array of dates/times (having missing dates in first column can be dealt with, but makes the reading more complicated than just duplicating the date for no more than there are).
Then, insert a NaN between each element in the time vector of start:stop times to stop the line (that's how PLOT() works in Matlab; when it sees NaN in a sequence of points it lifts the pen until the next non-NaN element is reached). If you use a fairly wide line width and format the time on 24hr clock, I'm guessing you'll get a reasonable approximation of the paper's figure.
If you use the builtin datetime object, it will interpret the times axes on its own albeit you may need to set the limits to make presentation look desirable.
The X vector will be the date of the observation for each time period while the Y vector will be the start/stop times. Note you'll have to duplicate the "double-up" the days to match the length of the Y vector.
With so many of your observation times being so short, your plot isn't going to be nearly as solid as the Figure; many of those are just barely going to even show up -- 1 minute out of a day is only 1/1440th of the length of the y axis; don't be surprised if it doesn't show up at all unless you make the marker larger.
At least give it a go on your own; don't expect somebody else to solve your problem for you entirely...
採用された回答
dpb
2018 年 3 月 28 日
編集済み: dpb
2018 年 3 月 28 日
Well, here's a (not quite so) crude second pass...
Incorporated comments from last night -- good luck! :)
timedata=readtable('abdur.dat');
refdate=clock; % use current year for the reference
yr=refdate(1); mo=refdate(2); da=refdate(3);
dates=datetime(timedata.Date,'InputFormat','ddMMMMyyyy','Format','ddMMMM'); % dates, without year
timedata.Start=datetime(timedata.Start,'InputFormat','HH:mm:ss','Format','HH:mm:ss'); % start time; will be relative today's date
timedata.Stop=datetime(timedata.Stop,'InputFormat','HH:mm:ss','Format','HH:mm:ss'); % stop time...
timedata.Date=datetime(strcat(cellstr(dates),num2str(yr)),'InputFormat','ddMMMMyyyy');
% now we've got the necessary data into a table; need to construct line segments to plot
% start by getting unique years and separate list by year
[u,ia]=unique(year(dates)); % unique years, location in dates array first of each year
ib=cumsum([1;3*diff(ia)]); % location in full X,Y vector of start,stop,NaT sets of 3
% each record in start/stop fields is one line segment; introduce NaT to break lines
X=[timedata.Date.'; timedata.Date.'; NaT(1,height(timedata))]; X=X(:);
Y=[timedata.Start.'; timedata.Stop.'; NaT(1,height(timedata))]; Y=Y(:);
H=datenum(Y); H=24*(H-fix(H)); % convert to 0:24 hours for plotting
figure
ib=[ib;length(X)]; % augment index array with final index
plot(X(ib(1):ib(2)),H(ib(1):ib(2)),'linewidth',3) % first year segment
hold on % so can add on
for i=2:length(ib)-1 % and the rest...
plot(X(ib(i):ib(i+1)),H(ib(i):ib(i+1)),'linewidth',3)
end
% dress up plot a little and annotate; much room here for creativity... :)
xlim([datetime(yr,5,1) datetime(yr,8,1)])
legend(num2str(u),'location','southwest')
ylabel('UTC')
This places a line at the correct position on the axes; the width of that line is arbitrary so doesn't actually reflect the time taken by the observation relative to the axis scale.
The "exercise for the student" to do that if this for a published paper or thesis or dissertation would be to convert from using PLOT() and the line to PATCH() or FILL() such that the area actually is representative of the length of a day on the x-axis. That may have the effect of making the data almost invisible, however owing to the extremely short time periods of many of the observations so you may be forced to using a much shorter axis range or other technique to actually be able to visualize your real data as compared to that in the reference paper that had much more observation time.
12 件のコメント
dpb
2018 年 11 月 28 日
The error message gave you the suggestion... :)
Where are you located so what is the local time zone name/language?
What does the input data you're using look like?
その他の回答 (2 件)
abdur rauf
2018 年 3 月 30 日
編集済み: abdur rauf
2018 年 3 月 30 日
4 件のコメント
dpb
2018 年 3 月 31 日
Glad to help as long as see evidence of trying; just can't always find the time immediately at the time of the question.
The number of available functions in Matlab can be overwhelming initially, granted; it takes "time in grade" to begin to become familiar with the various families of functions for graphics, string/character variables, input/output functions, time/date handling, etc., etc., etc., ... The key is that to learn your way around and to get started one must use the the documentation relentlessly and keep looking for things that might be related to what one is trying to accomplish.
One tool that doesn't get much recognition nor mention any longer with the change to having the documentation webpage-based are the venerable lookfor and help commands. 'help' by itself will list all the various areas and then drilling down to a section will list all the functions of that type on one page with a one-line description of what they do. This is an invaluable way to see what functions exist that may be useful for a given problem area before digging into the details of any particular one that looks like might be useful.
While TMW keeps trying to make things easier for newbies by introducing more high-level abstractions for data types and i/o functions and the like, it also does expand the number of functions to make the maze even more complex from that standpoint -- it's a catch-22 kind of deal or "there is no free lunch"...
Good luck, this should get you on your way; will be interested in seeing your final result...
dpb
2018 年 3 月 30 日
編集済み: dpb
2018 年 3 月 30 日
Somewhat more enhanced...turned into a function with some input parameters to control some features; uses the same input data file I created before; we've beat that subject to death; use whatever format you choose...just fix up the 'InputFormat' format string to match whatever your chosen form looks like.
function rauf(file,fixLeap,minObs)
% Plot observation durations as season of year grouped by year
% RAUF(file, fixLeap, minObsLength)
% file - input data file
% fixLeap - flag for leap year day adjustment; T--> Do
% minObs - minimum length of observation to plot, seconds
timedata=readtable(file);
refdate=clock; % use current year for the reference
yr=refdate(1); mo=refdate(2); da=refdate(3);
dates=datetime(timedata.Date,'InputFormat','ddMMMMyyyy','Format','ddMMMM'); % dates, display without year
% fix up for leap year if desired; add one to day if after Feb and is leap year
if fixLeap % if ask to make fixup
is=isleapyr(dates) & month(dates)>2; % find in leap year and7 after February
dates(is)=dateshift(dates(is),'start','day','next'); % shift those to next day
end
timedata.Start=datetime(timedata.Start,'InputFormat','HH:mm:ss','Format','HH:mm:ss'); % start time; relative to day's date
timedata.Stop= datetime(timedata.Stop, 'InputFormat','HH:mm:ss','Format','HH:mm:ss'); % stop time...
timedata.Date=datetime(strcat(cellstr(dates),num2str(yr)),'InputFormat','ddMMMMyyyy'); % date in reference year
timedata.ObsTime=timedata.Stop-timedata.Start; % add in observation duration
% now here's the place to introduce a minimum observation time to consider...
isLong=seconds(timedata.ObsTime)>minObs; % logical addressing if long enough
plotdata=timedata(isLong,:); % subset only those long enough to plot
dates=dates(isLong); % original dates to match so have year
% construct line segments to plot
% start by getting unique years and separate list by year
[u,ia]=unique(year(dates)); % unique years, location in dates array first of each year
ib=cumsum([1;3*diff(ia)]); % location in full X,Y vector of start,stop,NaT sets of 3
% each record in start/stop fields is one line segment; introduce NaT to break lines
X=[plotdata.Date.'; plotdata.Date.'; NaT(1,height(plotdata))]; X=datenum(X(:));
Y=[plotdata.Start.'; plotdata.Stop.'; NaT(1,height(plotdata))]; Y=datenum(Y(:));
Y=24*(Y-fix(Y)); % convert to 0:24 hours for plotting
figure
ib=[ib;length(X)]; % augment index array with final index
plot(X(ib(1):ib(2)),Y(ib(1):ib(2)),'linewidth',3) % first year segment
hold on
for i=2:length(ib)-1
plot(X(ib(i):ib(i+1)),Y(ib(i):ib(i+1)),'linewidth',3)
end
% dress up plot a little and annotate; much room here for creativity... :)
hAx=gca; % get axis handle to local variable
xlim([datenum(yr,6,1) datenum(yr,8,1)]) % set axis limits; fixup as wanted
datetick('x','mmm,'keeplimits') % set abbreviated month as label
xtk=hAx.XTick; % retrieve tick values
hAx.XAxis.MinorTickValues=xtk(1):xtk(end); % set minor tick values for day markers
hAx.XMinorTick='on' % turn minor ticks on so show up
ylim([0 24]) % 24-hr scale
hAx.YTick=(0:4:24); % show even tick marks
legend(num2str(u),'location','southwest'),legend('boxoff')
ylabel('UTC')
Call something like
file='abdur.dat';
fixLeap=1;
rauf(file,fixLeap,10*60)
to use the leapyear fixup and set the observation length to 10 minutes (in seconds). The above generated the following--
%
3 件のコメント
dpb
2018 年 3 月 30 日
And one last comment regarding the leap year controversy -- the reference year should really be chosen to be a non-leap year or if were to run the code in a leap year as is it would have the axis already drawn for the "plus one" position of March and all months past. Probably just remove the reference to clock and pick an arbitrary year to use; it really has no bearing on anything other than the Matlab variables need something for a year; the code pays no never mind to what that year is but the syntax needs it.
dpb
2018 年 3 月 30 日
編集済み: dpb
2018 年 3 月 30 日
Just glanced over the Answer to see if caught any typos or other foo-pahs after a little while away and one additional comment may be worthwhile -- when building X, Y for plotting, it may not be clear as to why introduced the NaT between each pair of start/stop times when each pair is a line and so one could draw each pair individually just looping "two-at-a-time". The trouble there is as you ran into doing every line individually is that each new line is a new PLOT() line object and therefore the default color will cycle unless you keep track of other things to decide when it should/should not change and what it should change to. By using the NaT/NaN between, as mentioned very early on, PLOT() "raises the pen" at each resulting in a broken line but all elements in the x, y vectors for each call to PLOT() are still the same line object and so have the same color...it is much easier to thus find those elements within each year to plot at the same time if one thought ahead to set the data up so that there would be line breaks where wanted.
Again, what seems arcane or perhaps much effort without appreciating "why" has a very simple reason behind it and a little more work up front saves a lot later on.
参考
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!