vg¶
Linear algrbra for humans: a very good vectorgeometry and linearalgebra toolbelt. Simple NumPy operations, made readable.
Functions¶
All functions are optionally vectorized, meaning they accept single inputs and stacks of inputs interchangeably. They return The Right Thing – a single result or a stack of results – without the need to reshape inputs or outputs. With the power of NumPy, the vectorized functions are fast.

vg.
normalize
(vector)[source]¶ Return the vector, normalized.
If vector is 2d, treats it as stacked vectors, and normalizes each one.

vg.
perpendicular
(v1, v2, normalized=True)[source]¶ Given two noncollinear vectors, return a vector perpendicular to both. For stacked inputs, compute the result vectors pairwise such that result[k] is perpendicular to v1[k] and v2[k].
Result vectors follow the righthand rule. When the right index finger points along v1 and the right middle finger along v2, the right thumb points along the result.
Parameters:  v1 (np.arraylike) – A 3x1 vector or a kx3 stack of vectors.
 v2 (np.arraylike) – A vector or stack of vectors with the same shape as v1.
 normalized (bool) – When True, the result vector is guaranteed to be unit length.
Returns: An array with the same shape as v1 and v2.
Return type: np.arraylike

vg.
project
(vector, onto)[source]¶ Compute the vector projection of vector onto the vector onto.
onto need not be normalized.

vg.
scalar_projection
(vector, onto)[source]¶ Compute the scalar projection of vector onto the vector onto.
onto need not be normalized.

vg.
reject
(vector, from_v)[source]¶ Compute the vector rejection of vector from from_v – i.e. the vector component of vector perpendicular to from_v.
from_v need not be normalized.

vg.
reject_axis
(vector, axis, squash=False)[source]¶ Compute the vector component of vector perpendicular to the basis vector specified by axis. 0 means x, 1 means y, 2 means z.
In other words, return a copy of vector that zeros the axis component.
When squash is True, instead of zeroing the component, it drops it, so an input vector (in R3) is mapped to a point in R2.
(N.B. Don’t be misled: this meaning of axis is pretty different from the typical meaning in numpy.)

vg.
magnitude
(vector)[source]¶ Compute the magnitude of vector. For stacked inputs, compute the magnitude of each one.
Parameters: vector (np.arraylike) – A 3x1 vector or a kx3 stack of vectors. Returns:  For 3x1 inputs, a float with the magnitude. For kx1
 inputs, a kx1 array.
Return type: object

vg.
angle
(v1, v2, look=None, assume_normalized=False, units='deg')[source]¶ Compute the unsigned angle between two vectors. For stacked inputs, the angle is computed pairwise.
When look is provided, the angle is computed in that viewing plane (look is the normal). Otherwise the angle is computed in 3space.
Parameters:  v1 (np.arraylike) – A 3x1 vector or a kx3 stack of vectors.
 v2 (np.arraylike) – A vector or stack of vectors with the same shape as v1.
 look (np.arraylike) – A 3x1 vector specifying the normal of a viewing plane, or None to compute the angle in 3space.
 assume_normalized (bool) – When True, assume the input vectors are unit length. This improves performance, however when the inputs are not normalized, setting this will cause an incorrect results.
 units (str) – ‘deg’ to return degrees or ‘rad’ to return radians.
Returns:  For 3x1 inputs, a float with the angle. For kx1 inputs,
a kx1 array.
Return type: object

vg.
signed_angle
(v1, v2, look, units='deg')[source]¶ Compute the signed angle between two vectors. For stacked inputs, the angle is computed pairwise.
Results are in the range 180 and 180 (or math.pi and math.pi). A positive number indicates a clockwise sweep from v1 to v2. A negative number is counterclockwise.
Parameters:  v1 (np.arraylike) – A 3x1 vector or a kx3 stack of vectors.
 v2 (np.arraylike) – A vector or stack of vectors with the same shape as v1.
 look (np.arraylike) – A 3x1 vector specifying the normal of the viewing plane.
 units (str) – ‘deg’ to return degrees or ‘rad’ to return radians.
Returns:  For 3x1 inputs, a float with the angle. For kx1 inputs,
a kx1 array.
Return type: object

vg.
rotate
(vector, around_axis, angle, units='deg', assume_normalized=False)[source]¶ Rotate a point or vector around a given axis. The direction of rotation around around_axis is determined by the righthand rule.
Parameters:  vector (np.arraylike) – A 3x1 vector or a kx3 stack of vectors.
 around_axis (np.arraylike) – A 3x1 vector specifying the axis of rotation.
 assume_normalized (bool) – When True, assume around_axis is unit length. This improves performance marginally, however when the inputs are not normalized, setting this will cause an incorrect results.
 units (str) – ‘deg’ to specify angle in degrees or ‘rad’ to specify radians.
Returns:  The transformed point or points. This has the same shape as
vector.
Return type: np.arraylike

vg.
almost_unit_length
(vector, atol=1e08)[source]¶ Test if the vector has almost unit length. For stacked inputs, test each one.
Parameters: vector (np.arraylike) – A 3x1 vector or a kx3 stack of vectors. Returns: For 3x1 inputs, a bool. For kx1 inputs, a kx1 array. Return type: object

vg.
almost_collinear
(v1, v2, atol=1e08)[source]¶ Test if v1 and v2 are almost collinear.
Mathematically speaking, the zero vector is collinear to everything. Geometrically that doesn’t necessarily make sense. If you care, test your inputs with vg.almost_zero.

vg.
almost_equal
(v1, v2, atol=1e08)[source]¶ Test if v1 and v2 are equal within the given absolute tolerance.

