Mean position of a function defined by xyz points - python

I have an irregular 2D mesh and I have a list of the values of each cell, and its corresponding x, y coordinates (for the cell centre). I would like to find the mean position of the function.
In one dimension I do
x = numpy.array([0, 0.5, 1])
z = numpy.array([0, 1, 0])
scipy.integrate.simps(x * z, x)
but in two dimensions this isn't possible because x and y are not evenly spaced.
The function would return (0, 0) for this mesh:
that has these z values:
SOLUTION:
this is just a centre of mass problem so you can just do
x = 1/sum(masses) * sum(mass_at_x * x)

This is just a centre of mass problem so you can just do
x = 1/sum(masses) * sum(mass_at_x * x)

Related

How to scatter randomly points on a sphere

using PyPlot
n = 50
u = range(0,stop=2*π,length=n);
v = range(0,stop=π,length=n);
x = cos.(u) * sin.(v)';
y = sin.(u) * sin.(v)';
z = ones(n) * cos.(v)';
scatter3D(vec(x),vec(y),vec(z);c="red",s=1)
However, if I multiply vec(x), vec(y), vec(z) with rand() ,
I still get the same plot with the only difference being that the axis change or in other words that the sphere gets "squished".
using PyPlot
n = 50
u = range(0,stop=2*π,length=n);
v = range(0,stop=π,length=n);
x = cos.(u) * sin.(v)';
y = sin.(u) * sin.(v)';
z = ones(n) * cos.(v)';
scatter3D(rand()*vec(x),rand()*vec(y),rand()*vec(z);c="red",s=1)
The simplest approach seems to be sampling a Gaussian for each dimension and then normalizing the length of the resulting vector as described in this answer. There's a very slight possibility of getting a vector with zero length, which can be handled with rejection sampling. Putting that together you would do this:
points = map(1:n) do _
while true
x = randn()
y = randn()
z = randn()
l = hypot(x, y, z)
l ≠ 0 && return (x, y, z) ./ l
end
end
This gives a vector of 3-tuples each representing x, y and z coordinates of points, which you can plot as before. Separate vectors of coordinates can be extracted using comprehensions:
xs = [p[1] for p in points]
ys = [p[2] for p in points]
zs = [p[3] for p in points]
This approach can readily be generalized to any number of dimensions.

Transpose 3D coordinates on a plane to a new 2D coordinate system

