Use quiver to plot a 2D vector map - python

I have a set of coordinate pairs (x, y) and I want to plot this set using quiver. I tried to check other relevant questions but I'm still struggling with this.
Imagine I want to plot 4 vectors with two arrays with x and y coordinates:
x = arange(0, 3)
y = arange(0, 3)
# vectors x coordinate values
fx = (0, 1, 1, 2)
# vectors y coordinate values
fy = (1, 0, 1, 2)
X, Y = meshgrid(x, y)
Q = quiver(X, Y, fx, fy)
The result is not 4 but 9 vectors, why?

You can pass four 1-D arrays to plt.quiver:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 4)
y = np.arange(0, 4)
# vectors x coordinate values
fx = (0, 1, 1, 2)
# vectors y coordinate values
fy = (1, 0, 1, 2)
Q = plt.quiver(x, y, fx, fy)
plt.xlim(-1, 4)
plt.ylim(-1, 4)
plt.show()
yields

Related

Generate 2D Gaussian with Python

How would i generate 1000 2D samples for a Gaussian with mu = (2,0), and sigma = [[1,0],[0,1]]? This is my code below so far:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
# Our 2-dimensional distribution will be over variables X and Y
N = 40
X = np.linspace(-2, 2, N)
Y = np.linspace(-2, 2, N)
X, Y = np.meshgrid(X, Y)
# Mean vector and covariance matrix
mu = np.array([2, 0])
Sigma = np.array([[ 1 , 0], [0, 1]])
# Pack X and Y into a single 3-dimensional array
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y
def multivariate_gaussian(pos, mu, Sigma):
"""Return the multivariate Gaussian distribution on array pos."""
n = mu.shape[0]
Sigma_det = np.linalg.det(Sigma)
Sigma_inv = np.linalg.inv(Sigma)
N = np.sqrt((2*np.pi)**n * Sigma_det)
# This einsum call calculates (x-mu)T.Sigma-1.(x-mu) in a vectorized
# way across all the input variables.
fac = np.einsum('...k,kl,...l->...', pos-mu, Sigma_inv, pos-mu)
return np.exp(-fac / 2) / N
# The distribution on the variables X, Y packed into pos.
Z = multivariate_gaussian(pos, mu, Sigma)
Does this look correct? How can I better this code?

rotate a set of 3d coordinates in python

I have a set of 3d coordinates of a molecule and a vector passing through its center of mass. I want to rotate the molecule coordinates and the vector to make the vector align with z-axis.
I used a script in the link below to calculate the rotation matrix from the vector to z-axis, then apply the same rotation matrix to the other 3d coordinates:
Calculate rotation matrix to align two vectors in 3D space?
But this method makes my molecule "flat" (in magentas the molecule before rotation and in yellow after rotation):
Front view of molecule and Side view of molecule
Does anyone know why this method doesn't work? Is it mathematically correct? Thank you!
The method in this answer of the question you linked to seems correct to me, and produces one rotation matrix (from the infinite set of rotation matrices that will align vec1 to vec2):
def rotation_matrix_from_vectors(vec1, vec2):
""" Find the rotation matrix that aligns vec1 to vec2
:param vec1: A 3d "source" vector
:param vec2: A 3d "destination" vector
:return mat: A transform matrix (3x3) which when applied to vec1, aligns it with vec2.
"""
a, b = (vec1 / np.linalg.norm(vec1)).reshape(3), (vec2 / np.linalg.norm(vec2)).reshape(3)
v = np.cross(a, b)
c = np.dot(a, b)
s = np.linalg.norm(v)
kmat = np.array([[0, -v[2], v[1]], [v[2], 0, -v[0]], [-v[1], v[0], 0]])
rotation_matrix = np.eye(3) + kmat + kmat.dot(kmat) * ((1 - c) / (s ** 2))
return rotation_matrix
That rotation matrix is orthonormal, as it should be.
Perhaps (aka, wild guess) what's happening with your data is that the various axes have considerably different variance (perhaps different units?) In this case, you should first normalize your data before rotation. For example, say your original data is an array x with x.shape == (n, 3) and your vector is v with shape (3,):
u, s = x.mean(0), x.std(0)
x2 = (x - u) / s
v2 = (v - u) / s
Now, try to apply your rotation on x2, aligning v2 to [0,0,1].
Here is a toy example for illustration:
n = 100
x = np.c_[
np.random.normal(0, 100, n),
np.random.normal(0, 1, n),
np.random.normal(4, 3, n),
]
v = np.array([1,2,3])
x = np.r_[x, v[None, :]] # adding v into x so we can visualize it easily
Without normalization
A = rotation_matrix_from_vectors(np.array(v), np.array((0,0,1)))
y = x # A.T
fig, axes = plt.subplots(nrows=2, ncols=2)
for ax, (a, b) in zip(np.ravel(axes), combinations(range(3), 2)):
ax.plot(y[:, a], y[:, b], '.')
ax.plot(y[-1, a], y[-1, b], 'ro')
ax.set_xlabel(a)
ax.set_ylabel(b)
axes[1][1].set_visible(False)
With prior normalization
u, s = x.mean(0), x.std(0)
x2 = (x - u) / s
v2 = (v - u) / s
A = rotation_matrix_from_vectors(np.array(v2), np.array((0,0,1)))
y = x2 # A.T
fig, axes = plt.subplots(nrows=2, ncols=2)
for ax, (a, b) in zip(np.ravel(axes), combinations(range(3), 2)):
ax.plot(y[:, a], y[:, b], '.')
ax.plot(y[-1, a], y[-1, b], 'ro')
ax.set_xlabel(a)
ax.set_ylabel(b)
axes[1][1].set_visible(False)

