0

enter image description here

https://scicomp.stackexchange.com/questions/1144/how-can-i-plot-piece-wise-defined-function-in-some-easily-accessed-open-source-t

①Why is it that the above source code can be used to create a plot, but the following source code cannot?

②Can you point me to a web site that has a table comparing (matplotlib) and (SymPy Plotting Module)?

③(matplotlib) to (SymPy Plotting Module) converter and a (SymPy Plotting Module) to (matplotlib) converter would be helpful.

from sympy import *

def define_fn(n):
    def fn(x):
        if n <= x <= n + 1:
            return float(x) - n
        elif n + 1 <= x <= n + 2:
            return 2.0 - x + n
        else:
            return 0.0
    return fn
f3 = define_fn(3)
f8 = define_fn(8)

print("#",f3)
print("#",f8)
plot(f3,f8)
# <function define_fn.<locals>.fn at 0x000002474E838280>
# <function define_fn.<locals>.fn at 0x000002474E838310>
# SymPyDeprecationWarning: .............
mrrclb46z
  • 89
  • 6
  • 2
    `matplotlib` is a big package that (normally) takes numpy arrays as inputs - or equivalent numeric lists. `sympy.plot` probably uses `matplotlib` in the background, but is designed to accept sympy expressions as inputs, converting them to numeric values as needed. Doesn't the `sympy` docs provide enough information? As a general rule you should not attempt to use `sympy` expressions in `numpy/scipy/matplotlib` functions - at least not until your have learned them well. As beginner, don't try to mix them. Learn one or the other, without worrying about equivalences. – hpaulj Mar 17 '22 at 21:39

3 Answers3

2

Let's make sure you understand what the link and your adaptation is doing. Your question about the difference in the plot packages suggests you don't have a clear idea of what package is doing what.

You have defined two python functions, that take one number.

In [11]: f3(4)
Out[11]: 1.0
In [12]: f8(9)
Out[12]: 1.0

With just python we can create a list of x values:

In [17]: x = [i / 10 for i in range(120)]

the corresponding y values:

In [18]: y1 = [f3(i) for i in x]
In [19]: y2 = [f8(i) for i in x]

and plot them with:

In [20]: plt.plot(x, y1, x, y2)
Out[20]: 
[<matplotlib.lines.Line2D at 0x7fe2589385e0>,
 <matplotlib.lines.Line2D at 0x7fe258938610>]
# plotted as you show

The link use np.linspace to create the x values as an array, and np.vectorize to apply the function(s) to all these values. matplotlib works with both arrays and lists.

There's nothing fancy about this use of matplotlib.


Statements like:

    if n <= x <= n + 1:
        return float(x) - n

only work with single numbers. That's basic python. Using a numpy array for x or a sympy symbol or expression will result in an error.

If x is a sympy symbol:

In [3]: f3(x)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [3], in <module>
----> 1 f3(x)

Input In [1], in define_fn.<locals>.fn(x)
      2 def fn(x):
----> 3     if n <= x <= n + 1:
      4         return float(x) - n
      5     elif n + 1 <= x <= n + 2:

File /usr/local/lib/python3.8/dist-packages/sympy/core/relational.py:398, in Relational.__bool__(self)
    397 def __bool__(self):
--> 398     raise TypeError("cannot determine truth value of Relational")

TypeError: cannot determine truth value of Relational

and with an array:

In [4]: f3(np.arange(3))
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [4], in <module>
----> 1 f3(np.arange(3))

Input In [1], in define_fn.<locals>.fn(x)
      2 def fn(x):
----> 3     if n <= x <= n + 1:
      4         return float(x) - n
      5     elif n + 1 <= x <= n + 2:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
hpaulj
  • 221,503
  • 14
  • 230
  • 353
1

①Why is it that the above source code can be used to create a plot, but the following source code cannot?

The linked example uses matplotlib which works with numeric inputs. Matplotlib doesn't know about sympy's world.