I have been working on a personal project to produce an image of the integer solutions to the equation x^2 + y^2 + z^2 = S where 'S' is any integer.
In other words, I am looking for all the 3D points [x,y,z] where x, y, and z are all perfect square integers and x + y + z = S
For example, S = 2809 will have solutions:
[144, 1296, 1369],
[144, 729, 1936],
[0, 0, 2809]
... plus all permutations of the above (i.e. 144+729+1936 = 1936+729+144)
Before I get to my question, here is a small tangent for some context:
All of the solutions to the general equation x + y + z = S will lie on a 2D plane defined by:
A = [S, 0, 0]
B = [0, S, 0]
C = [0, 0, S]
Here is a graph of all solutions (not just square points) to x + y + z = 50 to illustrate that all of the solutions to this equation will lie on the same plane bounded by ABC defined above. Notice that the tips of the triangle below are: [50, 0, 0], [0, 50, 0], and [0, 0, 50]
Back to my question:
After finding the square solution points, I want to transpose the 3D solution points into 2D coordinates based on the ABC plane with A as (0,0), B is the max 'x' value, and C is the max 'y' value. I then hope to output these solutions to an image file.
My linear algebra knowledge is sparse, and I have been unable to find a method to transpose 3D coordinates into 2D plane coordinates based on 3 non-colinear points.
My code is currently in python, but an algorithmic/mathematical answer is just as good!
Any help is much appreciated!
As I see it, you can already find your (x, y, z) points, and your question is about a way to project them onto a plane.
Please refer to projection matrix to learn how to project the 3d world onto an image plane of your choosing.
Specifically, you will have to express your (x, y, z) coordinates as homogeneous coordinates by refering to them as (x, y, z, 1), and to multiply them by a relevant camera matrix which is orthogonal to the plane on which you need to cast them.
This will yield 2d homogeneous coordinates of the form (x', y', f) from which you will be able to obtain the projected coordinates by (x_projected, y_projected) = (x'/f, y'/f).
OpenCV is your friend.
Recap:
Input: n (x, y, z) points
Obtain projection (camera) matrix M of size (4, 3) using opencv or calculate yourself using whatever tools.
Add last dimension 1 to all points to get them as 3d homogeneous coordinates: n points (x, y, z, 1)
Multiply all points by the matrix to obtain projected points as 2d homogeneous coordinates: M * (x, y, z, 1)^T = (x', y', f)
Get n actual 2d projected coordinates (relative to camera center as defined by the M matrix) by (x, y) = (x'/f, y'/f)
Bonus: you can stack all your (x, y, z, 1) points as columns into a (4, n) matrix, P, and the entire multiplication process will be R = M * P, a result matrix R of shape (3, n) whose columns are the resulting homogeneous coordinates.
I think Gulzar's answer is correct, but more centered around rendering (i.e. camera and homogenous coordinates). I did however figure out how to do what I wanted.
import ast
import math
import matplotlib.pyplot as plt
def dot_3d(a, b):
return (a[0]*b[0])+ (a[1]*b[1]) + (a[2]*b[2])
def minus_3d(a, b):
return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]
def midpoint_3d(a, b):
return [(a[0] + b[0])/2, (a[1] + b[1])/2, (a[2] + b[2])/2]
def normalize_3d(vec):
magnitude = math.sqrt(vec[0]**2 + vec[1]**2 + vec[2]**2)
return [vec[0]/magnitude, vec[1]/magnitude, vec[2]/magnitude]
X = 2809
A = [X, 0, 0]
B = [0, X, 0]
C = [0, 0, X]
S = set([])
for a in range(X+1):
if int(math.sqrt(a))**2 == a:
for b in range(X+1):
if int(math.sqrt(b))**2 == b:
for c in range(X+1):
if int(math.sqrt(c))**2 == c and a + b + c == X:
S.add(str([a, b, c]))
S = list(S)
origin = A
normal = normalize_3d([X/3, X/3, X/3])
ax1 = normalize_3d(minus_3d(B, A))
ax2 = normalize_3d(minus_3d(C, midpoint_3d(A, B)))
answers = []
for point_str in S:
point = ast.literal_eval(point_str)
x = dot_3d(ax1, minus_3d(point, origin))
y = dot_3d(ax2, minus_3d(point, origin))
answers.append([x, y])
plt.scatter([p[0] for p in answers], [p[1] for p in answers])
plt.xlabel('x')
plt.ylabel('y')
plt.show()
Starting 3D coordinates graphed:
"projected" coordinates on the ABC plane:

Is there a quick method to project points onto an certain grid?

I am now trying to project n points with 3 dimensional coordinates (x,y,z) onto a xy-grid with a certain size (like 64*64), of course the coordinate of such n points is restricted in this grid.
The goal is to print z coordinate of points which are projected onto each of grid elements. I write two for-loops, but is there any better method to avoid using for-loop to run it more quickly?
for i in range(XY_grid.shape[0]):
x = np.where((X_coordinate > i) & (X_coordinate <= i + 1), 1, 0)
for j in range(XY_grid.shape[1]):
y = np.where(( Y_coordinate > j) & (Y_coordinate <= j + 1), 1, 0)
print(x * y * Z_coordinate)
I think what you want is a 2D histogram:
import numpy as np
# generate some data (x, y, z)
x = np.arange(100)
y = np.random.rand(100)
z = np.arange(100)[::-1] * 1.5
# grid (x, y) onto a defined grid (0-127) in x and y
grid, xe, ye = np.histogram2d(x, y, bins=(np.arange(128), np.arange(128)), weights=None)
grid.sum()
>>> 100.0 # all data is in the grid (was only 100 points)
You can use the weight argument to add z values:
# grid (x, y) onto a defined grid (0-127) in x and y
grid, xe, ye = np.histogram2d(x, y, bins=(np.arange(128), np.arange(128)), weights=z)
grid.sum()
>>> 7425.0
z.sum()
>>> 7425.0 # all z values are in the produced grid
You can change the bins widths etc. to make them nonuniform, or keep them evenly spaced for a regular grid.
The resulting grid is a 2D numpy array which contains all of the z information that falls into each bin. You can easily just print it or loop over it to get every element in turn.
To print all the entries of Z_coordinate that coorespond to a specific point in X_coordinate and Y_coordinate you can do:
for i in range(XY_grid.shape[0]):
for j in range(XY_grid.shape[1]):
print(Z_coordinate[np.logical_and(X_coordinate==i, Y_coordinate==j)])

