pythonplotsympyparametric-equations

sympy's plot_parametric says TypeError: can't convert complex to float


I want to plot a curve which is actually has a S shape:

  1. draw a circle
  2. move the down part of half circle a whole diameter distance

but the code says TypeError: can't convert complex to float. Where is the complex number? how to fix it? Thanks

import sympy as sp
from sympy.plotting import *

u = sp.Symbol('u', real=True)
R0 = 2
boundLower = 0
boundUpper = 2 * sp.pi

x_u = sp.Piecewise(
    (R0*sp.cos(u)+R0, sp.And(boundLower <= u, u <= boundUpper/2)),
    (R0*sp.cos(u)+3*R0, sp.And(boundUpper/2 < u, u <= boundUpper)),
)

y_u = sp.Piecewise(
    (R0*sp.sin(u), sp.And(boundLower <= u,  u <= boundUpper/2)),
    (R0*sp.sin(u), sp.And(boundUpper/2 < u, u <= boundUpper)),
)

plot_parametric(x_u, y_u, (u, boundLower, boundUpper))

Solution

  • SymPy's plot involves some error-prone manipulations meant to boost the performance of plots; they involve complex data type which sometimes leads to errors when inequalities are involved. Reducing the number of inequalities helps in this case:

    x_u = sp.Piecewise(
        (R0*sp.cos(u)+R0, u <= boundUpper/2),
        (R0*sp.cos(u)+3*R0, u <= boundUpper),
    )
    
    y_u = sp.Piecewise(
        (R0*sp.sin(u), u <= boundUpper/2),
        (R0*sp.sin(u), u <= boundUpper),
    )
    
    plot_parametric(x_u, y_u, (u, boundLower, boundUpper))
    

    The above is how Piecewise is usually presented in SymPy: conditions are evaluated in the order given, and the first one to be True results in the evaluation of the corresponding expression. (u <= boundUpper could be replaced by True, by the way.) Result:

    piecewise

    This is still not ideal. The horizontal line from 0 to 4 should not be there, of course - it's an artifact of plotting. Also, this code displays

    UserWarning: The evaluation of the expression is problematic. We are trying a failback method that may still work. Please report this as a bug.

    I suggest to avoid Piecewise in plotting. Instead combine a plot from pieces using extend as shown below.

    x_u1 = R0*sp.cos(u)+R0
    x_u2 = R0*sp.cos(u)+3*R0
    
    y_u1 = R0*sp.sin(u)
    y_u2 = R0*sp.sin(u)
    
    p = plot_parametric(x_u1, y_u1, (u, boundLower, boundUpper/2), show=False)
    p.extend(plot_parametric(x_u2, y_u2, (u, boundUpper/2, boundUpper), show=False))
    p.show()
    

    Output (no warnings and no artifacts).

    better