octave-maintainers
[Top][All Lists]
Advanced

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

contour group objects


From: David Bateman
Subject: contour group objects
Date: Thu, 30 Oct 2008 00:20:32 +0100
User-agent: Mozilla-Thunderbird 2.0.0.16 (X11/20080724)

Please find attached the changeset that adds contour group objects to Octave and documents them. This is the last of the group objects to add for compatibility.

Note that as discussed I added the non matlab compatible properties "zlevelmode" and "zlevel" such that contour groups can equally be used for the contour3, meshc and surfc functions.

The changeset also adds a fairly naive, but still useful version of the clabel function. This version of clabel makes an assumption about the paper size of the plot for the LabelSpacing calculation, doesn't support the "manual" option, andmake a naive attempt to avoid labels on the border for contourf plots and could try and have better label placement than it currently does.

Should I push this?

Regards
David
--
David Bateman                                address@hidden
35 rue Gambetta                              +33 1 46 04 02 18 (Home)
92100 Boulogne-Billancourt FRANCE            +33 6 72 01 06 33 (Mob)
# HG changeset patch
# User David Bateman <address@hidden>
# Date 1225321985 -3600
# Node ID 73cc11bd63adfb8d85f0b00195bba4bda112d851
# Parent  2f774a9ba02b130ff796ceca289825f534934f1c
Add contour group objects and the clabel function

diff --git a/doc/ChangeLog b/doc/ChangeLog
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,7 @@
+2008-10-30  David Bateman  <address@hidden>
+
+       * interpreter/plot.txi: Document contour groups.
+
 2008-10-29  Thorsten Meyer  <address@hidden>
 
        * interpreter/system.txi, interpreter/poly.txi,
diff --git a/doc/interpreter/plot.txi b/doc/interpreter/plot.txi
--- a/doc/interpreter/plot.txi
+++ b/doc/interpreter/plot.txi
@@ -1710,7 +1710,76 @@
 @cindex series objects
 @cindex contour series
 
-TO BE WRITTEN
+Contour group objects are created by the @code{contour}, @code{contourf}
+and @code{contour3} functions. The are equally one of the handles returned
+by the @code{surfc} and @code{meshc} functions. The properties of the contour
+group are
+
address@hidden @code
address@hidden contourmatrix
+A read only property that contains the data return by @code{contourc} used to
+create the contours of the plot.
+
address@hidden fill
+A radio property that can have the values "on" or "off" that flags whether the
+contours to plot are to be filled.
+
address@hidden zlevelmode
address@hidden zlevel
+The radio property @code{zlevelmode} can have the values "none", "auto" or 
+"manual". When its value is "none" there is no z component to the plotted
+contours. When its value is "auto" the z value of the plotted contours is 
+at the same value as the contour itself. If the value is "manual", then the
+z value at which to plot the contour is determined by the @code{zlevel}
+property.
+
address@hidden levellistmode
address@hidden levellist
address@hidden levelstepmode
address@hidden levelstep
+If @code{levellistmode} is "manual", then the levels at whch to plot the 
+contours is determined by @code{levellist}. If @code{levellistmode} is
+set to "auto", then the distance between contours is determined by 
address@hidden If both @code{levellistmode} and @code{levelstepmode}
+are set to "auto", then there are assumed to be 10 equal spaced contours.
+
address@hidden textlistmode
address@hidden textlist
address@hidden textstepmode
address@hidden textstep
+If @code{textlistmode} is "manual", then the labelled contours 
+is determined by @code{textlist}. If @code{textlistmode} is set to 
+"auto", then the distance between labelled contours is determined by 
address@hidden If both @code{textlistmode} and @code{textstepmode}
+are set to "auto", then there are assumed to be 10 equal spaced 
+labelled contours.
+
address@hidden showtext
+Flag whether the contour labels are shown or not.
+
address@hidden labelspacing
+The distance between labels on a single contour in points.
+
address@hidden linewidth
address@hidden linestyle
address@hidden linecolor
+The properties of the contour lines. The properties @code{linewidth} and
address@hidden are similar to the correponding properties for lines. The
+property @code{linecolor} is a color property (@xref{Colors}), that can also
+have the values of "none" or "auto". If @code{linecolor} is "none", then no
+contour line is drawn. If @code{linecolor} is "auto" then the line color is
+determined by the colormap.
+
address@hidden xdata
address@hidden ydata
address@hidden zdata
+The original x, y, and z data of the contour lines.
+
address@hidden xdatasource
address@hidden ydatasource
address@hidden zdatasource
+Data source variables.
address@hidden table
 
 @node Error bar series
 @subsubsection Error bar series
diff --git a/scripts/ChangeLog b/scripts/ChangeLog
--- a/scripts/ChangeLog
+++ b/scripts/ChangeLog
@@ -1,3 +1,12 @@
+2008-10-30  David Bateman  <address@hidden>
+
+       * plot/__clabel__.m, plot/clabel.m: New functions.
+       * plot/Makefile.in (SOURCES): Add them here.
+       * plot/__contour__.m: Rewrite to use contour groups.
+       * plot/contourf.m: Call __contour__ instead of using specific code.
+       * plot/contour.m, plot/contour3.m: Minor modification to allow for
+       new interface to __contour__.
+
 2008-10-29  Thorsten Meyer  <address@hidden>
 
        * set/create_set.m, set/ismember.m, set/union.m, set/complement.m:
