Python Forum
Help with plotting a piecewise function
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help with plotting a piecewise function
#1
Hello, I am trying to plot a peicewise function but I get an error (ValueError: The truth value of an array with more than one element is ambiguous.) and despite reading the forums/help, I am unable to fix it. Can someone please help. Thanks
import math
import numpy as np
import matplotlib.pyplot as plt

import scipy
from scipy import optimize
import scipy.integrate as integrate


def current(x): return np.piecewise(x, [0 < x < 50, x > 50], [4-0.3*x, 0])
def voltage(x): return np.piecewise(x, [0 < x < 50, x > 50], [x*(1-0.03*x), 0])
def power(x): return current(x)* voltage(x)

points = 100  
tlim = 10e-3
t = np.linspace(0, tlim, points)


figure = plt.subplots(figsize=(10, 5))

axe = plt.subplot(311)
plt.title('Voltage')
plt.ylabel('Voltage [V]')
plt.grid()
plt.plot(t,voltage(t),color='black')

axe = plt.subplot(312)
plt.title('Current')
plt.ylabel('Current [A]')
plt.grid()
plt.plot(t,current(t),color='black')

axe = plt.subplot(313)
plt.title('Power')
plt.xlabel('Time [s]')
plt.ylabel('Power [W]')
plt.grid()
plt.plot(t,power(t),color='blue')

plt.show()
deanhystad write Jul-25-2024, 01:08 PM:
Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Reply
#2
Three problems (maybe more).

The first problem is you cannot have a comparison like "0 < x < 50" in the condition list. This is what causes the error you are seeing. x is a numpy array, not a single value. Numpy arrays don't understand how to be embedded in a comparison like 0 < x < 50. 0 < x creates a list of True/False, and [True, False, ...] < 50 doesn't make any sense. You need to do the comparisons the numpy way: (x > 0) * (x < 50). This does comparisons, x > 0 and x < 50, create two True/False arrays, and [True, False, ...] * [True, False, ...] does elementwise multiplication. For boolean values, * is the equivalent of lotical and.

In the all the following code I use a reduced range 0 < x < 5 to make it easy to print the output.
import numpy as np

x = np.linspace(-1, 10, 12)
a = (0 < x)
b = (x < 5)
c = (a * b)
print(a, b, c, sep="\n")
Output:
[False False True True True True True True True True True True] [ True True True True True True False False False False False False] [False False True True True True False False False False False False]
The second problem is in the function list. From the documentation.
Quote:funclistlist of callables, f(x,*args,**kw), or scalars
Each function is evaluated over x wherever its corresponding condition is True. It should take a 1d array as input and give an 1d array or a scalar value as output. If, instead of a callable, a scalar is provided then a constant function (lambda x: scalar) is assumed.
Each item in the funclist is a function. This is an expression, not a function: 4 - 0.3 * x.

You could do this:
import numpy as np

def function(x):
    return 4 - 0.3 * x

x = np.linspace(-1, 10, 12)
y = np.piecewise(x, [(0 < x) * (x < 5), x > 5], [function])
print(y)
Output:
[0. 0. 3.7 3.4 3.1 2.8 0. 0. 0. 0. 0. 0. ]
Or you could use a lambda expression. A lambda expression defines a function without using def.
import numpy as np

x = np.linspace(-1, 10, 12)
y = np.piecewise(x, [(0 < x) * (x < 5), x > 5], [lambda a: 4 - 0.3 * a])
print(y)
Output:
[0. 0. 3.7 3.4 3.1 2.8 0. 0. 0. 0. 0. 0. ]
There is also an error in your comparisons, but it probably won't have any effect on your results. The comparisons in your condlist contains holes. What should the value of y be for x <= 0 or x == 50? The code below exposes the holes.
import numpy as np

x = np.linspace(-1, 10, 12)
y = np.piecewise(x, [(0 < x) * (x < 5), x > 5], [1, 2])
print(y)
Output:
[0. 0. 1. 1. 1. 1. 0. 2. 2. 2. 2. 2.]
Notice not all values are 1 or 2. The 0's in the list indicate where neither condition in the condlist is true, so a default value is used instead. Since the default (0) is the value you want for all x <= 0 or x >= 50 I suppose you could take advantage of that.
import numpy as np

x = np.linspace(-1, 10, 12)
y = np.piecewise(x, [(0 < x) * (x < 5)], [1])
print(y)
Output:
[0. 0. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
Or, for your code
y = np.piecewise(x, [(0 < x) * (x < 50)], [lambda a: 4 - 0.3 * a])
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Help plotting function Pbworm1998 1 2,038 Sep-20-2019, 05:35 PM
Last Post: ndc85430

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020