Sympy's plot module converts sympy expressions to numeric approximations and plots them using matplotlib. Sympy's plot module abstracts away a lot of intricacies to make this work, and hides these from the casual user.

②Can you point me to a web site that has a table comparing (matplotlib) and (SymPy Plotting Module)?

Matplotlib is very huge. Sympy's plotting module uses a subset of functionality, carefully and ingeniously adapted to the symbolic world. Differences don't fit into a table. Matplotlib's extensive documentation can be found at matplotlib.org, but most people only look into the subset they are using. Sympy's plotting documentation fits onto one large webpage. For both libraries you will need extra tutorials, StackOverlow, and maybe diving into the freely available source code if you need functionality that isn't readily available.

③(matplotlib) to (SymPy Plotting Module) converter and a (SymPy Plotting Module) to (matplotlib) converter would be helpful.

That would be a titanic work, with lots of undefined cases. Sympy (as well as matplotlib) is developed by very talented volunteers, with limited resources.

Note that, if you really want to, you can "move" sympy plots to the matplotlib world and extend the plot there.

Here is how your source code could look like in sympy. First some remarks:

  • sympy functions and expressions can't work with Python's if-tests, you need symbolic functions such as PieceWise instead.
  • float(x) doesn't work for sympy's symbols
  • in general, sympy tries to avoid floats as they are approximate by definition while sympy almost always looks for exact symbolic solutions
from sympy import plot, Symbol, Piecewise, And

def define_fn(n):
    def fn(x):
        return Piecewise((x - n, (n <= x) & (x <= n + 1)),
                         (2 - x + n, (n + 1 <= x) & (x <= n + 2)),
                         (0, True))
    return fn

f3 = define_fn(3)
f8 = define_fn(8)

x = Symbol('x', real=True)
plot(f3(x), f8(x), (x, -1, 11))

sympy plot of piecewise functions

Although this works, it is not sympy's standard way. Usually, functions are written as expressions. Note how f3 is used as an expression that contains x, instead of the less flexible f3(x) of the previous example.

from sympy import plot, Symbol, Piecewise, And

x = Symbol('x', real=True)
n = Symbol('n', real=True)

fn = Piecewise((x - n, (n <= x) & (x <= n + 1)),
               (2 - x + n, (n + 1 <= x) & (x <= n + 2)),
               (0, True))

f3 = fn.subs(n, 3)  # Piecewise((x - 3, (x >= 3) & (x <= 4)), (5 - x, (x >= 4) & (x <= 5)), (0, True))
f8 = fn.subs(n, 8)  # Piecewise((x - 8, (x >= 8) & (x <= 9)), (10 - x, (x >= 9) & (x <= 10)), (0, True))

plot(f3, f8, (x, -1, 11))
JohanC
  • 71,591
  • 8
  • 33
  • 66
0
print("#",type(f3),f3)
print("#",type(f8),f8)
# <class 'function'> <function define_fn.<locals>.fn at 0x00000246464B9280>
# <class 'function'> <function define_fn.<locals>.fn at 0x00000246464B9310>

print("#",type(f3(x)),f3(x))
print("#",type(f8(x)),f8(x))
# Piecewise Piecewise((x - 3, (x >= 3) & (x <= 4)), (5 - x, (x >= 4) & (x <= 5)), (0, True))
# Piecewise Piecewise((x - 8, (x >= 8) & (x <= 9)), (10 - x, (x >= 9) & (x <= 10)), (0, True))

print("#",type(f3),f3)
print("#",type(f8),f8)
# Piecewise Piecewise((x - 3, (x >= 3) & (x <= 4)), (5 - x, (x >= 4) & (x <= 5)), (0, True))
# Piecewise Piecewise((x - 8, (x >= 8) & (x <= 9)), (10 - x, (x >= 9) & (x <= 10)), (0, True))
mrrclb46z
  • 89
  • 6