3-D interpolation using LinearNDInterpolator (Python) - python

I want to interpolate some 3-d data using the scipy LinearNDInterpolator function (Python 2.7). I can't quite figure out how to use it, though: below is my attempt. I'm getting the error ValueError: different number of values and points. This leads me to believe that the shape of "coords" is not appropriate for these data, but it looks in the documentation like the shape is okay.
Note that in the data I really want to use (instead of this example) the spacing of my grid is irregular, so something like RegularGridInterpolator will not do the trick.
Thanks very much for your help!
def f(x,y,z):
return 2 * x**3 + 3 * y**2 - z
x = np.linspace(1,2,2)
y = np.linspace(1,2,2)
z = np.linspace(1,2,2)
data = f(*np.meshgrid(x, y, z, indexing='ij', sparse=True))
coords = np.zeros((len(x),len(y),len(z),3))
coords[...,0] = x.reshape((len(x),1,1))
coords[...,1] = y.reshape((1,len(y),1))
coords[...,2] = z.reshape((1,1,len(z)))
coords = coords.reshape(data.size,3)
my_interpolating_function = LinearNDInterpolator(coords,data)
pts = np.array([[2.1, 6.2, 8.3], [3.3, 5.2, 7.1]])
print(my_interpolating_function(pts))

Related

plotting vector equations with increasing variables on both axes python

i have been attempting a vector plot (by using quiver) in which every location on the grid is assigned a vector dependant on the location and equations but i am stuck on trying to use a range of both axis parameters (x1 and x3), getting an error:TypeError: only length-1 arrays can be converted to Python scalars
this is the code as built so far and any help would be amazing:
def SVmotion(t,A,beta,f,j):
x1= np.arange(0,10001,100)
x3= np.arange(0,10001,100)
w=2*np.pi*f
k=w/beta
k1=k*np.sin(j)
k3=k*np.cos(j)
k_beta_x = k1*x1+k3*x3
theta = k_beta_x-w*t
Usvx1 = k3*A*complex(-np.sin(theta),np.cos(theta))
Usvx3 = k1*A*complex(-np.sin(theta),np.cos(theta))
Usvx1_real=Usvx1.real
Usvx3_real=Usvx3.real
return Usvx1_real, Usvx3_real
fig ,ax = plt.subplots()
ax.quiver(x1,x3,Usvx1_real,Usvx3_real)
SVmotion(0,1,3000,2,0)
The issue is that 'theta' is an array. Please check if the following helps.
import numpy as np
def SVmotion(t,A,beta,f,j):
x1= np.arange(0,10001,100)
x3= np.arange(0,10001,100)
w=2*np.pi*f
k=w/beta
k1=k*np.sin(j)
k3=k*np.cos(j)
k_beta_x = k1*x1+k3*x3
theta = k_beta_x-w*t
for t in theta:
Usvx1 = k3*A*complex(-np.sin(t),np.cos(t))
Usvx3 = k1*A*complex(-np.sin(t),np.cos(t))
Usvx1_real=Usvx1.real
Usvx3_real=Usvx3.real
return Usvx1_real, Usvx3_real
SVmotion(0,1,3000,2,0)
#(0.003627598728468422, 0.0)

how make a density plot of the eigenvalues of a symbolic matrix in python

