trouble with performing coordinate map/interpolation with interp2d - python

I have what is essentially a 4 column lookup table: cols 1, 2 are the respective xi,yj coordinates which map to x'i, y'j coordinates in the respective 3rd and 4th cols.
My goal is to provide a method to enter some (xnew,ynew) position within the range of my look-up values in the 1st and 2nd columns(xi,yj) then map that position to an interpolated (x'i,y'j) from the range of positions in the 3rd and 4th cols of the lut.
I have tried using interp2d, but have not been able to figure out how to enter the arrays into the proper format. For example: I don't understand why scipy.interpolate.interp2d(x'i, y'j, [xi,yj] kind='linear') gives me the following error:
ValueError: Invalid length for input z for non rectangular grid'.
This seems so simple, but I have not been able to figure it out. I will gladly provide more information if required.

interp2d requires that the interpolated function be 1D, see the docs:
z : 1-D ndarray The values of the function to interpolate at the data
points. If z is a multi-dimensional array, it is flattened before use.
So when you enter [xi,yj], it gets converted from its (2, n) shape to (2*n,), hence the error.
You can get around this setting up two different interpolating functions, one for each coordinate. If your lut is a single array of shape (n, 4), you would do something like:
x_interp = scipy.interpolate.interp2d(lut[0], lut[1], lut[2], kind = 'linear')
y_interp = scipy.interpolate.interp2d(lut[0], lut[1], lut[3], kind = 'linear')
And you can now do things like:
new_x, new_y = x_interp(x, y), y_interp(x, y)

Related

Python - How to pass elements stored in an array into a function?

All,
I'm new to python, so hopefully this is not a dumb question, but I have not been able to find out directions/information of how to do this task.
I am trying to create a program that determines if a given pixel is within a certain region. The method I found that recommended how to test this involves calculating polygonal areas. In this case, that would involve the shoelace function, which I have already found. The polygon coordinates are stored in a 2-dimensional array as [(x,y),(x1,y1),(x2,y2)...].
The given set of test coordinates and the function representing the shoelace function are below:
import numpy as np
testCoords = [(201,203)...(275,203)]
def polyArea(x,y):
return 0.5 * np.abs(np.dot(x, np.roll(y,1)) - np.dot(y, np.roll(x, 1)))
How do I pass the coordinates as stored in the 2-dimensional array into the shoelace function?
Your polyArea expects two arrays of x and y coordinates. Your testCoords variable is a list of several points represented by their (x, y) coordinates. We will turn the later into a shape that works well, by converting it to a numpy array and transposing it:
x, y = np.array(testCoords).transpose() # Often, `.transpose()` is abbreviated as `.T`
That will give you x == [201, ..., 275] and y == [203, ..., 203].
U just need to get the given pixel's x and y coordinate. Get the index of it (if needed) with:
my_pixel_coordinates = (260, 203)
testCoords = [(201,203), ... (275,203)] #your pixel position array
i = testCoords.index(my_pixel_coordinates)
And then get the x and y coordinates using your testCoords:
area = polyArea(testCoords[i][0], testCoords[i][1])
#'i' is the index of the pixel and 0 the first value (x) and 1 the second (y)
You can get any Array's values using the squared brackets

How to use np.gradient on multidimensional data?

