3

I want to plot a piecewise function, such as:

import sympy as sym
x = sym.symbols("x")
f = sym.Piecewise((-1, x < -1),
                  (x, sym.And(-1 <= x, x < 0)),
                  (x**2, sym.And(0 <= x, x < 1)),
                  (x**3, x >= 1))
sym.plotting.plot(f, (x, -3, 3))

However, when running this code, an exception was raised ...

AttributeError: 'BooleanFalse' object has no attribute 'evalf'

I think the problem may come from the two cases

sym.And(-1 <= x, x < 0)

and

sym.And(0 <= x, x < 1)

Here a python type 'bool' supposed, while the function 'evalf' can't convert the 'sympy' type 'BooleanFalse' into the python type 'bool'.

I wander how to deal with this problem, and is it possible to plot the piecewise functions without using the 'matplotlib' module?

gboffi
  • 22,939
  • 8
  • 54
  • 85
Frank King
  • 31
  • 3
  • The error you're seeing is a bug. I've opened an issue for it https://github.com/sympy/sympy/issues/10925 – asmeurer Mar 29 '16 at 19:50

3 Answers3

0

Your function definition is overdone, sympy evaluates the conditions in order and returns the 1st expression for which the condition is True.

I don't understand exactly which went wrong in your definition but a simpler definition works for me

In [19]: f = sym.Piecewise(
         (-1, x < -1),
         (x, x < 0),
         (x**2, x < 1),
         (x**3, True))
   ....: 

In [20]: sym.plotting.plot(f, (x, -3, 3))
Out[20]: <sympy.plotting.plot.Plot at 0x7f90cb9ec6d8>

enter image description here

In [21]: 

PS I have understood why your plot fails, it's because plot tries to evaluate the condition feeding a value for x, but the condition is the constant BooleanFalse that's the result of evaluating sym.And() at the time of definition of your piecewise function.

gboffi
  • 22,939
  • 8
  • 54
  • 85
  • Thanks a lot! I still wander whether I can write the conditions in a mathematical style, such as -1 <= x < 0, 0 <= x < 1, 1 <= x < 2 etc.? That's looks better, I think. – Frank King Mar 28 '16 at 10:43
  • No, you can't write them that way. Because of the way Python evaluation works, there's no way for SymPy to parse something like `-1 <= x < 0`. However, you can write `Interval.Ropen(-1, 0).contains(x)` (i.e., `x ∈ [-1, 0)`). – asmeurer Mar 29 '16 at 19:47
0

Which version of sympy are you using? I think this is a bug that's been fixed, but in the meantime, try this if you can't/don't want to update:

import sympy as sym
from sympy.abc import x
f = x**2
g = x**3
p = sym.Piecewise((-1, x < -1),
                  (x, x < 0),
                  (f, x < 1),
                  (g, True))
sym.plotting.plot(p, (x, -3, 3), adaptive=False)

EDIT:

you can write it as before with this method but as stated in gboffi's answer, I don't think sympy likes it... try this

import sympy as sym
from sympy.abc import x
f = x**2
g = x**3
p = sym.Piecewise((-1, x < -1),
                  (x, sym.And(-1 <= x, x < 0)),
                  (f, sym.And(0 <= x, x < 1)),
                  (g,  x >= 1))
sym.plotting.plot(p, (x, -3, 3), adaptive=False)
Silmathoron
  • 1,781
  • 1
  • 15
  • 32
  • Thanks! I use sympy 1.0, the latest one, why didn't my code work? Well, I consider the conditions in the piecewise functions (x < -1, -1 <= x < 0, etc.) are parallel, is that right? Or they seem to behave progressively? – Frank King Mar 28 '16 at 10:33
0

Comment: I have a similar problem with sympy 1.0. The code below gives the AttributeError in 1.0, but not in version 0.7.6.1 which works fine.

f = Piecewise((0, x < 0), (0, x > L), (1+0.3*x, True))
plot(f.subs({L:1}))
bigM
  • 1
  • 1