help-octave
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[changeset]: Re: Octave plot on time/date x-axis


From: David Bateman
Subject: [changeset]: Re: Octave plot on time/date x-axis
Date: Tue, 16 Sep 2008 16:20:27 +0200
User-agent: Thunderbird 2.0.0.16 (X11/20080725)

Bill Denney wrote:
David Bateman wrote:
Bill Denney wrote:
If you install the financial package, you can use the dateaxis command
which likely does what you're wanting to do.
How does dateaxis differ from the dateticks function?  Taking a quick
look at the matlab help pages, I can see that much of a difference in
them. Perhaps we should migrate dateaxis to Octave as the dateticks
command and make dateaxis depend on dateticks?

It differs in that I didn't know about it when I was implementing
dateaxis.  You're right that it's a good idea to migrate it to Octave
and have dateaxis be a call to datetick.  I probably won't be able to do
it soon, though because I'm moving in the next 1.5 weeks.

Have a good day,

Bill

How about something like the attached? Notice that for datetick we have to calculate the tick positions ourselves manually as they should fall of reasonable times. I've attempted to do this in this version, but it probably needs some work.

With this changeset dateaxis can then be implemented as

function varargout = dateaxis (varargin);
   [varargout{:}] = datetick (varargin{:});
endfunction

In any case this was based heavily on your dateaxis code Bill.

Cheers
David


--
David Bateman                                address@hidden
Motorola Labs - Paris +33 1 69 35 48 04 (Ph) Parc Les Algorithmes, Commune de St Aubin +33 6 72 01 06 33 (Mob) 91193 Gif-Sur-Yvette FRANCE +33 1 69 35 77 01 (Fax) The information contained in this communication has been classified as: [x] General Business Information [ ] Motorola Internal Use Only [ ] Motorola Confidential Proprietary

# HG changeset patch
# User David Bateman <address@hidden>
# Date 1221574709 -7200
# Node ID d246e374921480a55740d87c6508d90b26b3aa42
# Parent  0ed57cb917a1e9ea4c13c8be56c958bf89da0110
Add the datetick function

diff --git a/scripts/ChangeLog b/scripts/ChangeLog
--- a/scripts/ChangeLog
+++ b/scripts/ChangeLog
@@ -1,3 +1,12 @@ 2008-09-15  David Bateman  <address@hidden
+2008-09-16  David Bateman  <address@hidden>
+
+       * time/datetick.m: New function.
+       * time/Makefile.in (SOURCES): Add it here.
+       * time/datestr.m: More careful check for datevec format with 6
+       column arguments.
+       * plot/__go_draw_axes__ (do_tics_1): Use %.15g format rather than
+       %g format. Also use manual mode if xlabelmode is manual.
+
 2008-09-15  David Bateman  <address@hidden>
 
        * general/cell2mat.m: Backout previous change. Special case 2D
