Split numpy array into similar array based on its content - python

I have a 2D numpy array that represents the coordinates (x, y) of a curve, and I want to split that curve into parts of the same length, obtaining the coordinates of the division points.
The most easy example is a line defined for two points, for example [[0,0],[1,1]], and if I want to split it in two parts the result would be [0.5,0.5], and for three parts [[0.33,0.33],[0.67,0.67]] and so on.
How can I do that in a large array where the data is less simple? I'm trying to split the array by its length but the results aren't good.

If I understand well, what you want is a simple interpolation. For that, you can use scipy.interpolate (http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html):
from scipy.interpolate import interp1d
f = interp1d(x, y) ## for linear interpolation
f2 = interp1d(x, y, kind='cubic') ## for cubic interpolation
xnew = np.linspace(x.min(), x.max(), num=41, endpoint=False)
ynew = f(xnew) ## or f2(xnew) for cubic interpolation
You can create a function that returns the coordinates of the split points, given x, y and the number of desired points:
def split_curve(x, y, npts):
from scipy.interpolate import interp1d
f = interp1d(x, y)
xnew = np.linspace(x.min(), x.max(), num=npts, endpoint=False)
ynew = f(xnew)
return zip(xnew[1:], ynew[1:])
For example,
split_curve(np.array([0, 1]), np.array([0, 1]), 2) ## returns [(0.5, 0.5)]
split_curve(np.array([0, 1]), np.array([0, 1]), 3) ## [(0.33333333333333331, 0.33333333333333331), (0.66666666666666663, 0.66666666666666663)]
Note that x and y are numpy arrays and not lists.

take the length of the line on every axes, the split as you want.
example:
point 1: [0,0]
point 2: [1,1]
then:
length of the line on X axes: 1-0 = 1
also in the Y axes.
now, if you want to split it in two, just divide these lengths, and create a new array.
[0,0],[.5,.5],[1,1]

Related

Evenly sampled 3D meshgrid

