piecewise function with 3d plot - python

I am having trouble getting np.piecewise to work for multiple dimensional plotting due to broadcast errors.
Does anyone have any manner to get around this?
Here is what I have in a simplified executable script:
import numpy as np
from pylab import *
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d, Axes3D
num_steps = 100
x_arr = np.linspace(0,100, num_steps)
y_arr = np.linspace(0,20, num_steps)
def zfunc(x, y):
return np.piecewise(x, [x>=500, x<500], [x, -x])
x,y = np.meshgrid(x_arr, y_arr)
z =zfunc(x,y)
fig=plt.figure()
ax=fig.subplot(1,1,1,projection='3d')
p = x.plot_surface(x,y,z,rstride=1,cstride=1,cmap=cm.coolwarm,linewidth=0,antialiased=False)
plt.show()
Which gives the error:
return np.piecewise(x, [x>=500, x<500], [x, -x])
File "C:\Python27\lib\site-packages\numpy\lib\function_base.py", line 716, in piecewise
y[condlist[k]] = item
ValueError: array is not broadcastable to correct shape

Taking a look at the docstring of the function you're using is usually a good idea. I found this solution there.
np.piecewise(x, [x>=500, x<500], [lambda x: x, lambda x: -x])
funclist : list of callables, f(x,args,*kw), or scalars
Each function is evaluated over x wherever its corresponding
condition is True. It should take an array as input and give an 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.

Related

How to format the argument of scipy.optimize.fsolve for arrays of data

I'd like to use a solver (scipy.optimize.fsolve) to solve for the root of a function, fun(x,y). In this case, I want the argument (y) to be an array (e.g. an array of data). I would also like to avoid using for-loops to call fsolve for each value in y.
In specifying arg (y) as an array, I am getting an error that the result from the function call is not a proper array of floats. Other errors occur if I make "data" a tuple instead of an array.
Here is an MWE of the problem:
import numpy as np
from scipy.optimize import fsolve
def fun(x, y):
return x+y
data = np.array([1, 2, 3, 4])
x = fsolve(fun, x0=0, args=data)
print(x)
How can the input to fsolve be corrected so that it solves for the root of fun(x,y) for each value of y in the array (without using a for-loop)?
The function, that is passed to fsolve, takes at least one (possibly vector) argument and returns a value of the same length as mentioned here.
In your case, you are passing x0=0 and args=np.array([1,2,3,4]) to fsolve. The return value of fun has a different length to x0 (x0 is a scalar and args is an array having shape (4,)).
The following code solves your problem:
import numpy as np
from scipy.optimize import fsolve
def fun(x, y):
return x+y
data = np.array([1, 2, 3, 4])
x = fsolve(fun, x0=np.array([0,0,0,0]), args=data)
print(x)

Error for a given function: only size-1 arrays can be converted to Python scalars

i am a newbie and currently trying to plot this function so I can choose a range of x values for which I should perform my experiments in the ChemistryLab.
I found different articles on plotting functions and it all worked with generic functions like sin(x).
But once I input my function it does not work. The problem already occurs after the first two lines:
import numpy as np
import math
X = np.linspace(0, 512, 256)
f = ((x+22)- math.sqrt((x+22)**2-4*2*x))
--> TypeError: only size-1 arrays can be converted to Python scalars
I found threads saying X should be vectorize, however I could not come up with a solution.
Thanks for help in advance!
Create a vectorized function. For example:
equation_func = np.vectorize(math.sqrt)
new_f = equation_func(X)
Swap math.sqrt with a function containing your more sophisticated equation and you're home.
A good way to implement a mathematical function in Python is, perhaps unsurprisingly, as a Python function. Then you can, for example, use that function in a list comprehension to get an array of values:
import numpy as np
import math
import matplotlib.pyplot as plt
X = np.linspace(0, 512, 256)
def f(x):
return x + 22 - math.sqrt((x + 22)**2 - 8 * x)
Y = np.array([f(x) for x in X])
plt.plot(X, Y);

