comparison scripts/plot/legend.m @ 11198:9f080d23396f

Fix multi-parented legends with the gnuplot backend (fixes #30461 and #31522)
author David Bateman <dbateman@free.fr>
date Sun, 07 Nov 2010 22:35:40 +0100
parents fe3c3dfc07eb
children 91c606a68693
comparison
equal deleted inserted replaced
11197:836427db633b 11198:9f080d23396f
99 ## @end deftypefn 99 ## @end deftypefn
100 100
101 function [hlegend2, hobjects2, hplot2, text_strings2] = legend (varargin) 101 function [hlegend2, hobjects2, hplot2, text_strings2] = legend (varargin)
102 102
103 if (! ishandle (varargin {1}) || (strcmp (get (varargin {1}, "type"), "axes") 103 if (! ishandle (varargin {1}) || (strcmp (get (varargin {1}, "type"), "axes")
104 && !strcmp (get (varargin {1}, "tag"), "legend"))) 104 && ! strcmp (get (varargin {1}, "tag"), "legend")))
105 [ca, varargin, nargs] = __plt_get_axis_arg__ ("legend", varargin{:}); 105 [ca, varargin, nargs] = __plt_get_axis_arg__ ("legend", varargin{:});
106 fig = get (ca, "parent"); 106 fig = get (ca, "parent");
107 else 107 else
108 fig = get (0, "currentfigure"); 108 fig = get (0, "currentfigure");
109 ca = get (fig, "currentaxes"); 109 ca = get (fig, "currentaxes");
110 endif
111
112 plty = get(ca (strcmp (get (ca, "tag"), "plotyy")), "userdata");
113 if (isscalar (plty))
114 ca = [ca, plty];
115 else
116 ca = [ca, plty{:}];
110 endif 117 endif
111 118
112 if (all (ishandle (varargin{1}))) 119 if (all (ishandle (varargin{1})))
113 kids = flipud (varargin{1}(:)); 120 kids = flipud (varargin{1}(:));
114 varargin(1) = []; 121 varargin(1) = [];
330 endfor 337 endfor
331 else 338 else
332 k = nkids; 339 k = nkids;
333 while (k > 0) 340 while (k > 0)
334 typ = get (kids(k), "type"); 341 typ = get (kids(k), "type");
335 while (k > 0 342 while (k > 1
336 && ! (strcmp (typ, "line") || strcmp (typ, "surface") 343 && ! (strcmp (typ, "line") || strcmp (typ, "surface")
337 || strcmp (typ, "patch") || strcmp (typ, "hggroup"))) 344 || strcmp (typ, "patch") || strcmp (typ, "hggroup")))
338 typ = get (kids(--k), "type"); 345 typ = get (kids(--k), "type");
339 endwhile 346 endwhile
347 if (! (strcmp (typ, "line") || strcmp (typ, "surface")
348 || strcmp (typ, "patch") || strcmp (typ, "hggroup")))
349 break
350 endif
340 if (k > 0) 351 if (k > 0)
341 if (strcmp (get (kids(k), "type"), "hggroup")) 352 if (strcmp (get (kids(k), "type"), "hggroup"))
342 hgkids = get (kids(k), "children"); 353 hgkids = get (kids(k), "children");
343 for j = 1 : length (hgkids) 354 for j = 1 : length (hgkids)
344 hgobj = get (hgkids (j)); 355 hgobj = get (hgkids (j));
390 if (strcmp (orientation, "default")) 401 if (strcmp (orientation, "default"))
391 orientation = get (hlegend, "orientation"); 402 orientation = get (hlegend, "orientation");
392 endif 403 endif
393 box = get (hlegend, "box"); 404 box = get (hlegend, "box");
394 fkids = get (fig, "children"); 405 fkids = get (fig, "children");
395 delete (fkids (fkids == hlegend));
396 else 406 else
397 if (strcmp (textpos, "default")) 407 if (strcmp (textpos, "default"))
398 textpos = "left"; 408 textpos = "left";
399 endif 409 endif
400 if (strcmp (position, "default")) 410 if (strcmp (position, "default"))
434 444
435 ## Create the axis first 445 ## Create the axis first
436 ## FIXME hlegend should inherit properties from "ca" 446 ## FIXME hlegend should inherit properties from "ca"
437 curaxes = get (fig, "currentaxes"); 447 curaxes = get (fig, "currentaxes");
438 unwind_protect 448 unwind_protect
439 hlegend = axes ("tag", "legend", "userdata", struct ("handle", ca), 449 ud = ancestor(hplots, "axes");
440 "box", box, "outerposition", [0, 0, 0, 0], 450 if (!isscalar(ud))
441 "xtick", [], "ytick", [], "xticklabel", "", 451 ud = unique ([ud{:}]);
442 "yticklabel", "", "zticklabel", "", 452 endif
443 "xlim", [0, 1], "ylim", [0, 1], "visible", "off", 453 if (isempty (hlegend))
444 "activepositionproperty", "position"); 454 addprops = true;
445 455 hlegend = axes ("tag", "legend", "userdata", struct ("handle", ud),
456 "box", box, "outerposition", [0, 0, 0, 0],
457 "xtick", [], "ytick", [], "xticklabel", "",
458 "yticklabel", "", "zticklabel", "",
459 "xlim", [0, 1], "ylim", [0, 1], "visible", "off",
460 "activepositionproperty", "position");
461 else
462 addprops = false;
463 axes (hlegend);
464 delete (get (hlegend, "children"));
465 endif
446 ## Add text label to the axis first, checking their extents 466 ## Add text label to the axis first, checking their extents
447 nentries = numel (hplots); 467 nentries = numel (hplots);
448 texthandle = []; 468 texthandle = [];
449 maxwidth = 0; 469 maxwidth = 0;
450 maxheight = 0; 470 maxheight = 0;
451 for k = 1 : nentries 471 for k = 1 : nentries
452 if (strcmp (textpos, "right")) 472 if (strcmp (textpos, "right"))
453 texthandle = [texthandle, text(0, 0, text_strings {k}, 473 texthandle = [texthandle, text(0, 0, text_strings {k},
454 "horizontalalignment", "left")]; 474 "horizontalalignment", "left",
475 "userdata", hplots(k))];
455 else 476 else
456 texthandle = [texthandle, text(0, 0, text_strings {k}, 477 texthandle = [texthandle, text(0, 0, text_strings {k},
457 "horizontalalignment", "right")]; 478 "horizontalalignment", "right",
479 "userdata", hplots(k))];
458 endif 480 endif
459 units = get (texthandle (end), "units"); 481 units = get (texthandle (end), "units");
460 unwind_protect 482 unwind_protect
461 set (texthandle (end), "units", "points"); 483 set (texthandle (end), "units", "points");
462 extents = get (texthandle (end), "extent"); 484 extents = get (texthandle (end), "extent");
626 color = get (hplots(k), "color"); 648 color = get (hplots(k), "color");
627 style = get (hplots(k), "linestyle"); 649 style = get (hplots(k), "linestyle");
628 if (! strcmp (style, "none")) 650 if (! strcmp (style, "none"))
629 l1 = line ("xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3), 651 l1 = line ("xdata", ([xoffset, xoffset + linelength] + xk * xstep) / lpos(3),
630 "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4), 652 "ydata", [1, 1] .* (lpos(4) - yoffset - yk * ystep) / lpos(4),
631 "color", color, "linestyle", style); 653 "color", color, "linestyle", style, "marker", "none",
654 "userdata", hplots (k));
632 hobjects = [hobjects, l1]; 655 hobjects = [hobjects, l1];
633 endif 656 endif
634 marker = get (hplots(k), "marker"); 657 marker = get (hplots(k), "marker");
635 if (! strcmp (marker, "none")) 658 if (! strcmp (marker, "none"))
636 l1 = line ("xdata", (xoffset + 0.5 * linelength + xk * xstep) / lpos(3), 659 l1 = line ("xdata", (xoffset + 0.5 * linelength + xk * xstep) / lpos(3),
637 "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4), 660 "ydata", (lpos(4) - yoffset - yk * ystep) / lpos(4),
638 "color", color, "marker", marker, 661 "color", color, "linestyle", "none", "marker", marker,
639 "markeredgecolor", get (hplots (k), "markeredgecolor"), 662 "markeredgecolor", get (hplots (k), "markeredgecolor"),
640 "markerfacecolor", get (hplots (k), "markerfacecolor"), 663 "markerfacecolor", get (hplots (k), "markerfacecolor"),
641 "markersize", get (hplots (k), "markersize")); 664 "markersize", get (hplots (k), "markersize"),
665 "userdata", hplots (k));
642 hobjects = [hobjects, l1]; 666 hobjects = [hobjects, l1];
643 endif 667 endif
668
669 addlistener(hplots(k), "color", {@updateline, hlegend, linelength});
670 addlistener(hplots(k), "linestyle", {@updateline, hlegend, linelength});
671 addlistener(hplots(k), "marker", {@updateline, hlegend, linelength});
672 addlistener(hplots(k), "markeredgecolor", {@updateline, hlegend, linelength});
673 addlistener(hplots(k), "markerfacecolor", {@updateline, hlegend, linelength});
674 addlistener(hplots(k), "markersize", {@updateline, hlegend, linelength});
675 addlistener(hplots(k), "displayname", {@updateline, hlegend, linelength});
644 case "patch" 676 case "patch"
645 case "surface" 677 case "surface"
646 endswitch 678 endswitch
647 set (texthandle (k), "position", [(txoffset + xk * xstep) / lpos(3), ... 679 set (texthandle (k), "position", [(txoffset + xk * xstep) / lpos(3), ...
648 (lpos(4) - yoffset - yk * ystep) / lpos(4)]); 680 (lpos(4) - yoffset - yk * ystep) / lpos(4)]);
682 set (ca(i), "units", units); 714 set (ca(i), "units", units);
683 end_unwind_protect 715 end_unwind_protect
684 endfor 716 endfor
685 717
686 set (hlegend, "deletefcn", {@deletelegend2, ca, ... 718 set (hlegend, "deletefcn", {@deletelegend2, ca, ...
687 ca_pos, ca_outpos, t1}); 719 ca_pos, ca_outpos, t1, hplots});
688 addlistener (hlegend, "visible", {@hideshowlegend, ca, ... 720 addlistener (hlegend, "visible", {@hideshowlegend, ca, ...
689 ca_pos, new_pos, ... 721 ca_pos, new_pos, ...
690 ca_outpos, new_outpos}); 722 ca_outpos, new_outpos});
691 else 723 else
692 set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1}); 724 set (hlegend, "deletefcn", {@deletelegend2, ca, [], [], t1, hplots});
693 endif 725 endif
694 726
695 addproperty ("edgecolor", hlegend, "color", [0, 0, 0]); 727 if (addprops)
696 addproperty ("textcolor", hlegend, "color", [0, 0, 0]); 728 addproperty ("edgecolor", hlegend, "color", [0, 0, 0]);
697 addproperty ("location", hlegend, "radio", "north|south|east|west|{northeast}|southeast|northwest|southwest|northoutside|southoutside|eastoutside|westoutside|northeastoutside|southeastoutside|northwestoutside|southwestoutside"); 729 addproperty ("textcolor", hlegend, "color", [0, 0, 0]);
698 730 addproperty ("location", hlegend, "radio", "north|south|east|west|{northeast}|southeast|northwest|southwest|northoutside|southoutside|eastoutside|westoutside|northeastoutside|southeastoutside|northwestoutside|southwestoutside");
699 addproperty ("orientation", hlegend, "radio", "{vertical}|horizontal"); 731 addproperty ("orientation", hlegend, "radio",
700 addproperty ("string", hlegend, "any", text_strings); 732 "{vertical}|horizontal");
701 addproperty ("textposition", hlegend, "radio", "{left}|right"); 733 addproperty ("string", hlegend, "any", text_strings);
734 addproperty ("textposition", hlegend, "radio", "{left}|right");
735 else
736 set (hlegend, "string", text_strings);
737 endif
702 738
703 if (outside) 739 if (outside)
704 set (hlegend, "location", strcat (position, "outside"), 740 set (hlegend, "location", strcat (position, "outside"),
705 "orientation", orientation, "textposition", textpos); 741 "orientation", orientation, "textposition", textpos);
706 else 742 else
707 set (hlegend, "location", position, "orientation", orientation, 743 set (hlegend, "location", position, "orientation", orientation,
708 "textposition", textpos); 744 "textposition", textpos);
709 endif 745 endif
710 746 if (addprops)
711 addlistener (hlegend, "edgecolor", @updatelegendtext); 747 addlistener (hlegend, "edgecolor", @updatelegendtext);
712 addlistener (hlegend, "textcolor", @updatelegendtext); 748 addlistener (hlegend, "textcolor", @updatelegendtext);
713 addlistener (hlegend, "interpreter", @updatelegendtext); 749 addlistener (hlegend, "interpreter", @updatelegendtext);
714 750 addlistener (hlegend, "location", @updatelegend);
715 ## FIXME The listener function for these essentially has to 751 addlistener (hlegend, "orientation", @updatelegend);
716 ## replace the legend with a new one. For now they are just 752 addlistener (hlegend, "string", @updatelegend);
717 ## to stock the initial values (for the gnuplot backend) 753 addlistener (hlegend, "textposition", @updatelegend);
718 ##addlistener (hlegend, "location", @updatelegend); 754 endif
719 ##addlistener (hlegend, "orientation", @updatelegend);
720 ##addlistener (hlegend, "string", @updatelegend);
721 ##addlistener (hlegend, "textposition", @updatelegend);
722 unwind_protect_cleanup 755 unwind_protect_cleanup
723 set (fig, "currentaxes", curaxes); 756 set (fig, "currentaxes", curaxes);
724 end_unwind_protect 757 end_unwind_protect
725 endif 758 endif
726 endif 759 endif
730 hobjects2 = hobjects; 763 hobjects2 = hobjects;
731 hplot2 = hplots; 764 hplot2 = hplots;
732 text_strings2 = text_strings; 765 text_strings2 = text_strings;
733 endif 766 endif
734 767
768 endfunction
769
770 function updatelegend (h, d)
771 persistent recursive = false;
772 if (! recursive)
773 recursive = true;
774 [hplots, text_strings] = getlegenddata (h);
775 h = legend (fliplr (hplots), get (h, "string"));
776 recursive = false;
777 endif
735 endfunction 778 endfunction
736 779
737 function updatelegendtext (h, d) 780 function updatelegendtext (h, d)
738 kids = get (h, "children"); 781 kids = get (h, "children");
739 k = numel (kids); 782 k = numel (kids);
790 && strcmp (get (ca, "beingdeleted"), "off")) 833 && strcmp (get (ca, "beingdeleted"), "off"))
791 delete (ca); 834 delete (ca);
792 endif 835 endif
793 endfunction 836 endfunction
794 837
795 function deletelegend2 (h, d, ca, pos, outpos, t1) 838 function deletelegend2 (h, d, ca, pos, outpos, t1, hplots)
796 for i = 1 : numel (ca) 839 for i = 1 : numel (ca)
797 if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes") 840 if (ishandle (ca(i)) && strcmp (get (ca(i), "type"), "axes")
798 && (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off")) 841 && (isempty (gcbf()) || strcmp (get (gcbf(), "beingdeleted"),"off"))
799 && strcmp (get (ca(i), "beingdeleted"), "off")) 842 && strcmp (get (ca(i), "beingdeleted"), "off"))
800 if (!isempty (pos) && !isempty(outpos)) 843 if (!isempty (pos) && !isempty(outpos))
804 set (ca(i), "position", pos, "outerposition", outpos, "deletefcn", ""); 847 set (ca(i), "position", pos, "outerposition", outpos, "deletefcn", "");
805 unwind_protect_cleanup 848 unwind_protect_cleanup
806 set (ca(i), "units", units); 849 set (ca(i), "units", units);
807 end_unwind_protect 850 end_unwind_protect
808 endif 851 endif
809 if (i == 1)
810 set (t1, "deletefcn", "");
811 delete (t1);
812 endif
813 endif 852 endif
814 endfor 853 endfor
854 set (t1, "deletefcn", "");
855 delete (t1);
856 for i = 1 : numel (hplots)
857 if (strcmp (get (hplots (i), "type"), "line"))
858 dellistener (hplots (i), "color");
859 dellistener (hplots (i), "linestyle");
860 dellistener (hplots (i), "marker");
861 dellistener (hplots (i), "markeredgecolor");
862 dellistener (hplots (i), "markerfacecolor");
863 dellistener (hplots (i), "markersize");
864 dellistener (hplots (i), "displayname");
865 endif
866 endfor
867 endfunction
868
869 function updateline (h, d, hlegend, linelength)
870 lm = [];
871 ll = [];
872 kids = get (hlegend, "children");
873 for i = 1 : numel (kids)
874 if (get (kids (i), "userdata") == h
875 && strcmp (get (kids(i), "type"), "line"))
876 if (strcmp (get (kids (i), "marker"), "none"))
877 ll = kids (i);
878 else
879 lm = kids (i);
880 endif
881 endif
882 endfor
883
884 linestyle = get (h, "linestyle");
885 marker = get (h, "marker");
886 displayname = get (h, "displayname");
887
888 if ((isempty (displayname)
889 || (strcmp (marker, "none") && strcmp (linestyle, "none")))
890 && (! isempty (lm) || isempty (ll)))
891 ## An element was removed from the legend. Need to recall the
892 ## legend function to recreate a new legend
893 [hplots, text_strings] = getlegenddata (hlegend);
894 for i = 1 : numel (hplots)
895 if (hplots (i) == h)
896 hplots(i) = [];
897 text_strings(i) = [];
898 break;
899 endif
900 endfor
901 legend (hplots, text_strings);
902 elseif ((!isempty (displayname)
903 && (! strcmp (marker, "none") || ! strcmp (linestyle, "none")))
904 && isempty (lm) && isempty (ll))
905 ## An element was added to the legend. Need to recall the
906 ## legend function to recreate a new legend
907 [hplots, text_strings] = getlegenddata (hlegend);
908 hplots = [hplots, h];
909 text_strings = {text_strings{:}, displayname};
910 legend (hplots, text_strings);
911 else
912 if (! isempty (ll))
913 ypos1 = get (ll,"ydata");
914 xpos1 = get (ll,"xdata");
915 ypos2 = ypos1(1);
916 xpos2 = sum(xpos1) / 2;
917 delete (ll);
918 if (! isempty (lm))
919 delete (lm);
920 endif
921 else
922 ypos2 = get (lm,"ydata");
923 xpos2 = get (lm,"xdata");
924 ypos1 = [ypos2, ypos2];
925 xpos1 = xpos2 + [-0.5, 0.5] * linelength;
926 delete (lm);
927 endif
928 if (! strcmp (linestyle, "none"))
929 line ("xdata", xpos1, "ydata", ypos1, "color", get (h, "color"),
930 "linestyle", get (h, "linestyle"), "marker", "none",
931 "userdata", h, "parent", hlegend);
932 endif
933 if (! strcmp (marker, "none"))
934 line ("xdata", xpos2, "ydata", ypos2, "color", get (h, "color"),
935 "marker", marker, "markeredgecolor", get (h, "markeredgecolor"),
936 "markerfacecolor", get (h, "markerfacecolor"),
937 "markersize", get (h, "markersize"), "linestyle", "none",
938 "userdata", h, "parent", hlegend);
939 endif
940 endif
941 endfunction
942
943 function [hplots, text_strings] = getlegenddata (hlegend)
944 hplots = [];
945 text_strings = {};
946 ca = getfield (get (hlegend, "userdata"), "handle");
947 kids = [];
948 for i = 1 : numel (ca)
949 kids = [kids; get(ca (i), "children")];
950 endfor
951 k = numel (kids);
952 while (k > 0)
953 typ = get (kids(k), "type");
954 while (k > 0
955 && ! (strcmp (typ, "line") || strcmp (typ, "surface")
956 || strcmp (typ, "patch") || strcmp (typ, "hggroup")))
957 typ = get (kids(--k), "type");
958 endwhile
959 if (k > 0)
960 if (strcmp (get (kids(k), "type"), "hggroup"))
961 hgkids = get (kids(k), "children");
962 for j = 1 : length (hgkids)
963 hgobj = get (hgkids (j));
964 if (isfield (hgobj, "displayname")
965 && ! isempty (hgobj.displayname))
966 hplots = [hplots, hgkids(j)];
967 text_strings = {text_strings{:}, hbobj.displayname};
968 break;
969 endif
970 endfor
971 else
972 if (! isempty (get (kids (k), "displayname")))
973 hplots = [hplots, kids(k)];
974 text_strings = {text_strings{:}, get(kids (k), "displayname")};
975 endif
976 endif
977 if (--k == 0)
978 break;
979 endif
980 endif
981 endwhile
815 endfunction 982 endfunction
816 983
817 %!demo 984 %!demo
818 %! clf 985 %! clf
819 %! plot(1:10, 1:10, 1:10, fliplr(1:10)); 986 %! plot(1:10, 1:10, 1:10, fliplr(1:10));