diff --git a/scripts/plot/Makefile.in b/scripts/plot/Makefile.in
--- a/scripts/plot/Makefile.in
+++ b/scripts/plot/Makefile.in
@@ -40,6 +40,7 @@
   __axis_label__.m \
   __bar__.m \
   __bars__.m \
+  __clabel__.m \
   __contour__.m \
   __default_plot_options__.m \
   __errcomm__.m \
@@ -82,6 +83,7 @@
   box.m \
   caxis.m \
   cla.m \
+  clabel.m \
   clf.m \
   close.m \
   closereq.m \
diff --git a/scripts/plot/__clabel__.m b/scripts/plot/__clabel__.m
new file mode 100644
--- /dev/null
+++ b/scripts/plot/__clabel__.m
@@ -0,0 +1,112 @@
+## 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/>.
+
+## Undocumented internal function.
+
+function h = __clabel__ (c, v, hparent, LabelSpacing, z, varargin)
+  ## FIXME
+  ## Assume that the plot size is 4 by 3 inches.
+  lims = axis ();
+  xspacing = 72 * 4 / abs(lims(1) - lims(2));
+  yspacing = 72 * 3 / abs(lims(3) - lims(4));
+
+  if (isscalar (hparent) && ishandle(hparent) && 
+       strcmp (get (hparent, "type"), "hggroup"))
+    x = get (hparent, "xdata");
+    xmin = min (x(:));
+    xmax = max (x(:));
+    y = get (hparent, "ydata");
+    ymin = min (y(:));
+    ymax = max (y(:));
+  else
+    i1 = 1;
+    while (i1 < length (c))
+      clev = c(1,i1);
+      clen = c(2,i1);
+      p = c(:, i1+1:i1+clen)      
+
+      xmin = min (c(1,:));
+      xmax = max (c(1,:));
+      ymin = min (c(2,:));
+      ymax = max (c(2,:));
+
+      i1 += clen+1;
+    endwhile
+  endif
+
+  ## Decode contourc output format and place labels.
+  i1 = 1;
+  h = [];
+  while (i1 < length (c))
+    clev = c(1,i1);
+    clen = c(2,i1);
+
+    if (!isempty (v) && ! any (find (clev == v)))
+      i1 += clen+1;
+      continue;
+    endif
+
+    p = c(:, i1+1:i1+clen) .* repmat ([xspacing; yspacing], 1, clen);
+    d = sqrt (sumsq (diff (p, 1, 2)));
+    cumd = cumsum (d);
+    td = sum(d);
+    ntag = ceil (td / LabelSpacing);
+
+    if (all (c(:,i1+1) == c(:,i1+clen)))
+      Spacing = td / ntag;
+      pos = Spacing / 2 + [0:ntag-1] * Spacing;
+    else
+      pos = zeros(1, ntag);
+      pos(1) = (td - LabelSpacing * (ntag - 1)) ./ 2;
+      pos(2:ntag) = pos(1) + [1:ntag-1] * LabelSpacing;
+    endif
+
+    j1 = 2;
+    tlabel = sprintf ("%g", clev);
+    for i = 1 : ntag
+      tagpos = pos(i);
+      
+      while (j1 < clen && cumd(j1) < tagpos)
+       j1++;
+      endwhile
+      tpos = sum(c(:,i1+j1-1:i1+j1), 2) ./ 2;
+
+      if (tpos(1) != xmin &&  tpos(1) != xmax && 
+         tpos(2) != ymin &&  tpos(2) != ymax)
+       trot = 180 / pi * atan2 (diff (c(2,i1+j1-1:i1+j1)),
+                                diff (c(1,i1+j1-1:i1+j1)));
+
+       if (ischar (z))
+         ht = text (tpos(1), tpos(2), clev, tlabel, "rotation", trot, 
+                    "parent", hparent, "horizontalalignment", "center",
+                    "userdata", clev, varargin{:});
+       elseif (!isempty (z))
+         ht = text (tpos(1), tpos(2), z, tlabel, "rotation", trot, 
+                    "parent", hparent, "horizontalalignment", "center",
+                    "userdata", clev, varargin{:});
+       else
+         ht = text (tpos(1), tpos(2), tlabel, "rotation", trot,
+                    "parent", hparent, "horizontalalignment", "center",
+                    "userdata", clev, varargin{:});
+       endif
+       h = [h; ht];
+      endif
+    endfor
+    i1 += clen+1;
+  endwhile
+endfunction 
\ No newline at end of file
diff --git a/scripts/plot/__contour__.m b/scripts/plot/__contour__.m
--- a/scripts/plot/__contour__.m
+++ b/scripts/plot/__contour__.m
@@ -18,19 +18,19 @@
 
 ## Undocumented internal function.
 
-function [c, h] = __contour__ (varargin)
-
+function [c, hg] = __contour__ (varargin)
   ax = varargin{1};
-  z = varargin{2};
+  zlevel = varargin{2};
+  filled = "off";
 
   linespec.linestyle = "-";
-  linespec.color = "flat";
+  linespec.color = "auto";
   for i = 3 : nargin
     arg = varargin {i};
     if ((ischar (arg) || iscell (arg)))
-      [linespec, valid] = __pltopt__ ("contour", arg, false);
+      [linespec, valid] = __pltopt__ ("__contour__", arg, false);
       if (isempty (linespec.color))
-       linespec.color = "flat";
+       linespec.color = "auto";
       endif
       if (valid)
        have_line_spec = true;
@@ -44,55 +44,431 @@
   i = 3;
   while (i < length (varargin))
     if (ischar (varargin {i}))
