1 ## Copyright (C) 2007-2012 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{hg} =} __scatter__ (@dots{})
21 ## Undocumented internal function.
24 function hg = __scatter__ (varargin)
35 idx = isnan(x) | isnan (y) | isnan (z);
41 idx = isnan(x) | isnan (y);
44 z = zeros (length (x), 0);
47 firstnonnumeric = Inf;
49 if (! isnumeric (varargin{i}))
57 if (isempty (s) || ischar (s))
60 if (! ischar (varargin{istart}))
67 if (istart <= nargin && firstnonnumeric > istart)
74 elseif (firstnonnumeric == istart && ischar (varargin{istart})
75 && ! strcmpi (varargin{istart}, "filled"))
86 iarg = firstnonnumeric;
87 while (iarg <= nargin)
88 arg = varargin{iarg++};
89 if (ischar (arg) && strncmpi (arg, "filled", 6))
91 elseif ((ischar (arg) || iscell (arg)) && ! have_marker)
92 [linespec, valid] = __pltopt__ (fcn, arg, false);
95 marker = linespec.marker;
96 if (strncmp (marker, "none", 4))
98 elseif (isempty (marker))
100 [dummy, marker] = __next_line_style__ ();
103 error ("%s: invalid linespec", fcn);
106 newargs{end+1} = arg;
108 newargs{end+1} = varargin{iarg++};
114 c = __next_line_color__();
118 newargs = __add_datasource__ (fcn, hg, {"x", "y", "z", "c", "size"},
121 addproperty ("xdata", hg, "data", x);
122 addproperty ("ydata", hg, "data", y);
123 addproperty ("zdata", hg, "data", z);
125 addproperty ("cdata", hg, "data", __color_str_rgb__ (c));
127 addproperty ("cdata", hg, "data", c);
129 addproperty ("sizedata", hg, "data", s);
130 addlistener (hg, "xdata", @update_data);
131 addlistener (hg, "ydata", @update_data);
132 addlistener (hg, "zdata", @update_data);
133 addlistener (hg, "cdata", @update_data);
134 addlistener (hg, "sizedata", @update_data);
136 one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
138 if (numel (x) <= 100)
140 ## For small number of points, we'll construct an object for each point.
143 s = repmat (s, numel(x), 1);
146 if (one_explicit_color)
147 for i = 1 : numel (x)
149 h = __go_patch__ (hg, "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
150 "faces", 1, "vertices", [x(i), y(i), z(i,:)],
151 "facecolor", "none", "edgecolor", "none",
152 "marker", marker, "markersize", s(i),
153 "markeredgecolor", c, "markerfacecolor", c,
154 "linestyle", "none");
156 h = __go_patch__ (hg, "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
157 "faces", 1, "vertices", [x(i), y(i), z(i,:)],
158 "facecolor", "none", "edgecolor", "none",
159 "marker", marker, "markersize", s(i),
160 "markeredgecolor", c, "markerfacecolor", "none",
161 "linestyle", "none");
166 c = ones (rows (x), 1) * c;
168 for i = 1 : numel (x)
170 h = __go_patch__ (hg, "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
171 "faces", 1, "vertices", [x(i), y(i), z(i,:)],
172 "facecolor", "none", "edgecolor", "none",
173 "marker", marker, "markersize", s(i),
174 "markeredgecolor", "none",
175 "markerfacecolor", "flat",
176 "cdata", c(i,:), "facevertexcdata", c(i,:),
177 "linestyle", "none");
179 h = __go_patch__ (hg, "xdata", x(i), "ydata", y(i), "zdata", z(i,:),
180 "faces", 1, "vertices", [x(i), y(i), z(i,:)],
181 "facecolor", "none", "edgecolor", "none",
182 "marker", marker, "markersize", s(i),
183 "markeredgecolor", "flat",
184 "markerfacecolor", "none",
185 "cdata", c(i,:), "facevertexcdata", c(i,:),
186 "linestyle", "none");
194 ## For larger numbers of points, we split the points by common color.
197 if (one_explicit_color)
198 h = render_size_color (hg, vert, s, c, marker, filled, true);
201 c = ones (rows (x), 1) * c;
203 ## We want to group points by colour. So first get all the unique colours
204 [cc, ~, c_to_cc] = unique (c, "rows");
207 ## Now for each possible unique colour, get the logical index of
208 ## points that correspond to that colour
209 idx = (i == c_to_cc);
211 h = render_size_color (hg, vert(idx, :), s, c(idx,:),
212 marker, filled, true);
214 h = render_size_color (hg, vert(idx, :), s(idx), c(idx,:),
215 marker, filled, true);
222 if (! ischar (c) && rows (c) > 1)
223 ax = get (hg, "parent");
224 clim = get (ax, "clim");
225 if (min(c(:)) < clim(1))
227 set (ax, "clim", clim);
229 if (max(c(:)) > clim(2))
230 set (ax, "clim", [clim(1), max(c(:))]);
234 addproperty ("linewidth", hg, "patchlinewidth", 0.5);
235 addproperty ("marker", hg, "patchmarker", marker);
237 addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "none");
238 if (one_explicit_color)
239 addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", c);
241 addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "flat");
244 addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "none");
245 if (one_explicit_color)
246 addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", c);
248 addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "flat");
251 addlistener (hg, "linewidth", @update_props);
252 addlistener (hg, "marker", @update_props);
253 addlistener (hg, "markerfacecolor", @update_props);
254 addlistener (hg, "markeredgecolor", @update_props);
256 if (! isempty (newargs))
257 set (hg, newargs{:});
262 function h = render_size_color(hg, vert, s, c, marker, filled, isflat)
267 toolkit = get (ancestor (hg, "figure"), "__graphics_toolkit__");
268 ## Does gnuplot only support triangles with different vertex colors ?
269 ## TODO - Verify gnuplot can only support one color. If RGB triplets
270 ## can be assigned to each vertex, then fix __go_draw_axe__.m
271 gnuplot_hack = numel (x) > 1 && strcmp (toolkit, "gnuplot");
272 if (ischar (c) || ! isflat || gnuplot_hack)
274 h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z,
275 "faces", 1:numel(x), "vertices", vert,
276 "facecolor", "none", "edgecolor", "none",
278 "markeredgecolor", "none",
279 "markerfacecolor", c(1,:),
280 "markersize", s, "linestyle", "none");
282 h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z,
283 "faces", 1:numel(x), "vertices", vert,
284 "facecolor", "none", "edgecolor", "none",
286 "markeredgecolor", c(1,:),
287 "markerfacecolor", "none",
288 "markersize", s, "linestyle", "none");
292 h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z,
293 "faces", 1:numel(x), "vertices", vert,
294 "facecolor", "none", "edgecolor", "none",
295 "marker", marker, "markersize", s,
296 "markeredgecolor", "none",
297 "markerfacecolor", "flat",
298 "cdata", c, "facevertexcdata", c,
299 "linestyle", "none");
301 h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z,
302 "faces", 1:numel(x), "vertices", vert,
303 "facecolor", "none", "edgecolor", "none",
304 "marker", marker, "markersize", s,
305 "markeredgecolor", "flat",
306 "markerfacecolor", "none",
307 "cdata", c, "facevertexcdata", c,
308 "linestyle", "none");
312 ## FIXME: round the size to one decimal place. It's not quite right, though.
313 [ss, ~, s_to_ss] = unique (ceil (s*10) / 10);
315 idx = (i == s_to_ss);
316 h = render_size_color (hg, vert(idx,:), ss(i), c,
317 marker, filled, isflat);
322 function update_props (h, d)
323 lw = get (h, "linewidth");
324 m = get (h, "marker");
325 fc = get (h, "markerfacecolor");
326 ec = get (h, "markeredgecolor");
327 kids = get (h, "children");
329 for i = 1 : numel (kids)
330 set (kids (i), "linewidth", lw, "marker", m, "markerfacecolor", fc,
335 function update_data (h, d)
336 x1 = get (h, "xdata");
337 y1 = get (h, "ydata");
338 z1 = get (h, "zdata");
339 c1 = get (h, "cdata");
340 if (!ischar (c1) && rows (c1) == 1)
341 c1 = repmat (c1, numel (x1), 1);
343 size1 = get (h, "sizedata");
344 if (numel (size1) == 1)
345 size1 = repmat (size1, numel (x1), 1);
347 hlist = get (h, "children");
350 for i = 1 : length (hlist)
351 set (hlist(i), "vertices", [x1(i), y1(i)], "cdata", c1,
352 "markersize", size1(i));
355 for i = 1 : length (hlist)
356 set (hlist(i), "vertices", [x1(i), y1(i), z1(i)], "cdata", c1,
357 "markersize", size1(i));
362 for i = 1 : length (hlist)
363 set (hlist(i), "vertices", [x1(i), y1(i)], "cdata",
364 reshape(c1(i,:),[1, size(c1)(2:end)]),
365 "facevertexcdata", c1(i,:),
366 "markersize", size1(i));
369 for i = 1 : length (hlist)
370 set (hlist(i), "vertices", [x1(i), y1(i), z1(i)], "cdata",
371 reshape(c1(i,:),[1, size(c1)(2:end)]),
372 "facevertexcdata", c1(i,:),
373 "markersize", size1(i));