Mercurial > hg > octave-nkf
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)); |