-      opts{end+1} = varargin{i};
-      varargin(i) = [];
-      opts{end+1} = varargin{i};
-      varargin(i) = [];
+      if (strcmpi (varargin{i}, "fill"))
+       filled = varargin {i + 1};
+       varargin(i:i+1) = [];
+      elseif (strcmpi (varargin{i}, "linecolor"))
+       linespec.color = varargin {i + 1};
+       varargin(i:i+1) = [];
+      else
+       opts{end+1} = varargin{i};
+        varargin(i) = [];
+        opts{end+1} = varargin{i};
+        varargin(i) = [];
+      endif
     else
       i++;
     endif
   endwhile
 
-  if (ischar (z))
-    if (strcmpi (z, "none"))
-      z = NaN;
-    elseif (strcmpi (z, "base"))
+  if (length(varargin) < 5)
+    z1 = varargin{3};
+    x1 = 1 : rows(z1);
+    y1 = 1 : columns(z1);
+  else
+    x1 = varargin{3};
+    y1 = varargin{4};
+    z1 = varargin{5};
+  endif
+  if (length (varargin) == 4 || length (varargin) == 6)
+    vn = varargin {end};
+    vnauto = false;
+  else
+    vnauto = true;
+    vn = 10; 
+  endif
+
+  if (strcmpi (filled, "on"))
+    if (isvector (x1) || isvector (y1))
+      [x1, y1] = meshgrid (x1, y1);
+    endif
+    [nr, nc] = size (z1);
+    x0 = prepad(x1, nc+1, 2 * x1(1, 1) - x1(1, 2), 2);
+    x0 = postpad(x0, nc+2, 2 * x1(1, nc) - x1(1, nc - 1), 2);
+    x0 = [x0(1, :); x0; x0(1, :)];
+    y0 = prepad(y1, nr+1, 2 * y1(1, 1) - y1(2, 1), 1);
+    y0 = postpad(y0, nr+2, 2 * y1(nr, 1) - y1(nr - 1, 1));
+    y0 = [y0(:, 1), y0, y0(:, 1)];
+    z0 = -Inf(nr+2, nc+2);
+    z0(2:nr+1, 2:nc+1) = z1;
+    [c, lev] = contourc (x0, y0, z0, vn);
+  else
+    [c, lev] = contourc (x1, y1, z1, vn);
+  endif
+
+  hg = hggroup ();
+  opts = __add_datasource__ ("__countour__", hg, {"x", "y", "z"}, opts{:});
+
+  addproperty ("xdata", hg, "data", x1);
+  addproperty ("ydata", hg, "data", y1);
+  addproperty ("zdata", hg, "data", z1);
+  addproperty ("contourmatrix", hg, "data", c);
+
+  addlistener (hg, "xdata", @update_data);
+  addlistener (hg, "ydata", @update_data);
+  addlistener (hg, "zdata", @update_data);
+  addlistener (hg, "contourmatrix", @update_data);
+
+  addproperty ("fill", hg, "radio", "on|{off}", filled);
+
+  ## The properties zlevel and zlevelmode don't exist in matlab, but
+  ## allow the use of contourgroups with the contour3, meshc and surfc 
+  ## functions. 
+  if (isnumeric (zlevel))
+    addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", "manual")
+    addproperty ("zlevel", hg, "data", zlevel);
+  else
+    addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", zlevel)
+    if (ischar (zlevel) && strcmpi (zlevel, "manual"))
       z = varargin{3};
       z = 2 * (min (z(:)) - max (z(:)));
-    elseif (! strcmpi (z, "level"))
-      error ("unrecognized z argument");
+      addproperty ("zlevel", hg, "data", z);
+    else
+      addproperty ("zlevel", hg, "data", 0.);
     endif
   endif
 
-  [c, lev] = contourc (varargin{3:end});
+  if (isscalar (vn))
+    lvlstep = (max(z1(:)) - min(z1(:))) / vn;
+  else
+    lvlstep = (max(z1(:)) - min(z1(:))) / 10;
+  endif
 
-  ## Decode contourc output format.
-  i1 = 1;
-  h = [];
-  while (i1 < length (c))
-    clev = c(1,i1);
-    clen = c(2,i1);
+  addproperty ("levellist", hg, "data", lev);
+  addproperty ("levelstep", hg, "double", lvlstep);
+  if (vnauto)
+    addproperty ("levellistmode", hg, "radio", "{auto}|manual", "auto");
+    addproperty ("levelstepmode", hg, "radio", "{auto}|manual", "auto");
+  elseif (isscalar (vn))
+    addproperty ("levellistmode", hg, "radio", "{auto}|manual", "auto");
+    addproperty ("levelstepmode", hg, "radio", "{auto}|manual", "manual");
+  else
+    addproperty ("levellistmode", hg, "radio", "{auto}|manual", "manual");
+    addproperty ("levelstepmode", hg, "radio", "{auto}|manual", "auto");
+  endif
 