I want to make a colour plot of the difference of the two first eigenvalues of that matrix. In order to do this, first I have defined a symbolic matrix with two parametters "x" and "y". Then I obtain the eigenvectors and eigenvalues (shorted) and compute the gap beetwen the two first eigenvalues . Finally (and I think that here is the problem...) I make a grid of points X and Y in order to evaluate it with the function "energy_gap(x,y)" storing the result in Z and then using this in order to do the plot, but it doesn't work....Any idea why?
import numpy as np
import numpy
import matplotlib.pyplot as plt
from sympy.utilities.lambdify import lambdify
from sympy import symbols
x = symbols("x")
y = symbols("y")
matrix = [[x+2, x,y],[y**2,x,3],[y+4,2,1]]
simbolic_matrix = lambdify((x,y), matrix,'numpy')
def eigen_system(x,y):
values, vectors = numpy.linalg.eig(np.array(simbolic_matrix(x,y)))
values_short = np.sort(values)
vectors_short = vectors[:,values.argsort()]
return values_short , vectors_short
def energy_gap(x,y):
values , vectors = eigen_system(x,y)
gap = abs(values[1])-abs(values[0])
return gap
def plot_energy_gap():
x = np.arange(1.1, 3.0, 0.1)
y = np.arange(1.1, 3.0, 0.1)
X, Y = np.meshgrid(x, y)
Z = energy_gap(X,Y)
im = plt.imshow(Z, cmap=plt.cm.RdBu,extent=(1.1,3,1.1,3))
plt.colorbar(im)
plt.show()
plot_energy_gap()
Ok, after some extensive testing, I'm afraid I've come to the conclusion that numpys Eigen stuff calculator can operate on a mesh of matrices like you're trying. The best solution I could get was creating the mesh manuaslly:
def plot_energy_gap()
Z = []
for x in np.arange(1.1, 3.0, 0.1):
Z.append([])
for y in np.arange(1.1, 3.0, 0.1):
Z[-1].append(energy_gap(x, y))
im = plt.imshow(Z, cmap=plt.cm.RdBu,extent=(1.1,3,1.1,3))
plt.colorbar(im)
Maybe someone else can vectorize this. EDIT The one line version (forgot it):
Z = [[energy_gap(x, y) for y in np.arange(1.1, 3.0, 0.1)] for x in np.arange(1.1, 3.0, 0.1)]]

plotting conditional distribution in python

I'm new to python and trying to plot a gaussian distribution having the function defined as
I plotted normal distribution P(x,y) and it's giving correct output. code and output are below.
Code :
Output :
Now I need to plot a conditional distribution and the output should like . to do this I need to define a boundary condition for the equation. I tried to define a boundary condition but it's not working. the code which I tried is but it's giving wrong output
please help me how to plot the same.
Thanks,
You used the boundary condition on the wrong parameter, try to do it after creating the grid points.
R = np.arange(-4, 4, 0.1)
X, Y = np.meshgrid(R, R)
then validate X and Y based on the condition
valid_xy = np.sqrt(X**2+Y**2) >= 1
X = X[valid_xy]
Y = Y[valid_xy]
Then continue with the rest of the code.
Update
If you want just to reset values around the peak to zero, you can use the following code:
import numpy as np
import matplotlib.pyplot as plt
R = np.arange(-4, 4, 0.1)
X, Y = np.meshgrid(R, R)
Z = np.sum(np.exp(-0.5*(X**2+Y**2)))
P = (1/Z)*np.exp(-0.5*(X**2+Y**2))
# reset the peak
invalid_xy = (X**2+Y**2)<1
P[invalid_xy] = 0
# plot the result
fig = plt.figure(figsize=(10, 6))
ax = fig.add_subplot(111, projection='3d')
ax.scatter(X, Y, P, s=0.5, alpha=0.5)
plt.show()
You can't use np.meshgrid anymore because it will output a matrix where the coordinates of X and Y form a grid (hence its name) and not a custom shape (a grid minus a disc like you want):
However you can create your custom grid the following way:
R = np.arange(-,4,0.1)
xy_coord = np.array(((x,y) for x in R for y in R if (x*x + y*y) > 1))
X,Y = xy_coord.transpose()
X
# array([ 0. , 0. , 0. , ..., 3.9, 3.9, 3.9])
Y
# array([ 1.1, 1.2, 1.3, ..., 3.7, 3.8, 3.9])

numpy contour plot with cost function

