comparison scripts/plot/private/__bar__.m @ 17519:cc9befe5d271

Overhaul bar family of plot functions. * scripts/plot/bar.m, scripts/plot/barh.m: Document new "hist", "histc" arguments. * scripts/plot/private/__bar__.m: "grouped" bars now default to having a gap between them for Matlab compatibility. Added new style options "hist", "histc". Renamed variable names for clarity. Removed unnecessary for loops in listener functions. Stop recursion in listener functions.
author Rik <rik@octave.org>
date Mon, 30 Sep 2013 16:50:41 -0700
parents 177147bf7b55
children 76614e624818
comparison
equal deleted inserted replaced
17518:6c62150b454a 17519:cc9befe5d271
23 23
24 ## Author: jwe 24 ## Author: jwe
25 25
26 function varargout = __bar__ (vertical, func, varargin) 26 function varargout = __bar__ (vertical, func, varargin)
27 27
28 [hax, varargin, nargs] = __plt_get_axis_arg__ (func, varargin{:}); 28 [hax, varargin, nargin] = __plt_get_axis_arg__ (func, varargin{:});
29 29
30 ## Slightly smaller than 0.8 to avoid clipping issue in gnuplot 4.0 30 ## Slightly smaller than 0.8 to avoid clipping issue in gnuplot 4.0
31 width = 0.8 - 10 * eps; 31 width = 0.8 - 10 * eps;
32 group = true; 32 group = true;
33 bv = 0; 33 histc = NA;
34 34 bv = 0; # BaseValue
35 if (nargs > 1 && isnumeric (varargin{2})) 35
36 if (nargin > 1 && isnumeric (varargin{2}))
36 x = varargin{1}; 37 x = varargin{1};
37 if (isvector (x)) 38 if (isvector (x))
38 x = x(:); 39 x = x(:);
39 endif 40 endif
40 y = varargin{2}; 41 y = varargin{2};
63 idx = 2; 64 idx = 2;
64 endif 65 endif
65 66
66 newargs = {}; 67 newargs = {};
67 have_line_spec = false; 68 have_line_spec = false;
68 while (idx <= nargs) 69 while (idx <= nargin)
69 if (ischar (varargin{idx}) && strcmpi (varargin{idx}, "grouped")) 70 if (ischar (varargin{idx}) && strcmpi (varargin{idx}, "grouped"))
70 group = true; 71 group = true;
71 idx++; 72 idx++;
72 elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "stacked")) 73 elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "stacked"))
73 group = false; 74 group = false;
75 idx++;
76 elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "histc"))
77 group = true;
78 histc = true;
79 idx++;
80 elseif (ischar (varargin{idx}) && strcmpi (varargin{idx}, "hist"))
81 group = true;
82 histc = false;
74 idx++; 83 idx++;
75 else 84 else
76 if ((ischar (varargin{idx}) || iscellstr (varargin{idx})) 85 if ((ischar (varargin{idx}) || iscellstr (varargin{idx}))
77 && ! have_line_spec) 86 && ! have_line_spec)
78 [linespec, valid] = __pltopt__ (func, varargin{idx}, false); 87 [linespec, valid] = __pltopt__ (func, varargin{idx}, false);
85 continue; 94 continue;
86 endif 95 endif
87 endif 96 endif
88 if (isscalar (varargin{idx})) 97 if (isscalar (varargin{idx}))
89 width = varargin{idx++}; 98 width = varargin{idx++};
90 elseif (idx == nargs) 99 elseif (idx == nargin)
91 newargs = [newargs,varargin(idx++)]; 100 newargs = [newargs, varargin(idx++)];
92 elseif (ischar (varargin{idx}) 101 elseif (ischar (varargin{idx})
93 && strcmpi (varargin{idx}, "basevalue") 102 && strcmpi (varargin{idx}, "basevalue")
94 && isscalar (varargin{idx+1})) 103 && isscalar (varargin{idx+1}))
95 bv = varargin{idx+1}; 104 bv = varargin{idx+1};
96 idx += 2; 105 idx += 2;
97 else 106 else
98 newargs = [newargs,varargin(idx:idx+1)]; 107 newargs = [newargs, varargin(idx:idx+1)];
99 idx += 2; 108 idx += 2;
100 endif 109 endif
101 endif 110 endif
102 endwhile 111 endwhile
103 112
104 xlen = rows (x); 113 ngrp = rows (x);
105 ylen = rows (y); 114 if (ngrp != rows (y))
106
107 if (xlen != ylen)
108 error ("%s: length of X and Y must be equal", func); 115 error ("%s: length of X and Y must be equal", func);
109 endif 116 endif
110 if (any (x(2:end) < x(1:end-1))) 117 if (any (x(2:end) < x(1:end-1)))
111 error ("%s: X vector values must be in ascending order", func); 118 error ("%s: X vector values must be in ascending order", func);
112 endif 119 endif
113 120
114 ycols = columns (y); 121 nbars = columns (y);
122
123 ## Column width is 1 for 'hist*' styles. Otherwise, same as group width.
124 if (nbars == 1)
125 cwidth = 1;
126 gwidth = width;
127 elseif (islogical (histc))
128 cwidth = 1;
129 gwidth = width^2;
130 else
131 cwidth = gwidth = width;
132 endif
133
134 ## Complicated algorithm sizes bars with unitless parameter width.
135 ## If width is 1.0, adjacent bars in a group are touching.
136 ## Otherwise, bar size is cwidth and the remaining space is split evenly on
137 ## either side of the bar. For the default 0.8, spacing is [0.1 0.8 0.1].
138 ## Groups of bars are spaced by gwidth. If gwidth is 1.0 then adjacent
139 ## groups will just touch.
115 if (numel (x) > 1) 140 if (numel (x) > 1)
116 cutoff = min (diff (double (x))) / 2; 141 cutoff = min (diff (double (x))) / 2;
117 else 142 else
118 cutoff = 1; 143 cutoff = 1;
119 endif 144 endif
120 if (group) 145 if (group)
121 delta_p = delta_m = repmat (cutoff * width / ycols, size (x)); 146 gdelta = cutoff * gwidth / nbars;
122 else 147 cdelta = repmat ((1 - ((1 - cwidth) / 2)) * gdelta, size (x));
123 delta_p = delta_m = repmat (cutoff * width, size (x)); 148 else
124 endif 149 cdelta = repmat (cutoff * gwidth, size (x));
125 x1 = (x - delta_m)(:)'; 150 endif
126 x2 = (x + delta_p)(:)'; 151 x1 = (x - cdelta)(:)';
127 xb = repmat ([x1; x1; x2; x2](:), 1, ycols); 152 x2 = (x + cdelta)(:)';
153 xb = repmat ([x1; x1; x2; x2](:), 1, nbars);
128 154
129 if (group) 155 if (group)
130 offset = ((delta_p + delta_m) * [-(ycols - 1) / 2 : (ycols - 1) / 2]); 156 if (islogical (histc) && histc)
131 xb(1:4:4*ylen,:) += offset; 157 offset = 2*cdelta * [0:(nbars-1)] + cdelta(1); # not centered
132 xb(2:4:4*ylen,:) += offset; 158 else
133 xb(3:4:4*ylen,:) += offset; 159 offset = 2*cdelta * [-(nbars - 1) / 2 : (nbars - 1) / 2];
134 xb(4:4:4*ylen,:) += offset; 160 endif
161
162 xb(1:4:4*ngrp,:) += offset + (1-cwidth) / 2 * (2 * gdelta);
163 xb(2:4:4*ngrp,:) += offset + (1-cwidth) / 2 * (2 * gdelta);
164 xb(3:4:4*ngrp,:) += offset - (1-cwidth) / 2 * (2 * gdelta);
165 xb(4:4:4*ngrp,:) += offset - (1-cwidth) / 2 * (2 * gdelta);
166
135 y0 = zeros (size (y)) + bv; 167 y0 = zeros (size (y)) + bv;
136 y1 = y; 168 y1 = y;
137 else 169 else
138 y1 = cumsum (y,2); 170 y1 = cumsum (y,2);
139 y0 = [zeros(ylen,1)+bv, y1(:,1:end-1)]; 171 y0 = [zeros(ngrp,1)+bv, y1(:,1:end-1)];
140 endif 172 endif
141 173
142 yb = zeros (4*ylen, ycols); 174 yb = zeros (4*ngrp, nbars);
143 yb(1:4:4*ylen,:) = y0; 175 yb(1:4:4*ngrp,:) = y0;
144 yb(2:4:4*ylen,:) = y1; 176 yb(2:4:4*ngrp,:) = y1;
145 yb(3:4:4*ylen,:) = y1; 177 yb(3:4:4*ngrp,:) = y1;
146 yb(4:4:4*ylen,:) = y0; 178 yb(4:4:4*ngrp,:) = y0;
147 179
148 xb = reshape (xb, [4, numel(xb) / 4 / ycols, ycols]); 180 xb = reshape (xb, [4, ngrp, nbars]);
149 yb = reshape (yb, [4, numel(yb) / 4 / ycols, ycols]); 181 yb = reshape (yb, [4, ngrp, nbars]);
150 182
151 if (nargout < 2) 183 if (nargout < 2)
152 oldfig = []; 184 oldfig = [];
153 if (! isempty (hax)) 185 if (! isempty (hax))
154 oldfig = get (0, "currentfigure"); 186 oldfig = get (0, "currentfigure");
155 endif 187 endif
156 unwind_protect 188 unwind_protect
157 hax = newplot (hax); 189 hax = newplot (hax);
158 190
159 htmp = bars (hax, vertical, x, y, xb, yb, width, group, 191 htmp = bars (hax, vertical, x, y, xb, yb, gwidth, group,
160 have_line_spec, bv, newargs{:}); 192 have_line_spec, bv, newargs{:});
193
194 if (! ishold (hax))
195 if (all (x(:,1) == fix (x(:,1))))
196 if (vertical)
197 set (hax, "xtick", x(:,1));
198 else
199 set (hax, "ytick", x(:,1));
200 endif
201 endif
202 ## Hack prevents color and xlim setting changes when basevalue changes.
203 if (vertical)
204 set (hax, "clim", [0 1], "xlimmode", "manual");
205 else
206 set (hax, "clim", [0 1], "ylimmode", "manual");
207 endif
208 endif
161 unwind_protect_cleanup 209 unwind_protect_cleanup
162 if (! isempty (oldfig)) 210 if (! isempty (oldfig))
163 set (0, "currentfigure", oldfig); 211 set (0, "currentfigure", oldfig);
164 endif 212 endif
165 end_unwind_protect 213 end_unwind_protect
176 endif 224 endif
177 endif 225 endif
178 226
179 endfunction 227 endfunction
180 228
181 function tmp = bars (ax, vertical, x, y, xb, yb, width, group, have_color_spec, base_value, varargin) 229 function hglist = bars (hax, vertical, x, y, xb, yb, width, group, have_color_spec, base_value, varargin)
182 230
183 ycols = columns (y); 231 nbars = columns (y);
184 clim = get (ax, "clim"); 232 clim = get (hax, "clim");
185 tmp = []; 233 hglist = [];
186 234
187 for i = 1:ycols 235 for i = 1:nbars
188 hg = hggroup (); 236 hg = hggroup ();
189 tmp = [tmp; hg]; 237 hglist = [hglist; hg];
190 args = __add_datasource__ ("bar", hg, {"x", "y"}, varargin{:}); 238 args = __add_datasource__ ("bar", hg, {"x", "y"}, varargin{:});
191 239
192 if (vertical) 240 if (vertical)
193 if (! have_color_spec) 241 if (! have_color_spec)
194 if (ycols == 1) 242 if (nbars == 1)
195 lev = clim(1); 243 lev = clim(1);
196 else 244 else
197 lev = (i - 1) * (clim(2) - clim(1)) / (ycols - 1) - clim(1); 245 lev = (i - 1) * (clim(2) - clim(1)) / (nbars - 1) - clim(1);
198 endif 246 endif
199 h = patch (ax, xb(:,:,i), yb(:,:,i), "FaceColor", "flat", 247 h = patch (hax, xb(:,:,i), yb(:,:,i),
200 "cdata", lev, "parent", hg); 248 "FaceColor", "flat", "cdata", lev, "parent", hg);
201 else 249 else
202 h = patch (ax, xb(:,:,i), yb(:,:,i), "parent", hg); 250 h = patch (hax, xb(:,:,i), yb(:,:,i), "parent", hg);
203 endif 251 endif
204 else 252 else
205 if (! have_color_spec) 253 if (! have_color_spec)
206 if (ycols == 1) 254 if (nbars == 1)
207 lev = clim(1); 255 lev = clim(1);
208 else 256 else
209 lev = (i - 1) * (clim(2) - clim(1)) / (ycols - 1) - clim(1); 257 lev = (i - 1) * (clim(2) - clim(1)) / (nbars - 1) - clim(1);
210 endif 258 endif
211 h = patch (ax, yb(:,:,i), xb(:,:,i), "FaceColor", "flat", 259 h = patch (hax, yb(:,:,i), xb(:,:,i),
212 "cdata", lev, "parent", hg); 260 "FaceColor", "flat", "cdata", lev, "parent", hg);
213 else 261 else
214 h = patch (ax, yb(:,:,i), xb(:,:,i), "parent", hg); 262 h = patch (hax, yb(:,:,i), xb(:,:,i), "parent", hg);
215 endif 263 endif
216 endif 264 endif
217 265
218 if (i == 1) 266 if (i == 1)
219 x_axis_range = get (ax, "xlim"); 267 ## Add baseline object the first time through loop
220 h_baseline = line (ax, x_axis_range, [base_value, base_value], 268 x_axis_range = get (hax, "xlim");
221 "color", [0, 0, 0]); 269 h_baseline = line (hax, x_axis_range, [base_value, base_value],
222 set (h_baseline, "handlevisibility", "off"); 270 "color", [0, 0, 0]);
223 set (h_baseline, "xliminclude", "off"); 271 set (h_baseline, "handlevisibility", "off", "xliminclude", "off");
224 addlistener (ax, "xlim", @update_xlim); 272 set (h_baseline, "parent", get (hg, "parent"));
225 addlistener (h_baseline, "ydata", @update_baseline);
226 addlistener (h_baseline, "visible", @update_baseline);
227 endif 273 endif
228 274
229 ## Setup the hggroup and listeners 275 ## Setup the hggroup and listeners
230 addproperty ("showbaseline", hg, "radio", "{on}|off"); 276 addproperty ("showbaseline", hg, "radio", "{on}|off");
231 addproperty ("basevalue", hg, "data", base_value); 277 addproperty ("basevalue", hg, "data", base_value);
250 addlistener (hg, "barwidth", @update_group); 296 addlistener (hg, "barwidth", @update_group);
251 addlistener (hg, "barlayout", @update_group); 297 addlistener (hg, "barlayout", @update_group);
252 addlistener (hg, "horizontal", @update_group); 298 addlistener (hg, "horizontal", @update_group);
253 299
254 addproperty ("edgecolor", hg, "patchedgecolor", get (h, "edgecolor")); 300 addproperty ("edgecolor", hg, "patchedgecolor", get (h, "edgecolor"));
301 addproperty ("facecolor", hg, "patchfacecolor", get (h, "facecolor"));
302 addproperty ("linestyle", hg, "patchlinestyle", get (h, "linestyle"));
255 addproperty ("linewidth", hg, "patchlinewidth", get (h, "linewidth")); 303 addproperty ("linewidth", hg, "patchlinewidth", get (h, "linewidth"));
256 addproperty ("linestyle", hg, "patchlinestyle", get (h, "linestyle"));
257 addproperty ("facecolor", hg, "patchfacecolor", get (h, "facecolor"));
258 304
259 addlistener (hg, "edgecolor", @update_props); 305 addlistener (hg, "edgecolor", @update_props);
306 addlistener (hg, "facecolor", @update_props);
307 addlistener (hg, "linestyle", @update_props);
260 addlistener (hg, "linewidth", @update_props); 308 addlistener (hg, "linewidth", @update_props);
261 addlistener (hg, "linestyle", @update_props);
262 addlistener (hg, "facecolor", @update_props);
263 309
264 if (isvector (x)) 310 if (isvector (x))
265 addproperty ("xdata", hg, "data", x); 311 addproperty ("xdata", hg, "data", x);
266 else 312 else
267 addproperty ("xdata", hg, "data", x(:, i)); 313 addproperty ("xdata", hg, "data", x(:, i));
270 316
271 addlistener (hg, "xdata", @update_data); 317 addlistener (hg, "xdata", @update_data);
272 addlistener (hg, "ydata", @update_data); 318 addlistener (hg, "ydata", @update_data);
273 319
274 addproperty ("bargroup", hg, "data"); 320 addproperty ("bargroup", hg, "data");
275 set (tmp, "bargroup", tmp); 321 set (hglist, "bargroup", hglist);
276 if (! isempty (args)) 322 if (! isempty (args))
277 set (hg, args{:}); 323 set (hg, args{:});
278 endif 324 endif
279 if (i == 1)
280 set (h_baseline, "parent", get (hg, "parent"));
281 endif
282 endfor 325 endfor
283 326
284 update_xlim (ax, []); 327 update_xlim (hax, []);
285 endfunction 328 ## Add listeners outside of for loop to prevent constant updating during
286 329 ## creation of plot when patch objects are added.
287 function update_xlim (h, d) 330 addlistener (hax, "xlim", @update_xlim);
331 addlistener (h_baseline, "ydata", @update_baseline);
332 addlistener (h_baseline, "visible", @update_baseline);
333
334 endfunction
335
336 function update_xlim (h, ~)
288 kids = get (h, "children"); 337 kids = get (h, "children");
289 xlim = get (h, "xlim"); 338 xlim = get (h, "xlim");
290 339
291 for i = 1 : length (kids) 340 for i = 1 : length (kids)
292 obj = get (kids (i)); 341 obj = get (kids(i));
293 if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline")) 342 if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline"))
294 if (any (get (obj.baseline, "xdata") != xlim)) 343 if (any (get (obj.baseline, "xdata") != xlim))
295 set (obj.baseline, "xdata", xlim); 344 set (obj.baseline, "xdata", xlim);
296 endif 345 endif
297 endif 346 endif
298 endfor 347 endfor
299 endfunction 348 endfunction
300 349
301 function update_baseline (h, d) 350 function update_baseline (h, ~)
302 visible = get (h, "visible"); 351 visible = get (h, "visible");
303 ydata = get (h, "ydata")(1); 352 ydata = get (h, "ydata")(1);
304 353
354 ## Search axis for a bargroup that contains this baseline handle
305 kids = get (get (h, "parent"), "children"); 355 kids = get (get (h, "parent"), "children");
306 for i = 1 : length (kids) 356 for i = 1 : length (kids)
307 obj = get (kids (i)); 357 obj = get (kids(i));
308 if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline") 358 if (strcmp (obj.type, "hggroup") && isfield (obj, "baseline")
309 && obj.baseline == h) 359 && obj.baseline == h)
310 ## Only alter if changed to avoid recursion of the listener functions 360 set (obj.bargroup, "showbaseline", visible, "basevalue", ydata);
311 if (! strcmpi (get (kids(i), "showbaseline"), visible)) 361 break;
312 set (kids (i), "showbaseline", visible);
313 endif
314 if (! strcmpi (get (kids(i), "basevalue"), visible))
315 set (kids (i), "basevalue", ydata);
316 endif
317 endif 362 endif
318 endfor 363 endfor
319 endfunction 364 endfunction
320 365
321 function show_baseline (h, d, prop = "") 366 function show_baseline (h, ~, prop = "")
322 persistent recursion = false; 367 persistent recursion = false;
323 368
324 ## Don't allow recursion 369 ## Don't allow recursion
325 if (! recursion) 370 if (! recursion)
326 unwind_protect 371 unwind_protect
327 recursion = true; 372 recursion = true;
328 hlist = get (h, "bargroup"); 373 hlist = get (h, "bargroup");
329 if (strcmp (prop, "showbl")) 374 if (strcmp (prop, "showbl"))
330 showbaseline = get (h, "showbaseline"); 375 showbaseline = get (h, "showbaseline");
331 for hh = hlist(:)' 376 hlist = hlist(hlist != h); # remove current handle being updated
332 if (hh != h) 377 set (hlist, "showbaseline", showbaseline);
333 set (hh, "showbaseline", showbaseline);
334 endif
335 endfor
336 elseif (strcmp (prop, "visib")) 378 elseif (strcmp (prop, "visib"))
337 showbaseline = "on"; 379 showbaseline = "on";
338 if (all (strcmp (get (hlist, "visible"), "off"))) 380 if (all (strcmp (get (hlist, "visible"), "off")))
339 showbaseline = "off"; 381 showbaseline = "off";
340 endif 382 endif
344 recursion = false; 386 recursion = false;
345 end_unwind_protect 387 end_unwind_protect
346 endif 388 endif
347 endfunction 389 endfunction
348 390
349 function move_baseline (h, d) 391 function move_baseline (h, ~)
350 b0 = get (h, "basevalue"); 392 persistent recursion = false;
351 bl = get (h, "baseline"); 393
352 394 ## Don't allow recursion
353 if (get (bl, "ydata") != [b0, b0]) 395 if (! recursion)
354 set (bl, "ydata", [b0, b0]); 396 recursion = true;
355 endif 397 unwind_protect
356 398 b0 = get (h, "basevalue");
357 if (strcmpi (get (h, "barlayout"), "grouped")) 399 bl = get (h, "baseline");
358 update_data (h, d); 400 set (bl, "ydata", [b0, b0]);
359 endif 401
360 endfunction 402 if (strcmp (get (h, "barlayout"), "grouped"))
361 403 update_data (h);
362 function update_props (h, d) 404 endif
405 unwind_protect_cleanup
406 recursion = false;
407 end_unwind_protect
408 endif
409 endfunction
410
411 function update_props (h, ~)
363 kids = get (h, "children"); 412 kids = get (h, "children");
364 set (kids, "edgecolor", get (h, "edgecolor"), 413 set (kids, {"edgecolor", "linewidth", "linestyle", "facecolor"},
365 "linewidth", get (h, "linewidth"), 414 get (h, {"edgecolor", "linewidth", "linestyle", "facecolor"}));
366 "linestyle", get (h, "linestyle"), 415 endfunction
367 "facecolor", get (h, "facecolor")); 416
368 endfunction 417 function update_data (h, ~)
369
370 function update_data (h, d)
371 persistent recursion = false; 418 persistent recursion = false;
372 419
373 ## Don't allow recursion 420 ## Don't allow recursion
374 if (! recursion) 421 if (! recursion)
375 unwind_protect 422 unwind_protect
376 recursion = true; 423 recursion = true;
377 hlist = get (h, "bargroup"); 424 hlist = get (h, "bargroup");
378 x = get (h, "xdata"); 425 x = get (h, "xdata");
379 if (!isvector (x)) 426 if (! isvector (x))
380 x = x(:); 427 x = x(:);
381 endif 428 endif
382 y = []; 429 ydat = get (hlist, "ydata");
383 for hh = hlist(:)' 430 if (iscell (ydat))
384 ytmp = get (hh, "ydata"); 431 y = cell2mat (ydat.');
385 y = [y ytmp(:)]; 432 else
386 endfor 433 y = ydat;
434 endif
387 435
388 [xb, yb] = bar (x, y, get (h, "barwidth"), get (h, "barlayout"), 436 [xb, yb] = bar (x, y, get (h, "barwidth"), get (h, "barlayout"),
389 "basevalue", get (h, "basevalue")); 437 "basevalue", get (h, "basevalue"));
390 ny = columns (y); 438
391 vert = strcmpi (get (h, "horizontal"), "off"); 439 vertical = strcmp (get (h, "horizontal"), "off");
392 440 for i = 1:columns (y)
393 for i = 1:ny
394 hp = get (hlist(i), "children"); 441 hp = get (hlist(i), "children");
395 if (vert) 442 if (vertical)
396 set (hp, "xdata", xb(:,:,i), "ydata", yb(:,:,i)); 443 set (hp, "xdata", xb(:,:,i), "ydata", yb(:,:,i));
397 else 444 else
398 set (hp, "xdata", yb(:,:,i), "ydata", xb(:,:,i)); 445 set (hp, "xdata", yb(:,:,i), "ydata", xb(:,:,i));
399 endif 446 endif
400 endfor 447 endfor
402 recursion = false; 449 recursion = false;
403 end_unwind_protect 450 end_unwind_protect
404 endif 451 endif
405 endfunction 452 endfunction
406 453
407 function update_group (h, d) 454 function update_group (h, ~)
408 persistent recursion = false; 455 persistent recursion = false;
409 456
410 ## Don't allow recursion 457 ## Don't allow recursion
411 if (! recursion) 458 if (! recursion)
412 unwind_protect 459 unwind_protect
414 hlist = get (h, "bargroup"); 461 hlist = get (h, "bargroup");
415 barwidth = get (h, "barwidth"); 462 barwidth = get (h, "barwidth");
416 barlayout = get (h, "barlayout"); 463 barlayout = get (h, "barlayout");
417 horizontal = get (h, "horizontal"); 464 horizontal = get (h, "horizontal");
418 465
419 ## To prevent recursion, only change if modified 466 hlist = hlist(hlist != h); # remove current handle being updated
420 for hh = hlist(:)' 467 set (hlist, "barwidth", barwidth, "barlayout", barlayout,
421 if (hh != h) 468 "horizontal", horizontal);
422 if (get (hh, "barwidth") != barwidth) 469 update_data (h);
423 set (hh, "barwidth", barwidth);
424 endif
425 if (! strcmpi (get (hh, "barlayout"), barlayout))
426 set (hh, "barlayout", barlayout);
427 endif
428 if (! strcmpi (get (hh, "horizontal"), horizontal))
429 set (hh, "horizontal", horizontal);
430 endif
431 endif
432 endfor
433 update_data (h, d);
434 unwind_protect_cleanup 470 unwind_protect_cleanup
435 recursion = false; 471 recursion = false;
436 end_unwind_protect 472 end_unwind_protect
437 endif 473 endif
438 endfunction 474 endfunction