Bounding Boxes #13
Replies: 4 comments
-
Points Bounded BoxPythonA simple function would be: def find_bounding_rectangle(points):
if not points:
return None
min_x = min(point['x'] for point in points)
max_x = max(point['x'] for point in points)
min_y = min(point['y'] for point in points)
max_y = max(point['y'] for point in points)
return {'bottom_left': {'x': min_x, 'y': min_y}, 'top_right': {'x': max_x, 'y': max_y}} I like to break things down a bit more than that, so I'd rather do this: def _find_bounding_rectangle(x_points, y_points):
"""
Find the bounding rectangle of a set of points.
>>> _find_bounding_rectangle((2, 9, 3), (6, 2, 8))
{'bottom_left': {'x': 2, 'y': 2}, 'top_right': {'x': 9, 'y': 8}}
"""
if not x_points or not y_points:
return None
# x_points and y_points should be of the same size and twice traversable, but won't validate that here
return {
'bottom_left': {'x': min(x_points), 'y': min(y_points)},
'top_right': {'x': max(x_points), 'y': max(y_points)}
}
def _extract_x_points_and_y_points(points):
"""
Extract an x and y array from a points array (e.g. [{"x": 2, "y": 6}, ...])
>>> points = [{"x": 2, "y": 6}, {"x": 9, "y": 2}, {"x": 3, "y": 8}]
>>> x_points, y_points = _extract_x_points_and_y_points(points)
>>> (x_points, y_points)
([2, 9, 3], [6, 2, 8])
"""
return zip(*map(lambda point: (point['x'], point['y']), points))
def find_bounding_rectangle(points):
"""
Find the bounding rectangle of a set of points.
>>> points = [{"x": 2, "y": 6}, {"x": 9, "y": 2}, {"x": 3, "y": 8}]
>>> find_bounding_rectangle(points)
{'bottom_left': {'x': 2, 'y': 2}, 'top_right': {'x': 9, 'y': 8}}
"""
x_points, y_points = _extract_x_points_and_y_points(points)
return _find_bounding_rectangle(x_points, y_points) JSfunction findBoundingRectangle(points) {
if (!points || points.length === 0) {
return null;
}
let minX = Math.min(...points.map(p => p.x));
let maxX = Math.max(...points.map(p => p.x));
let minY = Math.min(...points.map(p => p.y));
let maxY = Math.max(...points.map(p => p.y));
// Return coordinates of the bounding rectangle
// Bottom-left and top-right corners are sufficient to define the rectangle
return { bottomLeft: { x: minX, y: minY }, topRight: { x: maxX, y: maxY } };
} Example: let points = [{ x: 2, y: 6 }, { x: 9, y: 2 }, { x: 3, y: 8 }];
let boundingRectangle = findBoundingRectangle(points);
console.log(boundingRectangle); |
Beta Was this translation helpful? Give feedback.
-
Fitting the data box into the view boxTo create functions in Python and JavaScript that adjust a view rectangle to snugly fit a data bounding box with some padding, you need to calculate the new bottom-left and top-right coordinates of the view rectangle. The padding is expressed as a percentage ratio of the dimensions of the data bounding box, which means it needs to be scaled accordingly. Pythondef adjust_view_rectangle(data_bounding_box, padding_percentage):
"""
Adjust the view rectangle to fit the data bounding box with padding.
Args:
data_bounding_box (dict): A dictionary with 'bottom_left' and 'top_right' coordinates of the data.
padding_percentage (float): Padding percentage of the data bounding box dimensions.
Returns:
dict: Adjusted view rectangle with 'bottom_left' and 'top_right' coordinates.
"""
# Extract coordinates
bottom_left = data_bounding_box['bottom_left']
top_right = data_bounding_box['top_right']
# Calculate dimensions of the bounding box
width = top_right['x'] - bottom_left['x']
height = top_right['y'] - bottom_left['y']
# Calculate padding
padding_width = width * padding_percentage
padding_height = height * padding_percentage
# Adjust coordinates
adjusted_bottom_left = {'x': bottom_left['x'] - padding_width, 'y': bottom_left['y'] - padding_height}
adjusted_top_right = {'x': top_right['x'] + padding_width, 'y': top_right['y'] + padding_height}
return {'bottom_left': adjusted_bottom_left, 'top_right': adjusted_top_right}
# Example usage
data_bounding_box = {'bottom_left': {'x': 2, 'y': 2}, 'top_right': {'x': 5, 'y': 5}}
padding_percentage = 0.1 # 10%
adjusted_view = adjust_view_rectangle(data_bounding_box, padding_percentage)
assert adjusted_view == {'bottom_left': {'x': 1.7, 'y': 1.7}, 'top_right': {'x': 5.3, 'y': 5.3}} JSfunction adjustViewRectangle(dataBoundingBox, paddingPercentage) {
/**
* Adjust the view rectangle to fit the data bounding box with padding.
*
* @param {Object} dataBoundingBox - An object with 'bottomLeft' and 'topRight' coordinates of the data.
* @param {number} paddingPercentage - Padding percentage of the data bounding box dimensions.
* @return {Object} Adjusted view rectangle with 'bottomLeft' and 'topRight' coordinates.
*/
// Extract coordinates
const { bottomLeft, topRight } = dataBoundingBox;
// Calculate dimensions of the bounding box
const width = topRight.x - bottomLeft.x;
const height = topRight.y - bottomLeft.y;
// Calculate padding
const paddingWidth = width * paddingPercentage;
const paddingHeight = height * paddingPercentage;
// Adjust coordinates
const adjustedBottomLeft = { x: bottomLeft.x - paddingWidth, y: bottomLeft.y - paddingHeight };
const adjustedTopRight = { x: topRight.x + paddingWidth, y: topRight.y + paddingHeight };
return { bottomLeft: adjustedBottomLeft, topRight: adjustedTopRight };
}
// Example usage
const dataBoundingBox = { bottomLeft: { x: 2, y: 2 }, topRight: { x: 5, y: 5 } };
const paddingPercentage = 0.1; // 10%
const adjustedView = adjustViewRectangle(dataBoundingBox, paddingPercentage);
console.log(adjustedView); |
Beta Was this translation helpful? Give feedback.
-
Shapes Bounding BoxesFor computing the bounding box of shapes, the approach is similar to that of points, with the distinction that the user provides the extreme horizontal and vertical bounds of each shape. These bounds can be the minimum and maximum Note that we could rewrite the points bounding box functions to reuse the shapes ones below, by considering a point to be an area-less shape. Pythondef find_shapes_bounding_box(shape_bounds):
"""
Finds the bounding box for a collection of shapes.
Args:
shape_bounds (list of dicts): A list where each dict contains 'min_x', 'max_x', 'min_y', and 'max_y' for a shape.
Returns:
dict: Bounding box with 'bottom_left' and 'top_right' coordinates.
"""
# Initialize min and max values to the first shape's bounds
if not shape_bounds:
return None
min_x = shape_bounds[0]['min_x']
max_x = shape_bounds[0]['max_x']
min_y = shape_bounds[0]['min_y']
max_y = shape_bounds[0]['max_y']
for bounds in shape_bounds:
min_x = min(min_x, bounds['min_x'])
max_x = max(max_x, bounds['max_x'])
min_y = min(min_y, bounds['min_y'])
max_y = max(max_y, bounds['max_y'])
return {'bottom_left': {'x': min_x, 'y': min_y}, 'top_right': {'x': max_x, 'y': max_y}}
# Example usage
shape_bounds = [
{'min_x': 1, 'max_x': 3, 'min_y': 1, 'max_y': 4},
{'min_x': 2, 'max_x': 5, 'min_y': 2, 'max_y': 3}
]
bounding_box = find_shapes_bounding_box(shape_bounds)
print(bounding_box) Shapes Bounding Boxes: JSfunction findShapesBoundingBox(shapeBounds) {
/**
* Finds the bounding box for a collection of shapes.
*
* @param {Array} shapeBounds - An array of objects, each containing 'minX', 'maxX', 'minY', and 'maxY' for a shape.
* @return {Object} Bounding box with 'bottomLeft' and 'topRight' coordinates.
*/
if (shapeBounds.length === 0) {
return null;
}
let minX = shapeBounds[0].minX;
let maxX = shapeBounds[0].maxX;
let minY = shapeBounds[0].minY;
let maxY = shapeBounds[0].maxY;
shapeBounds.forEach(bounds => {
minX = Math.min(minX, bounds.minX);
maxX = Math.max(maxX, bounds.maxX);
minY = Math.min(minY, bounds.minY);
maxY = Math.max(maxY, bounds.maxY);
});
return { bottomLeft: { x: minX, y: minY }, topRight: { x: maxX, y: maxY } };
}
// Example usage
const shapeBounds = [
{ minX: 1, maxX: 3, minY: 1, maxY: 4 },
{ minX: 2, maxX: 5, minY: 2, maxY: 3 }
];
const boundingBox = findShapesBoundingBox(shapeBounds);
console.log(boundingBox); |
Beta Was this translation helpful? Give feedback.
-
Shape Bounds for CirclesThe circle/disk is one quite common shape to use when plotting 2D data. To generate
These calculations give us the bounding box for each individual circle. Here's how you can implement functions to compute Pythondef get_circle_bounds(circles):
"""
Calculate the bounding box for each circle in a list.
Args:
circles (list of dicts): A list where each dict contains 'x', 'y', and 'radius' for a circle.
Returns:
list of dicts: A list of bounding boxes with 'min_x', 'max_x', 'min_y', and 'max_y' for each circle.
"""
shape_bounds = []
for circle in circles:
x, y, r = circle['x'], circle['y'], circle['radius']
bounds = {
'min_x': x - r,
'max_x': x + r,
'min_y': y - r,
'max_y': y + r
}
shape_bounds.append(bounds)
return shape_bounds
# Example usage
circles = [{'x': 3, 'y': 8, 'radius': 2}, {'x': 1, 'y': 4, 'radius': 1}]
circle_bounds = get_circle_bounds(circles)
print(circle_bounds) JSfunction getCircleBounds(circles) {
/**
* Calculate the bounding box for each circle in an array.
*
* @param {Array} circles - An array of objects, each containing 'x', 'y', and 'radius' for a circle.
* @return {Array} An array of bounding boxes with 'minX', 'maxX', 'minY', and 'maxY' for each circle.
*/
return circles.map(circle => ({
minX: circle.x - circle.radius,
maxX: circle.x + circle.radius,
minY: circle.y - circle.radius,
maxY: circle.y + circle.radius
}));
}
// Example usage
const circles = [{ x: 3, y: 8, radius: 2 }, { x: 1, y: 4, radius: 1 }];
const circleBounds = getCircleBounds(circles);
console.log(circleBounds); |
Beta Was this translation helpful? Give feedback.
-
When faced with issues such as Zoom UX can be improved or features such as Easily create data images and videos it helps to have some "bounding boxes" utilities.
Namely, you want to be able to do things like figure out the minimum bounding rectangle%2C%20max(y).) of a set of points (or shapes!) and figure out what the view rectangle should be to contain that bounding box snuggly.
Here are some ideas and code we can use when integrating those functionalities...
Beta Was this translation helpful? Give feedback.
All reactions