patternpythonMinor
Coordinates of 2D points zoomed in/out
Viewed 0 times
pointszoomedoutcoordinates
Problem
This might be a simple issue that I am overcomplicating, but I've spent quite some time reading about polygon scaling and I've come to the conclusion that it is not precisely what I need.
Given a set of
I've come up with the simple method shown below, but I wonder if there might be another approach and/or more reasonable zooming methods.
Given a set of
(x, y) coordinates for N points (shown in blue) I need the new set of coordinates that result after zooming in/out a given scale factor (shown in red).I've come up with the simple method shown below, but I wonder if there might be another approach and/or more reasonable zooming methods.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
N = 5
xy = [np.random.uniform(0., 1000., 2) for _ in range(N)]
x, y = zip(*xy)
# Center of xy points, defined as the center of the minimal rectangle that
# contains all points.
xy_center = ((min(x) + max(x)) * .5, (min(y) + max(y)) * .5)
# Difference between the center coordinates and the xy points.
delta_x, delta_y = xy_center[0] - x, xy_center[1] - y
# Zoom scale (0. < scale)
scale = 1.5
# Scaled xy points.
x_scale = xy_center[0] - scale * delta_x
y_scale = xy_center[1] - scale * delta_y
ax = plt.subplot(111)
# Original xy points.
ax.scatter(x, y, c='b')
# Defined center.
ax.scatter(*xy_center, marker='x', c='g')
# Zoomed points.
ax.scatter(x_scale, y_scale, c='r')
# Square: bottom left corner, width, height
ax.add_patch(
patches.Rectangle(
(min(x), min(y)), (max(x) - min(x)), (max(y) - min(y)), fill=False))
plt.show()Solution
When working with NumPy, it's best to keep all our data in the form of NumPy arrays, instead of converting back and forth between NumPy and Python data structures.
-
So instead of creating a NumPy array for each point and then zipping them to extract tuples of \$x\$-coordinates and \$y\$-coordinates, create one array for all the points:
We can extract the \$x\$-coordinates and \$y\$-coordinates, if we need them, by transposing the array:
but we won't need to do so until the very end when we pass the data to Matplotlib.
-
The coordinates of the origin can be computed like this:
-
To scale the points about the origin, use:
instead of (as in the code in the post):
The former is slightly quicker, as it has only two arithmetic operations on arrays as long as
Putting this together:
Here
-
So instead of creating a NumPy array for each point and then zipping them to extract tuples of \$x\$-coordinates and \$y\$-coordinates, create one array for all the points:
p = np.random.uniform(0., 1000., (N, 2))We can extract the \$x\$-coordinates and \$y\$-coordinates, if we need them, by transposing the array:
x, y = p.Tbut we won't need to do so until the very end when we pass the data to Matplotlib.
-
The coordinates of the origin can be computed like this:
o = (p.min(axis=0) + p.max(axis=0)) * .5-
To scale the points about the origin, use:
q = o * (1 - scale) + p * scaleinstead of (as in the code in the post):
delta = p - o
q = o + delta * scaleThe former is slightly quicker, as it has only two arithmetic operations on arrays as long as
p whereas the latter has three.Putting this together:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
N = 5
p = np.random.uniform(0., 1000., (N, 2))
# Center of points, defined as the center of the minimal rectangle
# that contains all points.
o = (p.min(axis=0) + p.max(axis=0)) * .5
# Scale factor (0. < scale)
scale = 1.5
# Points scaled about center.
q = o * (1 - scale) + p * scale
ax = plt.subplot(111)
ax.scatter(*p.T, c='b') # Original points.
ax.scatter(*o, marker='x', c='g') # Center.
ax.scatter(*q.T, c='r') # Scaled points.
ax.add_patch(patches.Rectangle(p.min(axis=0), *p.ptp(axis=0), fill=False))
plt.show()Here
numpy.ptp stands for peak-to-peak and computes the range of values (maximum − minimum) along an axis in an array.Code Snippets
p = np.random.uniform(0., 1000., (N, 2))o = (p.min(axis=0) + p.max(axis=0)) * .5q = o * (1 - scale) + p * scaledelta = p - o
q = o + delta * scaleimport numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
N = 5
p = np.random.uniform(0., 1000., (N, 2))
# Center of points, defined as the center of the minimal rectangle
# that contains all points.
o = (p.min(axis=0) + p.max(axis=0)) * .5
# Scale factor (0. < scale)
scale = 1.5
# Points scaled about center.
q = o * (1 - scale) + p * scale
ax = plt.subplot(111)
ax.scatter(*p.T, c='b') # Original points.
ax.scatter(*o, marker='x', c='g') # Center.
ax.scatter(*q.T, c='r') # Scaled points.
ax.add_patch(patches.Rectangle(p.min(axis=0), *p.ptp(axis=0), fill=False))
plt.show()Context
StackExchange Code Review Q#159183, answer score: 2
Revisions (0)
No revisions yet.