view scripts/plot/subplot.m @ 14237:11949c9795a0

Revamp %!demos in m-files to use Octave coding conventions on spacing, etc. Add clf() to all demos using plot features to get reproducibility. Use 64 as input to all colormaps (jet (64)) to get reproducibility. * bicubic.m, cell2mat.m, celldisp.m, cplxpair.m, interp1.m, interp2.m, interpft.m, interpn.m, profile.m, profshow.m, convhull.m, delaunay.m, griddata.m, inpolygon.m, voronoi.m, autumn.m, bone.m, contrast.m, cool.m, copper.m, flag.m, gmap40.m, gray.m, hot.m, hsv.m, image.m, imshow.m, jet.m, ocean.m, pink.m, prism.m, rainbow.m, spring.m, summer.m, white.m, winter.m, condest.m, onenormest.m, axis.m, clabel.m, colorbar.m, comet.m, comet3.m, compass.m, contour.m, contour3.m, contourf.m, cylinder.m, daspect.m, ellipsoid.m, errorbar.m, ezcontour.m, ezcontourf.m, ezmesh.m, ezmeshc.m, ezplot.m, ezplot3.m, ezpolar.m, ezsurf.m, ezsurfc.m, feather.m, fill.m, fplot.m, grid.m, hold.m, isosurface.m, legend.m, loglog.m, loglogerr.m, pareto.m, patch.m, pbaspect.m, pcolor.m, pie.m, pie3.m, plot3.m, plotmatrix.m, plotyy.m, polar.m, quiver.m, quiver3.m, rectangle.m, refreshdata.m, ribbon.m, rose.m, scatter.m, scatter3.m, semilogx.m, semilogxerr.m, semilogy.m, semilogyerr.m, shading.m, slice.m, sombrero.m, stairs.m, stem.m, stem3.m, subplot.m, surf.m, surfc.m, surfl.m, surfnorm.m, text.m, title.m, trimesh.m, triplot.m, trisurf.m, uigetdir.m, uigetfile.m, uimenu.m, uiputfile.m, waitbar.m, xlim.m, ylim.m, zlim.m, mkpp.m, pchip.m, polyaffine.m, spline.m, bicgstab.m, cgs.m, gplot.m, pcg.m, pcr.m, treeplot.m, strtok.m, demo.m, example.m, rundemos.m, speed.m, test.m, calendar.m, datestr.m, datetick.m, weekday.m: Revamp %!demos to use Octave coding conventions on spacing, etc.
author Rik <octave@nomad.inbox5.com>
date Fri, 20 Jan 2012 12:59:53 -0800
parents 72c96de7a403
children 4506eade9f04
line wrap: on
line source

## Copyright (C) 1995-2012 John W. Eaton
##
## 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} {} subplot (@var{rows}, @var{cols}, @var{index})
## @deftypefnx {Function File} {} subplot (@var{rcn})
## Set up a plot grid with @var{rows} by @var{cols} subwindows and plot
## in location given by @var{index}.
##
## If only one argument is supplied, then it must be a three digit value
## specifying the location in digits 1 (rows) and 2 (columns) and the plot
## index in digit 3.
##
## The plot index runs row-wise.  First all the columns in a row are filled
## and then the next row is filled.
##
## For example, a plot with 2 by 3 grid will have plot indices running as
## follows:
## @tex
## \vskip 10pt
## \hfil\vbox{\offinterlineskip\hrule
## \halign{\vrule#&&\qquad\hfil#\hfil\qquad\vrule\cr
## height13pt&1&2&3\cr height12pt&&&\cr\noalign{\hrule}
## height13pt&4&5&6\cr height12pt&&&\cr\noalign{\hrule}}}
## \hfil
## \vskip 10pt
## @end tex
## @ifnottex
##
## @example
## @group
## +-----+-----+-----+
## |  1  |  2  |  3  |
## +-----+-----+-----+
## |  4  |  5  |  6  |
## +-----+-----+-----+
## @end group
## @end example
##
## @var{index} may be a vector.  In which case, the new axis will enclose
## the grid locations specified.  The first demo illustrates an example:
##
## @example
## @code{demo ("subplot", 1)}
## @end example
##
## @end ifnottex
## @seealso{axes, plot}
## @end deftypefn

## Author: Vinayak Dutt <Dutt.Vinayak@mayo.EDU>
## Adapted-By: jwe

