function GnashPlot(varargin);
%   Invoke via GnashPlot;       With lots of data, a compound plot with daily quartiles, etc. appears.
%              GnashPlot('p');  for a point-to-point plot, suppressing daily quartiles, etc.
%              GnashPlot('p1'); for a point-to-point plot, one series per plot.
%              GnashPlot('s');  for a stepwise plot, not point-to-point, also suppressing daily quartiles, etc.
%              GnashPlot('3');  so that no more than 3 series will appear on the same plot.
%              GnashPlot('L');  the y-scale is to be logarithmic (base ten).
%              GnashPlot('z');  the vertical scale is to include zero.
%              GnashPlot('f');  use the full time span, even if there are leading/trailing non-data.
%              GnashPlot('w');  escalate to grouping by week, instead of by day.
%   The text parameter, if present, may include these specifications in any order,
%and a feature of matlab's syntax allows the parameter to follow the invocation without the
%tedious typing of brackets and apostrophes, as in
%              GnashPlot p1;
%   This presumes that Gnash has produced a dump to a disc file of many runs of data for
%some time span and that command Gnash.m has been used to read that file into MatLab,
%resulting in certain arrays being filled with lots of numbers and some texts according to
%a certain scheme. The columnwise format is general and the Gnash.m command will accept
%a wide variety of input arrangements, that need not have been produced by Gnash and which
%may also be interpreted by GnashPlot in a useful way.
%   This command works through those arrays, preparing plots of the data in GnashData,
%grouped according to the texts in GnashNames, specifically the last part of these texts.
%Suppose that the names are (in order)  A.x, A.YY, A.Z, B.C.x, B.C.Y. Since the second name
%matches the previous name when its last part (".YY") is removed, a fresh plot is not started
%so that its data is plotted along with the first name's data. The third name likewise.
%The fourth name however does not match with its suffix removed, so a fresh plot is started.
%   This scheme will work well only when the collection of names is well-organised,
%and also may result in rather too many runs being drawn on one plot. To avoid such messes,
%supply a limit such as three as in the above example invocations.
%   Experience has shown that matlab's plotting processes fumble when there are many plots
%so there is an arrangement that no more than 24 plots will be produced in one go
%(though each may have more than one run plotted in the one figure) to avoid this annoyance.
%If this protection is triggered, than a variable GnashPlotFirst will be left, containing
%the number of the run to start with on the next issuance of the command GnashPlot.
%The plotting will start afresh with figure 1 and so forth, until the next overflow.
%The threshold can be changed by using a variable GnashPlotLimit = 36, say.
%   Similarly, one collection of plots may follow the production of previous figures,
%and if there is to be comparison rather than overwriting of figure 1, 2, etc.,
%then a value can be put in a variable GnashPlotFirstFigure, such as 6.
%
%   Each plot is normally of a line joining the successive values for the various runs
%of data. Any missing values ("NaN", the result of reading a non-number such as "?"
%in the input data as performed by Gnash.m) will cause a break in the line. If however
%data are missing in the interior of the span, and this is signified by no data being
%supplied (rather than a wad of data specifying "no value"), then a line will join the
%last valid number before the gap to the first valid number after the gap.
%   Should there be a lengthy span of data (such as a year's worth) then for normal-sized
%plots, the horizontal separation will likely be such that many y-values are plotted
%for the same x-position (as resolved by the display) so that all that is shown is the
%minimum to maximum range of those values that fell upon the same dot column.
%If the plotting were to be done by an actual pen-with-ink plotter, there might arise
%a shading effect showing some sort of indication of the density of plotted points,
%but more likely there will just be a bland uniformity from minimum to maximum.
%Likewise, if another colour is to be plotted at the same place, the result will be
%of only the last colour plotted at each location, not some sort of splodge.
%   Rather than just pour ink into large undifferentiated areas, a different style
%is activated should there be more than 99 days in the span of data. For each day,
%a vertical line is plotted for the range minimum to lower quartile, and upper quartile
%to maximum, with a horizontal dash for the median. These relative positions will give
%some indication of the distribution of values in a day, rather than just a minimum
%to maximum line. Further, in the blank space between the two bands (mostly, depending),
%successive daily averages are joined by a jagged line, a stepwise line shows the weekly
%averages, and a horizontal line shows the overall average. This style is delivered through
%the use of an auxiliary matlab function, DayPlot, which may be invoked directly.
%   If however you prefer the massed blobs of colour with "last on wins", then specifying
%a letter "p" (or "P") in the text parameter will help you stick with fingerpainting.
%   The standard line plot joins the values with the time interpreted as being for the
%middle of its time interval in the sense that for half-hourly data the first half hour's
%value is representing the time interval 0:00 to 0:30 and so its time is 0:15,
%the next half hour's value would be for time 0:45, and so on. If however there are not
%all that many points, or a letter "s" exists in the text parameter, then a stepwise plot
%will be attempted where for each time interval a horizontal bar is drawn extending over
%the time interval. Thus the first half-hourly value would be a horizontal bar from time
%0:00 to 0:30, then a vertical join to the next horizontal bar from 0:30 to 1:00,
%and so on, to the last value for the day, ending its horizontal bar at time 24:00.
%Unfortunately, matlab regards hour 24 of a day as being the start of the next day
%and so rounds up the span width; to prevent that, the last time is shifted back a little
%so that it manifests as hour 23.999 or so of its day.
%   The timestep need not be half-hourly as such, it is taken as being the difference
%GnashTime(2) - GnashTime(1), thus presuming that the GnashTimes are regular.
%
%   Some attempt is made at choosing a suitable scale factor and annotation for the y-axis
%through inspection of the name of the runs on a plot, plus the maximum value. This is mainly
%to avoid triggering matlab's own scaling annoyances. These guesses may be misled, especially
%if the data are not for kilowatts. The columnwise data format accepted by command Gnash
%is flexible enough to encompass many other data sources.
%   In an attempt to maximise the graph area by squeezing the generous margins supplied by
%matlab, bizarre incantations are required. One consequence is the need for a function
%that is to be invoked when the plot's window size is changed, that re-applies these
%incantations, thus the usage of GnashPlotResqueeze.m which must be in a file separate
%from this source file, as otherwise, when this source file quits, its definition is lost
%and so should you resize a plot's on-screen window, it will not have its contents readjusted.
%This in turn means that the separate function doesn't have access to whether or not
%certain annotations were made (a XLabel, and a Legend) because parameters cannot be supplied
%nor variables held in common (though evalin may help) and I can't discover how to find out
%how matlab commands can discover whether an annotation was made or not.
%   At the moment a legend (if it is needed) appears in part only in the truncated margin.
%You can drag it to where it is fully visible, and choose a good location while you're at it.

%   Concocted by R.N.McLean (whom God preserve), 19'th February MMVII.
global GnashCols GnashData GnashNames GnashRows GnashTime GnashTitles;

disp('To plot GnashData as prepared by command Gnash.m by reading a dump from Gnash, or similarly formatted data.');
if ~exist('GnashData','var')
  disp('No sign of a variable GnashData, as produced by command Gnash.');
  return;
end;
if ~exist('GnashRows','var')
  disp('No sign of a variable GnashRows, as produced by command Gnash.');
  return;
 else
  disp(['GnashRows = ',int2str(GnashRows)]);
  if GnashRows ~= size(GnashData{1},1)	%Another check.
   disp([' but the number of rows in GnashData{1} is ',int2str(size(GnashData{1},1))]);	%Huh?
  end;		%Token check for coherence.
  if GnashRows ~= size(GnashTime,1)	%All should be aligned...
   disp([' but the number of values in GnashTime is ',int2str(size(GnashTime,1))]);	%Huh?
  end;		%Token check for coherence.
  if GnashRows < 2
   disp('At least two values are required for a line plot!');
   return;
  end;
end;

if ~exist('GnashCols','var')
  disp('No sign of a variable GnashCols, as produced by command Gnash.');
  return;
 else
  disp(['GnashCols = ',int2str(GnashCols)]);
  if GnashCols ~= max(size(GnashData))	%Another check.
   disp([' but the number of columns in GnashData is ',int2str(max(size(GnashData)))]);	%Huh?
  end;		%Token check for coherence.
end;
if ~exist('GnashNames','var')
  disp('No sign of a variable GnashNames, as produced by command Gnash.');
  return;
 else
  if GnashCols ~= max(size(GnashNames))	%Another check.
   disp([' but the number of names in GnashNames is ',int2str(max(size(GnashNames)))]);	%Huh?
  end;		%Token check for coherence, made incoherent by mutlub array orientation madness.
end;
if ~exist('GnashTitles','var')
  disp('No sign of a variable GnashTitles, as produced by command Gnash.');
  return;
 else
  if GnashCols ~= max(size(GnashTitles))	%Another check.
   disp([' but the number of names in GnashTitles is ',int2str(max(size(GnashTitles)))]);	%Huh?
  end;		%Token check for coherence. Sometimes, size = 8 1 and sometimes 1 8.
end;

%Inspect the optional parameter in a bizarre syntax. If there is a better way, I can't find it in the so-called "help" crud.
PointWise = 0; StepWise = 0; SameSpan = 0; WithZero = 0; LogScale = 0; StageLimit = 999;	%First, scrag my indicators.
if size(varargin,2) > 0		%This gibberish indicates that optional parameter(s) exist.
  PointWise = size(strfind(varargin{1},'p'),2) | size(strfind(varargin{1},'P'),2);	%Lunatic
  StepWise  = size(strfind(varargin{1},'s'),2) | size(strfind(varargin{1},'S'),2);	%Gibberish!
  SameSpan  = size(strfind(varargin{1},'f'),2) | size(strfind(varargin{1},'F'),2);	%But it works.
  LogScale  = size(strfind(varargin{1},'l'),2) | size(strfind(varargin{1},'L'),2);	%Grotesquely.
  Weekly    = size(strfind(varargin{1},'w'),2) | size(strfind(varargin{1},'W'),2);	%Madly.
  WithZero  = size(strfind(varargin{1},'z'),2) | size(strfind(varargin{1},'Z'),2);	%So enough..
  for Stupid = 9:-1:1		%And this is even worse.
   if size(strfind(varargin{1},int2str(Stupid)),2)	%A digit?
    StageLimit = Stupid;	%Yes. This is the digit.
    break;			%One is enough, as 9 is bigger than anticipation.
   end;				%But if not that digit,
  end;				%Try another.
  if StageLimit == 1		%Now see what happens.
    disp('One data series per plot.');	%Uphold grammar.
   elseif StageLimit <= 9	%Surely more than 9 will make a mess.
    disp(['Up to ',int2str(StageLimit),' data series per plot.']);	%So, a limit.
  end;				%Enough blather.
end;		%There are better ways to present parameters, I'm sure.

%Seek the clock information, to be used as the x-variable throughout.
FoundDayClock = 0;
for i = 1:GnashCols		%Inspect all the column names.
  if strfind(upper(GnashNames{i}),'AUX.DAYCLOCK')
    FoundDayClock = i;
    disp(['Aux.DayClock found in column ',int2str(i)]);
    GnashTime = GnashData{i};
  end;
end;	%On to the next.
if FoundDayClock == 0	%Did we find a combined clock value?
 disp('Can''t find Aux.Dayclock in the array GnashNames!');	%Nope.
 return;		%Abandon.
end;			%So much for date and time.
clear FoundDayClock;	%So cast off the assistants.

%Enough trepidation. Now for the assault. Work through the names, looking at the last part of each name.
GnashPlots = 0;		%Start.
GnashName = '';		%No predecessor.
GnashPlotLimit = 24;	%Too many plots at once condufes mutlob.
if evalin('base','exist(''GnashPlotLimit'',''var'')')	%Is a hint lying about?
 GnashPlotLimit = max(1,evalin('base','GnashPlotLimit'));	%Yes, grab it.
end;			%This is all very messy.
GnashColour=cellstr(strvcat('r','g','b','c','m','y','k'));	%A collection.
clear Stage StageCount;		%First, prepare a list of what to do.
StageCount = 0;			%The data series are to be plotted in stages.
if evalin('base','exist(''GnashPlotFirst'',''var'')')	%Have I left a mess on the floor?
  i = max(1,evalin('base','GnashPlotFirst'));	%Yes. Pick up where I left off.
  if i > 1				%Something happened?
   disp(['Starting with run ',int2str(i)]);	%Admission.
  end;					%This is all very messy.
  evalin('base','clear GnashPlotFirst');	%Hope for completion, this time.
 else					%Otherwise, a fresh start.
  i = 1;					%Thus.
end;					%So much for incapacities.
[ignore,index] = sort(GnashNames);	%OObtain a list in order, to facilitate comparisons.
for i = i:GnashCols		%Roll through the names to decide on the grouping.
 ii = index(i);				%Ah, but in what order?
 if strncmpi(GnashNames{ii},'Aux.',4)	%One of the auxiliaries?
   disp(['Skipping column ',int2str(ii),': ',GnashNames{ii}]);	%Yes. Skip the Aux. collection.
 elseif strncmpi(GnashNames{ii},'Date',4)%Probably a date column.
   disp(['Skipping column ',int2str(ii),': ',GnashNames{ii}]);	%So not worth plotting.
 elseif strncmpi(GnashNames{ii},'Time',4)%Probably a time column.
   disp(['Skipping column ',int2str(ii),': ',GnashNames{ii}]);	%So not worth plotting.
 else					%But otherwise, here is another one.
   if all(isnan(GnashData{ii}))		%Entirely untasty?
     disp(['No good values in run ',int2str(ii),': ',GnashNames{ii}]);
     continue;				%So, don't continue with it.
   end;				%Since nothing would be plotted.
   igood = find(~isnan(GnashData{ii}));	%If we're here, at least one is not bad.
   ngood = size(igood,1);		%How tasty?
   if ngood == 1			%Tasty enough?
     disp(['One good value only! ',num2str(GnashData{ii}(igood(1)))]);	%Alas.
     continue				%Don't continue, skip this one.
   end;				%Righto, by here, at least two good values exist.
   if GnashData{ii}(igood(1)) == GnashData{ii}(igood(2))	%Perhaps not suitable for plotting.
     clear vmax; vmax = max(GnashData{ii});	%As when all are equal.
     if vmax == min(GnashData{ii})		%Sigh. rescan the lot.
      nbad = size(find(isnan(GnashData{ii})),1);	%And again. Agh. No "count".
      disp(['All ',int2str(ngood),' values equal ',num2str(vmax),' (',int2str(nbad),' bad) for run ',int2str(ii),': ',GnashNames{ii}]);	%So, nothing worth plotting.
      continue;					%A horizontal line is boring, so don't continue.
     end;				%So much for a full scan for equality, dodging NaN.
   end;					%Enough of boring series.
   lgni = size(GnashNames{ii},2);	%Length of the name.
   l = strfind(GnashNames{ii},'.');	%I want the last dot, if any.
   ll = size(l,2);			%This is really messy.
   if ll > 0				%So, was a list of non-zero length prepared?
     lll = l(ll);			%Only now can I grab where the last dot is.
    else				%And if there were no last dot,
     lll = lgni + 1;			%Regard it as following the end of the name.
   end;					%Righto, we know where to look.
%   disp(['lll=',int2str(lll),',GnashName=',GnashName,',gn(',int2str(ii),')=',GnashNames{ii}]);	%This is what we're confronting.
   if StageCount >= StageLimit | ~strcmp(GnashName,GnashNames{ii}(1:lll - 1))	%So look. Has the preamble changed?
    if GnashPlots >= GnashPlotLimit		%Yes! A fresh batch is thus to begin.
      assignin('base','GnashPlotFirst',ii);	%Possibly, too many already. Remember where we got up to.
      disp(['Erk. too many plots at once confuses matlab. Pausing before run ',int2str(ii),': ',GnashNames{ii}]);
      disp(['Resume by commanding GnashPlot afresh to slog further towards run ',int2str(GnashCols)]);	%A hint.
      %disp(['But, you may have to execute global GnashPlotFirst; GnashPlotFirst = ',int2str(ii)]);	%Madness!
      break;				%Quit, with GnashPlotFirst lying about.
    end;				%Enough stumbling.
    GnashName = GnashNames{ii}(1:lll - 1);	%Grab its name.
    GnashPlots = GnashPlots + 1;	%Another stage begins.
    StageCount = 0;			%With no constituents just yet.
   end;				%We have decided to continue.
   StageCount = StageCount + 1;			%So, another series is ready for this stage.
   Stage{GnashPlots}.List(StageCount) = ii;	%Fingered for later.
   if StageCount == 1				%If the first of this stage,
     Stage{GnashPlots}.Head = GnashNames{ii};	%Name the leader.
   elseif StageCount == 2		%Are we grouping series into this stage?
     Stage{GnashPlots}.Head = GnashNames{ii}(1:lll - 1);	%Yes. Retain the group name part only.
   end;					%Thus determine the name for the stage's collection.
   if lll < lgni		%Have we a tail?
     Stage{GnashPlots}.Tail{StageCount} = GnashNames{ii}(lll + 1:lgni);	%Grab its text after the dot.
    else				%But if not,
     Stage{GnashPlots}.Tail{StageCount} = '..self';	%This might do.
   end;				%All this agonising,
 end;			%Just to select series to plot,
end;		%With a hope for a somewhat suitable grouping.
disp(['Plot servings: ',int2str(GnashPlots)]);	%Announce the number of servings.

%Enough organisation. Now for the plots. Work through the stages, each with its own list.
if evalin('base','exist(''GnashPlotFirstFigure'',''var'')')	%Probe.
  Fig = max(1,evalin('base','GnashPlotFirstFigure'));	%Avoid some previous figures?
 else					%But if there is no suggestion,
  Fig = 1;				%Start afresh.
end;					%So much for beginnings.
for PlotStage = 1:GnashPlots	%Step through the stages.
 StageCount = size(Stage{PlotStage}.List,2);	%How many series therein?
 it = Stage{PlotStage}.List(1);		%The first series of this stage.
 GnashName = GnashNames{it};		%Grab its name.
 GnashTitle = GnashTitles{it};		%And an associate.
 disp(['Starting figure ',int2str(Fig),' with column ',int2str(it),': ',GnashName]);	%Here we go.
 hold off; figure(Fig); clf;	%Selecting "hold on" here has caused odd behaviour.
 Fig = Fig + 1;			%Ready for the next time around.
 clear iSpan lSpan;			%Should determine these above, I think.
 for i = 1:StageCount			%Determine the plotworthy span.
  it = Stage{PlotStage}.List(i);	%Which run?
  iSpan(i) = find(~isnan(GnashData{it}),1,'first');	%The first live value.
  lSpan(i) = find(~isnan(GnashData{it}),1,'last');	%The last live value.
 end;					%There may be more than one span.
 if SameSpan				%Perhaps we may stretch the data span?
   iFirst = 1; iLast = GnashRows;	%Nope. All plots are to have the same scale.
  else					%But if the spans can be adjusted to suit,
   iFirst = min(iSpan);			%Discover the index bounds of live data.
   iLast = max(lSpan);			%In case all are to have the same span.
 end;					%So much for the time span of live data.
 clear l lunit big BigGnash BigIt;	%Perhaps some rescaling would be nice.
 l = 1;					%Since matlab's can be annoying.
 if size(strfind(GnashName,'.TimeStamp'),1)	%This is grotesque!
   GnashUnit = 'Date'; l = 2;
 elseif size(strfind(GnashName,'.Price'),1) + size(findstr(GnashName,'.Bid'),1) + size(findstr(GnashName,'.Offer'),1) %Now contemplate some rescaling.
   GnashUnit = 'whatevers'; l = 2;	%It would be nice to have definite information.
 elseif strncmpi(GnashName,'Lake.',5)	%As is known for these.
   GnashUnit = 'Metres'; l = 2;
 elseif size(strfind(GnashName,'.Speed.'),1)
   GnashUnit = 'Metres/Second'; l = 2;
 elseif size(strfind(GnashTitle,' Bearing'),1)	%This will not appear in other series. I hope.
   GnashUnit = 'Degrees'; l = 2;
 elseif size(strfind(GnashName,'.PhaseAngle'),1)
   GnashUnit = 'Degrees'; l = 2;
 elseif size(strfind(GnashTitle,' Rainfall,'),1)
   GnashUnit = 'millimetres'; l = 2;
 elseif size(strfind(GnashTitle,' Relative humidity,'),1)
   GnashUnit = '%'; l = 2;
 elseif size(strfind(GnashTitle,' Total irradiation, MJ'),1)
   GnashUnit = 'MEGA Joules'; l = 2;
 elseif size(strfind(GnashTitle,' sea level, HPascal'),1)
   GnashUnit = 'Hecto Pascal'; l = 2;
 elseif size(strfind(GnashTitle,' temperature, °C'),1)
   GnashUnit = '°C'; l = 2;
 elseif size(strfind(GnashTitle,'nano-Tesla'),1)	%An oddity.
   GnashUnit = 'micro-Tesla'; l = 3;	%For which I know 50000 nano-T should become 50 micro-T to forestall matlab.
 else					%Otherwise, presume kilowatts.
   BigGnash = -666;			%Start an attempt at finding the extremum, ignoring its sign.
   BigIt = -666;			%I'll also want to know which is the biggest.
   for i = 1:StageCount			%It seems that an explicit loop is needed.
    it = Stage{PlotStage}.List(i);	%Select a run from the current list.
    big = max(abs(GnashData{it}));	%Scan some series. Bad values are ignored...
    if big > BigGnash			%An advance?
      BigGnash = big;			%Yes, retain.
      BigIt = it;			%And finger.
    end;				%So much for that run.
   end;					%On to the next.
   UnitNameW=cellstr(strvcat('Watts','Kilowatts','MEGA Watts','GIGAWATTS','T E R R O R  W A T T S!'));	%Surely enough.
   UnitNameV=cellstr(strvcat('VArs', 'Kilovars', 'MEGA VArs', 'GIGAVARS', 'T E R R O R  V A R S!'));	%Enough of these too.
   l = 2;				%Start by supposing that the units are Kilowatts so 0.9 means 900 Watts..
   while BigGnash >= 1000		%A larger unit?
    l = l + 1;				%Yes. Step up a level.
    BigGnash = BigGnash/1000;		%Corresponding reduction.
   end;					%Thus allow up to 999.999... of them, else another escalation.
   lunit = l;			%But, possibly, the supplied numbers were in megawatts...
   if size(strfind(GnashNames{BigIt},'MW'),1) > 0	%Guess by inspecting the name. Note that only capital letters will be matched.
    lunit = l + 1;				%Found. So, the unit name is one further along.
   end;				%Well! That was fun.
   if size(strfind(GnashNames{BigIt},'GW'),1) > 0	%Might as well carry this through.
    lunit = l + 2;				%Trials showed that no ordinary names had these.
   end;				%One day, perhaps, proper unit announcements will be developed, as per Plingot.
   if lunit <= size(UnitNameW,1)	%So, are we within scope?
     if size(strfind(GnashNames{BigIt},'.Reactive'),1) > 0	%Yes. Some units are different.
       GnashUnit = UnitNameV{lunit};	%These.
      else				%Usually,
       GnashUnit = UnitNameW{lunit};	%These.
     end;
    else				%But it may be monstrous.
     GnashUnit = ['Huh? 10^',int2str(3*l - 6)];	%A something.
   end;					%Is better than nothing with unstated recaling.
 end;				%Enough of the name.
 GnashScale = 10^(3*l - 6);	%This works for even more monstrous values.
 clear BigGnash big BigIt UnitNameW lunit l;	%A struggle.

 hold on;		%Now start on the next plot.
 if PointWise | StepWise | GnashTime(end) - GnashTime(1) <= 99	%Lots of days in the span?
  for i = 1:StageCount			%Not so many. Plot successive values.
   it = Stage{PlotStage}.List(i);	%The series fingered.
   if StageCount > 1, disp([' Tail ',int2str(i),' (column ',int2str(it),'): ',Stage{PlotStage}.Tail{i}]); end;	%Advise of intent/ show progress.
   colour = GnashColour{mod(i - 1,size(GnashColour,1)) + 1};	%For this stage.
   DayAv = StageCount <= 1 & GnashTime(end) - GnashTime(1) > 24;%Worth adding day averages?
   if DayAv				%Ah, choices.
    clear live AvX AvY hop nhop ns l1 l2 nn;	%Scrub the chopping board.
    hop = find(fix(GnashTime(2:end)) - fix(GnashTime(1:end - 1)));	%Indices of the last element before a step in the day number.
    nhop = size(hop,1) + 1;		%I need also the last element of the series.
    hop(nhop) = GnashRows;		%The end index for the last day.
    ns = 0;				%Now prepare a set of steps.
    l1 = 1;				%Start with the start.
    for j = 1:nhop			%Step through the day hops.
      if ns > 0				%Has there been a previous day?
        if fix(GnashTime(l2 + 1)) - fix(AvX(ns)) > 1	%Yes, and is the new day adjacent?
          if ~isnan(AvY(ns))		%No, a gap. Is the chain not yet broken?
            ns = ns + 1;		%No, there is no break.
            AvX(ns) = AvX(ns - 1);	%So, break the chain.
            AvY(ns) = NaN;		%This stops the line.
          end;				%One break is enough, not one for each day.
        end;				%So much for day lurches.
      end;				%Enough struggle over continuation.
      l2 = hop(j);			%Finger the last value for the day.
      live = find(~isnan(GnashData{it}(l1:l2))) + l1 - 1;	%Some values might be bad.
      nn = size(live,1);		%The number of good values in this day.
      if nn > 0				%If even one, we're away.
        ns = ns + 1;			%Start another step.
        AvX(ns) = fix(GnashTime(l1));	%Its start time. Surely time zero of the day is good.
        AvY(ns) = sum(GnashData{it}(live))/nn;	%The average at last!
        ns = ns + 1;			%Prepare the end of the step.
        if l2 < GnashRows		%Will more steps follow?
          AvX(ns) = fix(GnashTime(l2 + 1));	%Yes, so I can use time zero of the next day.
         else				%But if this is the very last step, there is no next day.
          AvX(ns) = GnashTime(l2);	%And these are known to be middle times,
        end;				%Time zero of the next day provokes MatLab to include that whole day.
        AvY(ns) = AvY(ns - 1);		%And the same value.
      end;				%So much for live steps.
      l1 = l2 + 1;			%Finger the start of the next day.
    end;				%On to the next hop.
   end;				%The day averages are prepared.
   if (StepWise | GnashRows <= 2880) & ~PointWise	%Contemplate resolution for a "stairs" plot..
     half = (GnashTime(2) - GnashTime(1))/2;	%I know that the GnashTimes are for the CENTRE of their interval.
     xx(GnashRows + 1) = GnashTime(GnashRows) + half*0.9999;	%The END time of the last interval. If midnight, damn matlab starts a new day, which may start a new month, which may start a new year.
     xx(1:GnashRows) = GnashTime - half;		%All times but (GnashRows + 1) are adjusted to the START of their interval. And the first/last interval may not be the first/last of a day.
     yy(GnashRows + 1) = GnashData{it}(GnashRows);	%As the staircase STARTS with the first level.
     yy(1:GnashRows) = GnashData{it};			%With the last point repeated and with the END time.
     lurch = find(round((xx(2:end) - xx(1:end - 1) - 2*half)*24) == 1);	%A one-hour lurch forward. CURSE DAYLIGHT SAVING!
     for l = size(lurch,2):-1:1		%Step through them backwards so that I don't have to fiddle the fingers..
      it = lurch(l);			%The index of the lurch's start, which has a start xx position and time.
      disp(['Lurch(',int2str(l),') index ',int2str(it),' for ',datestr(fix(xx(it)),8),' ',datestr(fix(xx(it)))]);	%Are we puzzled?
      if datestr(fix(xx(it)),8) == 'Sun'	%Also suspicious. Shrinkdays are only on Sundays.
       xx = horzcat(xx(1:it),xx(it) + 2*half,xx(it + 1:end));	%Insert a step end time, (start of the next step, which isn't there)
       yy = horzcat(yy(1:it),            NaN,yy(it + 1:end));	%Thus do not continue the level to the next step's start.
      end;				%Thus insert a gap for the non-existent time of the shrink day.
      clear l;				%Since matlab will plot the day as having a standard width of 24 hours.
     end;				%When I'd prefer there to be a squeeze.
     clear lurch;			%Likewise a stretch for the stretch day. But its times are squeezed in to the Hilbert Hotel.
     lurch = find(round((xx(2:end) - xx(1:end - 1))/half) == 1) + 1;	%Finger elements with a suspiciously short step.
     for l = 1:size(lurch,2)		%The times have been fiddled to START times by subtracting half.
      it = lurch(l);			%But the Hilbert Hotel uses half-size half hours, so half/2 should have been subtracted.
      if datestr(fix(xx(it)),8) == 'Sun' & round((xx(it) - round(xx(it)))*24*60) < 180	%A Sunday, and not 3am itself.
        xx(it) = xx(it) + half/2;	%The find fingers the 3am start time, as not half on from its predecessor.
      end;				%Thus the test to skip its adjustment as it is already proper.
     end;				%Otherwise, five values instead of four would be fiddled.
     clear lurch;			%Enough of fighting with the stairs...
     stairs(xx,yy/GnashScale,colour);	%Do it.
     set(gca,'TickDir','out');		%Do not deface the data area with non-data.
     set(gca,'TickLength',get(gca,'TickLength')/4);	%Ticks should be small.
     clear xx yy half;			%Discard the scratchpads.
    else			%Otherwise, just join the dots at middle times.
     plot(GnashTime,GnashData{it}/GnashScale,colour);	%Yay!
     set(gca,'TickDir','out');		%Point towards the annotations.
     set(gca,'TickLength',get(gca,'TickLength')/4);	%Not excessively!
   end;				%So much for that plot.
   if DayAv			%Do we add day averages?
     plot(AvX,AvY/GnashScale,'b');	%Yep.
     clear live AvX AvY hop nhop ns l1 l2 nn;	%Finished with these.
   end;				%So much for that. No legend with one data series per plot.
  end;			%On to the next series.
 else		%If many days, fancy plotting.
  if StageCount == 1	%First, decide on related colours for the components of a plot.
    it = Stage{PlotStage}.List(1); disp([' Tail 1: ',Stage{PlotStage}.Tail{1}]);
    DayPlot(GnashTime,GnashData{it}/GnashScale,'g,r,m,c,b,k');	%Full separation.
  elseif StageCount == 2		%With just two,
    it = Stage{PlotStage}.List(1); disp([' Tail 1: ',Stage{PlotStage}.Tail{1}]);
    DayPlot(GnashTime,GnashData{it}/GnashScale,'m,m,m,r,y,y');	%Related colours.
    it = Stage{PlotStage}.List(2); disp([' Tail 2: ',Stage{PlotStage}.Tail{2}]);
    DayPlot(GnashTime,GnashData{it}/GnashScale,'b,b,b,k,c,c');	%And for the second series also.
    elseif StageCount == 3		%Even with three, there can be some associations.
    it = Stage{PlotStage}.List(1); disp([' Tail 1: ',Stage{PlotStage}.Tail{1}]);
    DayPlot(GnashTime,GnashData{it}/GnashScale,'m,m,m,r,r,r');	%Magenta and red.
    it = Stage{PlotStage}.List(2); disp([' Tail 2: ',Stage{PlotStage}.Tail{2}]);
    DayPlot(GnashTime,GnashData{it}/GnashScale,'c,c,c,g,g,g');	%Cyan and green.
    it = Stage{PlotStage}.List(3); disp([' Tail 3: ',Stage{PlotStage}.Tail{3}]);
    DayPlot(GnashTime,GnashData{it}/GnashScale,'b,b,b,k,k,k');	%Blue and black.
  else	%But if there are many series, just use one colour for all the components of each series to be plotted.
    for i = 1:StageCount	%Here we go.
     it = Stage{PlotStage}.List(i); disp([' Tail ',int2str(i),': ',Stage{PlotStage}.Tail{i}]);	%Announce.
     DayPlot(GnashTime,GnashData{it}/GnashScale,char(GnashColour{mod(i - 1,size(GnashColour,1)) + 1}));	%Yay!
    end;			%On to the next series of this stage.
  end;			%So much for colour encodement choices.
 end;		%The two sorts of plots. StageCount series have been plotted.
 wot = get(0,'DefaultTextInterpreter');	%Presumably, "TeX".
 set(0,'DefaultTextInterpreter','none');%This global default value will be referred to by title and legend, as their specifications seem not to have effect.
 if StageCount > 1		%Belatedly think: if only one line, there is no need for a legend.
   legend(Stage{PlotStage}.Tail,'Location','SouthWestOutside','Interpreter','none');	%This seems to accumulate additional lines, perhaps by rewriting the entire legend.
 end;		%These statements seem lost if done just after the "figure" command but before the plot commands.
 title([Stage{PlotStage}.Head,' ~ ',GnashTitle],'Interpreter','none');	%Do without the interpretation of underlines as for subscripts.
 ylabel(GnashUnit); grid on;	%But if done here, seem to work.
 if strcmp(GnashUnit,'Date')
  datetick('y');
 end;
 set(0,'DefaultTextInterpreter',wot); %Unfortunately, only the first legend etc. invocation refers to this mysterious default.
 %Annotation is a confounded nusiance, compounded by matlab's ill-described over-generality.
 %The usage of the calendar is interval-related, not point-related. This means that the annotation
 %for the year 2011 should appear in the middle of the interval for 2011, and likewise for months and days.
 %The tick marks are placed at the boundarries of these intervals, but, their associated annotations
 %are aligned with the ticks. The appears to be some scheme for messing about with this, but it is opaque.
 %Further, not all the date span may be occupied by live data. For comparison of multiple plots,
 %there may be a wish that all appear on the same scale, with alignment. Option SameSpan indicates this.
 %For a particular plot, the live data may occupy only a small portion of the span. I can't see how to
 %persuade matlab to annotate the short piece with regard to its short x-space usage. Matlab seems
 %determined to annotate as if the live span occupied the full span, but crams many annotations on top
 %of each other in the short live span. Even if only live data were presented to the plot command.
 %The may be some juggle involving xlim and others that will sweep this annoyance away, but I can't see it.
 clear wot d1 dn;
 lines = 2;		%Often, two annotation lines for the x-axis.
 d1 = fix(GnashTime(iFirst)); dn = fix(GnashTime(iLast));	%First and last days.
 if d1 == dn						%All in one day?
   datetick('x','HH PM');   xlabel([datestr(d1,'dddd'),' ',datestr(d1,'dd/mm/yyyy')]);	%The day, month and year are common.
  elseif datestr(d1,'mmyyyy') == datestr(dn,'mmyyyy')	%All in one month?
   datetick('x','dd');      xlabel([datestr(d1,'mmmm'),' ',datestr(d1,'yyyy')]);	%The month and year are common.
  elseif datestr(d1,'yyyy') == datestr(dn,'yyyy')	%All in one year?
   datetick('x','dd/mmmm'); xlabel(datestr(d1,'yyyy'));	%The year is in common. Alignment it to the tick, not between the tick, damnit, so supply the date to give "01/Jan" to imply this.
  else							%Crosses a year boundary.
   datetick('x','mmm/yyyy');				%Full detail, all on the one line.
   lines = 1;				%So, only one line.
 end;				%This is still inadequate annotation of the x-axis.
 xlim([GnashTime(iFirst) GnashTime(iLast)]);	%Squeeze to known bounds. SameSpan may make these 1:GnashRows.
 if LogScale			%Perhaps there is excessive spread.
  set(gca,'Yscale','log');	%This may help, but introduces its own difficulties.
 elseif WithZero		%But if linear, ought the y-span include zero?
  yspan = get(gca,'YLim');	%It is indicated to be nice.
  if yspan(1) >= 0		%If the lower bound is not negative,
   yspan(1) = 0;		%Make it zero.
  elseif yspan(2) <= 0		%Otherwise, if the upper bound is below water,
   yspan(2) = 0			%Raise it.
  end;				%Enough choices.
  set(gca,'YLim',yspan);	%Declare my wishes.
 end;				%So much for that.
 set(gcf,'ResizeFcn','GnashPlotResqueeze');	%On changing the figure's window size, invoke this.
 set(gcf,'Toolbar','none');	%I want more data space, less cybercrud.
 set(gcf,'Units','points'); hf = get(gcf,'Position');
 set(gca,'Units','points'); %ha = get(gca,'Position');
%   Now for some ad-hoc fiddles. The objective is to maximise the data plot area, and minimise wasted space.
%The x-axis annotation requires one or two lines, and the guessed approach is to allow space for that
%by specifying the height where the x-axis lies. There seems to be no control of the vertical space
%occupied by the annotation text, or the space between its two lines (the x-label and the x-axis annotation)
%but allowing 15 points per line seems to work. If 14, the tips of the lower line's text descenders are lost.
%Similarly, the title text is squeezed into the space above the level of the plotting area's ytop
%and with an allowance of less than 17, the tops of the glyphs brush the upper limit.
%Again, there seems to be no facility for squeezing the vertical space below the title text and above
%the top of the plot area. Even if there were, that space is needed for the case where the annotation
%of the y-axis tick marks is at the top of the plot area, and thus the top half of its glyphs
%extends above the top of the pliot area.
%   As for the left and right bounds, the unbalanced allowances look balanced. Much less than 38 to the left
%results in the y-axis label being trimmed, and there seems no way to squeeze the space between
%the base of the label text and the start of the y-axis tick annotations..
 global GnashPlotXlabelXbase;			%Put this where GnashPlotResqueeze can get at.
 GnashPlotXlabelXbase = 17*lines;		%The x-axis base position. lines = 1 or 2.
 xtop = hf(4) - GnashPlotXlabelXbase - 17;	%The x-axis top, up from the x-axis base level.
 %disp(['lines=',num2str(lines),',xtop=',num2str(xtop)]);
 set(gca,'Position',[38 GnashPlotXlabelXbase (hf(3) - 56) xtop]);	%[lmargin ybase rmargin +ytop].
 clear d1 dn hf ha GnashPlotXlabelXbase xtop;			%Enough agonising.
end;		%On to the next plot.

hold off;	%Presumably, liberate the last plot.
if evalin('base','exist(''GnashPlotFirst'',''var'')')	%Am I leaving a mess on the floor?
  disp(' ');			%Yes. Reduce the mess on the screen.
  disp(['Another GnashPlot command will resume, starting with run ',int2str(evalin('base','GnashPlotFirst')),' on the way to run ',int2str(GnashCols)]);
 else				%But if there is no restart position,
  disp('So much for that.');	%Then we're done.
end;				%Well, that was fun.
clear i it l ll lll lgni Stage StageCount PlotStage GnashPlots GnashName GnashTitle GnashUnit GnashScale GnashColour;
%END; just fall out!

