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)
Related
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
If I have a nxnxn grid of values, say 32x32x32, and I want to rotate this cube grid of values by some rotation angle in either the x, y, or z axes, and interpolate missing values, what would be the best way to go about doing this without using any existing algorithms from packages (such as Scipy)?
I'm familiar with applying a 3D rotation matrix to a 3D grid of points when it's represented as a [n, 3] matrix, but I'm not sure how to go about applying a rotation when the representation is given in its 3D form as nxnxn.
I found a prior Stack Overflow post about this topic, but it uses three for loops for its approach, which doesn't really scale in terms of speed. Is there a more vectorized approach that can accomplish a similar task?
Thanks in advance!
One way I could think of would look like this:
reshape nxnxn matrix to an array containing n-dimensional points
apply rotation on this array
reshape array back to nxnxn
Here is some code:
import numpy as np
#just a way to create some nxnxn matrix
n = 4
a = np.arange(n)
b = np.array([a]*n)
mat = np.array([b]*n)
#creating an array containg n-dimensional points
flat_mat = mat.reshape((int(mat.size/n),n))
#just a random matrix we will use as a rotation
rot = np.eye(n) + 2
#apply the rotation on each n-dimensional point
result = np.array([rot.dot(x) for x in flat_mat])
#return to original shape
result=result.reshape((n,n,n))
print(result)
I created a fits file. It is just a 2D array, I can visualize it using plt.imshow(fits.getdata(my_file)). Is there a way to turn it into a healpix map? If yes, please provide a detailed answer. If no, please explain why. Any help appreciated!
I am aware of healpy.fitsfunc.write_map(filename, m) but I struggle with using it (cannot set the m parameter) and do not know if this function is any help with my task
The hp.write_map function is only to write a pre-existing healpix map from memory into a fits file.
From your question, It is not clear what sort of data you have. But assuming that you have a 2d grid of data since you use imshow. You need to convert it to a healpix map before you use hp.write_map.
Depending on your coordinate system, you need to know the coordinates of each of the grid points, to convert the grid into healpix map.
To convert some data (scalar) into a healpix map, after finding the coordinates, You can write a function like this, which takes the coordinates and makes a healpix map for you.
def make_map_vec(theta, phi, data):
assert len(theta) == len(phi) == len(data)
e1map = np.full(hp.nside2npix(NSIDE), hp.UNSEEN, dtype=np.float)
index = hp.ang2pix(NSIDE, theta, phi)
values = np.fromiter((np.sum(data[index==i]) for i in np.unique(index)), float, count=len(np.unique(index)))
e1map[np.unique(index)] = values
return e1map
This link gives you the coordinate system used by healpix.
I have the same problem, I want to plot a 2d array in mollweide projection.
My 2d array is a 180*360 array, using matplotlib.pyplot. imshow the axis don't follow the projection:
so to resolve this problem I want to use mollview of healpy but I don't know to convert my 2d array Data(180*360) into an object that mollview could plot.
In the previous answer, you assume data is 1D array having same length as theta and phi. I tried to test it doing this :
test = np.ones((180,360))
data = test.reshape(180*360)
theta = []
phi = []
for i in range (360):
for j in range (180):
theta.append((j)*np.pi/180)
phi.append((i)*np.pi/180)
theta = np.asarray(theta)
phphi = np.asarray(y)
def make_map_vec(theta, phi, data):
assert len(theta) == len(phi) == len(data)
e1map = np.full(hp.nside2npix(NSIDE), hp.UNSEEN, dtype=np.float)
index = hp.ang2pix(NSIDE, theta, phi)
values = np.fromiter((np.sum(data[index==i]) for i in np.unique(index)), float, count=len(np.unique(index)))
e1map[np.unique(index)] = values
return e1map
map_test = make_map_vec(theta,phi,data)
hp.mollview(map_test,title="Mollview image RING")
I got :
which is not correct.
Do you know if there is any other way to get a map from a 2D array?
Consider a 3D numpy array D of dimension, say, (30 x 40 x 50). For each voxel D[x,y,z] I want to store a vector that contains neighboring voxels within a certain radius (including the D[x,y,z] itself).
(As an example here is a picture of such a sphere of radius 2: https://puu.sh/wwIYW/e3bd63ceae.png)
Is there a simple and fast way to code this?
I have written a function for it, but it is painfully slow and IDLE eventually crashes because the data structure I store the vectors in becomes too large.
Current code:
def searchlight(M_in):
radius = 4
[m,n,k] = M_in.shape
M_out = np.zeros([m,n,k],dtype=object)
count = 0
for i in range(m):
for j in range(n):
for z in range(k):
i_interval = list(range((i-4),(i+5)))
j_interval = list(range((j-4),(j+5)))
z_interval = list(range((z-4),(z+5)))
coordinates = list(itertools.product(i_interval,j_interval,z_interval))
coordinates = [pair for pair in coordinates if ((abs(pair[0]-i)+abs(pair[1]-j)+abs(pair[2]-z))<=radius)]
coordinates = [pair for pair in coordinates if ((pair[0]>=0) and (pair[1]>=0) and pair[2]>=0) and (pair[0]<m) and (pair[1]<n) and (pair[2]<k)]
out = []
for pair in coordinates:
out.append(M_in[pair[0],pair[1],pair[2]])
M_out[i,j,z] = out
count = count +1
return M_out
Here a way to do that. For efficiency, you need therefore to use ndarrays : This only take in account complete voxels. Edges must be managed "by hand".
from pylab import *
a=rand(100,100,100) # the data
r=4
ra=range(-r,r+1)
sphere=array([[x,y,z] for x in ra for y in ra for z in ra if np.abs((x,y,z)).sum()<=r])
# the unit "sphere"
indcenters=array(meshgrid(*(range(r,n-r) for n in a.shape),indexing='ij'))
# indexes of the centers of the voxels. edges are cut.
all_inds=(indcenters[newaxis].T+sphere.T).T
#all the indexes.
voxels=np.stack([a[tuple(inds)] for inds in all_inds],-1)
# the voxels.
#voxels.shape is (92, 92, 92, 129)
All the costly operations are vectorized. Comprehension lists are prefered for clarity in external loop.
You can now perform vectorized operations on voxels. for exemple the brightest voxel :
light=voxels.sum(-1)
print(np.unravel_index(light.argmax(),light.shape))
#(33,72,64)
All of this is of course extensive in memory. you must split your space for
big data or voxels.
Since you say the data structure is too large, you'll likely have to compute the vector on the fly for a given voxel. You can do this pretty quickly though:
class SearchLight(object):
def __init__(self, M_in, radius):
self.M_in = M_in
m, n, k = self.M_in.shape
# compute the sphere coordinates centered at (0,0,0)
# just like in your sample code
i_interval = list(range(-radius,radius+1))
j_interval = list(range(-radius,radius+1))
z_interval = list(range(-radius,radius+1))
coordinates = list(itertools.product(i_interval,j_interval,z_interval))
coordinates = [pair for pair in coordinates if ((abs(pair[0])+abs(pair[1])+abs(pair[2]))<=radius)]
# store those indices as a template
self.sphere_indices = np.array(coordinates)
def get_vector(self, i, j, k):
# offset sphere coordinates by the requested centre.
coordinates = self.sphere_indices + [i,j,k]
# filter out of bounds coordinates
coordinates = coordinates[(coordinates >= 0).all(1)]
coordinates = coordinates[(coordinates < self.M_in.shape).all(1)]
# use those coordinates to index the initial array.
return self.M_in[coordinates[:,0], coordinates[:,1], coordinates[:,2]]
To use the object on a given array you can simply do:
sl = SearchLight(M_in, 4)
# get vector of values for voxel i,j,k
vector = sl.get_vector(i,j,k)
This should give you the same vector you would get from
M_out[i,j,k]
in your sample code, without storing all the results at once in memory.
This can also probably be further optimized, particularly in terms of the coordinate filtering, but it may not be necessary. Hope that helps.
As the title suggests, how would one create a numpy array of 3D coordinates of a geometric shape?
Currently, I have the easiest shape already figured out:
latva = 6
latvb = 6
latvc = 6
latdiv = 20
latvadiv = latva / latdiv
latvbdiv = latvb / latdiv
latvcdiv = latvc / latdiv
lol = np.zeros((latdiv**3,4),dtype=np.float64)
lol[:,:3] = (np.arange(latdiv**3)[:,None]//(latdiv**2,latdiv,1)*(latvadiv,latvbdiv,latvcdiv)%(latva,latvb,latvc))
creates an array of (8000,4). If you then split the array along the 1,2,3 column (Ignoring the 4th as it's meaningless in this question) and plot it (Personally, I use pyplot) you get a Cube!
Easy enough. Also works for a rectangle.
But I've not the foggiest idea of how to get any further - say plotting a rhombus.
I'm not interested in black magic like spheres, ovals or shapes whose sides do not change following a line. Just things like your standard rhombus/Rhomboid/Parallelepiped/Whatever_you_want_to_call_it.
Any ideas on how to accomplish this?
Because you already have convenient method to generate points in square or cube, the simplest way to make rhombus, parallelogram for 2D case and parallelepiped for 3D case is to apply affine transform to calculate new point coordinates.
For example, to make rhombus, you can find matrix as combination of translation by (-centerX, -centerY), rotation by Pi/4, scaling along axes (if needed) and translation to needed position.
AffMatrix = ShiftMatrix * RotateMatrix * ScaleMatrix * BackShiftMatrix
for each point coordinates:
(NewX, NewY) = (AffMatrix) * (X, Y)
Rhomboid will include also shear transform.
I think that numpy has ready-to-use routines to create and combine (multiply) affine matrices.