-    if (all (c(:,i1+1) == c(:,i1+clen)))
-      p = c(:, i1+1:i1+clen-1);
+  addproperty ("labelspacing", hg, "double", 144);
+  addproperty ("textlist", hg, "data", lev);
+  addproperty ("textlistmode", hg, "radio", "{auto}|manual", "auto");
+  addproperty ("textstep", hg, "double", lvlstep);
+  addproperty ("textstepmode", hg, "radio", "{auto}|manual", "auto");
+  addproperty ("showtext", hg, "radio", "on|{off}", "off");
+
+  addproperty ("linecolor", hg, "color", linespec.color, "{auto}|none");
+  addproperty ("linestyle", hg, "linelinestyle", linespec.linestyle);
+  addproperty ("linewidth", hg, "linelinewidth", 0.5);
+
+  addlistener (hg, "fill", @update_data);
+
+  addlistener (hg, "zlevelmode", @update_zlevel);
+  addlistener (hg, "zlevel", @update_zlevel);
+
+  addlistener (hg, "levellist", @update_data);
+  addlistener (hg, "levelstep", @update_data);
+  addlistener (hg, "levellistmode", @update_data);
+  addlistener (hg, "levelstepmode", @update_data);
+
+  addlistener (hg, "labelspacing", @update_text);
+  addlistener (hg, "textlist", @update_text);
+  addlistener (hg, "textlistmode", @update_text);
+  addlistener (hg, "textstep", @update_text);
+  addlistener (hg, "textstepmode", @update_text);
+  addlistener (hg, "showtext", @update_text);
+
+  addlistener (hg, "linecolor", @update_line);
+  addlistener (hg, "linestyle", @update_line);
+  addlistener (hg, "linewidth", @update_line);
+
+  add_patch_children (hg);
+
+  if (!isempty (opts))
+    set (hg, opts{:});
+  endif
+endfunction
+
+function add_patch_children (hg)
+  c = get (hg, "contourmatrix");
+  lev = get (hg, "levellist");
+  fill = get (hg, "fill");
+  z = get (hg, "zlevel");
+  zmode = get (hg, "zlevelmode");
+  lc = get (hg, "linecolor");
+  lw = get (hg, "linewidth");
+  ls = get (hg, "linestyle");
+  filled = get (hg, "fill");
+
+  if (strcmpi (lc, "auto"))
+    lc = "flat";
+  endif
+
+  if (strcmpi (filled, "on"))
+    if (diff (lev) < 10*eps) 
+      lvl_eps = 1e-6;
     else
-      p = [c(:, i1+1:i1+clen), NaN(2, 1)];
+      lvl_eps = min (diff (lev)) / 1000.0;
     endif
 
-    if (isnan (z))
-      h = [h; patch(ax, p(1,:), p(2,:), "facecolor", "none", 
-                   "edgecolor", linespec.color, "linestyle", 
-                   linespec.linestyle, "cdata", clev, opts{:})];
-    elseif (!ischar(z))
-      h = [h; patch(ax, p(1,:), p(2,:), z * ones (1, columns (p)), "facecolor",
-                   "none", "edgecolor", linespec.color, 
-                   "linestyle", linespec.linestyle, "cdata", clev, opts{:})];
+    ## Decode contourc output format.
+    i1 = 1;
+    ncont = 0;
+    while (i1 < columns (c))
+      ncont++;
+      cont_lev(ncont) = c(1, i1);
+      cont_len(ncont) = c(2, i1);
+      cont_idx(ncont) = i1+1;
+
+      ii = i1+1:i1+cont_len(ncont);
+      cur_cont = c(:, ii);
+      startidx = ii(1);
+      stopidx = ii(end);
+      cont_area(ncont) = polyarea (c(1, ii), c(2, ii));
+      i1 += c(2, i1) + 1;
+    endwhile
+
+    ## Handle for each level the case where we have (a) hole(s) in a patch.
+    ## Those are to be filled with the color of level below or with the
+    ## background colour.
+    for k = 1:numel (lev)
+      lvl_idx = find (abs (cont_lev - lev(k)) < lvl_eps);
+      len = numel (lvl_idx);
+      if (len > 1)
+       ## mark = logical(zeros(size(lvl_idx)));
+       mark = false (size (lvl_idx));
+       a = 1;
+       while (a < len)
+         ## take 1st patch
+          b = a + 1;
+          pa_idx = lvl_idx(a);
+          ## get pointer to contour start, and contour length
+          curr_ct_idx = cont_idx(pa_idx);
+          curr_ct_len = cont_len(pa_idx);
+         ## get contour
+          curr_ct = c(:, curr_ct_idx:curr_ct_idx+curr_ct_len-1);
+          b_vec = (a+1):len;
+          next_ct_pt_vec = c(:, cont_idx(lvl_idx(b_vec)));
+          in = inpolygon (next_ct_pt_vec(1,:), next_ct_pt_vec(2,:),
+                         curr_ct(1, :), curr_ct(2, :));
+          mark(b_vec(in)) = !mark(b_vec(in));
+          a++;
+       endwhile
+       if (numel (mark) > 0)
+         ## All marked contours describe a hole in a larger contour of
+         ## the same level and must be filled with colour of level below.
+          ma_idx = lvl_idx(mark);
+          if (k > 1)
+           ## Find color of level below.
+            tmp = find(abs(cont_lev - lev(k - 1)) < lvl_eps);
+            lvl_bel_idx = tmp(1);
+           ## Set color of patches found.
+           cont_lev(ma_idx) = cont_lev(lvl_bel_idx);
+          else
+           ## Set lowest level contour to NaN.
+           cont_lev(ma_idx) = NaN;
+          endif
+       endif
+      endif
+    endfor
+
+    ## The algorithm can create patches with the size of the plotting
+    ## area, we would like to draw only the patch with the highest level.
+    del_idx = [];
+    max_idx = find (cont_area == max (cont_area));
+    if (numel (max_idx) > 1)
+      ## delete double entries
+      del_idx = max_idx(1:end-1);
+      cont_area(del_idx) = cont_lev(del_idx) = [];
+      cont_len(del_idx) = cont_idx(del_idx) = [];
+    endif
+
+    ## Now we have everything together and can start plotting the patches
+    ## beginning with largest area.
+    [tmp, svec] = sort (cont_area);
+    len = ncont - numel (del_idx);
+    h = [];
+    for n = 1:len
+      idx = svec(n);
+      ctmp = c(:, cont_idx(idx):cont_idx(idx) + cont_len(idx) - 1);
+      if (all (ctmp(:,1) == ctmp(:,end)))
+        ctmp(:, end) = [];
+      else
+       ## Special case unclosed contours
+      endif
+      h = [h; patch(ctmp(1, :), ctmp(2, :), cont_lev(idx), "edgecolor", lc, 
+                   "linestyle", ls, "linewidth", lw, "parent", hg)];
+    endfor
+
+    if (min (lev) == max (lev))
+      set (gca (), "clim", [min(lev)-1, max(lev)+1]);
     else