a = np.array(x)
b = np.array(y)
a_transpose = a.transpose()
a_trans_times_a = np.dot(a_transpose,a)
a_trans_times_b = np.dot(a_transpose,b)
def cost(theta):
x_times_theta = np.dot(a, theta)
_y_minus_x_theta = b - x_times_theta
_y_minus_x_theta_transpose = _y_minus_x_theta.transpose()
return np.dot(_y_minus_x_theta_transpose, _y_minus_x_theta)
n = 256
p = np.linspace(-100,100, n)
q= np.linspace(-100,100, n)
P, Q = np.meshgrid(p,q)
pl.contourf(P, Q, cost(np.array([P,Q])) ,8, alpha =0.75, cmap = 'jet')
C = pl.contour(P,Q, cost(np.array([P,Q])), 8, colors = 'black', linewidth = 0.5 )
Hi, I'm trying to make a contour plot using a cost function on two parameters, involving matrix multiplication. I've tested the cost function and it works properly in interactive session. However, running it on a linspace makes it get error "ValueError: objects are not aligned". I understand now that it has to do with how I structure P,Q. Would the solution involve writing a for loop to explicitly get an array of outputs? How would I write this?
EDIT: a,b are matrices with correct size. The cost function takes a 2-vector and outputs a number.
It's hard to know exactly without having at hand the shapes of a and b, but this error is probably caused by np.array[P,Q] being a 3-dimensional array. It seems you expect it to be 2-dimensional and for np.dot(a,theta) to perform matrix multiplication.
Presumably you want theta to be the the angular coordinate at a particular x and y value. In this case you should do
theta = np.arctan2(Q,P) #this is a 2D array of theta coordinates
costarray = cost(theta)
pl.contourf(P,Q,costarray,8,alpha=0.75,cmap='jet')

Correct usage of scipy.interpolate.RegularGridInterpolator

I am a little confused by the documentation for scipy.interpolate.RegularGridInterpolator.
Say for instance I have a function f: R^3 => R which is sampled on the vertices of the unit cube. I would like to interpolate so as to find values inside the cube.
import numpy as np
# Grid points / sample locations
X = np.array([[0,0,0], [0,0,1], [0,1,0], [0,1,1], [1,0,0], [1,0,1], [1,1,0], [1,1,1.]])
# Function values at the grid points
F = np.random.rand(8)
Now, RegularGridInterpolator takes a points argument, and a values argument.
points : tuple of ndarray of float, with shapes (m1, ), ..., (mn, )
The points defining the regular grid in n dimensions.
values : array_like, shape (m1, ..., mn, ...)
The data on the regular grid in n dimensions.
I interpret this as being able to call as such:
import scipy.interpolate as irp
rgi = irp.RegularGridInterpolator(X, F)
However, when I do so, I get the following error:
ValueError: There are 8 point arrays, but values has 1 dimensions
What am I misinterpreting in the docs?
Ok I feel silly when I answer my own question, but I found my mistake with help from the documentation of the original regulargrid lib:
https://github.com/JohannesBuchner/regulargrid
points should be a list of arrays that specifies how the points are spaced along each axis.
For example, to take the unit cube as above, I should set:
pts = ( np.array([0,1.]), )*3
or if I had data which was sampled at higher resolution along the last axis, I might set:
pts = ( np.array([0,1.]), np.array([0,1.]), np.array([0,0.5,1.]) )
Finally, values has to be of shape corresponding to the grid laid out implicitly by points. For example,
val_size = map(lambda q: q.shape[0], pts)
vals = np.zeros( val_size )
# make an arbitrary function to test:
func = lambda pt: (pt**2).sum()
# collect func's values at grid pts
for i in range(pts[0].shape[0]):
for j in range(pts[1].shape[0]):
for k in range(pts[2].shape[0]):
vals[i,j,k] = func(np.array([pts[0][i], pts[1][j], pts[2][k]]))
So finally,
rgi = irp.RegularGridInterpolator(points=pts, values=vals)
runs and performs as desired.
Your answer is nicer, and it's perfectly OK for you to accept it. I'm just adding this as an "alternate" way to script it.
import numpy as np
import scipy.interpolate as spint
RGI = spint.RegularGridInterpolator
x = np.linspace(0, 1, 3) # or 0.5*np.arange(3.) works too
# populate the 3D array of values (re-using x because lazy)
X, Y, Z = np.meshgrid(x, x, x, indexing='ij')
vals = np.sin(X) + np.cos(Y) + np.tan(Z)
# make the interpolator, (list of 1D axes, values at all points)
rgi = RGI(points=[x, x, x], values=vals) # can also be [x]*3 or (x,)*3
tst = (0.47, 0.49, 0.53)
print rgi(tst)
print np.sin(tst[0]) + np.cos(tst[1]) + np.tan(tst[2])
returns:
1.93765972087
1.92113615659

Categories

Resources