# TypeError in parametric_plot3d with real or imag

The code to plot a surface using parametric_plot_3d:

var("u,v")
parametric_plot3d([sqrt(u + I*v).real(), sqrt(u + I*v).imag(),v],(u,-1,1), (v,-1,1))


The full traceback of the error is quite long, so I give only the first few lines and last few lines:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-...-....> in <module>
----> 1 parametric_plot3d([sqrt(u + I*v).real(), sqrt(u + I*v).imag(),v],(u,-Integer(1),Integer(1)), (v,-Integer(1),Integer(1)))

.../sage/misc/decorators.py in wrapper(*args, **kwds)
649                     kwds[new_name] = kwds[old_name]
650                     del kwds[old_name]
--> 651             return func(*args, **kwds)
652
653         return wrapper

...

.../sage/rings/number_field/number_field_element.pyx in sage.rings.number_field.number_field_element.NumberFieldElement.__float__ (build/cythonized/sage/rings/number_field/number_field_element.cpp:19236)()
1908             if c.imag == 0:
1909                 return c.real
-> 1910             raise TypeError('unable to coerce to a real number')
1911
1912     def _complex_double_(self, CDF):

TypeError: unable to coerce to a real number


Edit: I am also getting similar errors using the log function, arctan function, etc.

edit retag close merge delete

errors come from the following

sage: f=sqrt(abs(u + I*v))
sage: plot3d(f,(-1,1),(-1,1))

( 2021-02-23 11:31:08 +0200 )edit

One way out is to use python functions

def f(u,v): return sqrt(u + I*v).real()


and so on

( 2021-02-23 11:34:21 +0200 )edit

It seems to be a bug, but I have some trouble pinpointing it...

EDIT :FredericC's remark points to a problem converting sage.rings.real_mpfr.RealNumber to something palatable to plot3d. However, tring the "manual" conversion on real values succeeds ; I am still unable to reproduce the problem outside of a "plot3d" call...

( 2021-02-23 11:47:13 +0200 )edit

@FrédéricC's I've tried the method you've mentioned. It gives the same type of error.

( 2021-02-24 05:01:51 +0200 )edit

Sort by » oldest newest most voted

In addition to the solutions provided in other answers and comments, you can keep symbolic expresions, but first converting them with the help of the fast_callable function, that is:

var("u,v")
xuv = fast_callable(sqrt(u + I*v).real(), vars=[u,v])
yuv = fast_callable(sqrt(u + I*v).imag(), vars=[u,v])
zuv = v
parametric_plot3d([xuv, yuv, zuv], (u,-1,1), (v,-1,1))

more

It gave me the desired result, but I don't really understand why this one works and the others don't.

( 2021-02-26 10:40:02 +0200 )edit

The work of parametric_plot3d is really done by an internal function, _parametric_plot3d_surface, which, in turn, first calls setup_for_eval_on_grid. The docstring of this last function says: "Calculate the necessary parameters to construct a list of points, and make the functions fast_callable". So, setup_for_eval_on_grid compiles the expressions in parametric_plot3d to a form that can be quickly evaluated. This is done by calling fast_float, which finally calls fast_callable. For reasons that I ignore, the whole process fails in the case considered here. Thus, direct calls to fast_callable helps to solve the problem.

( 2021-02-26 12:11:16 +0200 )edit

This is a long comment rather than an answer.

## Plotting in Sage can use two types of arguments

Many of Sage's plotting functions, including, plot, parametric_plot, implicit_plot, plot3d, parametric_plot3d, implicit_plot3d, can accept as arguments either symbolic expressions or callable functions.

### Symbolic expressions

If symbolic expressions are used, as in the question, Sage tries to convert them into "fast callable" functions.

The very long error traceback in the question shows the code path goes through a number of functions in sage/symbolic/expression_conversions.py, sage/symbolic/expression.pyx, sage/ext/fast_callable.pyx, sage/ext/fast_eval.pyx, as one might expect (although it's really long), and finally, quite unexpectedly I think, in sage/rings/number_field/number_field_element.pyx.

I don't fully understand the problem there, so I would not know how to get the desired plot using symbolic expressions.

### Callable functions

Using callable functions that are not symbolic expressions, as @FrédéricC suggests, no need to define the variables with var before plotting, or to recall their names in the ranges.

This could be done as follows:

sage: xyz = [lambda u, v: sqrt(u + I*v).real(), lambda u, v: sqrt(u + I*v).imag(), lambda u, v: v]
sage: parametric_plot3d(xyz, (-1, 1), (-1, 1))


or less condensed:

sage: xuv = lambda u, v: sqrt(u + I*v).real()
sage: yuv = lambda u, v: sqrt(u + I*v).imag()
sage: zuv = lambda u, v: v
sage: parametric_plot3d([xuv, yuv, zuv], (-1, 1), (-1, 1))


or with a different color and some transparency:

sage: parametric_plot3d([xuv, yuv, zuv], (-1, 1), (-1, 1), color='steelblue', opacity=0.5)

more