There exist a lot of questions on this, but I can't find one that describes this particular use case.
I have a matrix P, which gives a scalar value in a 3D field of size (dx,dy,dz)=(360, 720, 30) over 41 timesteps. That is,
>>> np.shape(P)
(41, 30, 360, 720)
As is seen, the z-index (we'll call it the "vertical") is the second dimension.
I want to calculate dP/dz for this field.
However, the spacing in z is not uniform in any of the three spatial dimensions, and is time-variate (simply imagine that each grid point is allowed to float around per-timestep). That is, there is an associated matrix giving the vertical coordinates of each grid point in the 3D space, Z3, where
>>> np.shape(Z3)
(41, 30, 360, 720)
How do I then use np.gradient() to obtain P'(t, x, y), where P'=dP/dz?
When I try differentiating along axis 1, I get:
>>> np.gradient(P, Z3, axis=1)
*** ValueError: distances must be either scalars or 1d
This error is very opaque, since it contradicts the documentation, which describes the ability to pass N dimensional spacings. However, this does work:
>>> np.gradient(P[0,:,0,0], Z3[0,:,0,0])
This essentially gives me dP/dz in one "vertical column" of the field, i.e. the derivative of P at the origin at time=0, P'(0,0,0). Consider the horrifically slow code:
dpdz = np.zeros(np.shape(P))
for i in range(np.shape(P)[0]):
for j in range(np.shape(P)[2]):
for k in range(np.shape(P)[3]):
dpdz[i,:,j,k] = np.gradient(P[i,:,j,k], Z3[i,:,j,k])
This is exactly the result that I would expect np.gradient(P, Z3, axis=1) to give. Is there a way to make this work?

Contour plot on 2 parameter data in python

Hi I have a numpy object with shape (1000,3) that I wish do a contour plot of. The first two columns represent x and y values and the 3rd is the associated density value at the the point denoted by the x and y values. These are NOT evenly spaced as the x and y values were generated by MCMC sampling methods. I wish to plot the x and y values and demarcate points which have density at a certain level.
I have tried calling the contour function but it does not appear to work.
presuming I have a data object such that np.shape(data) gives (1000,3)
plt.figure()
contour(data[:,0],data[:,1],data[:,2])
plt.show()
this does not seem to work and gives the following error
TypeError: Input z must be a 2D array
I understand z, the 3rd column needs to be some sort of meshgrid, but the all the examples I have seen seen to rely on constructing one from evenly spaced x and y which I do not have. Help appreciated on how I can resolve this.
EDIT: I have figured it out. Need to use the method for unevenly spaced points as described here.
https://matplotlib.org/devdocs/gallery/images_contours_and_fields/griddata_demo.html#sphx-glr-gallery-images-contours-and-fields-griddata-demo-py

fill Numpy array with axisymmetric values

I'm trying to find a fast way to fill a Numpy array with rotation symmetric values. Imagine an array of zeros containing a cone shaped area. I have a 1D array of values and want to rotate it 360° around the center of the array. There is no 2D function like z=f(x,y), so I can't calculate the 2D values explicitly. I have something that works, but the for-loop is too slow for big arrays. This should make a circle:
values = np.ones(100)
x = np.arange(values.size)-values.size/2+0.5
y = values.size/2-0.5-np.arange(values.size)
x,y = np.meshgrid(x,y)
grid = np.rint(np.sqrt(x**2+y**2))
arr = np.zeros_like(grid)
for i in np.arange(values.size/2):
arr[grid==i] = values[i+values.size/2]
My 1D array is of course not as simple. Can someone think of a way to get rid of the for-loop?
Update: I want to make a circular filter for convolutional blurring. Before I used np.outer(values,values) which gave me a rectangular filter. David's hint allows me to create a circular filter very fast. See below:
square filter with np.outer()
circular filter with David's answer
You can use fancy indexing to achieve this:
values = np.ones(100)
x = np.arange(values.size)-values.size/2+0.5
y = values.size/2-0.5-np.arange(values.size)
x,y = np.meshgrid(x,y)
grid = np.rint(np.sqrt(x**2+y**2)).astype(np.int)
arr = np.zeros_like(grid)
size_half = values.size // 2
inside = (grid < size_half)
arr[inside] = values[grid[inside] + size_half]
Here, inside select the indices that lie inside the circle, since only these items can be derived from values.
You can do something like that:
x=y=np.arange(-500,501)
r=np.random.randint(0,256,len(x)/np.sqrt(2)+1)
X,Y=np.meshgrid(x,y)
im=(X*X+Y*Y)**(1/2)
circles=r.take(np.int64(im))
plt.imshow(circles)

Natgrid interpolation in Matplotlib producing Null Values

Everyone,
I am currently having some difficulty with the interpolation produced by griddata in matplotlib. I have a data set that contains 3 values per a data point. I am attempting to plot this data in a contour. The problem I am having is that the the built in delauny interpolation breaks on some data sets. So, I have tried to move over to the natgrid interpolatoin. This works for some data. However, other data sets it produces some null values in the output of griddata. I should also mention that these null values occur in an area where most values are the same (0 in this case).
Are there any suggestions as to what could cause this?
Edit: Here are some more details.
The source data is rather large and cannot be pasted in here. So, I used a pastebin to hold it. I hope this is allowed. That is available here: http://pastebin.com/C7Nvvcaw. This is formatted like x, y, z. So the first column is the x value and so on. This is the result for printing every item in the xyz list and piping it into a file.
The same applies for the post interpolation data. So, I have used a pastebin as well. Here it is: http://pastebin.com/ZB6S2qFk. Each [] corresponds with a particular y value. The y values are not included because they are in the separate lists. Though, they just range from 0-50 for the Y axis and 0-100 for the X axis. This is the output of printing every item in the zi list from my code and piping it into a file.
Now for the code, I have not attached all of the code because a large part of it is out of the scope of this question. So, I will post the relevant components. The initial data is in a list of lists providing the ability to navigate the data in 3 dimensions. I suppose this is similar to a 3 dimensional array, though it is not and just a list of lists. The source data's list is called xyz.
#Function to get individual column of data
def column(matrix, i):
return [row[i] for row in matrix]
#Getting Max and Mins
xmin = float(min(column(xyz, 0)))
xmax = float(max(column(xyz, 0)))
ymin = float(min(column(xyz, 1)))
ymax = float(max(column(xyz, 1)))
#Resolution for interpolation (x and y list lengths)
resx = 100
resy = 50
xi = np.linspace(xmin, xmax, resx)
yi = np.linspace(ymin, ymax, resy)
x = np.array(column(xyz, 0))
y = np.array(column(xyz, 1))
z = np.array(column(xyz, 2))
zi = griddata(x, y, z, xi, yi, interp='nn')
EDIT: I found a solution. The 0 values are breaking the interpolation. I was able to catch them and change them all to 0.1 and the interpolation no longer produces the null values. this is acceptable in my case because 0 and 0.1 fall under the same contour color. For other users if you need to retain absolute accuracy of the data, I would suggest transforming all the values by +1, interpolating, then transforming the interpolated values -1. This will retain the accuracy without breaking the interpolation method.
Thanks for any help,
Daniel

Categories

Resources