Skip to content

Commit a07636c

Browse files
authored
Get nearest graphics (#519)
* bugfix * center works, need to figure out what's wrong with edge * allow passing graphic collection to subset * allow passing graphic collection to subset * move get_nearest_graphics to utils * move stuff * test for get nearest * black * more black
1 parent ae9ccc2 commit a07636c

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

fastplotlib/graphics/line_collection.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def cmap(self, args):
8181
if isinstance(args, str):
8282
name = args
8383
transform, alpha = None, 1.0
84-
if len(args) == 1:
84+
elif len(args) == 1:
8585
name = args[0]
8686
transform, alpha = None, None
8787

fastplotlib/utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from .functions import *
55
from .gpu import enumerate_adapters, select_adapter, print_wgpu_report
6+
from ._plot_helpers import *
67

78

89
@dataclass

fastplotlib/utils/_plot_helpers.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from typing import Sequence
2+
3+
import numpy as np
4+
5+
from ..graphics._base import Graphic
6+
from ..graphics._collection_base import GraphicCollection
7+
8+
9+
def get_nearest_graphics(
10+
pos: tuple[float, float] | tuple[float, float, float],
11+
graphics: Sequence[Graphic] | GraphicCollection,
12+
) -> np.ndarray[Graphic]:
13+
"""
14+
Returns the nearest ``graphics`` to the passed position ``pos`` in world space.
15+
Uses the distance between ``pos`` and the center of the bounding sphere for each graphic.
16+
17+
Parameters
18+
----------
19+
pos: (x, y) | (x, y, z)
20+
position in world space, z-axis is ignored when calculating L2 norms if ``pos`` is 2D
21+
22+
graphics: Sequence, i.e. array, list, tuple, etc. of Graphic | GraphicCollection
23+
the graphics from which to return a sorted array of graphics in order of closest
24+
to furthest graphic
25+
26+
Returns
27+
-------
28+
tuple[Graphic]
29+
nearest graphics to ``pos`` in order
30+
31+
"""
32+
33+
if isinstance(graphics, GraphicCollection):
34+
graphics = graphics.graphics
35+
36+
if not all(isinstance(g, Graphic) for g in graphics):
37+
raise TypeError("all elements of `graphics` must be Graphic objects")
38+
39+
pos = np.asarray(pos)
40+
41+
if pos.shape != (2,) or not pos.shape != (3,):
42+
raise TypeError
43+
44+
# get centers
45+
centers = np.empty(shape=(len(graphics), len(pos)))
46+
for i in range(centers.shape[0]):
47+
centers[i] = graphics[i].world_object.get_world_bounding_sphere()[: len(pos)]
48+
49+
# l2
50+
distances = np.linalg.norm(centers[:, : len(pos)] - pos, ord=2, axis=1)
51+
52+
sort_indices = np.argsort(distances)
53+
return np.asarray(graphics)[sort_indices]

tests/test_plot_helpers.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import numpy as np
2+
import fastplotlib as fpl
3+
4+
5+
def make_circle(center, radius: float, n_points: int = 75) -> np.ndarray:
6+
theta = np.linspace(0, 2 * np.pi, n_points)
7+
xs = radius * np.sin(theta)
8+
ys = radius * np.cos(theta)
9+
10+
return np.column_stack([xs, ys]) + center
11+
12+
13+
def test_get_nearest_graphics():
14+
circles = list()
15+
16+
centers = [[0, 0], [0, 20], [20, 0], [20, 20]]
17+
18+
for center in centers:
19+
circles.append(make_circle(center, 5, n_points=75))
20+
21+
fig = fpl.Figure()
22+
23+
lines = fig[0, 0].add_line_collection(circles, cmap="jet", thickness=5)
24+
25+
fig[0, 0].add_scatter(np.array([[0, 12, 0]]))
26+
27+
# check distances
28+
nearest = fpl.utils.get_nearest_graphics((0, 12), lines)
29+
assert nearest[0] is lines[1] # closest
30+
assert nearest[1] is lines[0]
31+
assert nearest[2] is lines[3]
32+
assert nearest[3] is lines[2] # furthest
33+
assert nearest[-1] is lines[2]

0 commit comments

Comments
 (0)