comparison scripts/plot/subplot.m @ 8744:4142982c66c6

subplot.m: Compatible placement of subplots.
author Ben Abbott <bpabbott@mac.com>
date Sun, 15 Feb 2009 19:07:05 -0500
parents 81d6ab3ac93c
children 995f8b064b32
comparison
equal deleted inserted replaced
8743:1bd918cfb6e2 8744:4142982c66c6
80 tmp = (tmp - index) / 10; 80 tmp = (tmp - index) / 10;
81 columns = rem (tmp, 10); 81 columns = rem (tmp, 10);
82 tmp = (tmp - columns) / 10; 82 tmp = (tmp - columns) / 10;
83 rows = rem (tmp, 10); 83 rows = rem (tmp, 10);
84 84
85 elseif (! (isscalar (columns) && isscalar (rows) && isscalar (index))) 85 elseif (! (isscalar (columns) && isscalar (rows)))
86 error ("subplot: columns, rows, and index have to be scalars"); 86 error ("subplot: columns, and rows must be scalars");
87 elseif (any (index < 1) || any (index > rows*columns))
88 error ("subplot: index value must be greater than 1 and less than rows*columns")
87 endif 89 endif
88 90
89 columns = round (columns); 91 columns = round (columns);
90 rows = round (rows); 92 rows = round (rows);
91 index = round (index); 93 index = round (index);
96 98
97 if (columns < 1 || rows < 1 || index < 1) 99 if (columns < 1 || rows < 1 || index < 1)
98 error ("subplot: columns,rows,index must be be positive"); 100 error ("subplot: columns,rows,index must be be positive");
99 endif 101 endif
100 102
101 xsize = 1 / columns; 103 units = get (0, "defaultaxesunits");
102 ysize = 1 / rows; 104 unwind_protect
103 105 set (0, "defaultaxesunits", "normalized")
104 yp = fix ((index-1)/columns); 106 pos = subplot_position (rows, columns, index, "outerposition", units);
105 xp = index - yp*columns - 1; 107
106 108 cf = gcf ();
107 x0 = xp * xsize; 109
108 y0 = (rows - yp - 1) * ysize; 110 set (cf, "nextplot", "add");
109 111
110 pos = [x0, y0, xsize, ysize]; 112 found = false;
111 113 kids = get (cf, "children");
112 x1 = x0 + xsize; 114 for child = reshape (kids, 1, numel (kids))
113 y1 = y0 + ysize; 115 ## Check whether this child is still valid; this might not be the
114 116 ## case anymore due to the deletion of previous children (due to
115 cf = gcf (); 117 ## "deletefcn" callback or for legends/colorbars that are deleted
116 118 ## with their corresponding axes).
117 set (cf, "nextplot", "add"); 119 if (! ishandle (child))
118
119 found = false;
120 kids = get (cf, "children");
121 for child = reshape (kids, 1, numel (kids))
122 ## Check whether this child is still valid; this might not be the
123 ## case anymore due to the deletion of previous children (due to
124 ## "deletefcn" callback or for legends/colorbars that are deleted
125 ## with their corresponding axes).
126 if (! ishandle (child))
127 continue;
128 endif
129 if (strcmp (get (child, "type"), "axes"))
130 ## Skip legend and colorbar objects.
131 if (strcmp (get (child, "tag"), "legend") ||
132 strcmp (get (child, "tag"), "colorbar"))
133 continue; 120 continue;
134 endif 121 endif
135 objpos = get (child, "outerposition"); 122 if (strcmp (get (child, "type"), "axes"))
136 if (objpos == pos) 123 ## Skip legend and colorbar objects.
137 ## If the new axes are in exactly the same position as an 124 if (strcmp (get (child, "tag"), "legend") ||
138 ## existing axes object, use the existing axes. 125 strcmp (get (child, "tag"), "colorbar"))
139 found = true; 126 continue;
140 tmp = child; 127 endif
141 else 128 objpos = get (child, "outerposition");
142 ## If the new axes overlap an old axes object, delete the old 129 if (all (objpos == pos))
143 ## axes. 130 ## If the new axes are in exactly the same position as an
144 objx0 = objpos(1); 131 ## existing axes object, use the existing axes.
145 objx1 = objx0 + objpos(3); 132 found = true;
146 objy0 = objpos(2); 133 tmp = child;
147 objy1 = objy0 + objpos(4); 134 else
148 if (! (x0 >= objx1 || x1 <= objx0 || y0 >= objy1 || y1 <= objy0)) 135 ## If the new axes overlap an old axes object, delete the old
149 delete (child); 136 ## axes.
150 endif 137 x0 = pos(1);
138 x1 = x0 + pos(3);
139 y0 = pos(2);
140 y1 = y0 + pos(4);
141 objx0 = objpos(1);
142 objx1 = objx0 + objpos(3);
143 objy0 = objpos(2);
144 objy1 = objy0 + objpos(4);
145 if (! (x0 >= objx1 || x1 <= objx0 || y0 >= objy1 || y1 <= objy0))
146 delete (child);
147 endif
148 endif
151 endif 149 endif
152 endif 150 endfor
153 endfor 151
154 152 if (found)
155 if (found) 153 set (cf, "currentaxes", tmp);
156 set (cf, "currentaxes", tmp); 154 else
157 else 155 pos2 = subplot_position (rows, columns, index, "position", units);
158 border = [0.130, 0.110, 0.225, 0.185] .* [xsize, ysize, xsize, ysize]; 156 tmp = axes ("outerposition", pos, "position", pos2);
159 pos2 = [pos(1:2) + border(1:2), pos(3:4) - border(1:2) - border(3:4)]; 157 endif
160 tmp = axes ("outerposition", pos, "position", pos2); 158
161 endif 159 unwind_protect_cleanup
160 set (0, "defaultaxesunits", units);
161 end_unwind_protect
162 162
163 if (nargout > 0) 163 if (nargout > 0)
164 h = tmp; 164 h = tmp;
165 endif 165 endif
166 166
167 endfunction 167 endfunction
168
169 function pos = subplot_position (rows, columns, index, position_property, units)
170
171 ## For 1 row and 1 column return the usual default.
172 if (rows == 1 && columns == 1)
173 if (strcmpi (position_property, "position"))
174 pos = get (0, "defaultaxesposition");
175 else
176 pos = get (0, "defaultaxesouterposition");
177 endif
178 return
179 endif
180
181 ## This produces compatible behavior for the "position" property.
182 margins.left = 0.130;
183 margins.right = 0.095;
184 margins.top = 0.075;
185 margins.bottom = 0.110;
186 pc = 1 ./ [0.1860, (margins.left + margins.right - 1)];
187 margins.column = 1 ./ polyval (pc , columns);
188 pr = 1 ./ [0.2282, (margins.top + margins.bottom - 1)];
189 margins.row = 1 ./ polyval (pr , rows);
190
191 ## Calculate the width/height of the subplot axes.
192 width = 1 - margins.left - margins.right - (columns-1)*margins.column;
193 width = width / columns;
194 height = 1 - margins.top - margins.bottom - (rows-1)*margins.row;
195 height = height / rows;
196
197 if (strcmp (position_property, "outerposition") )
198 ## Calculate the outerposition/position inset
199 if (rows > 1)
200 inset.top = 8/420;
201 inset.bottom = max (polyval ([0.1382,-0.0026], width), 16/420);
202 else
203 inset.bottom = margins.bottom;
204 inset.top = margins.top;
205 endif
206 if (columns > 1)
207 if (strcmpi (units, "normalized"))
208 inset.right = max (polyval ([0.1200,-0.0014], width), 5/560);
209 else
210 inset.right = max (polyval ([0.1252,-0.0023], width), 5/560);
211 endif
212 inset.left = 22/560;
213 else
214 inset.left = margins.left;
215 inset.right = margins.right;
216 endif
217 ## Apply the inset to the geometries for the "position" property.
218 margins.column = margins.column - inset.right - inset.left;
219 margins.row = margins.row - inset.top - inset.bottom;
220 width = width + inset.right + inset.left;
221 height = height + inset.top + inset.bottom;
222 endif
223
224 yp = fix ((index(:)-1)/columns);
225 xp = index(:) - yp*columns - 1;
226 yp = (rows - 1) - yp;
227
228 x0 = xp .* (width + margins.column) + margins.left;
229 y0 = yp .* (height + margins.row) + margins.bottom;
230
231 if (numel(x0) > 1)
232 x1 = max (x0) + width;
233 y1 = max (y0) + height;
234 x0 = min (x0);
235 y0 = min (y0);
236 pos = [x0, y0, x1-x0, y1-y0];
237 else
238 pos = [x0, y0, width, height];
239 endif
240
241 endfunction
242
243 %!demo
244 %! clf
245 %! r = 3;
246 %! c = 3;
247 %! fmt = {'horizontalalignment', 'center', 'verticalalignment', 'middle'};
248 %! for n = 1:(r*c)
249 %! subplot (r, c, n)
250 %! xlabel (sprintf ("xlabel #%d", n))
251 %! ylabel (sprintf ("ylabel #%d", n))
252 %! title (sprintf ("title #%d", n))
253 %! text (0.5, 0.5, sprintf('subplot(%d,%d,%d)', r, c, n), fmt{:})
254 %! axis ([0 1 0 1])
255 %! endfor
256 %! subplot (r, c, 1:3)
257 %! xlabel (sprintf ("xlabel #%d:%d", 1, 3))
258 %! ylabel (sprintf ("ylabel #%d:%d", 1, 3))
259 %! title (sprintf ("title #%d:%d", 1, 3))
260 %! text (0.5, 0.5, sprintf('subplot(%d,%d,%d:%d)', r, c, 1, 3), fmt{:})
261 %! axis ([0 1 0 1])
262