Fix test for setting of datasource properties. Add the edgecolor property to contours
1 ## Copyright (C) 2007, 2008, 2009 David Bateman
3 ## This file is part of Octave.
5 ## Octave is free software; you can redistribute it and/or modify it
6 ## under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 3 of the License, or (at
8 ## your option) any later version.
10 ## Octave is distributed in the hope that it will be useful, but
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ## General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with Octave; see the file COPYING. If not, see
17 ## <http://www.gnu.org/licenses/>.
20 ## @deftypefn {Function File} {[@var{c}, @var{hg}] =} __contour__ (@dots{})
21 ## Undocumented internal function.
24 function [c, hg] = __contour__ (varargin)
29 linespec.linestyle = "-";
30 linespec.color = "auto";
34 if ((ischar (arg) || iscell (arg)))
35 [linespec, valid] = __pltopt__ ("__contour__", arg, false);
36 if (isempty (linespec.color))
37 linespec.color = "auto";
40 have_line_spec = true;
49 while (i < length (varargin))
50 if (ischar (varargin {i}))
51 if (strcmpi (varargin{i}, "fill"))
52 filled = varargin {i + 1};
54 elseif (strcmpi (varargin{i}, "linecolor"))
55 linespec.color = varargin {i + 1};
56 edgecolor = linespec.color;
57 if (ischar (edgecolor) && strcmpi (edgecolor, "auto"))
61 elseif (strcmpi (varargin{i}, "edgecolor"))
62 linespec.color = varargin {i + 1};
63 edgecolor = linespec.color;
64 if (ischar (edgecolor) && strcmpi (edgecolor, "flat"))
65 linespec.color = "auto";
69 opts{end+1} = varargin{i};
71 opts{end+1} = varargin{i};
79 if (length(varargin) < 5)
88 if (length (varargin) == 4 || length (varargin) == 6)
97 lvl = linspace (min (z1(!isinf(z1))), max (z1(!isinf(z1))),
103 if (strcmpi (filled, "on"))
104 if (isvector (x1) || isvector (y1))
105 [x1, y1] = meshgrid (x1, y1);
107 [nr, nc] = size (z1);
108 x0 = prepad(x1, nc+1, 2 * x1(1, 1) - x1(1, 2), 2);
109 x0 = postpad(x0, nc+2, 2 * x1(1, nc) - x1(1, nc - 1), 2);
110 x0 = [x0(1, :); x0; x0(1, :)];
111 y0 = prepad(y1, nr+1, 2 * y1(1, 1) - y1(2, 1), 1);
112 y0 = postpad(y0, nr+2, 2 * y1(nr, 1) - y1(nr - 1, 1));
113 y0 = [y0(:, 1), y0, y0(:, 1)];
114 z0 = -Inf(nr+2, nc+2);
115 z0(2:nr+1, 2:nc+1) = z1;
116 [c, lev] = contourc (x0, y0, z0, lvl);
118 [c, lev] = contourc (x1, y1, z1, lvl);
122 opts = __add_datasource__ ("__countour__", hg, {"x", "y", "z"}, opts{:});
124 addproperty ("xdata", hg, "data", x1);
125 addproperty ("ydata", hg, "data", y1);
126 addproperty ("zdata", hg, "data", z1);
127 addproperty ("contourmatrix", hg, "data", c);
129 addlistener (hg, "xdata", @update_data);
130 addlistener (hg, "ydata", @update_data);
131 addlistener (hg, "zdata", @update_data);
132 addlistener (hg, "contourmatrix", @update_data);
134 addproperty ("fill", hg, "radio", "on|{off}", filled);
136 ## The properties zlevel and zlevelmode don't exist in matlab, but
137 ## allow the use of contourgroups with the contour3, meshc and surfc
139 if (isnumeric (zlevel))
140 addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", "manual")
141 addproperty ("zlevel", hg, "data", zlevel);
143 addproperty ("zlevelmode", hg, "radio", "{none}|auto|manual", zlevel)
144 if (ischar (zlevel) && strcmpi (zlevel, "manual"))
146 z = 2 * (min (z(:)) - max (z(:)));
147 addproperty ("zlevel", hg, "data", z);
149 addproperty ("zlevel", hg, "data", 0.);
153 lvlstep = sum (abs (diff (lvl))) / (length (lvl) - 1);
155 addproperty ("levellist", hg, "data", lev);
156 addproperty ("levelstep", hg, "double", lvlstep);
158 addproperty ("levellistmode", hg, "radio", "{auto}|manual", "auto");
159 addproperty ("levelstepmode", hg, "radio", "{auto}|manual", "auto");
160 elseif (isscalar (vn))
161 addproperty ("levellistmode", hg, "radio", "{auto}|manual", "auto");
162 addproperty ("levelstepmode", hg, "radio", "{auto}|manual", "manual");
164 addproperty ("levellistmode", hg, "radio", "{auto}|manual", "manual");
165 addproperty ("levelstepmode", hg, "radio", "{auto}|manual", "auto");
168 addproperty ("labelspacing", hg, "double", 144);
169 addproperty ("textlist", hg, "data", lev);
170 addproperty ("textlistmode", hg, "radio", "{auto}|manual", "auto");
171 addproperty ("textstep", hg, "double", lvlstep);
172 addproperty ("textstepmode", hg, "radio", "{auto}|manual", "auto");
173 addproperty ("showtext", hg, "radio", "on|{off}", "off");
175 addproperty ("linecolor", hg, "color", linespec.color, "{auto}|none");
176 addproperty ("linestyle", hg, "linelinestyle", linespec.linestyle);
177 addproperty ("linewidth", hg, "linelinewidth", 0.5);
179 ## FIXME It would be good to hide this property which is just an undocumented
180 ## alias for linecolor
181 addproperty ("edgecolor", hg, "color", edgecolor, "{flat}|none");
183 addlistener (hg, "fill", @update_data);
185 addlistener (hg, "zlevelmode", @update_zlevel);
186 addlistener (hg, "zlevel", @update_zlevel);
188 addlistener (hg, "levellist", @update_data);
189 addlistener (hg, "levelstep", @update_data);
190 addlistener (hg, "levellistmode", @update_data);
191 addlistener (hg, "levelstepmode", @update_data);
193 addlistener (hg, "labelspacing", @update_text);
194 addlistener (hg, "textlist", @update_text);
195 addlistener (hg, "textlistmode", @update_text);
196 addlistener (hg, "textstep", @update_text);
197 addlistener (hg, "textstepmode", @update_text);
198 addlistener (hg, "showtext", @update_text);
200 addlistener (hg, "linecolor", @update_line);
201 addlistener (hg, "linestyle", @update_line);
202 addlistener (hg, "linewidth", @update_line);
204 addlistener (hg, "edgecolor", @update_edgecolor);
206 add_patch_children (hg);
213 function add_patch_children (hg)
214 c = get (hg, "contourmatrix");
215 lev = get (hg, "levellist");
216 fill = get (hg, "fill");
217 z = get (hg, "zlevel");
218 zmode = get (hg, "zlevelmode");
219 lc = get (hg, "linecolor");
220 lw = get (hg, "linewidth");
221 ls = get (hg, "linestyle");
222 filled = get (hg, "fill");
224 if (strcmpi (lc, "auto"))
228 if (strcmpi (filled, "on"))
229 if (diff (lev) < 10*eps)
232 lvl_eps = min (diff (lev)) / 1000.0;
235 ## Decode contourc output format.
238 while (i1 < columns (c))
240 cont_lev(ncont) = c(1, i1);
241 cont_len(ncont) = c(2, i1);
242 cont_idx(ncont) = i1+1;
244 ii = i1+1:i1+cont_len(ncont);
248 cont_area(ncont) = polyarea (c(1, ii), c(2, ii));
252 ## Handle for each level the case where we have (a) hole(s) in a patch.
253 ## Those are to be filled with the color of level below or with the
254 ## background colour.
255 for k = 1:numel (lev)
256 lvl_idx = find (abs (cont_lev - lev(k)) < lvl_eps);
257 len = numel (lvl_idx);
259 ## mark = logical(zeros(size(lvl_idx)));
260 mark = false (size (lvl_idx));
266 ## get pointer to contour start, and contour length
267 curr_ct_idx = cont_idx(pa_idx);
268 curr_ct_len = cont_len(pa_idx);
270 curr_ct = c(:, curr_ct_idx:curr_ct_idx+curr_ct_len-1);
272 next_ct_pt_vec = c(:, cont_idx(lvl_idx(b_vec)));
273 in = inpolygon (next_ct_pt_vec(1,:), next_ct_pt_vec(2,:),
274 curr_ct(1, :), curr_ct(2, :));
275 mark(b_vec(in)) = !mark(b_vec(in));
278 if (numel (mark) > 0)
279 ## All marked contours describe a hole in a larger contour of
280 ## the same level and must be filled with colour of level below.
281 ma_idx = lvl_idx(mark);
283 ## Find color of level below.
284 tmp = find(abs(cont_lev - lev(k - 1)) < lvl_eps);
285 lvl_bel_idx = tmp(1);
286 ## Set color of patches found.
287 cont_lev(ma_idx) = cont_lev(lvl_bel_idx);
289 ## Set lowest level contour to NaN.
290 cont_lev(ma_idx) = NaN;
296 ## The algorithm can create patches with the size of the plotting
297 ## area, we would like to draw only the patch with the highest level.
299 max_idx = find (cont_area == max (cont_area));
300 if (numel (max_idx) > 1)
301 ## delete double entries
302 del_idx = max_idx(1:end-1);
303 cont_area(del_idx) = cont_lev(del_idx) = [];
304 cont_len(del_idx) = cont_idx(del_idx) = [];
307 ## Now we have everything together and can start plotting the patches
308 ## beginning with largest area.
309 [tmp, svec] = sort (cont_area);
310 len = ncont - numel (del_idx);
314 ctmp = c(:, cont_idx(idx):cont_idx(idx) + cont_len(idx) - 1);
315 if (all (ctmp(:,1) == ctmp(:,end)))
318 ## Special case unclosed contours
320 h = [h; patch(ctmp(1, :), ctmp(2, :), cont_lev(idx), "edgecolor", lc,
321 "linestyle", ls, "linewidth", lw, "parent", hg)];
324 if (min (lev) == max (lev))
325 set (gca (), "clim", [min(lev)-1, max(lev)+1]);
327 set (gca(), "clim", [min(lev), max(lev)]);
330 set (gca (), "layer", "top");
332 ## Decode contourc output format.
335 while (i1 < length (c))
339 if (all (c(:,i1+1) == c(:,i1+clen)))
340 p = c(:, i1+1:i1+clen-1);
342 p = [c(:, i1+1:i1+clen), NaN(2, 1)];
347 h = [h; patch(p(1,:), p(2,:), "facecolor", "none",
348 "edgecolor", lc, "linestyle", ls, "linewidth", lw,
349 "cdata", clev, "parent", hg)];
351 h = [h; patch(p(1,:), p(2,:), clev * ones (1, columns (p)),
352 "facecolor", "none", "edgecolor", lc,
353 "linestyle", ls, "linewidth", lw, "cdata", clev,
356 h = [h; patch(p(1,:), p(2,:), z * ones (1, columns (p)),
357 "facecolor", "none", "edgecolor", lc,
358 "linestyle", ls, "linewidth", lw, "cdata", clev,
367 function update_zlevel (h, d)
368 z = get (h, "zlevel");
369 zmode = get (h, "zlevelmode");
370 kids = get (h, "children");
374 set (kids, "zdata", []);
376 for i = 1 : length (kids)
377 set (kids(i), "zdata", get (kids (i), "cdata") .*
378 ones (size (get (kids (i), "xdata"))));
381 for i = 1 : length (kids)
382 set (kids(i), "zdata", z .* ones (size (get (kids (i), "xdata"))));
387 function update_edgecolor (h, d)
388 ec = get (h, "edgecolor");
389 lc = get (h, "linecolor");
390 if (ischar (ec) && strcmpi (ec, "flat"))
391 if (! strcmpi (lc, "auto"))
392 set (h, "linecolor", "auto");
394 elseif (! isequal (ec, lc))
395 set (h, "linecolor", ec);
399 function update_line (h, d)
400 lc = get (h, "linecolor");
401 ec = get (h, "edgecolor");
402 if (strcmpi (lc, "auto"))
405 if (! isequal (ec, lc))
406 set (h, "edgecolor", lc);
408 set (findobj (h, "type", "patch"), "edgecolor", lc,
409 "linewidth", get (h, "linewidth"), "linestyle", get (h, "linestyle"));
412 function update_data (h, d)
413 persistent recursive = false;
418 delete (get (h, "children"));
420 if (strcmpi (get (h, "levellistmode"), "manual"))
421 lvl = get (h, "levellist");
422 elseif (strcmpi (get (h, "levelstepmode"), "manual"))
423 z = get (h, "zdata");
424 lvl = ceil ((max(z(:)) - min (z(:)) ./ get (h, "levelstep")));
429 if (strcmpi (get (h, "fill"), "on"))
430 X = get (h, "xdata");
431 Y = get (h, "ydata");
432 Z = get (h, "zdata");
433 if (isvector (X) || isvector (Y))
434 [X, Y] = meshgrid (X, Y);
437 X0 = prepad(X, nc+1, 2 * X(1, 1) - X(1, 2), 2);
438 X0 = postpad(X0, nc+2, 2 * X(1, nc) - X(1, nc - 1), 2);
439 X0 = [X0(1, :); X0; X0(1, :)];
440 Y0 = prepad(Y, nr+1, 2 * Y(1, 1) - Y(2, 1), 1);
441 Y0 = postpad(Y0, nr+2, 2 * Y(nr, 1) - Y(nr - 1, 1));
442 Y0 = [Y0(:, 1), Y0, Y0(:, 1)];
443 Z0 = -Inf(nr+2, nc+2);
444 Z0(2:nr+1, 2:nc+1) = Z;
445 [c, lev] = contourc (X0, Y0, Z0, lvl);
447 [c, lev] = contourc (get (h, "xdata"), get (h, "ydata"),
448 get (h, "zdata"), lvl);
450 set (h, "contourmatrix", c);
452 if (strcmpi (get (h, "levellistmode"), "manual"))
454 elseif (strcmpi (get (h, "levelstepmode"), "manual"))
455 set (h, "levellist", lev);
457 set (h, "levellist", lev);
458 z = get (h, "zdata");
459 lvlstep = (max(z(:)) - min(z(:))) / 10;
460 set (h, "levelstep", lvlstep);
463 add_patch_children (h);
470 function update_text (h, d)
471 persistent recursive = false;
476 delete (findobj (h, "type", "text"));
478 if (strcmpi (get (h, "textlistmode"), "manual"))
479 lvl = get (h, "textlist");
480 elseif (strcmpi (get (h, "textstepmode"), "manual"))
481 lev = get (h, "levellist");
483 if (diff (lev) < 10*eps)
486 lvl_eps = min (abs (diff (lev))) / 1000.0;
489 stp = get (h, "textstep");
490 t = [0, floor(cumsum(diff (lev)) / (abs(stp) - lvl_eps))];
491 lvl = lev([true, t(1:end-1) != t(2:end)]);
492 set (h, "textlist", lvl);
494 lvl = get (h, "levellist");
495 set (h, "textlist", lvl, "textstep", get (h, "levelstep"));
498 if (strcmpi (get (h, "showtext"), "on"))
499 switch (get (h, "zlevelmode"))
501 __clabel__ (get (h, "contourmatrix"), lvl, h,
502 get (h, "labelspacing"), get (h, "zlevel"));
504 __clabel__ (get (h, "contourmatrix"), lvl, h,
505 get (h, "labelspacing"), "auto");
507 __clabel__ (get (h, "contourmatrix"), lvl, h,
508 get (h, "labelspacing"), []);