diff --git a/scripts/plot/__go_draw_axes__.m b/scripts/plot/__go_draw_axes__.m
--- a/scripts/plot/__go_draw_axes__.m
+++ b/scripts/plot/__go_draw_axes__.m
@@ -1549,7 +1549,7 @@ function do_tics_1 (ticmode, tics, label
 function do_tics_1 (ticmode, tics, labelmode, labels, color, ax,
                    plot_stream, mirror, mono, axispos, tickdir)
   colorspec = get_text_colorspec (color, mono);
-  if (strcmpi (ticmode, "manual"))
+  if (strcmpi (ticmode, "manual") || strcmpi (labelmode, "manual"))
     if (isempty (tics))
       fprintf (plot_stream, "unset %stics;\n", ax);
     elseif (strcmpi (labelmode, "manual") && ! isempty (labels))
@@ -1562,14 +1562,15 @@ function do_tics_1 (ticmode, tics, label
        nlabels = numel (labels);
        fprintf (plot_stream, "set format %s \"%%s\";\n", ax);
        if (mirror)
-         fprintf (plot_stream, "set %stics %s %s (", ax, tickdir, axispos);
+         fprintf (plot_stream, "set %stics %s %s mirror (", ax, 
+                  tickdir, axispos);
        else
          fprintf (plot_stream, "set %stics %s %s nomirror (", ax,
                   tickdir, axispos);
        endif
        labels = regexprep(labels, "%", "%%");
        for i = 1:ntics
-         fprintf (plot_stream, " \"%s\" %g", labels{k++}, tics(i));
+         fprintf (plot_stream, " \"%s\" %.15g", labels{k++}, tics(i));
          if (i < ntics)
            fputs (plot_stream, ", ");
          endif
@@ -1584,13 +1585,14 @@ function do_tics_1 (ticmode, tics, label
     else
       fprintf (plot_stream, "set format %s \"%%g\";\n", ax);
       if (mirror)
-       fprintf (plot_stream, "set %stics %s %s (", ax, tickdir, axispos );
+       fprintf (plot_stream, "set %stics %s %s mirror (", ax, tickdir,
+                axispos);
       else
        fprintf (plot_stream, "set %stics %s %s nomirror (", ax, tickdir,
                 axispos);
       endif
-      fprintf (plot_stream, " %g,", tics(1:end-1));
-      fprintf (plot_stream, " %g);\n", tics(end));
+      fprintf (plot_stream, " %.15g,", tics(1:end-1));
+      fprintf (plot_stream, " %.15g);\n", tics(end));
     endif
   else
     fprintf (plot_stream, "set format %s \"%%g\";\n", ax);
diff --git a/scripts/time/Makefile.in b/scripts/time/Makefile.in
--- a/scripts/time/Makefile.in
+++ b/scripts/time/Makefile.in
@@ -33,8 +33,8 @@ INSTALL_DATA = @INSTALL_DATA@
 INSTALL_DATA = @INSTALL_DATA@
 
 SOURCES = addtodate.m asctime.m calendar.m clock.m ctime.m date.m \
-  datenum.m datestr.m datevec.m eomday.m etime.m is_leap_year.m now.m \
-  weekday.m
+  datenum.m datestr.m datetick.m datevec.m eomday.m etime.m is_leap_year.m \
+  now.m weekday.m
 
 DISTFILES = $(addprefix $(srcdir)/, Makefile.in $(SOURCES))
 
diff --git a/scripts/time/datestr.m b/scripts/time/datestr.m
--- a/scripts/time/datestr.m
+++ b/scripts/time/datestr.m
@@ -196,7 +196,8 @@ function retval = datestr (date, f, p)
       ## Make sure that the input really is a datevec.
       maxdatevec = [Inf, 12, 31, 23, 59, 60];
       for i = 1:numel (maxdatevec)
-        if (any (date(:,i) > maxdatevec(i)))
+        if (any (date(:,i) > maxdatevec(i)) || 
+           (i != 6 && any (floor (date(:, i)) != date (:, i))))
           v = datevec (date, p);
           break;
         endif
diff --git a/scripts/time/datetick.m b/scripts/time/datetick.m
new file mode 100644
--- /dev/null
+++ b/scripts/time/datetick.m
@@ -0,0 +1,288 @@
+## Copyright (C) 2008  David Bateman
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} datetick (@var{form})
+## @deftypefnx {Function File} {} datetick (@var{axis}, @var{form})
+## @deftypefnx {Function File} {} datetick (@dots{}, "keeplimits")
+## @deftypefnx {Function File} {} datetick (@dots{}, "keepticks")
+## @deftypefnx {Function File} {} datetick (@dots{ax}, @dots{})
+## Adds date formatted tick labels to an axis. The axis the apply the
+## ticks to is determined by @var{axis} that can take the values "x",
+## "y" or "z". The default value is "x". The formating of the labels is
+## determined by the variable @var{form}, that can either be a string in
+## the format needed by @code{dateform}, or a positive integer that can
+## be accepted by @code{datestr}.
+## @seealso{datenum, datestr}
+## @end deftypefn
+
+function datetick (varargin)
+
+  [h, varargin, nargin] = __plt_get_axis_arg__ ("datetick", varargin{:});
+
+  if (nargin < 1)
+    print_usage ();
+  else
+    oldh = gca ();
+    unwind_protect
+      axes (h);
+      __datetick__ (varargin{:});
+    unwind_protect_cleanup
+      axes (oldh);
+    end_unwind_protect
+  endif
+endfunction
+
+%!demo
+%! yr = 1900:10:2000;
+%! pop = [76.094, 92.407, 106.461, 123.077 131.954, 151.868, 179.979, ...
+%!        203.984, 227.225, 249.623, 282.224];
+%! plot (datenum (yr, 1, 1), pop);
+%! title ("US population (millions)");
+%! xlabel ("Year");
+%! datetick ("x", "YYYY");
+
+function __datetick__ (varargin)
+
+  keeplimits = false;
+  keeptick = false;
+  idx = [];
+  for i = 1 : nargin
+    arg = varargin {i};
+    if (ischar (arg))
+      if (strcmpi (arg, "keeplimits"))
+       keeplimits = true;
+       idx = [idx, i];
+      elseif (strcmpi (arg, "keeptick"))
+       keeptick = true;
+       idx = [idx, i];
+      endif
+    endif
+  endfor
+
+  varargin(idx) = [];
+  nargin = length (varargin);
+  form = [];
+  ax = "x";
+
+  if (nargin != 0)
+    arg = varargin{1};
+    if (ischar(arg) && (strcmp (arg, "x") || strcmp (arg, "y") || 
+                       strcmp (arg, "z")))
+      ax = arg;
+      if (nargin > 1)
+       form = varargin{2};
+       varargin(1:2) = [];
+      else
+       varargin(1) = [];
+      endif
+    else
+      form = arg;
+      varargin(1) = [];
+    endif
+  endif
+
+  ## Don't publish the existence of this variable for use with dateaxis
+  if (length (varargin) > 0)
+    startdate = varargin{1};
+  else
+    startdate = [];
+  endif
+
+  if (isnumeric (form))
+    if (! isscalar (form) || floor (form) != form || form < 0)
+      error ("datetick: expecting form argument to be a positive integer");
+    endif
+  elseif (! ischar (form) && !isempty (form))
+    error ("datetick: expecting valid date format string");
+  endif
+
+  if (keeptick)
+    ticks = get (gca (), strcat (ax, "tick"))
+  else
+    ## Need to do our own axis tick position calculation as
+    ## year, etc, don't fallback on nice datenum values.
+    objs = findall (gca());
+    xmax = NaN;
+    xmin = NaN;
+    for i = 1 : length (objs)
+      fld = get (objs (i));
+      if (isfield (fld, strcat (ax, "data")))
+       xdata = getfield (fld, strcat (ax, "data"))(:);
+       xmin = min (xmin, min (xdata));
+       xmax = max (xmax, max (xdata));
+      endif
+    endfor
+
+    if (isnan (xmin) || isnan (xmax))
+      xmin = 0;
+      xmax = 1;
+    elseif (xmin == xmax)
+      xmax = xmin + 1;
+    endif
+
+    N = 3;
+    if (xmax - xmin < N)
+      ## Day scale or less
+      if (xmax - xmin < N / 24 / 60 / 60) 
+       scl = 1 / 24 / 60 / 60;
+      elseif (xmax - xmin < N / 24 / 6)
+       scl = 1 / 24 / 60;
+      else
+       scl = 1 / 24;
+      endif
+      sep = __calc_tick_sep__ (xmin / scl , xmax / scl);
+      xmin = sep * floor (xmin / scl / sep);
+      xmax = sep * ceil (xmax / scl / sep);
+      nticks = (xmax - xmin) / sep + 1;
+      xmin *= scl;
+      xmax *= scl;
+    else
+      [ymin, mmin, dmin] = datevec (xmin);
+      [ymax, mmax, dmax] = datevec (xmax);
+      minyear = ymin + (mmin - 1) / 12 + (dmin - 1) / 12 / 30;    
+      maxyear = ymax + (mmax - 1) / 12 + (dmax - 1) / 12 / 30;    
+      minmonth = mmin + (dmin - 1) / 30;    
+      maxmonth = (ymax  - ymin) * 12 + mmax + (dmax - 1) / 30;    
+
+      if (maxmonth - minmonth < N)
+       sep = __calc_tick_sep__ (xmin, xmax);
+       xmin = sep * floor (xmin / sep);
+       xmax = sep * ceil (xmax / sep);
+       nticks = (xmax - xmin) / sep + 1;
+      elseif (maxyear - minyear < N)
+       sep = __calc_tick_sep__ (minmonth , maxmonth);
+       xmin = datenum (ymin, sep * floor (minmonth / sep), 1);
+       xmax = datenum (ymin, sep * ceil (maxmonth / sep), 1);
+       nticks = ceil (maxmonth / sep) - floor (minmonth / sep) + 1;
+      else
+       sep = __calc_tick_sep__ (minyear , maxyear);
+       xmin = datenum (sep * floor (minyear / sep), 1, 1);
+       xmax = datenum (sep * ceil (maxyear / sep), 1, 1);
+       nticks = ceil (maxyear / sep) - floor (minyear / sep) + 1;
+      endif
+    endif
+    ticks = xmin + [0 : nticks - 1] / (nticks - 1) * (xmax - xmin);
+  endif
+
+  if (isempty (form))
+    r = max(ticks) - min(ticks);
+    if r < 10/60/24
+      ## minutes and seconds
+      form = 13;
+    elseif r < 2
+      ## hours
+      form = 15;
+    elseif r < 15
+      ## days
+      form = 8;
+    elseif r < 365
+      ## months
+      form = 6;
+    elseif r < 90*12
+      ## quarters
+      form = 27;
+    else
+      ## years
+      form = 10;
+    endif
+  endif
+
+  if (length (ticks) == 6)
+    ## Careful that its not treated as a datevec
+    if (! isempty (startdate))
+      sticks = strvcat (datestr (ticks(1:end-1) - ticks(1) + startdate, form),
+                       datestr (ticks(end) - ticks(1) + startdate, form));
+    else
+      sticks = strvcat (datestr (ticks(1:end-1), form), 
+                       datestr (ticks(end), form));
+    endif
+  else
+    if (! isempty (startdate))
+      sticks = datestr (ticks - ticks(1) + startdate, form);
+    else
+      sticks = datestr (ticks, form);
+    endif
+  endif
+
+  sticks = mat2cell (sticks, ones (rows (sticks), 1), columns (sticks));
+
+  if (keeptick)
+    if (keeplimits)
+      set (gca(), strcat (ax, "ticklabel"), sticks);
+    else
+      set (gca(), strcat (ax, "ticklabel"), sticks, strcat (ax, "lim"), 
+          [min(ticks), max(ticks)]);
+    endif
+  else
+    if (keeplimits)
+      set (gca(), strcat (ax, "tick"), ticks, strcat (ax, "ticklabel"), 
sticks);
+    else
+      set (gca(), strcat (ax, "tick"), ticks, strcat (ax, "ticklabel"), sticks,
+          strcat (ax, "lim"), [min(ticks), max(ticks)]);
+    endif
+  endif
+endfunction
+
+function [a, b] = __magform__ (x)
+  if (x == 0)
+    a = 0;
+    b = 0;
+  else
+    l = log10 (abs (x));
+    r = fmod (l, 1);
+    a = 10 .^ r;
+    b = fix (l - r);
+    if (a < 1)
+      a *= 10;
+      b -= 1;
+    endif
+    if (x < 0)
+      a = -a;
+    endif
+  endif
+endfunction
+
+## A translation from Tom Holoryd's python code at
+## http://kurage.nimh.nih.gov/tomh/tics.py
+function sep = __calc_tick_sep__ (lo, hi)
+  persistent sqrt_2  = sqrt (2.0);
+  persistent sqrt_10 = sqrt (10.0);
+  persistent sqrt_50 = sqrt (50.0);
+
+  ticint = 5;
+
+  ## Reference: Lewart, C. R., "Algorithms SCALE1, SCALE2, and
+  ## SCALE3 for Determination of Scales on Computer Generated
+  ## Plots", Communications of the ACM, 10 (1973), 639-640.
+  ## Also cited as ACM Algorithm 463.
+
+  [a, b] = __magform__ ((hi - lo) / ticint);
+
+  if (a < sqrt_2)
+    x = 1;
+  elseif (a < sqrt_10)
+    x = 2;
+  elseif (a < sqrt_50)
+    x = 5;
+  else
+    x = 10;
+  endif
+  sep = x * 10 .^ b;
+endfunction
+

reply via email to

[Prev in Thread] Current Thread [Next in Thread]