-      h = [h; patch(ax, p(1,:), p(2,:), clev * ones (1, columns (p)),
-                   "facecolor", "none", "edgecolor", linespec.color, 
-                   "linestyle", linespec.linestyle, "cdata", clev, opts{:})];
+      set (gca(), "clim", [min(lev), max(lev)]);
     endif
-    i1 += clen+1;
-  endwhile
-  
+
+    set (gca (), "layer", "top");
+  else
+    ## Decode contourc output format.
+    i1 = 1;
+    h = [];
+    while (i1 < length (c))
+      clev = c(1,i1);
+      clen = c(2,i1);
+
+      if (all (c(:,i1+1) == c(:,i1+clen)))
+       p = c(:, i1+1:i1+clen-1);
+      else
+       p = [c(:, i1+1:i1+clen), NaN(2, 1)];
+      endif
+
+      switch (zmode)
+       case "none"
+         h = [h; patch(p(1,:), p(2,:), "facecolor", "none", 
+                       "edgecolor", lc, "linestyle", ls, "linewidth", lw,
+                       "cdata", clev, "parent", hg)]; 
+       case "auto"
+         h = [h; patch(p(1,:), p(2,:), clev * ones (1, columns (p)),
+                       "facecolor", "none", "edgecolor", lc, 
+                       "linestyle", ls, "linewidth", lw, "cdata", clev, 
+                       "parent", hg)];
+       otherwise
+         h = [h; patch(p(1,:), p(2,:), z * ones (1, columns (p)),
+                       "facecolor", "none", "edgecolor", lc,
+                       "linestyle", ls, "linewidth", lw, "cdata", clev,
+                       "parent", hg)];
+      endswitch
+      i1 += clen+1;
+    endwhile
+  endif
+
 endfunction