vg.
principal_components
(coords)[source]¶ Compute the principal components of the input coordinates. These are useful for dimensionality reduction and feature modeling.
Parameters: coords (np.arraylike) – A nxk stack of coordinates. Returns: A kxk stack of vectors. Return type: np.ndarray

vg.
major_axis
(coords)[source]¶ Compute the first principal component of the input coordinates. This is the vector which best describes the multidimensional data using a single dimension.
Parameters: coords (np.arraylike) – A nxk stack of coordinates. Returns: A kx1 vector. Return type: np.ndarray

vg.
apex
(points, along)[source]¶ Find the most extreme point in the direction provided.
Parameters:  points (np.arraylike) – A kx3 stack of points in R^3.
 along (np.arraylike) – A 3x1 vector specifying the direction of interest.
Returns: A 3x1 point taken from points.
Return type: np.ndarray

vg.
farthest
(from_points, to_point, ret_index=False)[source]¶ Find the point farthest from the given point.
Parameters:  from_points (np.arraylike) – A kx3 stack of points in R^3.
 to_point (np.arraylike) – A 3x1 point of interest.
 ret_index (bool) – When True, return both the point and its index.
Returns: A 3x1 vector taken from from_points.
Return type: np.ndarray

vg.
within
(points, radius, of_point, atol=1e08, ret_indices=False)[source]¶ Select points within a given radius of a point.
Parameters:  points (np.arraylike) – A kx3 stack of points in R^3.
 radius (float) – The radius of the sphere of interest centered on of_point.
 of_point (np.arraylike) – The 3x1 point of interest.
 atol (float) – The distance tolerance. Points within radius + atol of of_point are selected.
 ret_indexes (bool) – When True, return both the points and their indices.
Returns: A 3x1 vector taken from points.
Return type: np.ndarray

vg.matrix.
pad_with_ones
(matrix)[source]¶  Add a column of ones. Transform from:
 array([[1., 2., 3.],
 [2., 3., 4.], [5., 6., 7.]])
 to:
 array([[1., 2., 3., 1.],
 [2., 3., 4., 1.], [5., 6., 7., 1.]])

vg.matrix.
transform
(vertices, transform)[source]¶ Apply the given transformation matrix to the vertices using homogenous coordinates.

vg.matrix.
unpad
(matrix)[source]¶  Strip off a column (e.g. of ones). Transform from:
 array([[1., 2., 3., 1.],
 [2., 3., 4., 1.], [5., 6., 7., 1.]])
 to:
 array([[1., 2., 3.],
 [2., 3., 4.], [5., 6., 7.]])

vg.shape.
check
(locals_namespace, name, shape)[source]¶ Convenience function for invoking vg.shape.check_value() with a locals() dict.
Parameters:  namespace (dict) – A subscriptable object, typically locals().
 name (str) – Key to pull from namespace.
 shape (list) – Shape to validate. To require 3 by 1, pass (3,). To require n by 3, pass (1, 3).
Returns: The wildcard dimension (if one) or a tuple of wildcard dimensions (if more than one).
Return type: object
Example
>>> def my_fun_function(points): ... vg.shape.check(locals(), 'points', (1, 3)) ... # Proceed with confidence that `points` is a k x 3 array.
Example
>>> def my_fun_function(points): ... k = vg.shape.check(locals(), 'points', (1, 3)) ... print("my_fun_function invoked with {} points".format(k))

vg.shape.
check_value
(a, shape, **kwargs)[source]¶ Check that the given argument has the expected shape. Shape dimensions can be ints or 1 for a wildcard. The wildcard dimensions are returned, which allows them to be used for subsequent validation or elsewhere in the function.
Parameters:  a (np.arraylike) – An arraylike input.
 shape (list) – Shape to validate. To require 3 by 1, pass (3,). To require n by 3, pass (1, 3).
 name (str) – Variable name to embed in the error message.
Returns: The wildcard dimension (if one) or a tuple of wildcard dimensions (if more than one).
Return type: object
Example
>>> vg.shape.check_value(np.zeros((4, 3)), (1, 3)) >>> # Proceed with confidence that `points` is a k x 3 array.
Example
>>> k = vg.shape.check_value(np.zeros((4, 3)), (1, 3)) >>> k 4
Constants¶

vg.
basis
¶ The cartesian basis vectors.

vg.basis.
x
= array([1., 0., 0.])¶

vg.basis.
neg_x
= array([1., 0., 0.])¶

vg.basis.
y
= array([0., 1., 0.])¶

vg.basis.
neg_y
= array([ 0., 1., 0.])¶

vg.basis.
z
= array([0., 0., 1.])¶

vg.basis.
neg_z
= array([ 0., 0., 1.])¶
Style guide¶
Use the named secondary arguments. They tend to make the code more readable:
import vg
result = vg.proj(v1, onto=v2)
Design principles¶
Linear algebra is useful and it doesn’t have to be dificult to use. With the power of abstractions, simple operations can be made simple, without poring through lecture slides, textbooks, inscrutable Stack Overflow answers, or dense NumPy docs. Code that uses linear algebra and geometric transformation should be readable like English, without compromising efficiency.
These common operations should be abstracted for a few reasons:
 If a developer is not programming linalg every day, they might forget the underlying formula. These forms are easier to remember and more easily referenced.
 These forms tend to be selfdocumenting in a way that the NumPy forms are not. If a developer is not programming linalg every day, this will again come in handy.
 These implementations are more robust. They automatically inspect
ndim
on their arguments, so they work equally well if the argument is a vector or a stack of vectors. They are more careful about checking edge cases like a zero norm or zero cross product and returning a correct result or raising an appropriate error.
Versioning¶
This library adheres to Semantic Versioning.