comparison scripts/plot/legend.m @ 10989:6ea65c5de87a

Respect the units and paperunits figure properties and the units and fontunits axes properties
author David Bateman <dbateman@free.fr>
date Thu, 16 Sep 2010 23:13:22 +0200
parents 848f3a13b7cf
children 529b36293297
comparison
equal deleted inserted replaced
10988:f1c4527b4024 10989:6ea65c5de87a
1 ## Copyright (C) 2001, 2006, 2007, 2008, 2009 Laurent Mazet 1 ## Copyright (C) 2010 David Bateman
2 ## Copyright (C) 2006 John W. Eaton
3 ## 2 ##
4 ## This file is part of Octave. 3 ## This file is part of Octave.
5 ## 4 ##
6 ## Octave is free software; you can redistribute it and/or modify it 5 ## Octave is free software; you can redistribute it and/or modify it
7 ## under the terms of the GNU General Public License as published by 6 ## under the terms of the GNU General Public License as published by
20 ## -*- texinfo -*- 19 ## -*- texinfo -*-
21 ## @deftypefn {Function File} {} legend (@var{str1}, @var{str2}, @dots{}) 20 ## @deftypefn {Function File} {} legend (@var{str1}, @var{str2}, @dots{})
22 ## @deftypefnx {Function File} {} legend (@var{matstr}) 21 ## @deftypefnx {Function File} {} legend (@var{matstr})
23 ## @deftypefnx {Function File} {} legend (@var{cell}) 22 ## @deftypefnx {Function File} {} legend (@var{cell})
24 ## @deftypefnx {Function File} {} legend (@dots{}, "location", @var{pos}) 23 ## @deftypefnx {Function File} {} legend (@dots{}, "location", @var{pos})
24 ## @deftypefnx {Function File} {} legend (@dots{}, "orientation", @var{orient})
25 ## @deftypefnx {Function File} {} legend (@var{hax}, @dots{}) 25 ## @deftypefnx {Function File} {} legend (@var{hax}, @dots{})
26 ## @deftypefnx {Function File} {} legend (@var{hobjs}, @dots{}) 26 ## @deftypefnx {Function File} {} legend (@var{hobjs}, @dots{})
27 ## @deftypefnx {Function File} {} legend (@var{hax}, @var{hobjs}, @dots{}) 27 ## @deftypefnx {Function File} {} legend (@var{hax}, @var{hobjs}, @dots{})
28 ## @deftypefnx {Function File} {} legend ("@var{option}") 28 ## @deftypefnx {Function File} {} legend ("@var{option}")
29 ## 29 ##
68 ## 68 ##
69 ## @item @tab outside @tab 69 ## @item @tab outside @tab
70 ## can be appended to any location string 70 ## can be appended to any location string
71 ## @end multitable 71 ## @end multitable
72 ## 72 ##
73 ## The optional parameter @var{orient} determines if the key elements
74 ## are placed vertically or horizontally. The allowed values are "vertical"
75 ## or "horizontal" with the default being "vertical".
76 ##
73 ## The following customizations are available using @var{option}: 77 ## The following customizations are available using @var{option}:
74 ## 78 ##
75 ## @table @asis 79 ## @table @asis
76 ## @item "show" 80 ## @item "show"
77 ## Show legend on the plot 81 ## Show legend on the plot
92 ## @item "right" 96 ## @item "right"
93 ## Place text to the right of the keys 97 ## Place text to the right of the keys
94 ## @end table 98 ## @end table
95 ## @end deftypefn 99 ## @end deftypefn
96 100
97 function legend (varargin) 101 function [hlegend2, hobjects2, hplot2, text_strings2] = legend (varargin)
98 102
99 [ca, varargin, nargin] = __plt_get_axis_arg__ ("legend", varargin{:}); 103 [ca, varargin, nargs] = __plt_get_axis_arg__ (true, "legend", varargin{:});
100 nargs = nargin; 104 if (isnan (ca))
105 fig = get (0, "currentfigure");
106 if (isempty (fig))
107 ca = gca ();
108 fig = get (ca, "parent");
109 else
110 ca = get (fig, "children");
111 ca ( ! strcmp (get (get (fig, "children"), "type"), "axes")) = [];
112 ca_pos = get (get (fig, "currentaxes"), "position");
113 ca_outpos = get (get (fig, "currentaxes"), "outerposition");
114 for i = numel (ca) : -1 : 1
115 if (! all (ca_pos, get (ca(i), "position") )
116 || ! all (ca_outpos, get (ca(i), "outerposition")))
117 ca(i) = [];
118 endif
119 endfor
120 endif
121 else
122 fig = get (ca, "parent");
123 endif
101 124
102 if (all (ishandle (varargin{1}))) 125 if (all (ishandle (varargin{1})))
103 kids = flipud (varargin{1}(:)); 126 kids = flipud (varargin{1}(:));
104 varargin(1) = []; 127 varargin(1) = [];
105 nargs = numel (varargin); 128 nargs = numel (varargin);
106 else 129 else
107 kids = get (ca, "children"); 130 kids = get (fig, "children");
131 kids (strcmp (get (kids, "tag"), "legend")) = [];
132 if (isscalar (kids))
133 kids = get(kids, "children")(:);
134 else
135 kids = [get(kids, "children"){:}](:);
136 endif
108 endif 137 endif
109 nkids = numel (kids); 138 nkids = numel (kids);
110 139
140 position = "northeast";
141 orientation = "vertical";
111 if (nargs > 0) 142 if (nargs > 0)
112 pos = varargin{nargs}; 143 pos = varargin{nargs};
113 if (isnumeric (pos) && isscalar (pos) && round (pos) == pos) 144 if (isnumeric (pos) && isscalar (pos) && round (pos) == pos)
114 if (pos >= -1 && pos <= 4) 145 if (pos >= -1 && pos <= 4)
115 set (ca, "keypos", pos); 146 position = {"northeastoutside", "best", "northeast",
147 "northwest", "southwest", "southeast"} (pos + 2);
116 nargs--; 148 nargs--;
117 else 149 else
118 error ("legend: invalid position specified"); 150 error ("legend: invalid position specified");
119 endif 151 endif
120 endif 152 endif
121 endif 153 endif
122 154
123 if (nargs > 1) 155 while (nargs > 1)
124 pos = varargin{nargs-1}; 156 pos = varargin{nargs-1};
125 str = varargin{nargs}; 157 str = varargin{nargs};
126 if (strcmpi (pos, "location") && ischar (str)) 158 if (strcmpi (pos, "location") && ischar (str))
127 set (ca, "keypos", str); 159 position = lower (str);
128 nargs -= 2; 160 nargs -= 2;
129 endif 161 elseif (strcmpi (pos, "orientation") && ischar (str))
162 orientation = lower (str);
163 nargs -= 2;
164 else
165 break;
166 endif
167 endwhile
168
169 ## Validate the orientation
170 switch (orientation)
171 case {"vertical", "horizontal"}
172 otherwise
173 error ("legend: unrecognized legend orientation");
174 endswitch
175
176 ## Validate the position type is valid
177 outside = false;
178 inout = findstr (position, "outside");
179 if (! isempty (inout))
180 outside = true;
181 position = position(1:inout-1);
182 else
183 outside = false;
130 endif 184 endif
131 185
132 k = 1; 186 switch (position)
133 turn_on_legend = false; 187 case {"north", "south", "east", "west", "northeast", "northwest", ...
188 "southeast", "southwest"}
189 case "best"
190 warning ("legend: 'Best' not yet implemented for location specifier\n");
191 position = "northeast";
192 otherwise
193 error ("legend: unrecognized legend position");
194 endswitch
195
196 show = "create";
197 textpos = "default";
198 reverse = false;
199 box = "default";
200
201 hlegend = [];
202 fkids = get (fig, "children");
203 for i = 1 : numel(fkids)
204 if (ishandle (fkids (i)) && strcmp (get (fkids (i), "type"), "axes")
205 && (strcmp (get (fkids (i), "tag"), "legend")))
206 udata = get (fkids (i), "userdata");
207 if (! isempty (intersect (udata.handle, ca)))
208 hlegend = fkids (i);
209 break;
210 endif
211 endif
212 endfor
134 213
135 if (nargs == 1) 214 if (nargs == 1)
136 arg = varargin{1}; 215 arg = varargin{1};
137 if (ischar (arg)) 216 if (ischar (arg))
138 if (rows (arg) == 1) 217 if (rows (arg) == 1)
139 str = tolower (deblank (arg)); 218 str = tolower (deblank (arg));
140 switch (str) 219 switch (str)
141 case {"off", "hide"} 220 case {"off", "hide"}
142 set (ca, "key", "off"); 221 show = "off";
143 nargs--; 222 nargs--;
144 case "show" 223 case "show"
145 set (ca, "key", "on"); 224 show = "on";
146 nargs--; 225 nargs--;
147 case "toggle" 226 case "toggle"
148 val = get (ca, "key"); 227 if (isempty (hlegend) || strcmp (get (hlegend, "visible"), "off"))
149 if (strcmpi (val, "on")) 228 show = "on";
150 set (ca, "key", "off"); 229 else
151 else 230 show = "off";
152 set (ca, "key", "on");
153 endif 231 endif
154 nargs--; 232 nargs--;
155 case "boxon" 233 case "boxon"
156 set (ca, "key", "on", "keybox", "on"); 234 box = "on";
157 nargs--; 235 nargs--;
158 case "boxoff" 236 case "boxoff"
159 set (ca, "keybox", "off"); 237 box = "off";
160 nargs--; 238 nargs--;
161 case "left" 239 case "left"
162 set (ca, "keyreverse", "off") 240 textpos = "left";
241 reverse = false;
163 nargs--; 242 nargs--;
164 case "right" 243 case "right"
165 set (ca, "keyreverse", "on") 244 textpos = "right";
245 reverse = true;
166 nargs--; 246 nargs--;
167 otherwise 247 otherwise
168 endswitch 248 endswitch
169 else 249 else
170 varargin = cellstr (arg); 250 varargin = cellstr (arg);
176 else 256 else
177 error ("legend: expecting argument to be a character string"); 257 error ("legend: expecting argument to be a character string");
178 endif 258 endif
179 endif 259 endif
180 260
181 if (nargs > 0) 261 if (strcmp (show, "off"))
182 have_data = false; 262 if (! isempty (hlegend))
183 for k = 1:nkids 263 set (hlegend, "visible", "off");
184 typ = get (kids(k), "type"); 264 set (get (hlegend, "children"), "visible", "off");
185 if (strcmp (typ, "line") || strcmp (typ, "surface") 265 hlegend = [];
186 || strcmp (typ, "patch") || strcmp (typ, "hggroup")) 266 endif
187 have_data = true; 267 hobjects = [];
268 hplots = [];
269 text_strings = {};
270 elseif (strcmp (show, "on"))
271 if (! isempty (hlegend))
272 set (hlegend, "visible", "on");
273 set (get (hlegend, "children"), "visible", "on");
274 else
275 hobjects = [];
276 hplots = [];
277 text_strings = {};
278 endif
279 elseif (strcmp (box, "on"))
280 if (! isempty (hlegend))
281 set (hlegend, "visible", "on", "box", "on");
282 endif
283 elseif (strcmp (box, "off"))
284 if (! isempty (hlegend))
285 set (hlegend, "box", "off", "visible", "off");
286 endif
287 else
288 hobjects = [];
289 hplots = [];
290 text_strings = {};
291
292 if (nargs > 0)
293 have_data = false;
294 for k = 1:nkids
295 typ = get (kids(k), "type");
296 if (strcmp (typ, "line") || strcmp (typ, "surface")
297 || strcmp (typ, "patch") || strcmp (typ, "hggroup"))
298 have_data = true;
299 break;
300 endif
301 endfor
302
303 if (! have_data)
304 warning ("legend: plot data is empty; setting key labels has no effect");
305 endif
306 endif
307
308 if (strcmp (textpos, "default"))
309 warned = false;
310 k = nkids;
311 for i = 1 : nargs
312 arg = varargin{i};
313 if (ischar (arg))
314 typ = get (kids(k), "type");
315 while (k > 0
316 && ! (strcmp (typ, "line") || strcmp (typ, "surface")
317 || strcmp (typ, "patch") || strcmp (typ, "hggroup")))
318 typ = get (kids(--k), "type");
319 endwhile
320 if (k > 0)
321 if (strcmp (get (kids(k), "type"), "hggroup"))
322 hgkids = get (kids(k), "children");
323 for j = 1 : length (hgkids)
324 hgobj = get (hgkids (j));
325 if (isfield (hgobj, "displayname"))
326 set (hgkids(j), "displayname", arg);
327 hplots = [hplots, hgkids(j)];
328 text_strings = {text_strings{:}, arg};
329 break;
330 endif
331 endfor
332 else
333 set (kids(k), "displayname", arg);
334 hplots = [hplots, kids(k)];
335 text_strings = {text_strings{:}, arg};
336 endif
337
338 if (--k == 0)
339 break;
340 endif
341 elseif (! warned)
342 warned = true;
343 warning ("legend: ignoring extra labels");
344 endif
345 else
346 error ("legend: expecting argument to be a character string");
347 endif
348 endfor
349 else
350 k = nkids;
351 while (k > 0)
352 typ = get (kids(k), "type");
353 while (k > 0
354 && ! (strcmp (typ, "line") || strcmp (typ, "surface")
355 || strcmp (typ, "patch") || strcmp (typ, "hggroup")))
356 typ = get (kids(--k), "type");
357 endwhile
358 if (k > 0)
359 if (strcmp (get (kids(k), "type"), "hggroup"))
360 hgkids = get (kids(k), "children");
361 for j = 1 : length (hgkids)
362 hgobj = get (hgkids (j));
363 if (isfield (hgobj, "displayname")
364 && ! isempty (hgobj.displayname))
365 hplots = [hplots, hgkids(j)];
366 text_strings = {text_strings{:}, hbobj.displayname};
367 break;
368 endif
369 endfor
370 else
371 if (! isempty (get (kids (k), "displayname")))
372 hplots = [hplots, kids(k)];
373 text_strings = {text_strings{:}, get(kids (k), "displayname")};
374 endif
375 endif
376 if (--k == 0)
377 break;
378 endif
379 endif
380 endwhile
381 endif
382
383 if (isempty (hplots))
384 if (! isempty (hlegend))
385 fkids = get (fig, "children");
386 delete (fkids (fkids == hlegend));
387 hlegend = [];
388 hobjects = [];
389 hplots = [];
390 text_strings = {};
391 endif
392 else
393 ## Delete the old legend if it exists
394 if (! isempty (hlegend))
395 fkids = get (fig, "children");
396 delete (fkids (fkids == hlegend));
397 endif
398
399 ## Force the figure to be drawn here, so that the figure position
400 ## is updated correctly before reading it
401 drawnow ();
402
403 ## Get axis size and fontsize in points.
404 ## Rely on listener to handle coversion.
405 units = get (ca(1), "units");
406 fontunits = get (ca(1), "fontunits");
407 unwind_protect
408 set (ca(1), "units", "points");
409 set (ca(1), "fontunits", "points");
410 ca_pos = get (ca(1), "position");
411 ca_outpos = get (ca(1), "outerposition");
412 ca_fontsize = get (ca(1), "fontsize");
413 unwind_protect_cleanup
414 set (ca(1), "units", units);
415 set (ca(1), "fontunits", fontunits);
416 end_unwind_protect
417
418 ## Padding between legend entries horizontally and vertically
419 xpad = 2;
420 ypad = 2;
421
422 ## Length of line segments in the legend in points
423 linelength = 15;
424
425 ## Create the axis first
426 ## FIXME hlegend should inherit properties from "ca"
427 curaxes = get (fig, "currentaxes");
428 unwind_protect
429 hlegend = axes ("tag", "legend", "userdata", struct ("handle", ca),
430 "box", "off", "outerposition", [0, 0, 0, 0],
431 "xtick", [], "ytick", [], "xticklabel", "",
432 "yticklabel", "", "zticklabel", "",
433 "xlim", [0, 1], "ylim", [0, 1], "visible", "off",
434 "activepositionproperty", "position");
435
436 ## Add text label to the axis first, checking their extents
437 nentries = numel (hplots);
438 texthandle = [];
439 maxwidth = 0;
440 maxheight = 0;
441 for k = 1 : nentries
442 if (reverse)
443 texthandle = [texthandle, text(0, 0, text_strings {k},
444 "horizontalalignment", "left")];
445 else
446 texthandle = [texthandle, text(0, 0, text_strings {k},
447 "horizontalalignment", "right")];
448 endif
449 units = get (texthandle (end), "units");
450 unwind_protect
451 set (texthandle (end), "units", "points");
452 extents = get (texthandle (end), "extent");
453 ## FIXME fudge for gnuplot as the text extents are calculated from
454 ## the FreeType text render rather than from gnuplot itself. Your
455 ## luck will vary depending on the terminals that are used.
456 if (strcmp (get (fig, "__backend__"), "gnuplot"))
457 extents = [0,0,1,0] + [1,1,1.22,1] .* extents;
458 linelength = 20;
459 endif
460 maxwidth = max (maxwidth, extents (3));
461 maxheight = max (maxheight, extents (4));
462 unwind_protect_cleanup
463 set (texthandle (end), "units", units);
464 end_unwind_protect
465 endfor
466
467 num1 = nentries;
468 if (strcmp (orientation, "vertical"))
469 height = nentries * (ypad + maxheight);
470 if (outside)
471 if (height > ca_pos (4))
472 ## Avoid shrinking the height of the axis to zero if outside
473 num1 = ca_pos(4) / (maxheight + ypad) / 2;
474 endif
475 else
476 if (height > 0.9 * ca_pos (4))
477 num1 = 0.9 * ca_pos(4) / (maxheight + ypad);
478 endif
479 endif
480 else
481 width = nentries * (ypad + maxwidth);
482 if (outside)
483 if (width > ca_pos (3))
484 ## Avoid shrinking the width of the axis to zero if outside
485 num1 = ca_pos(3) / (maxwidth + ypad) / 2;
486 endif
487 else
488 if (width > 0.9 * ca_pos (3))
489 num1 = 0.9 * ca_pos(3) / (maxwidth + ypad);
490 endif
491 endif
492 endif
493 num2 = ceil (nentries / num1);
494
495 xstep = 3 * xpad + (maxwidth + linelength);
496 if (reverse)
497 xoffset = xpad;
498 txoffset = 2 * xpad + linelength;
499 else
500 xoffset = 2 * xpad + maxwidth;
501 txoffset = xpad + maxwidth;
502 endif
503 ystep = (ypad + maxheight);
504 yoffset = ystep / 2;
505
506 ## Place the legend in the desired position
507 if (strcmp (orientation, "vertical"))
508 lpos = [0, 0, num2 * xstep, num1 * ystep];
509 else
510 lpos = [0, 0, num1 * xstep, num2 * ystep];
511 endif
512 switch(position)
513 case "north"
514 if (outside)
515 lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ...
516 ca_outpos(2) + ca_outpos(4) - lpos(4), lpos(3), lpos(4)];
517
518 new_pos = [ca_pos(1), ca_pos(2), ca_pos(3), ca_pos(4) - lpos(4)];
519 new_outpos = [ca_outpos(1), ca_outpos(2), ca_outpos(3), ...
520 ca_outpos(4) - lpos(4)];
521 else
522 ca_pos
523 lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ...
524 ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
525 endif
526 case "south"
527 if (outside)
528 lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ca_outpos(2), ...
529 lpos(3), lpos(4)];
530 new_pos = [ca_pos(1), ca_pos(2) + lpos(4), ca_pos(3), ...
531 ca_pos(4) - lpos(4)];
532 new_outpos = [ca_outpos(1), ca_outpos(2) + lpos(4), ...
533 ca_outpos(3), ca_outpos(4) - lpos(4)];
534 else
535 lpos = [ca_pos(1) + (ca_pos(3) - lpos(3)) / 2, ...
536 ca_pos(2) + ypad, lpos(3), lpos(4)];
537 endif
538 case "east"
539 if (outside)
540 lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ...
541 ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
542 new_pos = [ca_pos(1), ca_pos(2), ca_pos(3) - lpos(3), ca_pos(4)];
543 new_outpos = [ca_outpos(1), ca_outpos(2), ...
544 ca_outpos(3) - lpos(3), ca_outpos(4)];
545 else
546 lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
547 ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
548 endif
549 case "west"
550 if (outside)
551 lpos = [ca_outpos(1), ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, ...
552 lpos(3), lpos(4)];
553 new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ...
554 ca_pos(3) - lpos(3), ca_pos(4)];
555 new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2), ...
556 ca_outpos(3) - lpos(3), ca_outpos(4)];
557 else
558 lpos = [ca_pos(1) + ypad, ...
559 ca_pos(2) + (ca_pos(4) - lpos(4)) / 2, lpos(3), lpos(4)];
560 endif
561 case "northeast"
562 if (outside)
563 lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ...
564 ca_outpos(2) + ca_outpos(4) - lpos(4), lpos(3), lpos(4)];
565 new_pos = [ca_pos(1), ca_pos(2), ca_pos(3) - lpos(3), ...
566 ca_pos(4) - lpos(4)];
567 new_outpos = [ca_outpos(1), ca_outpos(2), ...
568 ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)];
569 else
570 lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
571 ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
572 endif
573 case "northwest"
574 if (outside)
575 lpos = [ca_outpos(1), ca_outpos(2) + ca_outpos(4) - lpos(4), ...
576 lpos(3), lpos(4)];
577 new_pos = [ca_pos(1) + lpos(3), ca_pos(2), ...
578 ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)];
579 new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2), ...
580 ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)];
581 else
582 lpos = [ca_pos(1) + ypad, ...
583 ca_pos(2) + ca_pos(4) - lpos(4) - ypad, lpos(3), lpos(4)];
584 endif
585 case "southeast"
586 if (outside)
587 lpos = [ca_outpos(1) + ca_outpos(3) - lpos(3), ca_outpos(2),
588 lpos(3), lpos(4)];
589 new_pos = [ca_pos(1), ca_pos(2) + lpos(4), ...
590 ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)];
591 new_outpos = [ca_outpos(1), ca_outpos(2) + lpos(4), ...
592 ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)];
593 else
594 lpos = [ca_pos(1) + ca_pos(3) - lpos(3) - ypad, ...
595 ca_pos(2) + ypad, lpos(3), lpos(4)];
596 endif
597 case "southwest"
598 if (outside)
599 lpos = [ca_outpos(1), ca_outpos(2), 0, lpos(3), lpos(4)];
600 new_pos = [ca_pos(1) +lpos(3), ca_pos(2) + lpos(4), ...
601 ca_pos(3) - lpos(3), ca_pos(4) - lpos(4)];
602 new_outpos = [ca_outpos(1) + lpos(3), ca_outpos(2) + lpos(4), ...
603 ca_outpos(3) - lpos(3), ca_outpos(4) - lpos(4)];
604 else
605 lpos = [ca_pos(1) + ypad, ca_pos(2) + ypad, lpos(3), lpos(4)];
606 endif
607 endswitch
608
609 units = get (hlegend, "units");
610 unwind_protect
611 set (hlegend, "units", "points");
612 set (hlegend, "position", lpos, "outerposition", lpos);
613 unwind_protect_cleanup
614 set (hlegend, "units", units);
615 end_unwind_protect
616
617 ## Now write the line segments and place the text objects correctly
618 xk = 0;
619 yk = 0;
620 for k = 1 : numel (hplots)
621 hobjects = [hobjects, texthandle (k)];
622 color = get (hplots (k), "color");
623 style = get (hplots (k), "linestyle");
624 if (! strcmp (style, "none"))
625 l1 = line ("xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3),
626 "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4),
627 "color", color, "linestyle", style);
628 hobjects = [hobjects, l1];
629 endif
630 marker = get (hplots (k), "marker");
631 if (! strcmp (marker, "none"))
632 l1 = line ("xdata", (xoffset + 0.5 * linelength + xk * xstep) / lpos(3),
633 "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4),
634 "color", color, "marker", marker,
635 "markeredgecolor", get (hplots (k), "markeredgecolor"),
636 "markerfacecolor", get (hplots (k), "markerfacecolor"),
637 "markersize", get (hplots (k), "markersize"));
638 hobjects = [hobjects, l1];
639 endif
640 set (texthandle (k), "position", [(txoffset + xk * xstep) / lpos(3), ...
641 (lpos(4) - yoffset - yk * ystep) / lpos(4)]);
642
643 if (strcmp (orientation, "vertical"))
644 yk++;
645 if (yk > num1)
646 yk = 0;
647 xk++;
648 endif
649 else
650 xk++;
651 if (xk > num1)
652 xk = 0;
653 yk++;
654 endif
655 endif
656 endfor
657
658 ## Add an invisible text object to original axis
659 ## that when it is destroyed will remove the legend
660 t1 = text (0, 0, "", "parent", ca(1), "tag", "legend",
661 "handlevisibility", "off", "visible", "off",
662 "xliminclude", "off", "yliminclude", "off");
663 set (t1, "deletefcn", {@deletelegend1, hlegend});
664
665 ## Resize the axis the legend is attached to if the
666 ## legend is "outside" the plot and create listener to
667 ## resize axis to original size if the legend is deleted,
668 ## hidden or shown
669 if (outside)
670 for i = 1 : numel (ca)
671 units = get (ca(i), "units");
672 unwind_protect
673 set (ca(i), "units", "points");
674 set (ca (i), "position", new_pos, "outerposition", new_outpos);
675 unwind_protect_cleanup
676 set (ca(i), "units", units);
677 end_unwind_protect
678 endfor
679
680 set (hlegend, "deletefcn", {@deletelegend2, ca, ...
681 ca_pos, ca_outpos, t1});
682 addlistener (hlegend, "visible", {@hideshowlegend, ca, ...
683 ca_pos, new_pos, ...
684 ca_outpos, new_outpos});
685 else
686 set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1});
687 endif
688 unwind_protect_cleanup
689 set (fig, "currentaxes", curaxes);
690 end_unwind_protect
691 endif
692 endif
693
694 if (nargout > 0)
695 hlegend2 = hlegend2;
696 hobjects2 = hobjects;
697 hplot2 = hplots;
698 text_strings2 = text_strings;
699 endif
700
701 endfunction
702
703 function hideshowlegend (h, d, ca, pos1, pos2, outpos1, outpos2)
704 isvisible = strcmp (get (h, "visible"), "off");
705 if (! isvisible)
706 kids = get (h, "children");
707 for i = 1 : numel (kids)
708 if (! strcmp (get (kids(i), "visible"), "off"))
709 isvisible = true;
188 break; 710 break;
189 endif 711 endif
190 endfor 712 endfor
191 if (! have_data)
192 warning ("legend: plot data is empty; setting key labels has no effect");
193 endif
194 endif 713 endif
195 714
196 warned = false; 715 for i = 1 : numel (ca)
197 k = nkids; 716 if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") &&
198 for i = 1:nargs 717 (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) &&
199 arg = varargin{i}; 718 strcmp (get (ca(i), "beingdeleted"), "off"))
200 if (ischar (arg)) 719 units = get (ca(i), "units");
201 typ = get (kids(k), "type"); 720 unwind_protect
202 while (k > 1 721 set (ca(i), "units", "points");
203 && ! (strcmp (typ, "line") || strcmp (typ, "surface") 722 if (isvisible)
204 || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) 723 set (ca(i), "position", pos2, "outerposition", outpos2);
205 typ = get (kids(--k), "type");
206 endwhile
207 if (k > 0)
208 if (strcmp (get (kids(k), "type"), "hggroup"))
209 hgkids = get (kids(k), "children");
210 for j = 1 : length (hgkids)
211 hgobj = get (hgkids (j));
212 if (isfield (hgobj, "keylabel"))
213 set (hgkids(j), "keylabel", arg);
214 break;
215 endif
216 endfor
217 else 724 else
218 set (kids(k), "keylabel", arg); 725 set (ca(i), "position", pos1, "outerposition", outpos1);
219 endif 726 endif
220 turn_on_legend = true; 727 unwind_protect_cleanup
221 if (--k == 0) 728 set (ca(i), "units", units);
222 break; 729 end_unwind_protect
223 endif 730 endif
224 elseif (! warned) 731 endfor
225 warned = true; 732 endfunction
226 warning ("legend: ignoring extra labels"); 733
734 function deletelegend1 (h, d, ca)
735 if (ishandle (ca) && strcmp (get (ca, "type"), "axes") &&
736 (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) &&
737 strcmp (get (ca, "beingdeleted"), "off"))
738 delete (ca);
739 endif
740 endfunction
741
742 function deletelegend2 (h, d, ca, pos, outpos, t1)
743 for i = 1 : numel (ca)
744 if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") &&
745 (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) &&
746 strcmp (get (ca(i), "beingdeleted"), "off"))
747 if (!isempty (pos) && !isempty(outpos))
748 units = get (ca(i), "units");
749 unwind_protect
750 set (ca(i), "units", "points");
751 set (ca(i), "position", pos, "outerposition", outpos, "deletefcn", "");
752 unwind_protect_cleanup
753 set (ca(i), "units", units);
754 end_unwind_protect
227 endif 755 endif
228 else 756 if (i == 1)
229 error ("legend: expecting argument to be a character string"); 757 set (t1, "deletefcn", "");
758 delete (t1);
759 endif
230 endif 760 endif
231 endfor 761 endfor
232
233 if (turn_on_legend)
234 set (ca, "key", "on");
235 endif
236
237 endfunction 762 endfunction
238 763
239 %!demo 764 %!demo
240 %! clf 765 %! clf
241 %! plot(1:10, 1:10, 1:10, fliplr(1:10)); 766 %! plot(1:10, 1:10, 1:10, fliplr(1:10));