function h = subplot (varargin)

  align_axes = false;
  replace_axes = false;
  have_position = false;
  initial_args_decoded = false;

  if (nargin > 2)
    ## R, C, N?
    arg1 = varargin{1};
    arg2 = varargin{2};
    arg3 = varargin{3};
    if (isnumeric (arg1) && isscalar (arg1) && isnumeric (arg2)
        && isscalar (arg2) && isnumeric (arg3))
      rows = arg1;
      cols = arg2;
      index = arg3;
      varargin(1:3)= [];
      initial_args_decoded = true;
    endif
  endif

  if (! initial_args_decoded && nargin > 1)
    ## check for 'position', pos, ...
    if (strcmpi (varargin{1}, "position"))
      arg = varargin{2};
      if (isnumeric (arg) && numel (arg) == 4)
        pos = arg;
        varargin(1:2) = [];
        have_position = true;
        initial_args_decoded = true;
      else
        error ("expecting position to be a 4-element numeric array");
      endif
    endif
  endif
    
  if (! initial_args_decoded && nargin > 0)
    arg = varargin{1};
    if (nargin == 1 && ishandle (arg))
      ## Axes handle?
      axes (arg);
      cf = get (0, "currentfigure");
      set (cf, "nextplot", "add");
      return;
    elseif (isscalar (arg) && arg >= 0)
      ## RCN?
      index = rem (arg, 10);
      arg = (arg - index) / 10;
      cols = rem (arg, 10);
      arg = (arg - cols) / 10;
      rows = rem (arg, 10);
      varargin(1) = [];
      initial_args_decoded = true;
    else
      error ("subplot: expecting axes handle or RCN argument");
    endif
  endif

  if (! initial_args_decoded)
    print_usage ();
  endif

  if (! have_position)
    cols = round (cols);
    rows = round (rows);
    index = round (index);

    if (any (index < 1) || any (index > rows*cols))
      error ("subplot: INDEX value must be greater than 1 and less than ROWS*COLS");
    endif

    if (cols < 1 || rows < 1 || index < 1)
      error ("subplot: COLS, ROWS, and INDEX must be be positive");
    endif
  endif

  nargs = numel (varargin);
  while (nargs > 0)
    arg = varargin{1};
    if (strcmpi (arg, "align"))
      align_axes = true;
    elseif (strcmpi (arg, "replace"))
      replace_axes = true;
    else
      break;
    endif
    varargin(1) = [];
    nargs--;
  endwhile

  axesunits = get (0, "defaultaxesunits");
  cf = gcf ();
  figureunits = get (cf, "units");
  unwind_protect
    units = "normalized";
    set (0, "defaultaxesunits", units);
    set (cf, "units", "pixels");

    ## FIXME: At the moment we force gnuplot to use the aligned mode
    ##        which will set "activepositionproperty" to "position".
    ##        Τhis can yield to text overlap between labels and titles
    ##        see bug #31610
    if (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot"))
      align_axes = true;
    endif

    if (! have_position)
      if (align_axes)
        pos = subplot_position (rows, cols, index, "position");
      elseif (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot"))
        pos = subplot_position (rows, cols, index, "outerpositiontight");
      else
        pos = subplot_position (rows, cols, index, "outerposition");
      endif
    endif

    set (cf, "nextplot", "add");

    found = false;
    kids = get (cf, "children");
    for child = reshape (kids, 1, numel (kids))
      ## Check whether this child is still valid; this might not be the
      ## case anymore due to the deletion of previous children (due to
      ## "deletefcn" callback or for legends/colorbars that are deleted
      ## with their corresponding axes).
      if (! ishandle (child))
        continue;
      endif
      if (strcmp (get (child, "type"), "axes"))
        ## Skip legend and colorbar objects.
        if (strcmp (get (child, "tag"), "legend")
            || strcmp (get (child, "tag"), "colorbar"))
          continue;
        endif
        if (align_axes)
          objpos = get (child, "position");
        else
          objpos = get (child, "outerposition");
        endif
        if (all (objpos == pos) && ! replace_axes)
          ## If the new axes are in exactly the same position as an
          ## existing axes object, use the existing axes.
          found = true;
          tmp = child;
        else
          ## If the new axes overlap an old axes object, delete the old
          ## axes.
          x0 = pos(1);
          x1 = x0 + pos(3);
          y0 = pos(2);
          y1 = y0 + pos(4);
          objx0 = objpos(1);
          objx1 = objx0 + objpos(3);
          objy0 = objpos(2);
          objy1 = objy0 + objpos(4);
          if (! (x0 >= objx1 || x1 <= objx0 || y0 >= objy1 || y1 <= objy0))
            delete (child);
          endif
        endif
      endif
    endfor

    if (found)
      set (cf, "currentaxes", tmp);
    elseif (align_axes)
      tmp = axes ("box", "off", "position", pos, varargin{:});
    elseif (strcmp (get (cf, "__graphics_toolkit__"), "gnuplot"))
      tmp = axes ("box", "off", "outerposition", pos, varargin{:});
    else
      tmp = axes ("looseinset", [0 0 0 0], "box", "off", "outerposition", pos,
                  "autopos_tag", "subplot", varargin{:});
    endif

  unwind_protect_cleanup
    set (0, "defaultaxesunits", axesunits);
    set (cf, "units", figureunits);
  end_unwind_protect

  if (nargout > 0)
    h = tmp;
  endif

endfunction

function pos = subplot_position (rows, cols, index, position_property)

  if (rows == 1 && cols == 1)
    ## Trivial result for subplot (1,1,1)
    if (strcmpi (position_property, "position"))
      pos = get (0, "defaultaxesposition");
    else
      pos = get (0, "defaultaxesouterposition");
    endif
    return
  endif

  if (strcmp (position_property, "outerposition")
      || strcmp (position_property, "outerpositiontight"))
    margins.left   = 0.05;
    margins.bottom = 0.05;
    margins.right  = 0.05;
    margins.top    = 0.05;
    if (strcmp (position_property, "outerpositiontight"))
      margins.column = 0.;
      margins.row = 0.;
    else
      margins.column = 0.04 / cols;
      margins.row = 0.04 / rows;
    endif
    width = 1 - margins.left - margins.right - (cols-1)*margins.column;
    width = width / cols;
    height = 1 - margins.top - margins.bottom - (rows-1)*margins.row;
    height = height / rows;
  else
    defaultaxesposition = get (0, "defaultaxesposition");

    ## The outer margins surrounding all subplot "positions" are independent
    ## of the number of rows and/or columns
    margins.left   = defaultaxesposition(1);
    margins.bottom = defaultaxesposition(2);
    margins.right  = 1.0 - margins.left - defaultaxesposition(3);
    margins.top    = 1.0 - margins.bottom - defaultaxesposition(4);

    ## Fit from Matlab experiments
    pc = 1 ./ [0.1860, (margins.left + margins.right - 1)];
    margins.column = 1 ./ polyval (pc , cols);
    pr = 1 ./ [0.2282, (margins.top + margins.bottom - 1)];
    margins.row    = 1 ./ polyval (pr , rows);

    ## Calculate the width/height of the subplot axes "position".
    ## This is also consistent with Matlab
    width = 1 - margins.left - margins.right - (cols-1)*margins.column;
    width = width / cols;
    height = 1 - margins.top - margins.bottom - (rows-1)*margins.row;
    height = height / rows;
  endif

  ## Index offsets from the lower left subplot
  yi = fix ((index(:)-1)/cols);
  xi = index(:) - yi*cols - 1;
  yi = (rows - 1) - yi;

  ## Lower left corner of the subplot, i.e. position(1:2)
  x0 = xi .* (width + margins.column) + margins.left;
  y0 = yi .* (height + margins.row) + margins.bottom;

  if (numel(x0) > 1)
    ## subplot (row, col, m:n)
    x1 = max (x0(:)) + width;
    y1 = max (y0(:)) + height;
    x0 = min (x0(:));
    y0 = min (y0(:));
    pos = [x0, y0, x1-x0, y1-y0];
  else
    ## subplot (row, col, num)
    pos = [x0, y0, width, height];
  endif

endfunction

%!demo
%! clf;
%! r = 3;
%! c = 3;
%! fmt = {"horizontalalignment", "center", "verticalalignment", "middle"};
%! for n = 1 : r*c
%!   subplot (r, c, n);
%!   xlabel (sprintf ("xlabel #%d", n));
%!   ylabel (sprintf ("ylabel #%d", n));
%!   title (sprintf ("title #%d", n));
%!   text (0.5, 0.5, sprintf("subplot(%d,%d,%d)", r, c, n), fmt{:});
%!   axis ([0 1 0 1]);
%! endfor
%! subplot (r, c, 1:3);
%! xlabel (sprintf ("xlabel #%d:%d", 1, 3));
%! ylabel (sprintf ("ylabel #%d:%d", 1, 3));
%! title (sprintf ("title #%d:%d", 1, 3));
%! text (0.5, 0.5, sprintf("subplot(%d,%d,%d:%d)", r, c, 1, 3), fmt{:});
%! axis ([0 1 0 1]);

%!demo
%! clf;
%! x = 0:1;
%! for n = 1:4
%!   subplot (2, 2, n, "align");
%!   plot (x, x);
%!   xlabel (sprintf ("xlabel (2,2,%d)", n));
%!   ylabel (sprintf ("ylabel (2,2,%d)", n));
%!   title (sprintf ("title (2,2,%d)", n));
%! endfor
%! subplot (1, 2, 1, "align");
%! plot (x, x);
%! xlabel ("xlabel (1,2,1)");
%! ylabel ("ylabel (1,2,1)");
%! title ("title (1,2,1)");