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