def unify_arguments(funcs): """ Return a tuple of variables of the functions, as well as the number of "free" variables (i.e., variables that defined in a callable function). INPUT: - ``funcs`` -- a list of functions; these can be symbolic expressions, polynomials, etc OUTPUT: functions, expected arguments - A tuple of variables in the functions - A tuple of variables that were "free" in the functions EXAMPLES:: sage: x,y,z=var('x,y,z') sage: f(x,y)=x+y-z sage: g(x,y)=x+y sage: h(y)=-y sage: sage.plot.misc.unify_arguments((f,g,h)) ((x, y, z), (z,)) sage: sage.plot.misc.unify_arguments((g,h)) ((x, y), ()) sage: sage.plot.misc.unify_arguments((f,z)) ((x, y, z), (z,)) sage: sage.plot.misc.unify_arguments((h,z)) ((y, z), (z,)) sage: sage.plot.misc.unify_arguments((x+y,x-y)) ((x, y), (x, y)) """ from sage.symbolic.callable import is_CallableSymbolicExpression vars = set() free_variables = set() if not isinstance(funcs, (list, tuple)): funcs = [funcs] for f in funcs: if is_CallableSymbolicExpression(f): f_args = set(f.arguments()) vars.update(f_args) else: f_args = set() try: free_vars = set(f.variables()).difference(f_args) vars.update(free_vars) free_variables.update(free_vars) except AttributeError: # we probably have a constant pass return tuple(sorted(vars, key=lambda x: str(x))), tuple( sorted(free_variables, key=lambda x: str(x)))
def unify_arguments(funcs): """ Returns a tuple of variables of the functions, as well as the number of "free" variables (i.e., variables that defined in a callable function). INPUT: - ``funcs`` -- a list of functions; these can be symbolic expressions, polynomials, etc OUTPUT: functions, expected arguments - A tuple of variables in the functions - A tuple of variables that were "free" in the functions EXAMPLES: sage: x,y,z=var('x,y,z') sage: f(x,y)=x+y-z sage: g(x,y)=x+y sage: h(y)=-y sage: sage.plot.misc.unify_arguments((f,g,h)) ((x, y, z), (z,)) sage: sage.plot.misc.unify_arguments((g,h)) ((x, y), ()) sage: sage.plot.misc.unify_arguments((f,z)) ((x, y, z), (z,)) sage: sage.plot.misc.unify_arguments((h,z)) ((y, z), (z,)) sage: sage.plot.misc.unify_arguments((x+y,x-y)) ((x, y), (x, y)) """ from sage.symbolic.callable import is_CallableSymbolicExpression vars=set() free_variables=set() if not isinstance(funcs, (list, tuple)): funcs=[funcs] for f in funcs: if is_CallableSymbolicExpression(f): f_args=set(f.arguments()) vars.update(f_args) else: f_args=set() try: free_vars = set(f.variables()).difference(f_args) vars.update(free_vars) free_variables.update(free_vars) except AttributeError: # we probably have a constant pass return tuple(sorted(vars, key=lambda x: str(x))), tuple(sorted(free_variables, key=lambda x: str(x)))
def adapt_to_callable(f, nargs=None): """ Tries to make every function in f into a (fast) callable function, returning a new list of functions and the expected arguments. INPUT: - ``f`` -- a list of functions; these can be symbolic expressions, polynomials, etc - ``nargs`` -- number of input args to have in the output functions OUTPUT: functions, expected arguments """ from sage.misc.misc import deprecation deprecation( "adapt_to_callable is a deprecated function. Please use functions from sage.misc.plot instead." ) try: from sage.symbolic.callable import is_CallableSymbolicExpression if sum([is_CallableSymbolicExpression(z) for z in f]): # Sum to get common universe; this works since f is # callable, and summing gets the arguments in the right # order. vars = sum(f).args() else: # Otherwise any free variable names in any order try: vars = tuple(sorted(set(sum([z.variables() for z in f], ())))) if len(vars) > 1: from sage.misc.misc import deprecation deprecation( "Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)" ) except AttributeError: vars = () f = [fast_float_constant(x) for x in f] except TypeError: vars = () f = [fast_float_constant(x) for x in f] if nargs is not None and len(vars) != nargs: vars = (vars + ('_', ) * nargs)[:nargs] return fast_float(f, *vars), vars
def adapt_to_callable(f, nargs=None): """ Tries to make every function in f into a (fast) callable function, returning a new list of functions and the expected arguments. INPUT: - ``f`` -- a list of functions; these can be symbolic expressions, polynomials, etc - ``nargs`` -- number of input args to have in the output functions OUTPUT: functions, expected arguments """ from sage.misc.misc import deprecation deprecation("adapt_to_callable is a deprecated function. Please use functions from sage.misc.plot instead.") try: from sage.symbolic.callable import is_CallableSymbolicExpression if sum([is_CallableSymbolicExpression(z) for z in f]): # Sum to get common universe; this works since f is # callable, and summing gets the arguments in the right # order. vars = sum(f).args() else: # Otherwise any free variable names in any order try: vars = tuple(sorted(set(sum( [z.variables() for z in f], ()) ))) if len(vars) > 1: from sage.misc.misc import deprecation deprecation("Substitution using function-call syntax and unnamed arguments is deprecated and will be removed from a future release of Sage; you can use named arguments instead, like EXPR(x=..., y=...)") except AttributeError: vars = () f = [fast_float_constant(x) for x in f] except TypeError: vars = () f = [fast_float_constant(x) for x in f] if nargs is not None and len(vars) != nargs: vars = (vars + ('_',)*nargs)[:nargs] return fast_float(f, *vars), vars
def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): """ Plots a function in 3d. INPUT: - ``f`` - a symbolic expression or function of 2 variables - ``urange`` - a 2-tuple (u_min, u_max) or a 3-tuple (u, u_min, u_max) - ``vrange`` - a 2-tuple (v_min, v_max) or a 3-tuple (v, v_min, v_max) - ``adaptive`` - (default: False) whether to use adaptive refinement to draw the plot (slower, but may look better). This option does NOT work in conjunction with a transformation (see below). - ``mesh`` - bool (default: False) whether to display mesh grid lines - ``dots`` - bool (default: False) whether to display dots at mesh grid points - ``plot_points`` - (default: "automatic") initial number of sample points in each direction; an integer or a pair of integers - ``transformation`` - (default: None) a transformation to apply. May be a 3 or 4-tuple (x_func, y_func, z_func, independent_vars) where the first 3 items indicate a transformation to Cartesian coordinates (from your coordinate system) in terms of u, v, and the function variable fvar (for which the value of f will be substituted). If a 3-tuple is specified, the independent variables are chosen from the range variables. If a 4-tuple is specified, the 4th element is a list of independent variables. ``transformation`` may also be a predefined coordinate system transformation like Spherical or Cylindrical. .. note:: ``mesh`` and ``dots`` are not supported when using the Tachyon raytracer renderer. EXAMPLES: We plot a 3d function defined as a Python function:: sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2)) Graphics3d Object .. PLOT:: sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2))) We plot the same 3d function but using adaptive refinement:: sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2), adaptive=True) Graphics3d Object .. PLOT:: sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2), adaptive=True)) Adaptive refinement but with more points:: sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2), adaptive=True, initial_depth=5) Graphics3d Object .. PLOT:: sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2), adaptive=True, initial_depth=5)) We plot some 3d symbolic functions:: sage: var('x,y') (x, y) sage: plot3d(x^2 + y^2, (x,-2,2), (y,-2,2)) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(x**2 + y**2, (x,-2,2), (y,-2,2))) :: sage: plot3d(sin(x*y), (x, -pi, pi), (y, -pi, pi)) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x*y), (x, -pi, pi), (y, -pi, pi))) We give a plot with extra sample points:: sage: var('x,y') (x, y) sage: plot3d(sin(x^2+y^2),(x,-5,5),(y,-5,5), plot_points=200) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x**2+y**2),(x,-5,5),(y,-5,5), plot_points=200)) :: sage: plot3d(sin(x^2+y^2),(x,-5,5),(y,-5,5), plot_points=[10,100]) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x**2+y**2),(x,-5,5),(y,-5,5), plot_points=[10,100])) A 3d plot with a mesh:: sage: var('x,y') (x, y) sage: plot3d(sin(x-y)*y*cos(x),(x,-3,3),(y,-3,3), mesh=True) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x-y)*y*cos(x),(x,-3,3),(y,-3,3), mesh=True)) Two wobby translucent planes:: sage: x,y = var('x,y') sage: P = plot3d(x+y+sin(x*y), (x,-10,10),(y,-10,10), opacity=0.87, color='blue') sage: Q = plot3d(x-2*y-cos(x*y),(x,-10,10),(y,-10,10),opacity=0.3,color='red') sage: P + Q Graphics3d Object .. PLOT:: x,y=var('x y') P = plot3d(x+y+sin(x*y), (x,-10,10),(y,-10,10), opacity=0.87, color='blue') Q = plot3d(x-2*y-cos(x*y),(x,-10,10),(y,-10,10),opacity=0.3,color='red') sphinx_plot(P+Q) We draw two parametric surfaces and a transparent plane:: sage: L = plot3d(lambda x,y: 0, (-5,5), (-5,5), color="lightblue", opacity=0.8) sage: P = plot3d(lambda x,y: 4 - x^3 - y^2, (-2,2), (-2,2), color='green') sage: Q = plot3d(lambda x,y: x^3 + y^2 - 4, (-2,2), (-2,2), color='orange') sage: L + P + Q Graphics3d Object .. PLOT:: L = plot3d(lambda x,y: 0, (-5,5), (-5,5), color="lightblue", opacity=0.8) P = plot3d(lambda x,y: 4 - x**3 - y**2, (-2,2), (-2,2), color='green') Q = plot3d(lambda x,y: x**3 + y**2 - 4, (-2,2), (-2,2), color='orange') sphinx_plot(L+P+Q) We draw the "Sinus" function (water ripple-like surface):: sage: x, y = var('x y') sage: plot3d(sin(pi*(x^2+y^2))/2,(x,-1,1),(y,-1,1)) Graphics3d Object .. PLOT:: x, y = var('x y') sphinx_plot(plot3d(sin(pi*(x**2+y**2))/2,(x,-1,1),(y,-1,1))) Hill and valley (flat surface with a bump and a dent):: sage: x, y = var('x y') sage: plot3d( 4*x*exp(-x^2-y^2), (x,-2,2), (y,-2,2)) Graphics3d Object .. PLOT:: x, y = var('x y') sphinx_plot(plot3d( 4*x*exp(-x**2-y**2), (x,-2,2), (y,-2,2))) An example of a transformation:: sage: r, phi, z = var('r phi z') sage: trans=(r*cos(phi),r*sin(phi),z) sage: plot3d(cos(r),(r,0,17*pi/2),(phi,0,2*pi),transformation=trans,opacity=0.87).show(aspect_ratio=(1,1,2),frame=False) .. PLOT:: r, phi, z = var('r phi z') trans = (r*cos(phi),r*sin(phi),z) P = plot3d(cos(r),(r,0,17*pi/2),(phi,0,2*pi),transformation=trans,opacity=0.87) P.aspect_ratio([1,1,2]) sphinx_plot(P) An example of a transformation with symbolic vector:: sage: cylindrical(r,theta,z)=[r*cos(theta),r*sin(theta),z] sage: plot3d(3,(theta,0,pi/2),(z,0,pi/2),transformation=cylindrical) Graphics3d Object .. PLOT:: r, theta, z = var('r theta z') cylindrical=(r*cos(theta),r*sin(theta),z) P = plot3d(z-z+3,(theta,0,pi/2),(z,0,pi/2),transformation=cylindrical) sphinx_plot(P) Many more examples of transformations:: sage: u, v, w = var('u v w') sage: rectangular=(u,v,w) sage: spherical=(w*cos(u)*sin(v),w*sin(u)*sin(v),w*cos(v)) sage: cylindric_radial=(w*cos(u),w*sin(u),v) sage: cylindric_axial=(v*cos(u),v*sin(u),w) sage: parabolic_cylindrical=(w*v,(v^2-w^2)/2,u) Plot a constant function of each of these to get an idea of what it does:: sage: A = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=rectangular,plot_points=[100,100]) sage: B = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=spherical,plot_points=[100,100]) sage: C = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_radial,plot_points=[100,100]) sage: D = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: E = plot3d(2,(u,-pi,pi),(v,-pi,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact ....: def _(which_plot=[A,B,C,D,E]): ....: show(which_plot) <html>... Now plot a function:: sage: g=3+sin(4*u)/2+cos(4*v)/2 sage: F = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=rectangular,plot_points=[100,100]) sage: G = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=spherical,plot_points=[100,100]) sage: H = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_radial,plot_points=[100,100]) sage: I = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: J = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact ....: def _(which_plot=[F, G, H, I, J]): ....: show(which_plot) <html>... TESTS: Make sure the transformation plots work:: sage: show(A + B + C + D + E) sage: show(F + G + H + I + J) Listing the same plot variable twice gives an error:: sage: x, y = var('x y') sage: plot3d( 4*x*exp(-x^2-y^2), (x,-2,2), (x,-2,2)) Traceback (most recent call last): ... ValueError: range variables should be distinct, but there are duplicates """ if transformation is not None: params = None from sage.symbolic.callable import is_CallableSymbolicExpression # First, determine the parameters for f (from the first item of urange # and vrange, preferably). if len(urange) == 3 and len(vrange) == 3: params = (urange[0], vrange[0]) elif is_CallableSymbolicExpression(f): params = f.variables() from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense if isinstance(transformation, (tuple, list, Vector_callable_symbolic_dense)): if len(transformation) == 3: if params is None: raise ValueError( "must specify independent variable names in the ranges when using generic transformation" ) indep_vars = params elif len(transformation) == 4: indep_vars = transformation[3] transformation = transformation[0:3] else: raise ValueError("unknown transformation type") # find out which variable is the function variable by # eliminating the parameter variables. all_vars = set( sum([list(s.variables()) for s in transformation], [])) dep_var = all_vars - set(indep_vars) if len(dep_var) == 1: dep_var = dep_var.pop() transformation = _ArbitraryCoordinates(transformation, dep_var, indep_vars) else: raise ValueError( "unable to determine the function variable in the transform" ) if isinstance(transformation, _Coordinates): R = transformation.to_cartesian(f, params) return parametric_plot3d.parametric_plot3d(R, urange, vrange, **kwds) else: raise ValueError('unknown transformation type') elif adaptive: P = plot3d_adaptive(f, urange, vrange, **kwds) else: u = fast_float_arg(0) v = fast_float_arg(1) P = parametric_plot3d.parametric_plot3d((u, v, f), urange, vrange, **kwds) P.frame_aspect_ratio([1.0, 1.0, 0.5]) return P
def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): """ INPUT: - ``f`` - a symbolic expression or function of 2 variables - ``urange`` - a 2-tuple (u_min, u_max) or a 3-tuple (u, u_min, u_max) - ``vrange`` - a 2-tuple (v_min, v_max) or a 3-tuple (v, v_min, v_max) - ``adaptive`` - (default: False) whether to use adaptive refinement to draw the plot (slower, but may look better). This option does NOT work in conjuction with a transformation (see below). - ``mesh`` - bool (default: False) whether to display mesh grid lines - ``dots`` - bool (default: False) whether to display dots at mesh grid points - ``plot_points`` - (default: "automatic") initial number of sample points in each direction; an integer or a pair of integers - ``transformation`` - (default: None) a transformation to apply. May be a 3 or 4-tuple (x_func, y_func, z_func, independent_vars) where the first 3 items indicate a transformation to Cartesian coordinates (from your coordinate system) in terms of u, v, and the function variable fvar (for which the value of f will be substituted). If a 3-tuple is specified, the independent variables are chosen from the range variables. If a 4-tuple is specified, the 4th element is a list of independent variables. ``transformation`` may also be a predefined coordinate system transformation like Spherical or Cylindrical. .. note:: ``mesh`` and ``dots`` are not supported when using the Tachyon raytracer renderer. EXAMPLES: We plot a 3d function defined as a Python function:: sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2)) Graphics3d Object .. PLOT:: sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2))) We plot the same 3d function but using adaptive refinement:: sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2), adaptive=True) Graphics3d Object .. PLOT:: sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2), adaptive=True)) Adaptive refinement but with more points:: sage: plot3d(lambda x, y: x^2 + y^2, (-2,2), (-2,2), adaptive=True, initial_depth=5) Graphics3d Object .. PLOT:: sphinx_plot(plot3d(lambda x, y: x**2 + y**2, (-2,2), (-2,2), adaptive=True, initial_depth=5)) We plot some 3d symbolic functions:: sage: var('x,y') (x, y) sage: plot3d(x^2 + y^2, (x,-2,2), (y,-2,2)) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(x**2 + y**2, (x,-2,2), (y,-2,2))) :: sage: plot3d(sin(x*y), (x, -pi, pi), (y, -pi, pi)) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x*y), (x, -pi, pi), (y, -pi, pi))) We give a plot with extra sample points:: sage: var('x,y') (x, y) sage: plot3d(sin(x^2+y^2),(x,-5,5),(y,-5,5), plot_points=200) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x**2+y**2),(x,-5,5),(y,-5,5), plot_points=200)) :: sage: plot3d(sin(x^2+y^2),(x,-5,5),(y,-5,5), plot_points=[10,100]) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x**2+y**2),(x,-5,5),(y,-5,5), plot_points=[10,100])) A 3d plot with a mesh:: sage: var('x,y') (x, y) sage: plot3d(sin(x-y)*y*cos(x),(x,-3,3),(y,-3,3), mesh=True) Graphics3d Object .. PLOT:: var('x y') sphinx_plot(plot3d(sin(x-y)*y*cos(x),(x,-3,3),(y,-3,3), mesh=True)) Two wobby translucent planes:: sage: x,y = var('x,y') sage: P = plot3d(x+y+sin(x*y), (x,-10,10),(y,-10,10), opacity=0.87, color='blue') sage: Q = plot3d(x-2*y-cos(x*y),(x,-10,10),(y,-10,10),opacity=0.3,color='red') sage: P + Q Graphics3d Object .. PLOT:: x,y=var('x y') P = plot3d(x+y+sin(x*y), (x,-10,10),(y,-10,10), opacity=0.87, color='blue') Q = plot3d(x-2*y-cos(x*y),(x,-10,10),(y,-10,10),opacity=0.3,color='red') sphinx_plot(P+Q) We draw two parametric surfaces and a transparent plane:: sage: L = plot3d(lambda x,y: 0, (-5,5), (-5,5), color="lightblue", opacity=0.8) sage: P = plot3d(lambda x,y: 4 - x^3 - y^2, (-2,2), (-2,2), color='green') sage: Q = plot3d(lambda x,y: x^3 + y^2 - 4, (-2,2), (-2,2), color='orange') sage: L + P + Q Graphics3d Object .. PLOT:: L = plot3d(lambda x,y: 0, (-5,5), (-5,5), color="lightblue", opacity=0.8) P = plot3d(lambda x,y: 4 - x**3 - y**2, (-2,2), (-2,2), color='green') Q = plot3d(lambda x,y: x**3 + y**2 - 4, (-2,2), (-2,2), color='orange') sphinx_plot(L+P+Q) We draw the "Sinus" function (water ripple-like surface):: sage: x, y = var('x y') sage: plot3d(sin(pi*(x^2+y^2))/2,(x,-1,1),(y,-1,1)) Graphics3d Object .. PLOT:: x, y = var('x y') sphinx_plot(plot3d(sin(pi*(x**2+y**2))/2,(x,-1,1),(y,-1,1))) Hill and valley (flat surface with a bump and a dent):: sage: x, y = var('x y') sage: plot3d( 4*x*exp(-x^2-y^2), (x,-2,2), (y,-2,2)) Graphics3d Object .. PLOT:: x, y = var('x y') sphinx_plot(plot3d( 4*x*exp(-x**2-y**2), (x,-2,2), (y,-2,2))) An example of a transformation:: sage: r, phi, z = var('r phi z') sage: trans=(r*cos(phi),r*sin(phi),z) sage: plot3d(cos(r),(r,0,17*pi/2),(phi,0,2*pi),transformation=trans,opacity=0.87).show(aspect_ratio=(1,1,2),frame=False) .. PLOT:: r, phi, z = var('r phi z') trans = (r*cos(phi),r*sin(phi),z) P = plot3d(cos(r),(r,0,17*pi/2),(phi,0,2*pi),transformation=trans,opacity=0.87) P.aspect_ratio([1,1,2]) sphinx_plot(P) An example of a transformation with symbolic vector:: sage: cylindrical(r,theta,z)=[r*cos(theta),r*sin(theta),z] sage: plot3d(3,(theta,0,pi/2),(z,0,pi/2),transformation=cylindrical) Graphics3d Object .. PLOT:: r, theta, z = var('r theta z') cylindrical=(r*cos(theta),r*sin(theta),z) P = plot3d(z-z+3,(theta,0,pi/2),(z,0,pi/2),transformation=cylindrical) sphinx_plot(P) Many more examples of transformations:: sage: u, v, w = var('u v w') sage: rectangular=(u,v,w) sage: spherical=(w*cos(u)*sin(v),w*sin(u)*sin(v),w*cos(v)) sage: cylindric_radial=(w*cos(u),w*sin(u),v) sage: cylindric_axial=(v*cos(u),v*sin(u),w) sage: parabolic_cylindrical=(w*v,(v^2-w^2)/2,u) Plot a constant function of each of these to get an idea of what it does:: sage: A = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=rectangular,plot_points=[100,100]) sage: B = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=spherical,plot_points=[100,100]) sage: C = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_radial,plot_points=[100,100]) sage: D = plot3d(2,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: E = plot3d(2,(u,-pi,pi),(v,-pi,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact ... def _(which_plot=[A,B,C,D,E]): ... show(which_plot) <html>... Now plot a function:: sage: g=3+sin(4*u)/2+cos(4*v)/2 sage: F = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=rectangular,plot_points=[100,100]) sage: G = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=spherical,plot_points=[100,100]) sage: H = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_radial,plot_points=[100,100]) sage: I = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=cylindric_axial,plot_points=[100,100]) sage: J = plot3d(g,(u,-pi,pi),(v,0,pi),transformation=parabolic_cylindrical,plot_points=[100,100]) sage: @interact ... def _(which_plot=[F, G, H, I, J]): ... show(which_plot) <html>... TESTS: Make sure the transformation plots work:: sage: show(A + B + C + D + E) sage: show(F + G + H + I + J) Listing the same plot variable twice gives an error:: sage: x, y = var('x y') sage: plot3d( 4*x*exp(-x^2-y^2), (x,-2,2), (x,-2,2)) Traceback (most recent call last): ... ValueError: range variables should be distinct, but there are duplicates """ if transformation is not None: params=None from sage.symbolic.callable import is_CallableSymbolicExpression # First, determine the parameters for f (from the first item of urange # and vrange, preferably). if len(urange) == 3 and len(vrange) == 3: params = (urange[0], vrange[0]) elif is_CallableSymbolicExpression(f): params = f.variables() from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense if isinstance(transformation, (tuple, list,Vector_callable_symbolic_dense)): if len(transformation)==3: if params is None: raise ValueError("must specify independent variable names in the ranges when using generic transformation") indep_vars = params elif len(transformation)==4: indep_vars = transformation[3] transformation = transformation[0:3] else: raise ValueError("unknown transformation type") # find out which variable is the function variable by # eliminating the parameter variables. all_vars = set(sum([list(s.variables()) for s in transformation],[])) dep_var=all_vars - set(indep_vars) if len(dep_var)==1: dep_var = dep_var.pop() transformation = _ArbitraryCoordinates(transformation, dep_var, indep_vars) else: raise ValueError("unable to determine the function variable in the transform") if isinstance(transformation, _Coordinates): R = transformation.to_cartesian(f, params) return parametric_plot3d.parametric_plot3d(R, urange, vrange, **kwds) else: raise ValueError('unknown transformation type') elif adaptive: P = plot3d_adaptive(f, urange, vrange, **kwds) else: u=fast_float_arg(0) v=fast_float_arg(1) P=parametric_plot3d.parametric_plot3d((u,v,f), urange, vrange, **kwds) P.frame_aspect_ratio([1.0,1.0,0.5]) return P