How to plot observations against season and time of day?
Mostrar comentarios más antiguos
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 comentarios
dpb
el 23 de Mzo. de 2018
No data...nothing can do without to see what you're working from in c
abdur rauf
el 23 de Mzo. de 2018
Editada: abdur rauf
el 29 de Mzo. de 2018
dpb
el 24 de Mzo. de 2018
DATA!!!!???? Can't reproduce anything w/o something to start from and I'm not going to try to reproduce what you've already got, sorry...
That is, you say "having PMSE observation time T, and the corresponding date."
Where are they?; they're not in the script are they? If so, I can't decipher what is what without more comments/explanation of "who's who in the zoo" than is in the code.
As to "how"; I'd have to think about that some with some data in hand; I think possibly simply line will do it with the start/stop time for each contiguous times inserting a NaN to break the lines between each separate period.
But, that's the information one needs to build the plot that isn't here...
I'd guess the way to get the data into Matlab would be to just create a text file to read in that contains each observation period start:stop time stamp either as two columns or paired times in one column; whether all years are in one file or there's a separate one for each year or whatever is pretty-much up to whatever is most convenient to prepare the data given its source, but that's what you need in some form or fashion however you choose to do so.
abdur rauf
el 25 de Mzo. de 2018
Editada: Walter Roberson
el 25 de Mzo. de 2018
dpb
el 25 de Mzo. de 2018
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...
Respuesta aceptada
Más respuestas (2)
abdur rauf
el 30 de Mzo. de 2018
Editada: abdur rauf
el 30 de Mzo. de 2018
4 comentarios
set(gca,'XTick',[153 154 ....
set(gca,'XTickLabel',{'Jun','','','...,'','Jul','',...
NB: This has precisely the problem/feature I outlined above of the location of the month relative to the start day number is off-by-one for either the leap year or the nonleap years depending upon which you used to compute the tick mark day number. So, why bother; just use the calendar date and go on; you can't have it both ways on one plot.
I'll also note again that the arbitrary width of the line is far more than the one day "jitter" so the visualization of actual time along the axis is skewed so again you're just fooling yourself in thinking that making the offset by one for the leap year is doing anything significant as far as being able to tell anything from the plot.
The "exercise for the student" to correct that perception is to expand on what I did above except to recast to use fill to draw areas whose width actually does correspond to the length of the period on the x-axis.
If you want to expand the axis somewhat to make the width a little more, use
xlim(datenum([datetime(yr,6,1) datetime(yr,8,1)]))
or whatever range that suits your fancy.
ADDENDUM
If you want to exclude years that don't have duration of observations over some lower bound, introduce what is the minimum time you want to be considered and test for that either while building the X, Y vectors or wait until plotting and put the test in the loop to skip any less than that; no need to do everything by hand.
Of course, if this is just a "one time only" exercise, simply edit the input file to exclude the ones you don't want; if it's something you'll be doing multiple times during the course of continuing research it'll well be worth doing programmatically.
I believe with the last revision (posted as separate, second Answer to not replace the earlier) I have done my duty. :)
Your mission, should you choose to accept it... is to look at the code enough to understand what it is doing and how; it is NOT that complicated if you'll use the debugger to look at intermediate steps and such aa the steps that build the X, Y vectors for plotting. Use some shorter sections so you can see what is going on...it's simply using how data are arranged in memory in Matlab in column-major order by default and judiciously creating and then reshaping a 2D array to produce the sequence desired for plotting.
Similarly if you study the building of the index vector for selecting subsections; it's easily worked out with pencil/paper what that actually is doing. Such "tricks" are the keys to really learning to use Matlab as it is intended and to get away from what you've done in entering every individual number by hand; essentially not using any of the capability of Matlab at all. If any data change, you have no choice but to redo it all.
Such machinations seem totally arcane initially, granted, but only by seeing such and finally seeing that fundamentally they're really not that mysterious will one began to get the hang of using Matlab power; beginning to see the patterns behind data to generalize is the key.
abdur rauf
el 31 de Mzo. de 2018
dpb
el 31 de Mzo. de 2018
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...
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 comentarios
dpb
el 30 de Mzo. de 2018
Oh, I forgot my utility routine isleapyr; you'll need it to run the above--
function is=isleapyr(yr)
% returns T for input year being a leapyear
if isdatetime(yr), yr=year(yr); end
is=eomday(yr,2)==29;
dpb
el 30 de Mzo. de 2018
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.
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.
Categorías
Más información sobre Holidays / Seasons en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