How to make a function that outputs an array with a predefined size?

I want to make a function that outputs an array of predefined size. The function is dependent on variables x, y, rx, and ry, and d. Variables x and y are directly related to the cartesian values. rx and ry are the radius of the blobs generated from the function.
I have already converted array indiies from the traditional 0, 0 on the upper left corner to the middle most pixel. This array should always be odd in herms of length and width.
The blob below gives me one array at a time. I need a stack of arrays I can add together. When I change x and y, the size of the array changes, but I need the array to be the same size or zeroed out at on the borders.
I have some code that follows:
def equation(x, y):
return 1 * np.exp(-(x**2 + y**2))
def make_matrix(xs, ys, x_min=nxs, y_min=nys): #makes cartesian values
out = [] #outputs array
for i in range(x_min, xs - center_x):
row = []
for j in range(y_min, ys - center_y):
row.append(equation(i, j))
out.append(row)
return out
blob = np.asarray(list(np.float_(make_matrix(x, y))))
Vectorization is your friend here. No need to compute lists element-by element when your function can be evaluated element-wise for an entire array.
def make_matrix(xs, ys, x_min=nxs, y_min=nys):
x = np.arange(x_min, xs - center_x).reshape(1, -1)
y = np.arange(y_min, ys - center_y).reshape(-1, 1)
out = np.exp(-(x**2 + y**2))
return out
The reshape operations create a 1xN row vector for x and a Nx1 column vector for y. These shapes ensure that broadcasting in the add (+) operation expands x**2 + y**2 to an array of the final size you want.

numpy's interp function - how to find a value of x for a given value of y?

So I have an array of values of x (in increasing order) and the corresponding y values. Numpy's interp function takes in the X value, and the x and y arrays. How do I get the value of X for a given value of Y?? Eg if y = 0, x = ?.
Cheers!
code:
j = (((1840/(2*pi))**0.5)*exp(phi)) - 1.0 #y axis, phi is a 1-D array
t = linspace(0, 40, 100) #x axis
a = interp(<x-value>,t,j) # this gives me the corresponding y value!
So what should I do to get the x value for a given y value!!
y_interp = np.interp(x_interp, x, y) yields an interpolation of the function y_interp = f(x_interp) based on a previous interpolation y = f(x), where x.size = y.size, x_interp.size = y_interp.size.
If you want x as a function of y, you have to construct the inverse function. As #NPE indicated, you have to make sure that x and y are always increasing. An easy way to check this is to use
np.all(np.diff(x) > 0)
np.all(np.diff(y) > 0)
Now finding the inverse function is actually very simple: you have to reverse the roles of x and y (since we deal with interpolations).
With my notations: x_value = np.interp(y_value, x, y).
With your notations: x_value = interp(y_value, j, t)
When using Numpy make sure you're using a Numpy array: np.array([])
#x data array
x_data = np.array([1,2,3,4])
#y data array
y_data = np.array([1,3,2,1])
#the known max y value is 3
y_max = 3
# sort the arrays
order = y_data.argsort()
y_data = y_data[order]
x_data = x_data[order]
# call the interpolation function but reverse the array datasets to find the corresponding x value
x = np.interp(y_max, y_data, x_data, left=None, right=None, period=None)
For this example the result is x = 2 when max y = 3. The maximum is (2,3).
Furthermore you can append data to a numpy array: x_data = np.append(x_data, appendedValue)

Categories

Resources