+
+function update_zlevel (h, d)
+  z = get (h, "zlevel");
+  zmode = get (h, "zlevelmode");
+  kids = get (h, "children");
+
+  switch (zmode)
+    case "none"
+      set (kids, "zdata", []);
+    case "auto"
+      for i = 1 : length (kids)
+       set (kids(i), "zdata", get (kids (i), "cdata") .* 
+            ones (size (get (kids (i), "xdata"))));
+      endfor
+    otherwise
+      for i = 1 : length (kids)
+       set (kids(i), "zdata", z .* ones (size (get (kids (i), "xdata"))));
+      endfor
+  endswitch
+endfunction
+
+function update_line (h, d)
+  lc = get (h, "linecolor");
+  if (strcmpi (lc, "auto"))
+    lc = "flat";
+  endif
+  set (findobj (h, "type", "patch"), "edgecolor", lc,
+       "linewidth", get (h, "linewidth"), "linestyle", get (h, "linestyle"));
+endfunction
+
+function update_data (h, d)
+  persistent recursive = false;
+
+  if (!recursive)
+    recursive = true;
+
+    delete (get (h, "children"));
+
+    if (strcmpi (get (h, "levellistmode"), "manual"))
+      lvl = get (h, "levellist");
+    elseif (strcmpi (get (h, "levelstepmode"), "manual"))
+      z = get (h, "zdata");
+      lvl = ceil ((max(z(:)) - min (z(:)) ./ get (h, "levelstep")));
+    else
+      lvl = 10;
+    endif
+
+    if (strcmpi (get (h, "fill"), "on"))
+      X = get (h, "xdata");
+      Y = get (h, "ydata");
+      Z = get (h, "zdata");
+      if (isvector (X) || isvector (Y))
+       [X, Y] = meshgrid (X, Y);
+      endif
+      [nr, nc] = size (Z);
+      X0 = prepad(X, nc+1, 2 * X(1, 1) - X(1, 2), 2);
+      X0 = postpad(X0, nc+2, 2 * X(1, nc) - X(1, nc - 1), 2);
+      X0 = [X0(1, :); X0; X0(1, :)];
+      Y0 = prepad(Y, nr+1, 2 * Y(1, 1) - Y(2, 1), 1);
+      Y0 = postpad(Y0, nr+2, 2 * Y(nr, 1) - Y(nr - 1, 1));
+      Y0 = [Y0(:, 1), Y0, Y0(:, 1)];
+      Z0 = -Inf(nr+2, nc+2);
+      Z0(2:nr+1, 2:nc+1) = Z;
+      [c, lev] = contourc (X0, Y0, Z0, lvl);
+    else
+      [c, lev] = contourc (get (h, "xdata"), get (h, "ydata"), 
+                          get (h, "zdata"), lvl); 
+    endif
+    set (h, "contourmatrix", c);
+
+    if (strcmpi (get (h, "levellistmode"), "manual"))
+      ## Do nothing
+    elseif (strcmpi (get (h, "levelstepmode"), "manual"))
+      set (h, "levellist", lev);
+    else
+      set (h, "levellist", lev);
+      z = get (h, "zdata");
+      lvlstep = (max(z(:)) - min(z(:))) / 10;
+      set (h, "levelstep", lvlstep);
+    endif
+
+    add_patch_children (h);
+    update_text (h, d);
+  endif
+
+  recursive = false;
+endfunction
+
+function update_text (h, d)
+  persistent recursive = false;
+
+  if (!recursive)
+    recursive = true;
+
+    delete (findobj (h, "type", "text"));
+
+    if (strcmpi (get (h, "textlistmode"), "manual"))
+      lvl = get (h, "textlist");
+    elseif (strcmpi (get (h, "textstepmode"), "manual"))
+      lev = get (h, "levellist");
+
+      if (diff (lev) < 10*eps) 
+       lvl_eps = 1e-6;
+      else
+       lvl_eps = min (abs (diff (lev))) / 1000.0;
+      endif
+
+      stp = get (h, "textstep");
+      t = [0, floor(cumsum(diff (lev)) / (abs(stp) - lvl_eps))];
+      lvl = lev([true, t(1:end-1) != t(2:end)]);
+      set (h, "textlist", lvl);
+    else
+      lvl = get (h, "levellist");
+      set (h, "textlist", lvl, "textstep", get (h, "levelstep"));
+    endif
+
+    if (strcmpi (get (h, "showtext"), "on"))
+      switch (get (h, "zlevelmode"))
+       case "manual"
+         __clabel__ (get (h, "contourmatrix"), lvl, h, 
+                     get (h, "labelspacing"), get (h, "zlevel"));
+       case "auto"
+         __clabel__ (get (h, "contourmatrix"), lvl, h,
+                     get (h, "labelspacing"), "auto");
+       otherwise
+         __clabel__ (get (h, "contourmatrix"), lvl, h,
+                     get (h, "labelspacing"), []);
+      endswitch
+    endif
+  endif
+
+  recursive = false;
+endfunction
diff --git a/scripts/plot/clabel.m b/scripts/plot/clabel.m
new file mode 100644
--- /dev/null
+++ b/scripts/plot/clabel.m
@@ -0,0 +1,137 @@
+## 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} {} clabel (@var{c}, @var{h})
+## @deftypefnx {Function File} {} clabel (@var{c}, @var{h}, @var{v})
+## @deftypefnx {Function File} {} clabel (@var{c}, @var{h}, "manual")
+## @deftypefnx {Function File} {} clabel (@var{c})
+## @deftypefnx {Function File} {} clabel (@var{c}, @var{h})
+## @deftypefnx {Function File} {} clabel (@dots{}, @var{prop}, @var{val}, 
@dots{})
+## @deftypefnx {Function File} address@hidden =} clabel (@dots{})
+## Adds labels to the contours of a contour plot. The contour plot is specified
+## by the contour matrix @var{c} and optionally the contourgroup object @var{h}
+## that are returned by @code{contour}, @code{contourf} and @code{contour3}.
+## The contour labels are rotated and placed in the contour itself.
+##
+## By default, all contours are labelled. However, the conours to label can be
+## specified by the vector @var{v}. If the "manual" argument is given then
+## the contours to label can be selected with the mouse.
+##
+## Additional property/value pairs that are valid properties of text objects
+## can be given and are passed to the underlying text cobjects. Additionally,
+## the property "LabelSpacing" is available allowing the spacing between labels
+## on a contour (in points) to be specified. The default is 144 points, or 2
+## inches.
+##
+## The returned value @var{h} is the set of text object that represent the
+## contour labels. The "userdata" property of the text objects contains the
+## numerical value of the contour label.
+##
+## An example of the use of @code{clabel} is
+##
+## @example
+## @group
+## [c, h] = contour (peaks(), -4 : 6);
+## clabel (c, h, -4 : 2 : 6, 'fontsize', 12);
+## @end group
+## @end example
+##
+## @seealso{contour, contourf, contour3, meshc, surfc, text}
+## @end deftypefn
+
+function retval = clabel (c, varargin)
+  label_spacing = 2 * 72;
+  have_hg = false;
+  have_labelspacing = false;
+
+  if (nargin < 1)
+    print_usage()
+  elseif (nargin == 1)
+    hparent = gca ();
+  else
+    arg = varargin{1};
+    if (isscalar (arg) && ishandle(arg) && 
+       strcmp (get (arg, "type"), "hggroup"))
+      obj = get (arg);
+      if (! isfield (obj, "contourmatrix"))
+       error ("clabel: expecting the handle to be a contour group");
+      endif
+      hg = arg;
+      have_hg = true;
+      varargin(1) = [];
+    else
+      hparent = gca ();
+    endif
+  endif
+
+  if (length(varargin) > 0 && isnumeric (varargin{1}))
+    v = varargin{1}(:);
+    varargin(1) = [];
+  else
+    v = [];
+  endif
+
+  for i = 1 : length (varargin) - 1
+    arg = varargin{i};
+    if (strcmpi (arg, "labelspacing"))
+      label_spacing = varargin{i+1};
+      have_labelspacing = true;
+      varargin(i:i+1) = [];
+      break;
+    endif
+  endfor
+
+  for i = 1 : length (varargin)
+    arg = varargin{i};
+    if (strcmpi (arg, "manual"))
+      error ("clabel: manual contouring mode not supported");
+    endif
+  endfor
+
+  if (have_hg)
+    if (! isempty (v))
+      if (have_labelspacing)
+       set (hg, "textlistmode", "manual", "textlist", v, 
+            "labelspacing", label_spacing, "showtext", "on");
+      else
+       set (hg, "textlistmode", "manual", "textlist", v, "showtext", "on");
+      endif
+    else
+      if (have_labelspacing)
+       set (hg,"showtext", "on", "labelspacing", label_spacing);
+      else
+       set (hg,"showtext", "on");
+      endif
+    endif
+    retval = findobj (hg, "type", "text");
+    if (! isempty (varargin))
+      set (retval, varargin {:});
+    endif
+  else
+    retval =  __clabel__ (c, v, hparent, label_spacing, [], varargin{:});
+  endif
+endfunction
+
+%!demo
+%! [c, h] = contour (peaks(), -4 : 6);
+%! clabel (c, h, -4 : 2 : 6, 'fontsize', 12);
+
+%!demo
+%! [c, h] = contourf (peaks(), -7 : 6);
+%! clabel (c, h, -6 : 2 : 6, 'fontsize', 12);
diff --git a/scripts/plot/contour.m b/scripts/plot/contour.m
--- a/scripts/plot/contour.m
+++ b/scripts/plot/contour.m
@@ -59,7 +59,7 @@
   unwind_protect
     axes (xh);
     newplot ();
