# HG changeset patch # User David Bateman # Date 1219332546 14400 # Node ID c4482fc30c7f0377b6b5ffbbd8d212bb6bc86130 # Parent 24701aa75ecbe5f64da30b756890888a858ef029 Add the ezplot function diff --git a/doc/ChangeLog b/doc/ChangeLog --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2008-08-21 David Bateman + + * interpreter/plot.txi: Document ezplot. + 2008-08-19 David Bateman * interpreter/numbers.txi: Document intwarning. diff --git a/doc/interpreter/plot.txi b/doc/interpreter/plot.txi --- a/doc/interpreter/plot.txi +++ b/doc/interpreter/plot.txi @@ -208,7 +208,10 @@ @DOCSTRING(fplot) Other functions that can create two-dimensional plots directly from a -function include @code{ezcontour}, @code{ezcontourf} and @code{ezpolar}. +function include @code{ezplot), @code{ezcontour}, @code{ezcontourf} and +@code{ezpolar}. + +@DOCSTRING(ezplot) @DOCSTRING(ezcontour) diff --git a/scripts/ChangeLog b/scripts/ChangeLog --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,9 @@ +2008-08-21 David Bateman + + * plot/ezplot.m : New function. + * plot/Makefile.in (SOURCES): Add ezplot.m to the list. + * plot/__ezplot__.m: Adapt to allow for use with the ezplot function. + 2008-08-20 Jaroslav Hajek * pkg/pkg.m (configure_make): Pass handle to is_architecture_dependent diff --git a/scripts/plot/Makefile.in b/scripts/plot/Makefile.in --- a/scripts/plot/Makefile.in +++ b/scripts/plot/Makefile.in @@ -96,6 +96,7 @@ ezcontour.m \ ezmeshc.m \ ezmesh.m \ + ezplot.m \ ezplot3.m \ ezpolar.m \ ezsurfc.m \ diff --git a/scripts/plot/__ezplot__.m b/scripts/plot/__ezplot__.m --- a/scripts/plot/__ezplot__.m +++ b/scripts/plot/__ezplot__.m @@ -26,15 +26,23 @@ else iscontour = false; endif - if (strcmp (pfunc, "plot3")) + if (strcmp (pfunc, "plot")) + isplot = true; + isplot3 = false; + ispolar = false; + nargs = 1; + elseif (strcmp (pfunc, "plot3")) + isplot = false; isplot3 = true; ispolar = false; - nargs = 1 + nargs = 1; elseif (strcmp (pfunc, "polar")) + isplot = false; isplot3 = false; ispolar = true; nargs = 1; else + isplot = false; isplot3 = false; ispolar = false; nargs = 2; @@ -51,12 +59,25 @@ parametric = false; fun = varargin {1}; if (ischar (fun)) - fun = vectorize (inline (fun)); - if (length (argnames (fun)) != nargs) + if (exist (fun, "file") || exist (fun, "builtin")) + fun = vectorize (inline (cstrcat (fun, "(t)"))); + else + fun = vectorize (inline (fun)); + endif + if (isplot && length (argnames (fun)) == 2) + nargs = 2; + elseif (length (argnames (fun)) != nargs) error ("%s: excepting a function of %d arguments", func, nargs); endif fstr = formula (fun); - if (isplot3) + if (isplot) + xarg = argnames(fun){1}; + if (nargs == 2) + yarg = argnames(fun){2}; + else + yarg = ""; + endif + elseif (isplot3) xarg = "x"; yarg = "y"; elseif (ispolar) @@ -67,15 +88,24 @@ yarg = argnames(fun){2}; endif elseif (strcmp (typeinfo (fun), "inline function")) - if (length (argnames (fun)) != nargs) + if (isplot && length (argnames (fun)) == 2) + nargs = 2; + elseif (length (argnames (fun)) != nargs) error ("%s: excepting a function of %d arguments", func, nargs); endif fun = vectorize (fun); fstr = formula (fun); - if (isplot3) + if (isplot) + xarg = argnames(fun){1}; + if (nargs == 2) + yarg = argnames(fun){2}; + else + yarg = ""; + endif + elseif (isplot3) xarg = "x"; yarg = "y"; - elseif (ispolar) + elseif (isplot || ispolar) xarg = ""; yarg = ""; else @@ -84,13 +114,26 @@ endif elseif (isa (fun, "function_handle")) fstr = func2str (fun); - args = regexp (substr (fstr, 3, findstr (fstr, ")")(1) - 3), - '(\w[\w\d]*)', 'tokens'); - if (length (args) != nargs) + if (length (findstr (fstr, ")")) != 0) + args = regexp (substr (fstr, 3, findstr (fstr, ")")(1) - 3), + '(\w[\w\d]*)', 'tokens'); + fstr = substr (fstr, findstr (fstr, ")")(1) + 1); + else + args = {{"x"}}; + endif + if (isplot && length (args) == 2) + nargs = 2; + elseif (length (args) != nargs) error ("%s: excepting a function of %d arguments", func, nargs); endif - fstr = substr (fstr, findstr (fstr, ")")(1) + 1); - if (isplot3) + if (isplot) + xarg = args{1}{1}; + if (nargs == 2) + yarg = args{2}{1}; + else + yarg = ""; + endif + elseif (isplot3) xarg = "x"; yarg = "y"; elseif (ispolar) @@ -104,13 +147,17 @@ error ("%s: expecting string, inline function or function handle", func); endif - if (nargin > 2) + if (nargin > 2 || (nargin == 2 && isplot)) funx = fun; fstrx = fstr; funy = varargin {2}; if (ischar (funy) && ! strcmp (funy, "circ") && ! strcmp (funy, "animate")) parametric = true; - funy = vectorize (inline (funy)); + if (exist (funy, "file") || exist (funy, "builtin")) + funy = vectorize (inline (cstrcat (funy, "(t)"))); + else + funy = vectorize (inline (funy)); + endif if (length (argnames (funy)) != nargs) error ("%s: excepting a function of %d arguments", func, nargs); endif @@ -125,19 +172,35 @@ elseif (isa (funy, "function_handle")) parametric = true; fstry = func2str (funy); - args = regexp (substr (fstry, 3, findstr (fstry, ")")(1) - 3), - '(\w[\w\d]*)', 'tokens'); + if (length (findstr (fstry, ")")) != 0) + args = regexp (substr (fstry, 3, findstr (fstry, ")")(1) - 3), + '(\w[\w\d]*)', 'tokens'); + fstry = substr (fstry, findstr (fstry, ")")(1) + 1); + else + args = {{"y"}}; + endif if (length (args) != nargs) error ("%s: excepting a function of %d arguments", func, nargs); endif - fstry = substr (fstry, findstr (fstry, ")")(1) + 1); + endif + + if (parametric && isplot) + xarg = "x"; + yarg = "y"; + if (nargs == 2) + error ("%s: can not define a parametric function in this manner"); + endif endif - if (parametric) + if (!isplot && parametric) funz = varargin {3}; if (ischar (funz) && ! strcmp (funz, "circ") && - ! strcmp (funy, "animate")) - funz = vectorize (inline (funz)); + ! strcmp (funz, "animate")) + if (exist (funz, "file") || exist (funz, "builtin")) + funz = vectorize (inline (cstrcat (funz, "(t)"))); + else + funz = vectorize (inline (funz)); + endif if (length (argnames (funz)) != nargs) error ("%s: excepting a function of %d arguments", func, nargs); endif @@ -162,12 +225,20 @@ endif endif - n = 60; + if (isplot && nargs != 2) + n = 500; + else + n = 60; + endif domain = []; circ = false; animate = false; if (parametric) - iarg = 4; + if (isplot) + iarg = 3; + else + iarg = 4; + endif else iarg = 2; endif @@ -197,7 +268,7 @@ endif if (circ) - if (iscontour || isplot3) + if (iscontour || isplot3 || isplot) needusage = true; return; endif @@ -221,15 +292,23 @@ error ("%s: animated graphs not implemented", func); endif - if (isplot3 || ispolar) + if (isplot3 || ispolar || (isplot && nargs == 1)) X = linspace (domain (1), domain (2), n); + elseif (isplot && numel (domain) == 2) + x = linspace (domain (1), domain (2), n); + [X, Y] = meshgrid (x, x); else x = linspace (domain (1), domain (2), n); y = linspace (domain (3), domain (4), n); [X, Y] = meshgrid (x, y); endif + if (parametric) - if (isplot3) + if (isplot) + XX = feval (funx, X); + Z = feval (funy, X); + X = XX; + elseif (isplot3) Z = feval (funz, X); XX = feval (funx, X); YY = feval (funy, X); @@ -252,26 +331,77 @@ '\./', '/'), '[\.]*\*', ''); fstry = regexprep (regexprep (regexprep (fstry,'\.\^\s*','^'), '\./', '/'), '[\.]*\*', ''); - fstrz = regexprep (regexprep (regexprep (fstrz,'\.\^\s*','^'), - '\./', '/'), '[\.]*\*', ''); - fstr = cstrcat ("[",fstrx,",",fstry,",",fstrz,"]"); + if (isplot) + fstr = cstrcat ("x = ",fstrx,", y = ",fstry); + else + fstrz = regexprep (regexprep (regexprep (fstrz,'\.\^\s*','^'), + '\./', '/'), '[\.]*\*', ''); + fstr = cstrcat ("x = ",fstrx,",y = ",fstry,", z = ",fstrz); + endif else if (isplot3) needusage = true; return; endif - if (ispolar) - Z = feval (fun, X); - else + fstr = regexprep (regexprep (regexprep (fstr,'\.\^\s*','^'), '\./', '/'), + '[\.]*\*', ''); + if (isplot && nargs == 2) + if (strcmp (typeinfo (fun), "inline function") && + !isempty (strfind (formula (fun) , "="))) + fun = inline (cstrcat (strrep (formula (fun), "=", "- ("), ")")); + else + fstr = cstrcat (fstr, " = 0"); + endif + Z = feval (fun, X, Y); - ## Eliminate the singularities - Z = __eliminate_sing__ (Z); + ## Matlab returns line objects for this case and so can't call + ## contour directly as it returns patch objects to allow colormaps + ## to work with contours. Therefore recreate the lines from the + ## output for contourc, and store in cell arrays. + [c, lev] = contourc (X, Y, Z, [0, 0]); + + i1 = 1; + XX = {}; + YY = {}; + while (i1 < length (c)) + clev = c(1,i1); + clen = c(2,i1); + XX = [XX, {c(1, i1+1:i1+clen)}]; + YY = [YY, {c(2, i1+1:i1+clen)}]; + i1 += clen+1; + endwhile + else + if (ispolar) + Z = feval (fun, X); + elseif (isplot) + Z = real (feval (fun, X)); + + ## Eliminate the singularities. This seems to be what matlab + ## does, but can't be sure. + XX = sort (Z (isfinite (Z))); + if (length (X) > 4) + d = XX(fix (7 * length (XX) / 8)) - XX(fix (length (XX) / 8)); + yrange = [max(XX(1) - d/8, XX(fix (length (XX) / 8)) - d), ... + min(XX(end) + d/8, XX(fix (7 * length (XX) / 8)) + d)]; + else + yrange = [XX(1), XX(end)]; + endif + + idx = 2 : length(Z); + idx = find (((Z(idx) > yrange(2) / 2) & (Z(idx-1) < yrange(1) / 2)) | + ((Z(idx) < yrange(1) / 2) & (Z(idx-1) > yrange (2) / 2))); + if (any(idx)) + Z(idx) = NaN; + endif + else + Z = feval (fun, X, Y); + + ## Eliminate the singularities + Z = __eliminate_sing__ (Z); + endif endif - - fstr = regexprep (regexprep (regexprep (fstr,'\.\^\s*','^'), '\./', '/'), - '[\.]*\*', ''); endif oldax = gca (); @@ -279,8 +409,21 @@ axes (ax); if (iscontour) [clev, h] = feval (pfunc, X, Y, Z); - elseif (ispolar) + elseif (isplot && nargs == 2) + h = []; + hold_state = get (ax, "nextplot"); + for i = 1 : length (XX) + h = [h; plot(XX{i}, YY{i})]; + if (i == 1) + set (ax, "nextplot", "add") + endif + endfor + set (ax, "nextplot", hold_state) + elseif (ispolar || isplot) h = feval (pfunc, X, Z); + if (isplot && !parametric) + axis ([X(1), X(end), yrange]); + endif else h = feval (pfunc, X, Y, Z); endif diff --git a/scripts/plot/ezplot.m b/scripts/plot/ezplot.m new file mode 100644 --- /dev/null +++ b/scripts/plot/ezplot.m @@ -0,0 +1,89 @@ +## Copyright (C) 2008 David Bateman +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## . + +## -*- texinfo -*- +## @deftypefn {Function File} {} ezplot (@var{f}) +## @deftypefnx {Function File} {} ezplot (@var{fx}, @var{fy}) +## @deftypefnx {Function File} {} ezplot (@dots{}, @var{dom}) +## @deftypefnx {Function File} {} ezplot (@dots{}, @var{n}) +## @deftypefnx {Function File} {} ezplot (@var{h}, @dots{}) +## @deftypefnx {Function File} {@var{h} =} ezplot (@dots{}) +## +## Plots in two-dimensions the curve defined by @var{f}. The function +## @var{f} may be a string, inline function or function handle and can +## have either one or two variables. If @var{f} has one variable, then +## the function is plotted over the domain @code{-2*pi < @var{x} < 2*pi} +## with 500 points. +## +## If @var{f} has two variables then @code{@var{f}(@var{x},@var{y}) = 0} +## is calculated over the meshed domain @code{-2*pi < @var{x} | @var{y} +## < 2*pi} with 60 by 60 in the mesh. For example +## +## @example +## ezplot (@@(@var{x}, @var{y}) @var{x} .^ 2 - @var{y} .^ 2 - 1) +## @end example +## +## If two functions are passed as strings, inline functions or function +## handles, then the parametric function +## +## @example +## @group +## @var{x} = @var{fx} (@var{t}) +## @var{y} = @var{fy} (@var{t}) +## @end group +## @end example +## +## is plotted over the domain @code{-2*pi < @var{t} < 2*pi} with 500 +## points. +## +## If @var{dom} is a two element vector, it represents the minimum and maximum +## value of @var{x}, @var{y} and @var{t}. If it is a four element +## vector, then the minimum and maximum values of @var{x} and @var{t} +## are determined by the first two elements and the minimum and maximum +## of @var{y} by the second pair of elements. +## +## @var{n} is a scalar defining the number of points to use in plotting +## the function. +## +## The optional return value @var{h} provides a list of handles to the +## the line objects plotted. +## +## @seealso{plot, ezplot3} +## @end deftypefn + +function retval = ezplot (varargin) + + [h, needusage] = __ezplot__ ("plot", varargin{:}); + + if (needusage) + print_usage (); + endif + + if (nargout > 0) + retval = h; + endif +endfunction + +%!demo +%! ezplot (@cos, @sin) + +%!demo +%! ezplot ("1/x") + +%!demo +%! ezplot (inline("x^2 - y^2 = 1"))