1## Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2005,
2## 2006, 2007, 2008, 2009 John W. Eaton
4## This file is part of Octave.
6## Octave is free software; you can redistribute it and/or modify it
7## under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 3 of the License, or (at
9## your option) any later version.
11## Octave is distributed in the hope that it will be useful, but
12## WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14## General Public License for more details.
16## You should have received a copy of the GNU General Public License
17## along with Octave; see the file COPYING. If not, see
18## <http://www.gnu.org/licenses/>.
21## @deftypefn {Function File} {} subplot (@var{rows}, @var{cols}, @var{index})
22## @deftypefnx {Function File} {} subplot (@var{rcn})
23## Set up a plot grid with @var{cols} by @var{rows} subwindows and plot
24## in location given by @var{index}.
26## If only one argument is supplied, then it must be a three digit value
27## specifying the location in digits 1 (rows) and 2 (columns) and the plot
30## The plot index runs row-wise. First all the columns in a row are filled
31## and then the next row is filled.
33## For example, a plot with 2 by 3 grid will have plot indices running as
37## \hfil\vbox{\offinterlineskip\hrule
38## \halign{\vrule#&&\qquad\hfil#\hfil\qquad\vrule\cr
39## height13pt&1&2&3\cr height12pt&&&\cr\noalign{\hrule}
40## height13pt&4&5&6\cr height12pt&&&\cr\noalign{\hrule}}}
61## Author: Vinayak Dutt <Dutt.Vinayak@mayo.EDU>
64function h = subplot (rows, columns, index)
66 if (nargin != 3 && nargin != 1)
72 if (! (isscalar (rows) && rows >= 0))
73 error ("subplot: input rcn has to be a positive scalar");
77 index = rem (tmp, 10);
78 tmp = (tmp - index) / 10;
79 columns = rem (tmp, 10);
80 tmp = (tmp - columns) / 10;
83 elseif (! (isscalar (columns) && isscalar (rows)))
84 error ("subplot: columns, and rows must be scalars");
85 elseif (any (index < 1) || any (index > rows*columns))
86 error ("subplot: index value must be greater than 1 and less than rows*columns")
89 columns = round (columns);
91 index = round (index);
93 if (index > columns*rows)
94 error ("subplot: index must be less than columns*rows");
97 if (columns < 1 || rows < 1 || index < 1)
98 error ("subplot: columns,rows,index must be be positive");
101 units = get (0, "defaultaxesunits");
103 set (0, "defaultaxesunits", "normalized")
104 pos = subplot_position (rows, columns, index, "position", units);
108 set (cf, "nextplot", "add");
111 kids = get (cf, "children");
112 for child = reshape (kids, 1, numel (kids))
113 ## Check whether this child is still valid; this might not be the
114 ## case anymore due to the deletion of previous children (due to
115 ## "deletefcn" callback or for legends/colorbars that are deleted
116 ## with their corresponding axes).
117 if (! ishandle (child))
120 if (strcmp (get (child, "type"), "axes"))
121 ## Skip legend and colorbar objects.
122 if (strcmp (get (child, "tag"), "legend") ||
123 strcmp (get (child, "tag"), "colorbar"))
126 objpos = get (child, "position");
127 if (all (objpos == pos))
128 ## If the new axes are in exactly the same position as an
129 ## existing axes object, use the existing axes.
133 ## If the new axes overlap an old axes object, delete the old
140 objx1 = objx0 + objpos(3);
142 objy1 = objy0 + objpos(4);
143 if (! (x0 >= objx1 || x1 <= objx0 || y0 >= objy1 || y1 <= objy0))
151 set (cf, "currentaxes", tmp);
153 pos = subplot_position (rows, columns, index, "outerposition", units);
154 pos2 = subplot_position (rows, columns, index, "position", units);
155 tmp = axes ("outerposition", pos, "position", pos2);
158 unwind_protect_cleanup
159 set (0, "defaultaxesunits", units);
168function pos = subplot_position (rows, columns, index, position_property, units)
170 ## For 1 row and 1 column return the usual default.
171 if (rows == 1 && columns == 1)
172 if (strcmpi (position_property, "position"))
173 pos = get (0, "defaultaxesposition");
175 pos = get (0, "defaultaxesouterposition");
180 ## This produces compatible behavior for the "position" property.
181 margins.left = 0.130;
182 margins.right = 0.095;
184 margins.bottom = 0.110;
185 pc = 1 ./ [0.1860, (margins.left + margins.right - 1)];
186 margins.column = 1 ./ polyval (pc , columns);
187 pr = 1 ./ [0.2282, (margins.top + margins.bottom - 1)];
188 margins.row = 1 ./ polyval (pr , rows);
190 ## Calculate the width/height of the subplot axes.
191 width = 1 - margins.left - margins.right - (columns-1)*margins.column;
192 width = width / columns;
193 height = 1 - margins.top - margins.bottom - (rows-1)*margins.row;
194 height = height / rows;
196 if (strcmp (position_property, "outerposition") )
197 ## Calculate the outerposition/position inset
200 inset.bottom = max (polyval ([0.1382,-0.0026], height), 16/420);
202 inset.bottom = margins.bottom;
203 inset.top = margins.top;
206 if (strcmpi (units, "normalized"))
207 inset.right = max (polyval ([0.1200,-0.0014], width), 5/560);
209 inset.right = max (polyval ([0.1252,-0.0023], width), 5/560);
213 inset.left = margins.left;
214 inset.right = margins.right;
216 ## Apply the inset to the geometries for the "position" property.
217 margins.column = margins.column - inset.right - inset.left;
218 margins.row = margins.row - inset.top - inset.bottom;
219 width = width + inset.right + inset.left;
220 height = height + inset.top + inset.bottom;
223 yp = fix ((index(:)-1)/columns);
224 xp = index(:) - yp*columns - 1;
225 yp = (rows - 1) - yp;
227 x0 = xp .* (width + margins.column) + margins.left;
228 y0 = yp .* (height + margins.row) + margins.bottom;
230 if (strcmp (position_property, "outerposition") )
231 x0 = x0 - inset.left;
232 y0 = y0 - inset.bottom;
236 x1 = max (x0) + width;
237 y1 = max (y0) + height;
240 pos = [x0, y0, x1-x0, y1-y0];
242 pos = [x0, y0, width, height];
251%! fmt = {'horizontalalignment', 'center', 'verticalalignment', 'middle'};
254%! xlabel (sprintf ("xlabel #%d", n))
255%! ylabel (sprintf ("ylabel #%d", n))
256%! title (sprintf ("title #%d", n))
257%! text (0.5, 0.5, sprintf('subplot(%d,%d,%d)', r, c, n), fmt{:})
260%! subplot (r, c, 1:3)
261%! xlabel (sprintf ("xlabel #%d:%d", 1, 3))
262%! ylabel (sprintf ("ylabel #%d:%d", 1, 3))
263%! title (sprintf ("title #%d:%d", 1, 3))
264%! text (0.5, 0.5, sprintf('subplot(%d,%d,%d:%d)', r, c, 1, 3), fmt{:})