Get all lattice points lying inside a Shapely polygon

I need to find all the lattice points inside and on a polygon.
Input:
from shapely.geometry import Polygon, mapping
sh_polygon = Polygon(((0,0), (2,0), (2,2), (0,2)))
Output:
(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1), (0, 2), (1, 2), (2, 2)
Please suggest if there is a way to get the expected result with or without using Shapely.
I have written this piece of code that gives points inside the polygon, but it doesn't give points on it. Also is there a better way to do the same thing:
from shapely.geometry import Polygon, Point
def get_random_point_in_polygon(poly):
(minx, miny, maxx, maxy) = poly.bounds
minx = int(minx)
miny = int(miny)
maxx = int(maxx)
maxy = int(maxy)
print("poly.bounds:", poly.bounds)
a = []
for x in range(minx, maxx+1):
for y in range(miny, maxy+1):
p = Point(x, y)
if poly.contains(p):
a.append([x, y])
return a
p = Polygon([(0,0), (2,0), (2,2), (0,2)])
point_in_poly = get_random_point_in_polygon(p)
print(len(point_in_poly))
print(point_in_poly)
Output:
poly.bounds: (0.0, 0.0, 2.0, 2.0)
1
[[1, 1]]
I have simplified my problem. Actually, I need to find all points inside and on a square with corners: (77,97), (141,101), (136,165), (73,160).
I would approach the problem as follows.
First, define a grid of lattice points. One could use, for example, itertools.product:
from itertools import product
from shapely.geometry import MultiPoint
points = MultiPoint(list(product(range(5), repeat=2)))
points = MultiPoint(list(product(range(10), range(5))))
or any NumPy solution from Cartesian product of x and y array points into single array of 2D points:
import numpy as np
x = np.linspace(0, 1, 5)
y = np.linspace(0, 1, 10)
points = MultiPoint(np.transpose([np.tile(x, len(y)), np.repeat(y, len(x))]))
Then, using intersection method of Shapely we can get those lattice points that lie both inside and on the boundary of the given polygon.
For your given example:
p = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
xmin, ymin, xmax, ymax = p.bounds
x = np.arange(np.floor(xmin), np.ceil(xmax) + 1) # array([0., 1., 2.])
y = np.arange(np.floor(ymin), np.ceil(ymax) + 1) # array([0., 1., 2.])
points = MultiPoint(np.transpose([np.tile(x, len(y)), np.repeat(y, len(x))]))
result = points.intersection(p)
And for a bit more sophisticated example:
p = Polygon([(-4.85571368308564, 37.1753007358263),
(-4.85520937147867, 37.174925051829),
(-4.85259349198842, 37.1783463712614),
(-4.85258684662671, 37.1799609243756),
(-4.85347524651836, 37.1804461589773),
(-4.85343407576431, 37.182006629169),
(-4.85516283166052, 37.1842384372115),
(-4.85624511894443, 37.1837967179202),
(-4.85533824429553, 37.1783762575331),
(-4.85674599573635, 37.177038261295),
(-4.85571368308564, 37.1753007358263)])
xmin, ymin, xmax, ymax = p.bounds # -4.85674599573635, 37.174925051829, -4.85258684662671, 37.1842384372115
n = 1e3
x = np.arange(np.floor(xmin * n) / n, np.ceil(xmax * n) / n, 1 / n) # array([-4.857, -4.856, -4.855, -4.854, -4.853])
y = np.arange(np.floor(ymin * n) / n, np.ceil(ymax * n) / n, 1 / n) # array([37.174, 37.175, 37.176, 37.177, 37.178, 37.179, 37.18 , 37.181, 37.182, 37.183, 37.184, 37.185])
points = MultiPoint(np.transpose([np.tile(x, len(y)), np.repeat(y, len(x))]))
result = points.intersection(p)
Is there not a function that will find lattice points that lie on a line? Those are the only ones you're missing. They are simply solutions to the line segment's defining equation. If not, it's easy enough to write the algorithm yourself, finding the points by brute force.
Do the following for each edge (p1, p2) of the polygon.
p1 = (x1, y1)
p2 = (x2, y2)
xdiff = x2 - x1
ydiff = y2 - y1
# Find the line's equation, y = mx + b
m = ydiff / xdiff
b = y1 - m*x1
for xval in range(x1+1, x2):
yval = m * xval + b
if int(yval) == yval:
# add (xval, yval) to your list of points
I've left details up to you: make sure that x1 < x2 (or adapt otherwise), handle a vertical segment, etc. This isn't particularly elegant, but it's fast, easy to implement, and easy to debug.

