Mercurial > octave
view scripts/plot/draw/fplot.m @ 30893:e1788b1a315f
maint: Use "fcn" as preferred abbreviation for "function" in m-files.
* accumarray.m, accumdim.m, quadl.m, quadv.m, randi.m, structfun.m,
__is_function__.m, uigetfile.m, uimenu.m, uiputfile.m, doc_cache_create.m,
colorspace_conversion_input_check.m, imageIO.m, argnames.m, vectorize.m,
vectorize.m, normest1.m, inputname.m, nthargout.m, display_info_file.m,
decic.m, ode15i.m, ode15s.m, ode23.m, ode23s.m, ode45.m, odeset.m,
check_default_input.m, integrate_adaptive.m, ode_event_handler.m,
runge_kutta_23.m, runge_kutta_23s.m, runge_kutta_45_dorpri.m,
runge_kutta_interpolate.m, starting_stepsize.m, __all_opts__.m, fminbnd.m,
fminsearch.m, fminunc.m, fsolve.m, fzero.m, sqp.m, fplot.m, plotyy.m,
__bar__.m, __ezplot__.m, flat_entry.html, profexport.m, movfun.m, bicg.m,
bicgstab.m, cgs.m, eigs.m, gmres.m, pcg.m, __alltohandles__.m, __sprand__.m,
qmr.m, tfqmr.m, dump_demos.m:
Replace "func", "fun", "fn" in documentation and variable names with "fcn".
author | Rik <rik@octave.org> |
---|---|
date | Mon, 04 Apr 2022 18:14:56 -0700 |
parents | 796f54d4ddbf |
children | 18b8f73595e0 |
line wrap: on
line source
######################################################################## ## ## Copyright (C) 2005-2022 The Octave Project Developers ## ## See the file COPYRIGHT.md in the top-level directory of this ## distribution or <https://octave.org/copyright/>. ## ## 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 ## <https://www.gnu.org/licenses/>. ## ######################################################################## ## -*- texinfo -*- ## @deftypefn {} {} fplot (@var{fcn}) ## @deftypefnx {} {} fplot (@var{fcn}, @var{limits}) ## @deftypefnx {} {} fplot (@dots{}, @var{tol}) ## @deftypefnx {} {} fplot (@dots{}, @var{n}) ## @deftypefnx {} {} fplot (@dots{}, @var{fmt}) ## @deftypefnx {} {} fplot (@dots{}, @var{property}, @var{value}, @dots{}) ## @deftypefnx {} {} fplot (@var{hax}, @dots{}) ## @deftypefnx {} {[@var{x}, @var{y}] =} fplot (@dots{}) ## Plot a function @var{fcn} within the range defined by @var{limits}. ## ## @var{fcn} is a function handle, inline function, or string containing the ## name of the function to evaluate. ## ## The limits of the plot are of the form @w{@code{[@var{xlo}, @var{xhi}]}} or ## @w{@code{[@var{xlo}, @var{xhi}, @var{ylo}, @var{yhi}]}}. If no limits ## are specified the default is @code{[-5, 5]}. ## ## The next three arguments are all optional and any number of them may be ## given in any order. ## ## @var{tol} is the relative tolerance to use for the plot and defaults ## to 2e-3 (.2%). ## ## @var{n} is the minimum number of points to use. When @var{n} is specified, ## the maximum stepsize will be @code{(@var{xhi} - @var{xlo}) / @var{n}}. More ## than @var{n} points may still be used in order to meet the relative ## tolerance requirement. ## ## The @var{fmt} argument specifies the linestyle to be used by the plot ## command. ## ## Multiple property-value pairs may also be specified, but they must appear ## in pairs. These arguments are applied to the line objects drawn by ## @code{plot}. ## ## The full list of line properties is documented at ## @ref{Line Properties}. ## ## If the first argument @var{hax} is an axes handle, then plot into this axes, ## rather than the current axes returned by @code{gca}. ## ## With no output arguments, the results are immediately plotted. With two ## output arguments, the 2-D plot data is returned. The data can subsequently ## be plotted manually with @code{plot (@var{x}, @var{y})}. ## ## Example: ## ## @example ## @group ## fplot (@@cos, [0, 2*pi]) ## fplot ("[cos(x), sin(x)]", [0, 2*pi]) ## @end group ## @end example ## ## Programming Notes: ## ## @code{fplot} works best with continuous functions. Functions with ## discontinuities are unlikely to plot well. This restriction may be removed ## in the future. ## ## @code{fplot} performance is better when the function accepts and returns a ## vector argument. Consider this when writing user-defined functions and use ## element-by-element operators such as @code{.*}, @code{./}, etc. ## ## @seealso{ezplot, plot} ## @end deftypefn function [X, Y] = fplot (varargin) [hax, varargin, nargin] = __plt_get_axis_arg__ ("fplot", varargin{:}); if (nargin < 1 || nargin > 5) print_usage (); endif fcn = varargin{1}; if (isa (fcn, "inline")) fcn = vectorize (inline (fcn)); nam = formula (fcn); elseif (is_function_handle (fcn)) nam = func2str (fcn); elseif (all (isalnum (fcn))) nam = fcn; elseif (ischar (fcn)) fcn = vectorize (inline (fcn)); nam = formula (fcn); else error ("fplot: FCN must be a function handle, inline function, or string"); endif if (nargin > 1 && isnumeric (varargin{2})) limits = varargin{2}; if (iscomplex (limits) || (numel (limits) != 2 && numel (limits) != 4)) error ("fplot: LIMITS must be a real vector with 2 or 4 elements"); endif i = 3; else limits = [-5, 5]; i = 2; endif n = 5; tol = 2e-3; fmt = {}; prop_vals = {}; while (i <= numel (varargin)) arg = varargin{i}; if (ischar (arg)) [~, valid_fmt] = __pltopt__ ("fplot", arg, false); if (valid_fmt) fmt(end+1) = arg; else if (i == numel (varargin)) error ("fplot: bad input in position %d", i); endif prop_vals(end+(1:2)) = varargin([i, i+1]); i++; # Skip PROPERTY. endif elseif (isnumeric (arg) && isscalar (arg) && arg > 0) if (arg == fix (arg)) n = arg; else tol = arg; endif else error ("fplot: bad input in position %d", i); endif i++; endwhile if (n != 5) ## n was specified x0 = linspace (limits(1), limits(2), n/2 + 1)'; else x0 = linspace (limits(1), limits(2), 5)'; n = 8; endif try y0 = feval (fcn, x0); if (isscalar (y0)) warning ("fplot: FCN is not a vectorized function which reduces performance"); fcn = @(x) arrayfun (fcn, x); # Create a new fcn that accepts vectors y0 = feval (fcn, x0); endif catch ## feval failed, maybe it is because the function is not vectorized? fcn = @(x) arrayfun (fcn, x); # Create a new fcn that accepts vectors y0 = feval (fcn, x0); warning ("fplot: FCN is not a vectorized function which reduces performance"); end_try_catch x = linspace (limits(1), limits(2), n)'; y = feval (fcn, x); if (rows (x0) == rows (y0)) fcn_transpose = false; elseif (rows (x0) == columns (y0)) fcn_transpose = true; y0 = y0.'; y = y.'; else error ("fplot: invalid function FCN (# of outputs not equal to inputs)"); endif err0 = Inf; ## FIXME: This algorithm should really use adaptive scaling as ## the numerical quadrature algorithms do so that extra points are ## used where they are needed and not spread evenly over the entire ## x-range. Try any function with a discontinuity, such as ## fplot (@tan, [-2, 2]) or fplot ("1./x", [-3, 2]), to see the ## problems with the current solution. while (n < 2^18) # Something is wrong if we need more than 250K points yi = interp1 (x0, y0, x, "linear"); ## relative error calculation using average of [yi,y] as reference ## since neither estimate is known a priori to be better than the other. err = 0.5 * max (abs ((yi - y) ./ (yi + y + eps))(:)); if (err < tol || abs (err - err0) < tol/2) ## Either relative tolerance has been met OR ## algorithm has stopped making any reasonable progress per iteration. break; endif x0 = x; y0 = y; err0 = err; n = 2 * (n - 1) + 1; x = linspace (limits(1), limits(2), n)'; y = feval (fcn, x); if (fcn_transpose) y = y.'; endif endwhile if (nargout == 2) X = x; Y = y; else if (isempty (hax)) hax = gca (); endif hl = plot (hax, x, y, fmt{:}); if (isempty (get (hl(1), "displayname"))) ## Set displayname for legend if FMT did not contain a name. if (isvector (y)) set (hl, "displayname", nam); else for i = 1:columns (y) nams{i} = sprintf ("%s(:,%i)", nam, i); endfor set (hl, {"displayname"}, nams(:)); endif endif ## Properties passed as input arguments override other properties. if (! isempty (prop_vals)) set (hl, prop_vals{:}); endif axis (hax, limits); legend (hax, "show"); endif endfunction %!demo %! clf; %! fplot (@cos, [0, 2*pi]); %! title ("fplot() single function"); %!demo %! clf; %! fplot ("[cos(x), sin(x)]", [0, 2*pi]); %! title ("fplot() multiple functions"); %!demo %! clf; %! fh = @(x) sin (pi*x) ./ (pi*x); %! fplot (fh, [-5, 5]); %! title ("fplot() sinc function (possible division by 0, near 0)"); %!test %! ## Multi-valued function %! [x, y] = fplot ("[cos(x), sin(x)]", [0, 2*pi]); %! assert (columns (y) == 2); %! assert (rows (x) == rows (y)); %! assert (y, [cos(x), sin(x)], -2e-3); %!test %! ## Function requiring transpose %! fcn = @(x) 2 * x(:).'; %! [x, y] = fplot (fcn, [-1, 1]); %! assert (columns (y) == 1); %! assert (rows (x) == rows (y)); %! assert (y, 2*x); %!test %! ## Constant value function %! fcn = @(x) 0; %! [x, y] = fplot (fcn, [-1, 1]); %! assert (columns (y) == 1); %! assert (rows (x) == rows (y)); %! assert (y, repmat ([0], size (x))); %!test <*59274> %! ## Manual displayname overrides automatic legend entry %! hf = figure ("visible", "off"); %! unwind_protect %! fplot (@sin, [0, 3], "displayname", "mysin"); %! hl = legend (); %! assert (get (hl, "string"), {"mysin"}); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect %!test <*59274> %! ## displayname in format string overrides automatic legend entry %! hf = figure ("visible", "off"); %! unwind_protect %! fplot (@sin, [0, 3], "+;mysin;"); %! hl = legend (); %! assert (get (hl, "string"), {"mysin"}); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect ## Test input validation %!error <Invalid call> fplot () %!error <Invalid call> fplot (1,2,3,4,5,6) %!error <FCN must be a function handle> fplot (1, [0 1]) %!error <LIMITS must be a real vector> fplot (@cos, [i, 2*i]) %!error <LIMITS must be a real vector with 2 or 4> fplot (@cos, [1]) %!error <LIMITS must be a real vector with 2 or 4> fplot (@cos, [1 2 3]) %!error <bad input in position 2> fplot (@cos, "linewidth") %!error <bad input in position 3> fplot (@cos, [-1,1], {1}) %!warning <FCN is not a vectorized function> %! fcn = @(x) 0; %! [x,y] = fplot (fcn, [-1,1]); %!error <invalid function FCN> %! fcn = @(x) [x;x]; %! fplot (fcn, [-1,1]);