I have a 3-dimensional meshgrid generated using the following code:
x = np.linspace(-1,1,100)
xx, yy, zz = np.meshgrid(x, x, x)
This generates a 100 x 100 x 100 point 3-d grid of points. I would like to plot an evenly-space sub-sampling of this same grid, without having to generate a new grid. My approach to this was to use np.linspace() to get an array of 10000 evenly-space indices from the original array to plot xx[subsample], yy[subsample], and zz[subsample]. I used
subsample = np.linspace(0,len(xx.flatten())-1,10000,dtype=int)
However, when I pass this array my plotting function, I get uneven structure (diagonal lines) in 3-dimensions:
My guess is that this is happening because I flattened the array, and then used np.linspace(), but I can't figure out how to sample the grid in 3-dimensions and have it come out evenly distributed. I would like to avoid generating a new meshgrid if at all possible.
My question is how would I evenly subsample my original 3-dimensional meshgrid, without having to generate a new meshgrid?
In [117]: x = np.linspace(-1,1,100)
...: xx, yy, zz = np.meshgrid(x, x, x)
In [118]: xx.shape
Out[118]: (100, 100, 100)
1000 equally spaced points in xx, similarly for all other grids:
In [119]: xx[::10,::10,::10].shape
Out[119]: (10, 10, 10)
Or with advanced indexing (making a copy)
In [123]: i=np.arange(0,100,10)
In [124]: xx[np.ix_(i,i,i)].shape
Out[124]: (10, 10, 10)
I think we could use np.ravel_multi_index to get an array of flattened indices. We'd have to generate 1000 tuples of indices to do that!
I don't see how we could get a 10,000 points. ::5 would give 8000 points.
Have you trying using arange? Using linspace for integers may have some rounding issues.
Could you try the following?
subsample = np.arange(0, xx.size, xx.size // 10000) # the last parameter is the step size
Also, be sure that xx.size is divisible by 10000, which is the case for your 100x100x100.
Tip: use .size to get the number of elements in an array. Use .ravel instead of .flatten as the latter creates a copy but ravel is just a view.
Edit: That subsample did not generate those diagonals but it just got a plane.
subsample_axis = [np.arange(0, xx.shape[i], 10) for i in range(len(xx.shape))]
subsample = np.zeros([len(axis) for axis in subsample_axis])
for i, axis in enumerate(subsample_axis):
shape = [len(axis) if j == i else 1 for j in range(len(xx.shape))]
subsample += axis.reshape(shape)*np.prod(xx.shape[i+1:])
subsample = subsample.ravel().astype('int')

How to efficiently interpolate a 3D array on a finer, uniformed-spacing grid?

I have a 3D array and want to interpolate it into a finer resolution grid. The 3D array is defined on a regular grid with even spacing. The interpolation is also on a regular grid with even spacing. The step size is 2^(-n), n=0,1,2,3 .... Interpolation should be either linear or higher order Bspline. For example, a 3D array a has sizes of (3,3,5) and the step size of the interpolation grid is (0.5, 0.5, 0.5)(n=1). Then the interpolation grid is defined as
x=np.linspace(0,2,num=5) # 3/0.5-1 = 5
y=np.linspace(0,2,num=5) # 3/0.5-1 = 5
z=np.linspace(0,4,num=9) # 5/0.5-1 = 9
xx, yy, zz = np.meshgrid(x, y, z, sparse=True)
Then the output array should have sizes of (5,5,9). Which interpolation function in scipy or numpy can do the job in a most efficient way?
I have found zoom is the most efficient function to do it. Check it out: https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.zoom.html

Creating a 2D array using values of coordinate points on a grid

Suppose I have a coordinate grid with a few points(masses) sprinkled in the grid. I can create this using:
import numpy as np
import matplotlib.pyplot as plt
points = np.array([[0,1],[2,1],[3,5]]) # array containing the coordinates of masses(points) in the form [x,y]
x1, y1 = zip(*points)
Now, I can plot using :
plt.plot(x1,y1,'.')
Now, say I create a 2D meshgrid using:
x = np.linspace(-10,10,10)
y = np.linspace(-10,10,10)
X,Y = np.meshgrid(x,y)
Now, what I want to do is to create a 2D array 'Z',(a map of the masses)that contains masses at the locations that are in the array points. When I mean masses, I just mean a scalar at those points. So I could do something like plt.contourf(X,Y,Z). The problem I'm having is that the indices for Z cannot be the same as the coordinates in points. There has to be some sort of conversion which I'm not able to figure out. Another way to look at it is I want:
Z[X,Y] = 1
I want Z to have 1's at locations which are specified by the array points. So the essence of the problem is how do I calculate the X and Y indices such that they correspond to x1, y1 in real coordinates.
For example, if I simply do Z[x1(i),y1(i)] = 1, contourf gives this:
Instead I want the spikes to be at (0,1),(2,1),(3,5).
To have 1 at the coordinates specified by x1, y1 and zeros everywhere else, I would write it like this:
x = np.linspace(-10, 10, 21)
y = np.linspace(-10, 10, 21)
Z = np.zeros((len(y), len(x)))
for i in range(len(x1)):
Z[10 + y1[i], 10 + x1[i]] = 1
Then you should be able to write plt.contourf(x, y, Z).
Tell me if that gives you the desired result.

Embedding the plane into 3d space for a matplotlib plot

I have a pair of 3d vectors u and v. I have another function f mapping 3d space onto real numbers (so, a scalar field). I want to draw a 2d plot f(xu + yv) using a colormap. So I need to end up with a matrix z filled with values of f, so I can go
pyplot.imshow(z)
But how can I do this? I tried
x = numpy.linspace(0, s2, 500)
y = numpy.linspace(0, 1, 500)
xs, ys = numpy.meshgrid(x, y)
z = f(u*xs + v*ys) # Not actually valid
Hoping that u*xs + v*ys would produce a matrix of 3d vectors, but that doesn't work. Also, even if I can get a matrix A of 3d vectors, what's the best way to get the matrix obtained by applying f to each element?

Python array values differ from defined function

I have defined and function and calling it to store the computed values in an array. However the values in array are different than what they should be. I have plotted both the output of the function and stored array values. Can anyone help me resolve this issue. Here is the code and the output.
from numpy import linspace, exp
import matplotlib.pyplot as pl
def gaussian(x, off, amp, cen, wid):
return off+amp * exp(-(x-cen)**2 /wid**2)
PhaseArray = [0 for x in range (100)]
for x in range(100):
PhaseArray[x] = gaussian(x, 0, 1000, 50, 15)
x = linspace(0,99,100)
fig = pl.figure()
pl.plot(PhaseArray, 'go-')
pl.plot(x, gaussian(x, 0, 1000, 50, 15), 'ro-')
pl.show()
The output plot looks like
linspace provides a vector of float numbers that go to gaussian as a vector and are processed according to numpy operators over vectors. On the other hand, to fill PhaseArray you feed gaussian by integer x that is processed in a different way. It explains the difference.

Categories