Issue in plotting array in python

TypeError: only size-1 arrays can be converted to Python scalars
import math
import numpy as np
import matplotlib.pyplot as plt
def myfunction(x):
return np.int(x)
myfunction2 = np.vectorize(myfunction)
x = np.array([0, math.pi/100, 2*math.pi])
y = math.sin(x)
plt.plot(myfunction2(x),y)
plt.show()
There are a few problems I see. First, you need to use np.sin in order to apply it to the entire vector. Second, your definition of x is only 3 elements long. I believe you are trying to use np.arange. Try x = np.arange(0,2*math.pi,math.pi/100,dtype='float32') instead.

matplotlib error: x and y must have same first dimension and lambda function

I'm quite new to python and especially new to the lambda functions. I tried plotting the function that I define below, but I get
ValueError: x and y must have same first dimension, but have shapes (100,) and (1,)
From what I've seen of function plotting, I think the error is in the definition of my functions, i.e. W is badly defined.
Here is the code:
import numpy as np
import matplotlib.pyplot as plt
def W(t):
s=lambda t: t
for k in range(5):
s=lambda t, y=s: y(t)+k
return s
t=np.linspace(0,1,100)
plt.plot(t,W(t))
If I change my code to this, it works:
import numpy as np
import matplotlib.pyplot as plt
def W(t):
s=lambda x: x
for k in range(5):
s=lambda x, y=s: y(x)+k
return s(t)
t=np.linspace(0,1,100)
plt.plot(t,W(t))

How does matplotlib accept function parameters? Are they lambdas?

The following syntax is very intuitive. Run in Spyder, and it plots a nonlinear function.
import numpy as numpy
import matplotlib.pyplot as plot
x = numpy.arange(0, 1, 0.01)
def nonlinear(x, deriv=False): #sigmoid
if (deriv==True):
return x*(1-x)
return 1/(1-numpy.exp(-x))
plot.plot(x, nonlinear(x))
My question is, how is the function nonlinear passed to plot.plot? Is it a lambda? How is nonlinear accepting an array without crashing when it does math ops?
It works fine because the usual arithmetic operations (e.g. / and - as you've used) are defined for numpy arrays; they're just performed element-wise. The same goes for np.exp(). You can see exactly what nonlinear(x) looks like for yourself (it's also a numpy array):
>>> import numpy as np
>>> def nonlinear(x): return 1/(1 + np.exp(-x))
...
>>> nonlinear(np.arange(0, 1, 0.1))
array([ 0.5 , 0.52497919, 0.549834 , 0.57444252, 0.59868766,
0.62245933, 0.64565631, 0.66818777, 0.68997448, 0.7109495 ])
You're just finding the value of the sigmoid evaluated at each point in the specified range, and passing those as the y-values to plot.
Python has special double underscore methods. e.g. __add__, __sub__, etc. https://docs.python.org/2/reference/datamodel.html has a more comprehensive list.
x + y is just x.__add__(y)
x * y is just x.__mul__(y)
Numpy makes use of these "magic" methods to implement point-wise arithmetic
The matplotlib plot function needs two lists (or numpy arrays) as arguments for x and y. As arshajii answered the syntax is vaild because the numpy array x is evaluated elementwise in the return statement of the nonlinear function (which is really nice).
However, in case the nonlinear function includes a case-by-case operation a numpy evaluation is not possible anymore (without some further numpy-magic). For example look at this continuously differentiable but non-smooth function:
from pylab import *
def nonlinear(x, x0=2):
return x**2 if x < x0 else 2*x0*(x - x0) + x0**2
x = linspace(0, 5, 100)
y = nonlinear(x)
The last line rises the error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Instead use a list comprehension
y = [nonlinear(x_, x0=2.5) for x_ in x]
plot(x, y)
show()
which results in the following figure

Categories