]> Creatis software - CreaPhase.git/blob - octave_packages/m/plot/private/__scatter__.m
update packages
[CreaPhase.git] / octave_packages / m / plot / private / __scatter__.m
1 ## Copyright (C) 2007-2012 David Bateman
2 ##
3 ## This file is part of Octave.
4 ##
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.
9 ##
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.
14 ##
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/>.
18
19 ## -*- texinfo -*-
20 ## @deftypefn {Function File} {@var{hg} =} __scatter__ (@dots{})
21 ## Undocumented internal function.
22 ## @end deftypefn
23
24 function hg = __scatter__ (varargin)
25
26   h = varargin{1};
27   nd = varargin{2};
28   fcn = varargin{3};
29   x = varargin{4}(:);
30   y = varargin{5}(:);
31   istart = 6;
32
33   if (nd == 3)
34     z = varargin{6}(:);
35     idx = isnan(x) | isnan (y) | isnan (z);
36     x (idx) = [];
37     y (idx) = [];
38     z (idx) = [];
39     istart = 7;
40   else
41     idx = isnan(x) | isnan (y);
42     x (idx) = [];
43     y (idx) = [];
44     z = zeros (length (x), 0);
45   endif
46
47   firstnonnumeric = Inf;
48   for i = istart:nargin
49     if (! isnumeric (varargin{i}))
50       firstnonnumeric = i;
51       break;
52     endif
53   endfor
54
55   if (istart <= nargin)
56     s = varargin{istart};
57     if (isempty (s) || ischar (s))
58       s = 6;
59     endif
60     if (! ischar (varargin{istart}))
61       istart++;
62     endif
63   else
64     s = 6;
65   endif
66
67   if (istart <= nargin && firstnonnumeric > istart)
68     c = varargin{istart};
69     if (isvector (c))
70       if (columns (c) != 3)
71         c = c(:);
72       endif
73     endif
74   elseif (firstnonnumeric == istart && ischar (varargin{istart})
75           && ! strcmpi (varargin{istart}, "filled"))
76     c = varargin{istart};
77     firstnonnumeric++;
78   else
79     c = [];
80   endif
81
82   newargs = {};
83   filled = false;
84   have_marker = false;
85   marker = "o";
86   iarg = firstnonnumeric;
87   while (iarg <= nargin)
88     arg = varargin{iarg++};
89     if (ischar (arg) && strncmpi (arg, "filled", 6))
90       filled = true;
91     elseif ((ischar (arg) || iscell (arg)) && ! have_marker)
92       [linespec, valid] = __pltopt__ (fcn, arg, false);
93       if (valid)
94         have_marker = true;
95         marker = linespec.marker;
96         if (strncmp (marker, "none", 4))
97           marker = "o";
98         elseif (isempty (marker))
99           have_marker = false;
100           [dummy, marker] = __next_line_style__ ();
101         endif
102       else
103         error ("%s: invalid linespec", fcn);
104       endif
105     else
106       newargs{end+1} = arg;
107       if (iarg <= nargin)
108         newargs{end+1} = varargin{iarg++};
109       endif
110     endif
111   endwhile
112
113   if (isempty (c))
114     c = __next_line_color__();
115   endif
116
117   hg = hggroup ();
118   newargs = __add_datasource__ (fcn, hg, {"x", "y", "z", "c", "size"},
119                              newargs{:});
120
121   addproperty ("xdata", hg, "data", x);
122   addproperty ("ydata", hg, "data", y);
123   addproperty ("zdata", hg, "data", z);
124   if (ischar (c))
125     addproperty ("cdata", hg, "data", __color_str_rgb__ (c));
126   else
127     addproperty ("cdata", hg, "data", c);
128   endif
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);
135
136   one_explicit_color = ischar (c) || isequal (size (c), [1, 3]);
137
138   if (numel (x) <= 100)
139
140     ## For small number of points, we'll construct an object for each point.
141
142     if (numel (s) == 1)
143       s = repmat (s, numel(x), 1);
144     endif
145
146     if (one_explicit_color)
147       for i = 1 : numel (x)
148         if (filled)
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");
155         else
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");
162         endif
163       endfor
164     else
165       if (rows (c) == 1)
166         c = ones (rows (x), 1) * c;
167       endif
168       for i = 1 : numel (x)
169         if (filled)
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");
178         else
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");
187
188         endif
189       endfor
190     endif
191
192   else
193
194     ## For larger numbers of points, we split the points by common color.
195
196     vert = [x, y, z];
197     if (one_explicit_color)
198       h = render_size_color (hg, vert, s, c, marker, filled, true);
199     else
200       if (rows (c) == 1)
201         c = ones (rows (x), 1) * c;
202       endif
203       ## We want to group points by colour. So first get all the unique colours
204       [cc, ~, c_to_cc] = unique (c, "rows");
205
206       for i = 1:rows (cc)
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);
210         if (isscalar (s))
211           h = render_size_color (hg, vert(idx, :), s, c(idx,:),
212                                  marker, filled, true);
213         else
214           h = render_size_color (hg, vert(idx, :), s(idx), c(idx,:),
215                                  marker, filled, true);
216         endif
217       endfor
218
219     endif
220   endif
221
222   if (! ischar (c) && rows (c) > 1)
223     ax = get (hg, "parent");
224     clim = get (ax, "clim");
225     if (min(c(:)) < clim(1))
226       clim(1) = min(c(:));
227       set (ax, "clim", clim);
228     endif
229     if (max(c(:)) > clim(2))
230       set (ax, "clim", [clim(1), max(c(:))]);
231     endif
232   endif
233
234   addproperty ("linewidth", hg, "patchlinewidth", 0.5);
235   addproperty ("marker", hg, "patchmarker", marker);
236   if (filled)
237     addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "none");
238     if (one_explicit_color)
239       addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", c);
240     else
241       addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "flat");
242     endif
243   else
244     addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "none");
245     if (one_explicit_color)
246       addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", c);
247     else
248       addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "flat");
249     endif
250   endif
251   addlistener (hg, "linewidth", @update_props);
252   addlistener (hg, "marker", @update_props);
253   addlistener (hg, "markerfacecolor", @update_props);
254   addlistener (hg, "markeredgecolor", @update_props);
255
256   if (! isempty (newargs))
257     set (hg, newargs{:});
258   endif
259
260 endfunction
261
262 function h = render_size_color(hg, vert, s, c, marker, filled, isflat)
263   if (isscalar (s))
264     x = vert(:,1);
265     y = vert(:,2);
266     z = vert(:,3:end);
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)
273       if (filled)
274         h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z,
275                           "faces", 1:numel(x), "vertices", vert,
276                           "facecolor", "none", "edgecolor", "none",
277                           "marker", marker,
278                           "markeredgecolor", "none",
279                           "markerfacecolor", c(1,:),
280                           "markersize", s, "linestyle", "none");
281       else
282         h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z,
283                           "faces", 1:numel(x), "vertices", vert,
284                           "facecolor", "none", "edgecolor", "none",
285                           "marker", marker,
286                           "markeredgecolor", c(1,:),
287                           "markerfacecolor", "none",
288                           "markersize", s, "linestyle", "none");
289       endif
290     else
291       if (filled)
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");
300       else
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");
309       endif
310     endif
311   else
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);
314     for i = 1:rows (ss)
315       idx = (i == s_to_ss);
316       h = render_size_color (hg, vert(idx,:), ss(i), c,
317                              marker, filled, isflat);
318     endfor
319   endif
320 endfunction
321
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");
328
329   for i = 1 : numel (kids)
330     set (kids (i), "linewidth", lw, "marker", m, "markerfacecolor", fc,
331          "edgecolor", ec);
332   endfor
333 endfunction
334
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);
342   endif
343   size1 = get (h, "sizedata");
344   if (numel (size1) == 1)
345     size1 = repmat (size1, numel (x1), 1);
346   endif
347   hlist = get (h, "children");
348   if (ischar (c1))
349     if (isempty (z1))
350       for i = 1 : length (hlist)
351         set (hlist(i), "vertices", [x1(i), y1(i)], "cdata", c1,
352              "markersize", size1(i));
353       endfor
354     else
355       for i = 1 : length (hlist)
356         set (hlist(i), "vertices", [x1(i), y1(i), z1(i)], "cdata", c1,
357              "markersize", size1(i));
358       endfor
359     endif
360   else
361     if (isempty (z1))
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));
367       endfor
368     else
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));
374       endfor
375     endif
376   endif
377 endfunction