How does matplotlib accept function parameters? Are they lambdas? - python

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

Related

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);

How do I use sympy.lambdify with Max function to substitute numpy.maximum instead of numpy.amax?

I'm trying to lambdify big analytic expression with sp.Max(x, 0) inside. I want to use numpy to vectorize my calculations, so x is going to be an array. I need element-wise maximum values of x and 0. Still, sympy changes sp.Max to np.amax by default. It finds maximum along the axis, that's not what I need. "modules" keyword in lambdify doesn't work as I expect.
I've tried:
import numpy as np
import sympy as sp
arr = np.array([1, 2, 3])
expr = sp.sin(x) + sp.Max(x, 0)
f = sp.lambdify(x, expr, modules=[{'Max': np.maximum}, 'numpy']) # docs say, priority of modules matters
help(f)
It gives:
Help on function _lambdifygenerated:
_lambdifygenerated(x)
Created with lambdify. Signature:
func(x)
Expression:
sin(x) + Max(0, x)
Source code:
def _lambdifygenerated(x):
return (sin(x) + amax((0,x)))
Imported modules:
sp.Max changed to amax for some reason.
If 'numpy' is not included into 'modules' list, it simply skips all other functions. I've also tried to swap dict and 'numpy' in list, but it haven't helped. Please, clarify, what's wrong? Is it a bug in sympy?
When using lambdify to create numpy functions intended to work vectorized, there often are subtle problems, especially when variables (x) and constants (0) are mixed.
In this case, sp.max supposes all of its possible many parameters being single values. np.amax gets the maximum of one flattened array. np.maximum gets the element-wise maximum of two arrays. The problem here is that the constant 0 doesn't automatically get expanded to a numpy array.
My workaround would be to replace sp.max with a custom function based on sp.Piecewise. Note that you would need a separate function if there would be more than 2 arguments to sp.max.
import numpy as np
import sympy as sp
from sympy.abc import x
def sympy_max2(a, b):
return sp.Piecewise((b, a < b), (a, True))
arr = np.array([11, 22, 33, -1, -2])
expr = sp.sin(x) + sympy_max2(0, x)
f = sp.lambdify(x, expr, modules=['numpy'])
print(f(arr)) # [10.00000979 21.99114869 33.99991186 -0.84147098 -0.90929743]
In the current version of SymPy I get return (sin(x) + amax((0,x), axis=0)) in the signature. Is this what you want?
To use the np.maximum function instead of np.amax, I found that specifying the amax method instead of the Max works. The np.maximum function also requires some tweaking, to receive the arguments that are used for the amax function.
import numpy as np
import sympy as sp
arr = np.array([11, 22, 33, -1, -2])
expr = sp.sin(x) + sp.Max(x, 0)
def custom_amax(x,**kwargs):
return np.maximum(x[0],x[1])
f = sp.lambdify(x, expr, modules=[{'amax': custom_amax}, 'numpy'])
f(arr) # [10.00000979, 21.99114869, 33.99991186, -0.84147098, -0.90929743]

How to return array from element-wise custom calculation on other numpy arrays?

I would like to obtain a numpy array from element-wise calculation on different numpy arrays. As of now, I am using a lambda function to return a value, repeat that for all values, create a list therefrom, and convert to numpy array:
import math
import numpy as np
def weightAdjLoads(loadsX, loadsY, angles, g):
adjust = lambda x, y, a: math.sqrt((abs(x) - math.sin(a)*g)**2 + (abs(y) - math.cos(a)*g)**2)
return np.array([adjust(x, y, a) for x, y, a in zip (loadsX, loadsY, angles)])
This seems to me like too much overhead. Are there any numpy routines which could do just that?
I am aware of methods such as numpy.sqrt(A**2 + B**2), where A and B are numpy arrays. However, those only allow to apply predefined formulas. How can I apply custom formulas on numpy arrays?
numpy.sqrt(A**2 + B**2) is parsed by the Python interpreter into calls roughly as follows:
tmp1 = A**2 # A.__pow__(2)
tmp2 = B**2 #
tmp3 = tmp1 + tmp2 # tmp1.__add__(tmp2)
tmp4 = np.sqrt(tmp3)
That is, there are defined numpy functions and methods for power, addition, sqrt etc.
Your lambda works with scalars, not numpy arrays:
math.sqrt((abs(x) - math.sin(a)*g)**2 + (abs(y) - math.cos(a)*g)**2)
Specifically it's the math trig functions that require scalars. abs works with arrays:
abs(A) => A.__abs__()
numpy provides a full set of trig functions, so this function should work with array, or scalar, arguments:
def foo(x, y, a):
return np.sqrt((abs(x) - np.sin(a)*g)**2 + (abs(y) - np.cos(a)*g)**2)
There are ways of wrapping your scalar adjust into a numpy function, but the speed savings relative to your list comprehension are minor.
f = np.vectorize(adjust)
f = np.frompyfunc(adjust, 3, 1)
Mainly they make it easier to broadcast arrays to a scalar functions. But to gain compiled speed you have to make a conversion such as in my foo, or use a third party package like cython, numba, or numexpr.

best method of making an array

I'm new to programming and am a bit unsure about how to write my own for loop. This is what I would like please?
Let us subdivide interval [0,1] into n points x0=0,...,xn−1=1.
Write a function compute_discrete_u(epsilon, n) that returns two numpy arrays:
x_array contains the coordinates of the n points
u_array contains the discrete values of u at these points.
u(x)=sin(1x+ϵ)
Thank you!
First of all, you do not need a for loop at all. You want to use numpy, so you can use the vectorized operations that numpy is built upon.
Here's the function you are literally asking for (and most likely not how you should solve your problem):
# Do NOT use this.
import numpy as np
def compute_discrete_u(epsilon, n):
x = np.linspace(0, 1, n)
return x, np.sin(x + expsilon)
That's quite an awkward API. From a design point-of-view, you are mixing two responsibilities in the function:
Generating a certain x vector
Calculating a u vector based on a mathematical function.
You should not do this for complexity and reusability reasons. What if you want a non-uniform x later on?
So here's what you should do:
import numpy as np
def compute_u(x, epsilon):
return np.sin(x + epsilon)
x = np.linspace(0, 1, num=101)
u = compute_u(x, epsilon=1e-3)
This is more easy to understand because the function is just the mathematical function. Additionally, you can compute u for any x array (or single float) you like. If you do not need compute_u elsewhere, you may even completely drop it and write u = np.sin(x + epsilon)

piecewise function with 3d plot

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.

Categories