Mercurial > jwe > octave
changeset 27821:9a498cde5bc5
annotation.m: Octave coding style changes.
annotation.m: Use '~' instead of temporary variable "dummy" to discard a
function input. Use a newline between "case" blocks when the blocks are
of reasonable size. Use more commas when defining arrays to clarify
how parser will treat array. Use numel() in preference to length().
Add more BIST tests for input validation.
author | Rik <rik@octave.org> |
---|---|
date | Fri, 13 Dec 2019 08:54:06 -0800 |
parents | bad702797afb |
children | 78435ddc9f88 |
files | scripts/plot/appearance/annotation.m |
diffstat | 1 files changed, 150 insertions(+), 121 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/plot/appearance/annotation.m Thu Dec 12 21:38:59 2019 -0800 +++ b/scripts/plot/appearance/annotation.m Fri Dec 13 08:54:06 2019 -0800 @@ -147,39 +147,33 @@ function varargout = annotation (varargin) + nargin = numel (varargin); + if (nargin == 0) + print_usage (); + endif + objtype = ""; hf = []; lims = []; x = y = []; opts = {}; - nargin = numel (varargin); - if (nargin == 0) - print_usage (); - endif - - ## Parent figure if (isfigure (varargin{1})) hf = varargin{1}; - varargin = varargin(2:end); - nargin -= 1; + varargin(1) = []; nargin -= 1; endif ## Annotation type - types = {"line", "arrow", "doublearrow", "textarrow", ... - "textbox", "ellipse", "rectangle"}; - if (ischar (varargin{1})) - objtype = varargin{1}; - varargin(1) = []; - nargin -= 1; - else + if (! ischar (varargin{1})) print_usage (); endif + objtype = varargin{1}; + varargin(1) = []; nargin -= 1; switch (objtype) - case types(1:4) + case {"line", "arrow", "doublearrow", "textarrow"} if (nargin == 0) lims = []; elseif (nargin >= 2) @@ -189,40 +183,42 @@ if (isnumeric (x) && isnumeric (y) && length (x) == 2 && length (y) == 2) - lims = [x(1) y(1) diff(x) diff(y)]; + lims = [x(1), y(1), diff(x), diff(y)]; else error ("annotation: X and Y must be 2-element vectors"); endif else print_usage (); endif - case types(5:end) + + case {"textbox", "ellipse", "rectangle"} if (nargin == 0) lims = []; else lims = varargin{1}; varargin(1) = []; - if (! isvector (lims) || length (lims) != 4) + if (! isvector (lims) || numel (lims) != 4) error ("annotation: POS must be a 4-element vector"); endif endif + otherwise error ("annotation: unknown annotation TYPE %s", objtype); + endswitch ## options opts = varargin; nopts = numel (opts); if (! isempty (opts)) - if (fix (nopts/2) != nopts/2 - || ! all (cellfun (@ischar, opts(1:2:end)))) + if (fix (nopts/2) != nopts/2 || ! all (cellfun (@ischar, opts(1:2:end)))) warning ("annotation: couldn't parse PROP/VAL pairs, skipping"); opts = {}; endif endif - ## create annotation + ## Create annotation showhidden = get (0, "showhiddenhandles"); set (0, "showhiddenhandles", "on"); @@ -263,17 +259,14 @@ function hax = buildoverlay (hf) - hax = axes ("parent", hf, "position", [0 0 1 1], ... - "visible", "off","tag", "scribeoverlay", ... - "xlim", [0 1], "ylim", [0 1], ... + hax = axes ("parent", hf, "visible", "off", "tag", "scribeoverlay", ... + "position", [0 0 1 1], "xlim", [0 1], "ylim", [0 1], ... "handlevisibility", "off"); - ## hidden property to store figure size in absolute (points) - ## coordinates + ## Hidden property to store figure size in absolute (points) coordinates. addproperty ("figsize_points", hax, "axesxminortickvalues", []); update_figsize_points (hf, {}, hax); - listener = {@update_figsize_points, hax}; addlistener (hf, "position", listener); @@ -282,9 +275,10 @@ endfunction -function update_figsize_points (hf, dummy, hax) +function update_figsize_points (hf, ~, hax) persistent recursive = false; + if (! recursive) recursive = true; units = get (hf, "units"); @@ -358,9 +352,10 @@ ## create line hli = line ([pos(1); (pos(1) + pos(3))], [pos(2); (pos(2) + pos(4))], - "parent", h, "color", get (h, "color"), + "color", get (h, "color"), "linestyle", get (h, "linestyle"), - "linewidth", get (h, "linewidth")); + "linewidth", get (h, "linewidth"), + "parent", h); linemenu (hui, h); set (hli, "uicontextmenu", hui); @@ -368,8 +363,8 @@ ## create patch(s) and text if (strcmp (objtype, "arrow")) [x, y] = arrowcoordinates (h); - hpa = patch (x, y, get (h, "color"), "parent", h, - "edgecolor", get (h, "color")); + hpa = patch (x, y, get (h, "color"), "edgecolor", get (h, "color"), + "parent", h); update_arrow (h, {}, "position", hpa); arrowmenu (hui, h); @@ -377,12 +372,12 @@ elseif (strcmp (objtype, "doublearrow")) [x, y] = arrowcoordinates (h, 1); - hpa = patch (x, y, get (h, "color"), "parent", h, - "edgecolor", get (h, "color")); + hpa = patch (x, y, get (h, "color"), "edgecolor", get (h, "color"), + "parent", h); [x, y] = arrowcoordinates (h, 2); - hpa(2) = patch (x, y, get (h, "color"), "parent", h, - "edgecolor", get (h, "color")); + hpa(2) = patch (x, y, get (h, "color"), "edgecolor", get (h, "color"), + "parent", h); update_arrow (h, {}, "position", hpa); @@ -391,17 +386,17 @@ elseif (strcmp (objtype, "textarrow")) [x, y] = arrowcoordinates (h); - hpa = patch (x, y, get (h, "color"), "parent", h, - "edgecolor", get (h, "color")); + hpa = patch (x, y, get (h, "color"), "edgecolor", get (h, "color"), + "parent", h); update_arrow (h, {}, "position", hpa); - hte = text (get (h, "position")(1), ... - get (h, "position")(2), ... - get (h, "string"), "parent", h, ... - "color", get (h, "color")); + hte = text (get (h, "position")(1), + get (h, "position")(2), + get (h, "string"), + "color", get (h, "color"), "parent", h); propnames = textprops ("names"); - for ii = 1:numel (propnames) - update_text (h, {}, propnames{ii}, hte); + for i = 1 : numel (propnames) + update_text (h, {}, propnames{i}, hte); endfor update_text (h, {}, "position", hte); @@ -426,22 +421,23 @@ addlistener (h, "headstyle", {@update_arrow, "position", hpa}); addlistener (h, "headlength", {@update_arrow, "position", hpa}); addlistener (h, "color", {@update_arrow, "color", hpa}); + elseif (strcmp (objtype, "doublearrow")) addlistener (h, "position", {@update_arrow, "position", hpa}); addlistener (h, "head1width", - {@update_arrow, "position", [hpa(1) 0]}); + {@update_arrow, "position", [hpa(1), 0]}); addlistener (h, "head2width", - {@update_arrow, "position", [0 hpa(2)]}); + {@update_arrow, "position", [0, hpa(2)]}); addlistener (h, "head1style", - {@update_arrow, "position", [hpa(1) 0]}); + {@update_arrow, "position", [hpa(1), 0]}); addlistener (h, "head2style", - {@update_arrow, "position", [0 hpa(2)]}); + {@update_arrow, "position", [0, hpa(2)]}); addlistener (h, "head1length", - {@update_arrow, "position", [hpa(1) 0]}); + {@update_arrow, "position", [hpa(1), 0]}); addlistener (h, "head2length", - {@update_arrow, "position", [0 hpa(2)]}); - addlistener (h, "color", - {@update_arrow, "color", hpa}); + {@update_arrow, "position", [0, hpa(2)]}); + addlistener (h, "color", {@update_arrow, "color", hpa}); + elseif (strcmp (objtype, "textarrow")) addlistener (h, "position", {@update_arrow, "position", hpa}); addlistener (h, "headwidth", {@update_arrow, "position", hpa}); @@ -449,17 +445,16 @@ addlistener (h, "headlength", {@update_arrow, "position", hpa}); addlistener (h, "color", {@update_arrow, "color", hpa}); propnames = textprops ("names"); - for ii = 1:numel (propnames) - addlistener (h, propnames{ii}, - {@update_text, propnames{ii}, hte}); - if (any (strcmp (propnames{ii}, + for i = 1 : numel (propnames) + addlistener (h, propnames{i}, + {@update_text, propnames{i}, hte}); + if (any (strcmp (propnames{i}, {"fontangle", "fontname", ... "fontsize", "fontweight", ... "horizontalalignment", "string", ... "textmargin", "textrotation", ... "verticalalignment"}))) - addlistener (h, propnames{ii}, ... - {@update_text, "position", hte}); + addlistener (h, propnames{i}, {@update_text, "position", hte}); endif endfor addlistener (h, "position", {@update_text, "position", hte}); @@ -481,8 +476,8 @@ hr = patch (x, y, "parent", h); propnames = rectprops ("names"); - for ii = 1:numel (propnames) - update_rect (h, {}, propnames{ii}, hr, objtype); + for i = 1 : numel (propnames) + update_rect (h, {}, propnames{i}, hr, objtype); endfor rectmenu (hui, h); @@ -490,9 +485,9 @@ ## Updaters addlistener (h, "position", {@update_rect, "position", hr, objtype}); - for ii = 1:numel (propnames) - addlistener (h, propnames{ii}, - {@update_rect, propnames{ii}, hr, objtype}); + for i = 1 : numel (propnames) + addlistener (h, propnames{i}, + {@update_rect, propnames{i}, hr, objtype}); endfor case "textbox" @@ -502,13 +497,13 @@ ## Create textbox hpa = patch ("parent", h); - hte = text (pos(1), pos(2), get (h, "string"), "parent", h, ... - "color", get (h, "color")); + hte = text (pos(1), pos(2), get (h, "string"), + "color", get (h, "color"), "parent", h); update_textbox (h, {}, "position", [hte hpa]); propnames = textboxprops ("names"); - for ii = 1:numel (propnames) - update_textbox (h, {}, propnames{ii}, [hte hpa]); + for i = 1 : numel (propnames) + update_textbox (h, {}, propnames{i}, [hte hpa]); endfor textboxmenu (hui, h); @@ -517,9 +512,9 @@ ## Updaters addlistener (h, "position", {@update_textbox, "position", [hte hpa]}); - for ii = 1:numel (propnames) - addlistener (h, propnames{ii}, - {@update_textbox, propnames{ii}, [hte hpa]}); + for i = 1 : numel (propnames) + addlistener (h, propnames{i}, + {@update_textbox, propnames{i}, [hte hpa]}); endfor addlistener (h, "horizontalalignment", {@update_textbox, "position", [hte hpa]}); @@ -653,7 +648,7 @@ def = get (hpar, prop); if (iscell (def)) - prompt = arrayfun (@(n) sprintf ("Line #%d:", n), 1:numel (def), + prompt = arrayfun (@(n) sprintf ("Line #%d:", n), 1 : numel (def), "uniformoutput", false); else prompt = ""; @@ -702,7 +697,7 @@ vals = set (hpar, prop); addbasemenu (hm, hpar, prop, vals, "Vertical Alignment"); - ## FIXME: Add text background properties when they are supported + ## FIXME: Add text background properties (Bug #57407). prop = "interpreter"; vals = set (hpar, prop); @@ -830,7 +825,7 @@ proptable(1:3:end), proptable(2:3:end), proptable(3:3:end)); endfunction -function addbasemenu (hm, hpar, pname, vals, mainlabel = "" ) +function addbasemenu (hm, hpar, pname, vals, mainlabel = "") if (isempty (mainlabel)) mainlabel = pname; @@ -841,16 +836,16 @@ is_numeric = ! iscell (vals); nv = numel (vals); htmp = zeros (1, nv); - for ii = 1:nv + for i = 1:nv if (! is_numeric) - val = label = vals{ii}; + val = label = vals{i}; else - val = vals(ii); + val = vals(i); label = disp (val); endif fcn = @() set (hpar, pname, val); - htmp(ii) = uimenu (h, "label", label, "callback", fcn); + htmp(i) = uimenu (h, "label", label, "callback", fcn); endfor handle_check (hpar, {}, htmp, pname, is_numeric); @@ -858,7 +853,7 @@ endfunction -function handle_check (h, dummy, hmenus, prop, is_numeric) +function handle_check (h, ~, hmenus, prop, is_numeric) vals = get (hmenus, "label"); current = get (h, prop); @@ -872,7 +867,7 @@ endfunction -function update_position (h1, dummy, h, force = false) +function update_position (h1, ~, h, force = false) if (! force) pos = convertposition (h, getappdata (h, "__former_units__"), @@ -881,23 +876,25 @@ set (h, "position", pos); else ## FIXME: Inefficient trick to force all objects to be redrawn - set (h, "position", [0 0 .5 .5], - "position", get (h, "position")); + set (h, "position", [0 0 .5 .5], "position", get (h, "position")); endif endfunction -function update_line (h, dummy, prop, hli) +function update_line (h, ~, prop, hli) persistent recursive = false; if (! recursive) switch (prop) case "color" set (hli, "color", get (h, "color")); + case "linestyle" set (hli, "linestyle", get (h, "linestyle")); + case "linewidth" set (hli, "linewidth", get (h, "linewidth")); + case "x" ## Update position x = get (h, "x"); @@ -927,6 +924,7 @@ pos = getnormpos (h); y = [pos(2) (pos(2) + pos(4))]; set (hli, "ydata", y); + case "position" ## Update x and y pos = get (h, "position"); @@ -960,13 +958,13 @@ headstyle = get (h, "headstyle"); pos = pos(1:2) .+ pos(3:4); elseif (nar == 1) - ln = get (h, "head1length"); # in points + ln = get (h, "head1length"); # in points wd = get (h, "head1width"); headstyle = get (h, "head1style"); pos = pos(1:2); ang += pi; elseif (nar == 2) - ln = get (h, "head2length"); # in points + ln = get (h, "head2length"); # in points wd = get (h, "head2width"); headstyle = get (h, "head2style"); pos = pos(1:2) .+ pos(3:4); @@ -978,34 +976,43 @@ case "diamond" x = [0 -ln/2 -ln -ln/2 0]; y = [0 -wd/2 0 wd/2 0]; + case "ellipse" pts = linspace (0, 2*pi, 12); x = ln/2 * (cos (pts) - 1); y = wd/2 * sin (pts); + case "rectangle" x = [0 0 -ln -ln 0]; y = [wd/2 -wd/2 -wd/2 wd/2 wd/2]; + case "vback1" x = [0 -ln -0.85*ln -ln 0]; y = [0 wd/2 0 -wd/2 0]; + case "vback2" x = [0 -ln -0.65*ln -ln 0]; y = [0 wd/2 0 -wd/2 0]; + case "vback3" x = [0 -ln -0.2*ln -ln 0]; y = [0 wd/2 0 -wd/2 0]; + case "plain" x = [0 -ln -ln -ln 0]; y = [0 wd/2 0 -wd/2 0]; + case "none" x = [0 0 0]; y = [0 0 0]; + otherwise + ## FIXME: This code is not reachable (12/13/2019) error ('annotation: "%s" headstyle not implemented', headstyle); endswitch - R = [cos(ang) -sin(ang); - sin(ang) cos(ang)]; + R = [cos(ang), -sin(ang); + sin(ang), cos(ang)]; XY = R * [x; y]; XY = pts2norm (h, XY); XY = pos(1:2).' .+ XY; @@ -1015,20 +1022,21 @@ endfunction -function update_arrow (h, dummy, prop, hpa = []) +function update_arrow (h, ~, prop, hpa = []) nar = []; - for ii = 1:numel (hpa) + for i = 1 : numel (hpa) if (numel (hpa) == 2) - nar = ii; + nar = i; endif - if (hpa(ii)) + if (hpa(i)) switch (prop) case "position" [x, y] = arrowcoordinates (h, nar); - set (hpa(ii), "xdata", x, "ydata", y); + set (hpa(i), "xdata", x, "ydata", y); + case "color" - set (hpa(ii), "facecolor", get (h, "color"), + set (hpa(i), "facecolor", get (h, "color"), "edgecolor", get (h, "color")); endswitch endif @@ -1036,14 +1044,14 @@ endfunction -function update_text (h, dummy, prop, hte) +function update_text (h, ~, prop, hte) persistent recursive = false; if (! recursive) switch (prop) case "position" if (isempty (get (h, "string"))) - return + return; endif pos = getnormpos (h); @@ -1056,12 +1064,13 @@ else set (hte, prop, get (h, prop)); endif + endswitch endif endfunction -function update_textbox (h, dummy, prop, htb) +function update_textbox (h, ~, prop, htb) persistent recursive = false; hte = htb(1); @@ -1069,11 +1078,12 @@ if (! recursive) switch (prop) - case {"edgecolor", "facealpha", - "linestyle", "linewidth"} + case {"edgecolor", "facealpha", "linestyle", "linewidth"} set (hpa, prop, get (h, prop)); + case {"backgroundcolor"} set (hpa, "facecolor", get (h, prop)); + otherwise if (! any (strcmp (prop, {"fitboxtotext", "position"}))) set (hte, prop, get (h, prop)); @@ -1106,6 +1116,7 @@ y = y(2); endswitch set (hte, "position", [x y 0]); + endswitch endif @@ -1163,8 +1174,8 @@ XY(2,:) -= dy; endswitch - R = [cos(rot) -sin(rot); - sin(rot) cos(rot)]; + R = [cos(rot), -sin(rot); + sin(rot), cos(rot)]; XY = R * XY; XY = pts2norm (get (hte, "parent"), XY); XY = pos(1:2) .- XY(:,pt).'; @@ -1172,14 +1183,14 @@ endfunction function nXY = pts2norm (h, pXY) - sz = get (get (h,"parent"), "figsize_points"); + sz = get (get (h, "parent"), "figsize_points"); nXY(1,:) = pXY(1,:) ./ sz(1); nXY(2,:) = pXY(2,:) ./ sz(2); endfunction function pXY = norm2pts (h, nXY) - sz = get (get (h,"parent"), "figsize_points"); + sz = get (get (h, "parent"), "figsize_points"); pXY(1,:) = nXY(1,:) .* sz(1); pXY(2,:) = nXY(2,:) .* sz(2); @@ -1190,22 +1201,25 @@ pos = get (h, "position"); ## First convert to normalized coordinates - sz = get (get (h,"parent"), "figsize_points"); + sz = get (get (h, "parent"), "figsize_points"); switch (from) case "centimeters" pos /= 2.54; pos *= 72; pos(1:2:end) /= sz(1); pos(2:2:end) /= sz(2); + case "inches" pos *= 72; pos(1:2:end) /= sz(1); pos(2:2:end) /= sz(2); + case "pixels" pos /= get (0, "screenpixelsperinch"); pos *= 72; pos(1:2:end) /= sz(1); pos(2:2:end) /= sz(2); + endswitch ## Then convert to requested coordinates @@ -1215,15 +1229,18 @@ sz *= 2.54; pos(1:2:end) *= sz(1); pos(2:2:end) *= sz(2); + case "inches" sz /= 72; pos(1:2:end) *= sz(1); pos(2:2:end) *= sz(2); + case "pixels" sz /= 72; sz *= get (0, "screenpixelsperinch"); pos(1:2:end) *= sz(1); pos(2:2:end) *= sz(2); + endswitch endfunction @@ -1294,11 +1311,11 @@ %! x0 = 0.5; %! y0 = 0.5; %! r = 0.3; -%! for ii = 1:4 -%! x = r * cos (ang(ii)) + x0; -%! y = r * sin (ang(ii)) + y0; +%! for i = 1:4 +%! x = r * cos (ang(i)) + x0; +%! y = r * sin (ang(i)) + y0; %! annotation ("textarrow", [x x0], [y y0], ... -%! "string", lab{ii}, "fontsize", 20); +%! "string", lab{i}, "fontsize", 20); %! endfor %! %! h = annotation ("doublearrow", [x0 x0], [y0-r y0+r], ... @@ -1357,7 +1374,7 @@ %! y = 1 - dy/2; %! %! jj = 1; -%! for ii = 1:nrows +%! for i = 1:nrows %! annotation ("textarrow", [0.3 0.5], [y y], ... %! "string", styles{jj}, "fontsize", 15, ... %! "headstyle", styles{jj}, "textcolor", "b"); @@ -1383,7 +1400,7 @@ %! "horizontalalignment", "center"); %! %! ## Textarrows -%! for ii = 1:10 +%! for i = 1:10 %! rot = floor (rand (1) * 360 / 90) * 90; %! annotation ("textarrow", 0.5 + [(0.6 * (rand(1) - .5)) 0], ... %! 0.5 + [(0.6 * (rand(1) - .5)) 0], ... @@ -1403,12 +1420,12 @@ %! %! ## Textarrows %! halig = {"right", "center", "left"}; -%! ii = 1; +%! i = 1; %! for x = .3:.2:.7 %! annotation ("textarrow", [x .5], [.5 .9], ... %! "string", {"Multiple lines", "text"}, ... -%! "headstyle", "none", "horizontalalignment", halig{ii}); -%! ii = ii + 1; +%! "headstyle", "none", "horizontalalignment", halig{i}); +%! i = i + 1; %! endfor %!demo @@ -1435,12 +1452,12 @@ %! %! %! ## Textarrows -%! for ii = 1:2 -%! annotation ("doublearrow", [(x0(ii) - .05) (x0(ii) + .05)], ... -%! [y0(ii) y0(ii)], "head1style", "vback3", ... +%! for i = 1:2 +%! annotation ("doublearrow", [(x0(i) - .05) (x0(i) + .05)], ... +%! [y0(i) y0(i)], "head1style", "vback3", ... %! "head2style", "vback3", ... %! "head1width", 4, "head2width", 4) -%! h = annotation ("textarrow", [0.5 x0(ii)], [.85 y0(ii)], ... +%! h = annotation ("textarrow", [0.5 x0(i)], [.85 y0(i)], ... %! "linestyle", "--", "headstyle", "none"); %! endfor %! set (h, "string", "Extrema", "fontsize", 15); @@ -1550,9 +1567,21 @@ %! end_unwind_protect ## Test input validation +%!error annotation () +%!error <Invalid call to annotation> annotation ({"line"}, 1:2, 1:2) +%!error <X and Y must be 2-element vectors> annotation ("line", {1:2}, 1:2) +%!error <X and Y must be 2-element vectors> annotation ("line", 1:2, {1:2}) +%!error <X and Y must be 2-element vectors> annotation ("line", 1:3, 1:2) +%!error <X and Y must be 2-element vectors> annotation ("line", 1:2, 1:3) +%!error <Invalid call to annotation> annotation ("line", 1:2) +%!error <POS must be a 4-element vector> annotation ("textbox", ones (4,4)) +%!error <POS must be a 4-element vector> annotation ("textbox", 1:3) %!error <unknown annotation TYPE foo> annotation ("foo") -%!error annotation ([], "foo") -%!error annotation ({}) -%!error annotation ("line", [.5 .6]) -%!error <X and Y must be 2-element vectors> annotation ("line", 1:3, 1:3) -%!error <POS must be a 4-element vector> annotation ("textbox", 1:3) +%!warning <couldn't parse PROP/VAL pairs, skipping> +%! hf = figure ("visible", "off"); +%! unwind_protect +%! annotation ("line", 1:2, 1:2, "color"); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect +%!error <unknown annotation TYPE foo> annotation ("foo")