-    [ctmp, htmp] = __contour__ (xh, NaN, varargin{:});
+    [ctmp, htmp] = __contour__ (xh, "none", varargin{:});
   unwind_protect_cleanup
     axes (oldh);
   end_unwind_protect
diff --git a/scripts/plot/contour3.m b/scripts/plot/contour3.m
--- a/scripts/plot/contour3.m
+++ b/scripts/plot/contour3.m
@@ -57,7 +57,7 @@
   unwind_protect
     axes (xh);
     newplot ();
-    [ctmp, htmp] = __contour__ (xh, "level", varargin{:});
+    [ctmp, htmp] = __contour__ (xh, "auto", varargin{:});
   unwind_protect_cleanup
     axes (oldh);
   end_unwind_protect
@@ -68,7 +68,7 @@
 
   if (nargout > 0)
     c = ctmp;
-    h = htmp
+    h = htmp;
   endif
 
 endfunction
diff --git a/scripts/plot/contourf.m b/scripts/plot/contourf.m
--- a/scripts/plot/contourf.m
+++ b/scripts/plot/contourf.m
@@ -57,204 +57,24 @@
 ## Author: Kai Habel <address@hidden>
 ## Author: Shai Ayal <address@hidden>
 
-function varargout = contourf (varargin)
+function [c, h] = contourf (varargin)
 
-  [ax, varargin] = __plt_get_axis_arg__ ("contourf", varargin{:});
+  [xh, varargin] = __plt_get_axis_arg__ ("contour", varargin{:});
 