Equivalent of `polyfit` for a 2D polynomial in Python

I'd like to find a least-squares solution for the a coefficients in
z = (a0 + a1*x + a2*y + a3*x**2 + a4*x**2*y + a5*x**2*y**2 + a6*y**2 +
a7*x*y**2 + a8*x*y)
given arrays x, y, and z of length 20. Basically I'm looking for the equivalent of numpy.polyfit but for a 2D polynomial.
This question is similar, but the solution is provided via MATLAB.
Here is an example showing how you can use numpy.linalg.lstsq for this task:
import numpy as np
x = np.linspace(0, 1, 20)
y = np.linspace(0, 1, 20)
X, Y = np.meshgrid(x, y, copy=False)
Z = X**2 + Y**2 + np.random.rand(*X.shape)*0.01
X = X.flatten()
Y = Y.flatten()
A = np.array([X*0+1, X, Y, X**2, X**2*Y, X**2*Y**2, Y**2, X*Y**2, X*Y]).T
B = Z.flatten()
coeff, r, rank, s = np.linalg.lstsq(A, B)
the adjusting coefficients coeff are:
array([ 0.00423365, 0.00224748, 0.00193344, 0.9982576 , -0.00594063,
0.00834339, 0.99803901, -0.00536561, 0.00286598])
Note that coeff[3] and coeff[6] respectively correspond to X**2 and Y**2, and they are close to 1. because the example data was created with Z = X**2 + Y**2 + small_random_component.
Based on the answers from #Saullo and #Francisco I have made a function which I have found helpful:
def polyfit2d(x, y, z, kx=3, ky=3, order=None):
'''
Two dimensional polynomial fitting by least squares.
Fits the functional form f(x,y) = z.
Notes
-----
Resultant fit can be plotted with:
np.polynomial.polynomial.polygrid2d(x, y, soln.reshape((kx+1, ky+1)))
Parameters
----------
x, y: array-like, 1d
x and y coordinates.
z: np.ndarray, 2d
Surface to fit.
kx, ky: int, default is 3
Polynomial order in x and y, respectively.
order: int or None, default is None
If None, all coefficients up to maxiumum kx, ky, ie. up to and including x^kx*y^ky, are considered.
If int, coefficients up to a maximum of kx+ky <= order are considered.
Returns
-------
Return paramters from np.linalg.lstsq.
soln: np.ndarray
Array of polynomial coefficients.
residuals: np.ndarray
rank: int
s: np.ndarray
'''
# grid coords
x, y = np.meshgrid(x, y)
# coefficient array, up to x^kx, y^ky
coeffs = np.ones((kx+1, ky+1))
# solve array
a = np.zeros((coeffs.size, x.size))
# for each coefficient produce array x^i, y^j
for index, (j, i) in enumerate(np.ndindex(coeffs.shape)):
# do not include powers greater than order
if order is not None and i + j > order:
arr = np.zeros_like(x)
else:
arr = coeffs[i, j] * x**i * y**j
a[index] = arr.ravel()
# do leastsq fitting and return leastsq result
return np.linalg.lstsq(a.T, np.ravel(z), rcond=None)
And the resultant fit can be visualised with:
fitted_surf = np.polynomial.polynomial.polyval2d(x, y, soln.reshape((kx+1,ky+1)))
plt.matshow(fitted_surf)
Excellent answer by Saullo Castro. Just to add the code to reconstruct the function using the least-squares solution for the a coefficients,
def poly2Dreco(X, Y, c):
return (c[0] + X*c[1] + Y*c[2] + X**2*c[3] + X**2*Y*c[4] + X**2*Y**2*c[5] +
Y**2*c[6] + X*Y**2*c[7] + X*Y*c[8])
You can also use scikit-learn for this.
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
x = np.linspace(0, 1, 20)
y = np.linspace(0, 1, 20)
X, Y = np.meshgrid(x, y, copy=False)
X = X.flatten()
Y = Y.flatten()
# Generate noisy data
np.random.seed(0)
Z = X**2 + Y**2 + np.random.randn(*X.shape)*0.01
# Process 2D inputs
poly = PolynomialFeatures(degree=2)
input_pts = np.stack([X, Y]).T
assert(input_pts.shape == (400, 2))
in_features = poly.fit_transform(input_pts)
# Linear regression
model = LinearRegression()
model.fit(in_features, Z)
# Display coefficients
print(dict(zip(poly.get_feature_names_out(), model.coef_.round(4))))
# Check fit
print(f"R-squared: {model.score(poly.transform(input_pts), Z):.3f}")
# Make predictions
Z_predicted = model.predict(poly.transform(input_pts))
Out:
{'1': 0.0, 'x0': 0.003, 'x1': -0.0074, 'x0^2': 0.9974, 'x0 x1': 0.0047, 'x1^2': 1.0014}
R-squared: 1.000
Note that if kx != ky the code will fail because the j and i indices are inverted in the loop.
You get (j,i) from enumerate(np.ndindex(coeffs.shape)), but then you address elements in coeffs as coeffs[i,j]. Since the shape of the coefficient matrix is given by the maximum polynomial order that you are asking to use, the matrix will be rectangular if kx != ky and you will exceed one of its dimensions.

Python: how to calculate the bucket points

import numpy as np
import math
length = 10
points = [(1,2,3),(1,1,1),(23, 29, 0),(17, 0, 5)]
bucketed_points = {}
max_x = max([x for (x,y,z) in points])
max_y = max([y for (x,y,z) in points])
max_z = max([z for (x,y,z) in points])
x_buckets = int(max_x)/length + 1
y_buckets = int(max_y)/length + 1
z_buckets = int(max_z)/length + 1
for x in range(0, int(x_buckets)):
for y in range(0, int(y_buckets)):
for z in range(0, int(z_buckets)):
bucketed_points["{0},{1},{2}".format(x, y, z)] = []
for point in points:
# Here's where we actually put them in buckets
x, y, z = point
x, y, z = map(lambda a: int(math.floor(a/length)), [x, y, z])
bucketed_points["{0},{1},{2}".format(x, y, z)].append(point)
print(bucketed_points)
I have four points (1,2,3), (1,1,1),(23, 29, 0), (17, 0, 5), what I need to do is moving all the points to the new location (0,0,0), (0,0,0), (20,30,0), (20,0,10) which represent the center points for a cube whose side length equals 10 (length = 10).

Categories

Resources