-  [X, Y, Z, lvl, patch_props] = parse_args (varargin);
-
-  [nr, nc] = size (Z);
-
-  [minx, maxx] = deal (min (X(:)), max (X(:)));
-  [miny, maxy] = deal (min (Y(:)), max (Y(:)));
-
-  if (diff (lvl) < 10*eps) 
-    lvl_eps = 1e-6;
-  else
-    lvl_eps = min (diff (lvl)) / 1000.0;
-  endif
-
-  X0 = prepad(X, nc+1, 2 * X(1, 1) - X(1, 2), 2);
-  X0 = postpad(X0, nc+2, 2 * X(1, nc) - X(1, nc - 1), 2);
-  X0 = [X0(1, :); X0; X0(1, :)];
-  Y0 = prepad(Y, nr+1, 2 * Y(1, 1) - Y(2, 1), 1);
-  Y0 = postpad(Y0, nr+2, 2 * Y(nr, 1) - Y(nr - 1, 1));
-  Y0 = [Y0(:, 1), Y0, Y0(:, 1)];
-
-  Z0 = -Inf(nr+2, nc+2);
-  Z0(2:nr+1, 2:nc+1) = Z;
-  [c, lev] = contourc (X0, Y0, Z0, lvl);
-  cmap = colormap ();
-
-  levx = linspace (min (lev), max (lev), size (cmap, 1));
-
-  newplot ();
-
-  ## Decode contourc output format.
-  i1 = 1;
-  ncont = 0;
-  while (i1 < columns (c))
-    ncont++;
-    cont_lev(ncont) = c(1, i1);
-    cont_len(ncont) = c(2, i1);
-    cont_idx(ncont) = i1+1;
-
-    ii = i1+1:i1+cont_len(ncont);
-    cur_cont = c(:, ii);
-    c(:, ii);
-    startidx = ii(1);
-    stopidx = ii(end);
-    cont_area(ncont) = polyarea (c(1, ii), c(2, ii));
-    i1 += c(2, i1) + 1;
-  endwhile
-
-  ## Handle for each level the case where we have (a) hole(s) in a patch.
-  ## Those are to be filled with the color of level below or with the
-  ## background colour.
-  for k = 1:numel (lev)
-    lvl_idx = find (abs (cont_lev - lev(k)) < lvl_eps);
-    len = numel (lvl_idx);
-    if (len > 1)
-      ## mark = logical(zeros(size(lvl_idx)));
-      mark = false (size (lvl_idx));
-      a = 1;
-      while (a < len)
-        # take 1st patch
-        b = a + 1;
-        pa_idx = lvl_idx(a);
-        # get pointer to contour start, and contour length
-        curr_ct_idx = cont_idx(pa_idx);
-        curr_ct_len = cont_len(pa_idx);
-        # get contour
-        curr_ct = c(:, curr_ct_idx:curr_ct_idx+curr_ct_len-1);
-        b_vec = (a+1):len;
-        next_ct_pt_vec = c(:, cont_idx(lvl_idx(b_vec)));
-        in = inpolygon (next_ct_pt_vec(1,:), next_ct_pt_vec(2,:),
-                       curr_ct(1, :), curr_ct(2, :));
-        mark(b_vec(in)) = !mark(b_vec(in));
-        a++;
-      endwhile
-      if (numel (mark) > 0)
-       ## All marked contours describe a hole in a larger contour of
-       ## the same level and must be filled with colour of level below.
-        ma_idx = lvl_idx(mark);
-        if (k > 1)
-         ## Find color of level below.
-          tmp = find(abs(cont_lev - lev(k - 1)) < lvl_eps);
-          lvl_bel_idx = tmp(1);
-         ## Set color of patches found.
-         cont_lev(ma_idx) = cont_lev(lvl_bel_idx);
-        else
-         ## Set lowest level contour to NaN.
-         cont_lev(ma_idx) = NaN;
-        endif
-      endif
-    endif
-  endfor
-
-  ## The algorithm can create patches with the size of the plotting
-  ## area, we would like to draw only the patch with the highest level.
-  del_idx = [];
-  max_idx = find (cont_area == max (cont_area));
-  if (numel (max_idx) > 1)
-    # delete double entries
-    del_idx = max_idx(1:end-1);
-    cont_area(del_idx) = cont_lev(del_idx) = [];
-    cont_len(del_idx) = cont_idx(del_idx) = [];
-  endif
-
-  ## Now we have everything together and can start plotting the patches
-  ## beginning with largest area.
-  [tmp, svec] = sort (cont_area);
-  len = ncont - numel (del_idx);
-  h = zeros (1, len);
-  for n = 1:len
-    idx = svec(n);
-    ii = cont_idx(idx):cont_idx(idx) + cont_len(idx) - 2;
-    h(n) = patch (c(1, ii), c(2, ii), cont_lev(idx), patch_props{:});
-  endfor
-
-  if (min (lev) == max (lev))
-    set (gca (), "clim", [min(lev)-1, max(lev)+1]);
-  else
-    set (gca(), "clim", [min(lev), max(lev)]);
-  endif
-
-  set (gca (), "layer", "top");
+  oldh = gca ();
+  unwind_protect
+    axes (xh);
+    newplot ();
+    [ctmp, htmp] = __contour__ (xh, "none", "fill", "on",
+                               "linecolor", "black", varargin{:});
+  unwind_protect_cleanup
+    axes (oldh);
+  end_unwind_protect
 
   if (nargout > 0)
-    varargout{2} = h;
-    varargout{1} = c;
+    c = ctmp;
+    h = htmp;
   endif
-
-endfunction
-
-function [X, Y, Z, lvl, patch_props] = parse_args (arg)
-
-  patch_props = {};
-  nolvl = false;
-
-  for n = 1:numel (arg)
-    if (ischar (arg{n}))
-      patch_props = arg(n:end);
-      arg(n:end) = [];
-      break;
-    endif
-  endfor
-
-  if (mod (numel (patch_props), 2) != 0)
-    error ("patch: property value is missing");
-  endif
-
-  if (numel (arg) < 3)
-    Z = arg{1};
-    [X, Y] = meshgrid (1:columns (Z), 1:rows (Z));
-  endif
-
-  if (numel (arg) == 1)
-    nolvl = true;
-    arg(1) = [];
-  elseif (numel (arg) == 2)
-    lvl = arg{2};
-    arg(1:2) = [];
-  elseif (numel (arg) == 3)
-    arg{1:3};
-    [X, Y, Z] = deal (arg{1:3});
-    arg(1:3) = [];
-    nolvl = true;
-  elseif (numel (arg) == 4)
-    [X, Y, Z, lvl] = deal (arg{1:4});
-    arg(1:4) = [];
-  endif
-
-  if (! ((isvector (X) && isvector (Y)) || size_equal (X, Y)))
-    error ("patch: X and Y must be of same size")
-  endif
-
-  if (isvector (X) || isvector (Y))
-    [X, Y] = meshgrid (X, Y);
-  endif
-
-  Z_no_inf = Z(!isinf (Z));
-  [minz, maxz] = deal (min (Z_no_inf(:)), max (Z_no_inf(:)));
-  Z(isnan (Z)) = -Inf;
-
-  if (nolvl)
-    lvl = linspace (minz, maxz, 12);
-  endif
-
-  if (isscalar (lvl))
-    lvl = linspace (minz, maxz, lvl + 2)(1:end-1);
-  else
-    idx1 = find(lvl < minz);
-    idx2 = find(lvl > maxz);
-    lvl(idx1(1:end-1)) = [];
-    lvl(idx2) = [];
-    if (isempty (lvl))
-      lvl = [minz, minz];
-    endif
-  endif
-
 endfunction
 
 %!demo

reply via email to

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