spatial-graph 0.0.1__tar.gz → 0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/.github/workflows/ci.yaml +17 -21
  2. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/.gitignore +3 -0
  3. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/.pre-commit-config.yaml +2 -2
  4. spatial_graph-0.0.1/README.md → spatial_graph-0.0.2/PKG-INFO +49 -12
  5. spatial_graph-0.0.1/PKG-INFO → spatial_graph-0.0.2/README.md +23 -29
  6. spatial_graph-0.0.2/examples/basic_usage.py +142 -0
  7. spatial_graph-0.0.2/examples/query_nearest_vispy.py +123 -0
  8. spatial_graph-0.0.2/pyproject.toml +77 -0
  9. spatial_graph-0.0.2/src/spatial_graph/__init__.py +13 -0
  10. spatial_graph-0.0.2/src/spatial_graph/dtypes.py +144 -0
  11. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/graph/graph.py +11 -4
  12. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/graph/wrapper_template.pyx +4 -1
  13. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/__init__.py +2 -3
  14. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/line_rtree.py +8 -4
  15. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/rtree.py +117 -5
  16. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/spatial_graph.py +9 -5
  17. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/tests/test_attributes.py +3 -2
  18. spatial_graph-0.0.2/tests/test_dtype.py +39 -0
  19. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/tests/test_rtree.py +2 -1
  20. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/tests/test_spatial_graph.py +2 -1
  21. spatial_graph-0.0.1/.cruft.json +0 -20
  22. spatial_graph-0.0.1/pyproject.toml +0 -32
  23. spatial_graph-0.0.1/spatial_graph/__init__.py +0 -15
  24. spatial_graph-0.0.1/spatial_graph/dtypes.py +0 -130
  25. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/LICENSE +0 -0
  26. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/graph/__init__.py +0 -0
  27. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/graph/src/LICENSE.txt +0 -0
  28. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/graph/src/graph_lite.h +0 -0
  29. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/point_rtree.py +0 -0
  30. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/src/ARCHITECTURE.md +0 -0
  31. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/src/LICENSE +0 -0
  32. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/src/config.h +0 -0
  33. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/src/rtree.c +0 -0
  34. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/src/rtree.h +0 -0
  35. {spatial_graph-0.0.1 → spatial_graph-0.0.2/src}/spatial_graph/rtree/wrapper_template.pyx +0 -0
  36. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/tests/test_assert.py +0 -0
  37. {spatial_graph-0.0.1 → spatial_graph-0.0.2}/tests/test_graph.py +2 -2
@@ -2,11 +2,9 @@ name: CI
2
2
 
3
3
  on:
4
4
  pull_request:
5
- branches:
6
- - main
5
+ branches: [main]
7
6
  push:
8
- branches:
9
- - main
7
+ branches: [main]
10
8
  tags: [v*]
11
9
  workflow_dispatch:
12
10
 
@@ -29,20 +27,20 @@ jobs:
29
27
  fail-fast: false
30
28
  matrix:
31
29
  os: [ubuntu-latest, windows-latest, macos-latest]
32
- python-version: ["3.9", "3.10", "3.11", "3.12"]
30
+ python-version: ["3.9", "3.11", "3.13"]
33
31
 
34
32
  steps:
35
33
  - uses: actions/checkout@v2
36
- - name: Set up Python ${{ matrix.python-version }}
37
- uses: actions/setup-python@v4
34
+ - uses: astral-sh/setup-uv@v6
38
35
  with:
39
36
  python-version: ${{ matrix.python-version }}
40
- - name: Install dependencies
41
- run: |
42
- pip install ".[dev]"
43
- - name: Test with pytest
44
- run: |
45
- pytest --color=yes -v tests
37
+ enable-cache: true
38
+ cache-dependency-glob: "**/pyproject.toml"
39
+ - name: Test with coverage
40
+ run: uv run pytest -v --cov=spatial_graph --cov-report=xml
41
+ - uses: codecov/codecov-action@v5
42
+ with:
43
+ token: ${{ secrets.CODECOV_TOKEN }}
46
44
 
47
45
  deploy:
48
46
  name: Deploy
@@ -58,21 +56,19 @@ jobs:
58
56
  - uses: actions/checkout@v4
59
57
  with:
60
58
  fetch-depth: 0
61
-
62
- - name: 🐍 Set up Python
63
- uses: actions/setup-python@v5
59
+ - uses: astral-sh/setup-uv@v6
64
60
  with:
65
- python-version: "3.x"
61
+ python-version: ${{ matrix.python-version }}
62
+ enable-cache: true
63
+ cache-dependency-glob: "**/pyproject.toml"
66
64
 
67
65
  - name: 👷 Build
68
- run: |
69
- python -m pip install build
70
- python -m build
66
+ run: uv build
71
67
 
72
68
  - name: 🚢 Publish to PyPI
73
69
  uses: pypa/gh-action-pypi-publish@release/v1
74
70
  with:
75
- password: ${{ secrets.PYPI_API_TOKEN }}
71
+ password: ${{ secrets.PYPI_API_TOKEN }}
76
72
 
77
73
  - uses: softprops/action-gh-release@v2
78
74
  with:
@@ -11,3 +11,6 @@ build
11
11
  dist
12
12
  .vscode
13
13
  docs/_build/
14
+
15
+ # remove me to enforce synchrony across development environments
16
+ uv.lock
@@ -15,13 +15,13 @@ repos:
15
15
  - id: check-added-large-files
16
16
 
17
17
  - repo: https://github.com/astral-sh/ruff-pre-commit
18
- rev: v0.7.2
18
+ rev: v0.12.2
19
19
  hooks:
20
20
  - id: ruff
21
21
  args: [--fix, --unsafe-fixes]
22
22
  - id: ruff-format
23
23
 
24
24
  - repo: https://github.com/pre-commit/mirrors-mypy
25
- rev: v1.13.0
25
+ rev: v1.16.1
26
26
  hooks:
27
27
  - id: mypy
@@ -1,15 +1,42 @@
1
- # spatial_graph
2
-
1
+ Metadata-Version: 2.4
2
+ Name: spatial-graph
3
+ Version: 0.0.2
4
+ Summary: A spatial graph datastructure for python.
5
+ Project-URL: homepage, https://github.com/funkelab/spatial_graph
6
+ Project-URL: repository, https://github.com/funkelab/spatial_graph
7
+ Author-email: Jan Funke <funkej@janelia.hhmi.org>, Talley Lambert <talley.lambert@gmail.com>
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.9
20
+ Requires-Dist: ct3>=3.3.3
21
+ Requires-Dist: numpy
22
+ Requires-Dist: setuptools>=75.8.0
23
+ Requires-Dist: witty>=v0.2.1
24
+ Description-Content-Type: text/markdown
25
+
26
+ # spatial-graph
27
+
28
+ [![License](https://img.shields.io/pypi/l/spatial-graph.svg?color=green)](https://github.com/funkelab/spatial_graph/raw/main/LICENSE)
29
+ [![PyPI](https://img.shields.io/pypi/v/spatial-graph.svg?color=green)](https://pypi.org/project/spatial-graph)
30
+ [![Python Version](https://img.shields.io/pypi/pyversions/spatial-graph.svg?color=green)](https://python.org)
3
31
  [![CI](https://github.com/funkelab/spatial_graph/actions/workflows/ci.yaml/badge.svg)](https://github.com/funkelab/spatial_graph/actions/workflows/ci.yaml)
32
+ [![codecov](https://codecov.io/gh/funkelab/spatial_graph/branch/main/graph/badge.svg)](https://codecov.io/gh/funkelab/spatial_graph)
4
33
 
5
34
  `spatial_graph` provides a data structure for directed and undirected graphs,
6
35
  where each node has an nD position (in time or space).
7
36
 
8
- Design Principles
9
- =================
37
+ ## Design Principles
10
38
 
11
- Goals
12
- -----
39
+ ### Goals
13
40
 
14
41
  * support for arbitrary number of dimensions
15
42
  * typed node identifiers and attributes
@@ -27,8 +54,7 @@ Goals
27
54
  * numpy for array interfaces
28
55
  * PYX API for graph algorithms in C/C++
29
56
 
30
- Non-Goals
31
- ---------
57
+ ### Non-Goals
32
58
 
33
59
  * graph algorithms
34
60
  * I/O
@@ -37,8 +63,7 @@ Non-Goals
37
63
  * out-of-memory support
38
64
  * networkx compatibility
39
65
 
40
- Python API
41
- ==========
66
+ ## Python API
42
67
 
43
68
  Graph creation:
44
69
 
@@ -104,9 +129,21 @@ Delete nodes/edges:
104
129
  graph.remove_nodes(nodes[:1000])
105
130
  ```
106
131
 
107
- Implementation Details
108
- ======================
132
+ ## Implementation Details
109
133
 
110
134
  A `SpatialGraph` consists of three data structures:
135
+
111
136
  * The `Graph` itself, holding nodes, edges, and their attributes ([graphlite](https://github.com/haasdo95/graphlite)).
112
137
  * Two R-trees for spatial node and edge queries (based on [rtree.c](https://github.com/tidwall/rtree.c)).
138
+
139
+ ## For Developers
140
+
141
+ To create a new release, tag the current commit with a
142
+ version number and push it to the `upstream` remote:
143
+
144
+ ```bash
145
+ git tag -a "vX.Y.Z" -m "vX.Y.Z"
146
+ git push upstream --follow-tags
147
+ ```
148
+
149
+ This will trigger the CI workflow, which will build the package and upload it to PyPI.
@@ -1,33 +1,17 @@
1
- Metadata-Version: 2.4
2
- Name: spatial-graph
3
- Version: 0.0.1
4
- Summary: A spatial graph datastructure for python.
5
- Project-URL: homepage, https://github.com/funkelab/spatial_graph
6
- Project-URL: repository, https://github.com/funkelab/spatial_graph
7
- Author-email: Jan Funke <funkej@janelia.hhmi.org>
8
- License: MIT
9
- License-File: LICENSE
10
- Requires-Python: >=3.9
11
- Requires-Dist: cheetah3
12
- Requires-Dist: numpy
13
- Requires-Dist: setuptools>=75.8.0
14
- Requires-Dist: witty>=v0.2.0
15
- Provides-Extra: dev
16
- Requires-Dist: pytest>=8.3.4; extra == 'dev'
17
- Description-Content-Type: text/markdown
18
-
19
- # spatial_graph
1
+ # spatial-graph
20
2
 
3
+ [![License](https://img.shields.io/pypi/l/spatial-graph.svg?color=green)](https://github.com/funkelab/spatial_graph/raw/main/LICENSE)
4
+ [![PyPI](https://img.shields.io/pypi/v/spatial-graph.svg?color=green)](https://pypi.org/project/spatial-graph)
5
+ [![Python Version](https://img.shields.io/pypi/pyversions/spatial-graph.svg?color=green)](https://python.org)
21
6
  [![CI](https://github.com/funkelab/spatial_graph/actions/workflows/ci.yaml/badge.svg)](https://github.com/funkelab/spatial_graph/actions/workflows/ci.yaml)
7
+ [![codecov](https://codecov.io/gh/funkelab/spatial_graph/branch/main/graph/badge.svg)](https://codecov.io/gh/funkelab/spatial_graph)
22
8
 
23
9
  `spatial_graph` provides a data structure for directed and undirected graphs,
24
10
  where each node has an nD position (in time or space).
25
11
 
26
- Design Principles
27
- =================
12
+ ## Design Principles
28
13
 
29
- Goals
30
- -----
14
+ ### Goals
31
15
 
32
16
  * support for arbitrary number of dimensions
33
17
  * typed node identifiers and attributes
@@ -45,8 +29,7 @@ Goals
45
29
  * numpy for array interfaces
46
30
  * PYX API for graph algorithms in C/C++
47
31
 
48
- Non-Goals
49
- ---------
32
+ ### Non-Goals
50
33
 
51
34
  * graph algorithms
52
35
  * I/O
@@ -55,8 +38,7 @@ Non-Goals
55
38
  * out-of-memory support
56
39
  * networkx compatibility
57
40
 
58
- Python API
59
- ==========
41
+ ## Python API
60
42
 
61
43
  Graph creation:
62
44
 
@@ -122,9 +104,21 @@ Delete nodes/edges:
122
104
  graph.remove_nodes(nodes[:1000])
123
105
  ```
124
106
 
125
- Implementation Details
126
- ======================
107
+ ## Implementation Details
127
108
 
128
109
  A `SpatialGraph` consists of three data structures:
110
+
129
111
  * The `Graph` itself, holding nodes, edges, and their attributes ([graphlite](https://github.com/haasdo95/graphlite)).
130
112
  * Two R-trees for spatial node and edge queries (based on [rtree.c](https://github.com/tidwall/rtree.c)).
113
+
114
+ ## For Developers
115
+
116
+ To create a new release, tag the current commit with a
117
+ version number and push it to the `upstream` remote:
118
+
119
+ ```bash
120
+ git tag -a "vX.Y.Z" -m "vX.Y.Z"
121
+ git push upstream --follow-tags
122
+ ```
123
+
124
+ This will trigger the CI workflow, which will build the package and upload it to PyPI.
@@ -0,0 +1,142 @@
1
+ # /// script
2
+ # requires-python = ">=3.13"
3
+ # dependencies = [
4
+ # "spatial-graph",
5
+ # ]
6
+ # [tool.uv.sources]
7
+ # spatial-graph = { path = ".." }
8
+ # ///
9
+
10
+ import numpy as np
11
+
12
+ import spatial_graph as sg
13
+
14
+
15
+ def main():
16
+ print("=== Spatial Graph Basic Usage Example ===\n")
17
+
18
+ # 1. Graph creation
19
+ print("1. Creating a 3D spatial graph...")
20
+ graph = sg.SpatialGraph(
21
+ ndims=3,
22
+ node_dtype="uint64",
23
+ node_attr_dtypes={"position": "double[3]"},
24
+ edge_attr_dtypes={"score": "float32"},
25
+ position_attr="position",
26
+ directed=False,
27
+ )
28
+ print(f" Created graph with {graph.ndims} dimensions")
29
+ print(f" Node dtype: {graph.node_dtype}")
30
+ print(f" Directed: {graph.directed}")
31
+ print()
32
+
33
+ # 2. Adding nodes
34
+ print("2. Adding nodes with positions...")
35
+ nodes = np.array([1, 2, 3, 4, 5], dtype="uint64")
36
+ positions = np.array(
37
+ [
38
+ [0.1, 0.1, 0.1],
39
+ [0.2, 0.2, 0.2],
40
+ [0.3, 0.3, 0.3],
41
+ [0.4, 0.4, 0.4],
42
+ [0.5, 0.5, 0.5],
43
+ ],
44
+ dtype="double",
45
+ )
46
+
47
+ graph.add_nodes(nodes, position=positions)
48
+ print(f" Added {len(nodes)} nodes")
49
+ print(f" Node IDs: {nodes}")
50
+ print(f" Positions shape: {positions.shape}")
51
+ print()
52
+
53
+ # 3. Adding edges
54
+ print("3. Adding edges with scores...")
55
+ edges = np.array([[1, 2], [3, 4], [5, 1]], dtype="uint64")
56
+ scores = np.array([0.2, 0.3, 0.4], dtype="float32")
57
+
58
+ graph.add_edges(edges, score=scores)
59
+ print(f" Added {len(edges)} edges")
60
+ print(f" Edges: {edges}")
61
+ print(f" Scores: {scores}")
62
+ print()
63
+
64
+ # 4. Query nodes in ROI
65
+ print("4. Querying nodes in ROI...")
66
+ roi = np.array([[0.0, 0.0, 0.0], [0.25, 0.25, 0.25]])
67
+ nodes_in_roi = graph.query_nodes_in_roi(roi)
68
+ print(f" ROI: {roi}")
69
+ print(f" Nodes in ROI: {nodes_in_roi}")
70
+ print()
71
+
72
+ # 5. Query edges in ROI
73
+ print("5. Querying edges in ROI...")
74
+ edges_in_roi = graph.query_edges_in_roi(roi)
75
+ print(f" Edges in ROI: {edges_in_roi}")
76
+ print()
77
+
78
+ # 6. Query nearest nodes
79
+ print("6. Querying nearest nodes...")
80
+ query_point = np.array([0.3, 0.3, 0.3])
81
+ nearest_nodes = graph.query_nearest_nodes(query_point, k=3)
82
+ print(f" Query point: {query_point}")
83
+ print(f" 3 nearest nodes: {nearest_nodes}")
84
+ print()
85
+
86
+ # 7. Query nearest edges
87
+ print("7. Querying nearest edges...")
88
+ nearest_edges = graph.query_nearest_edges(query_point, k=2)
89
+ print(f" 2 nearest edges: {nearest_edges}")
90
+ print()
91
+
92
+ # 8. Access node attributes
93
+ print("8. Accessing node attributes...")
94
+ if len(nodes_in_roi) > 0:
95
+ node_positions = graph.node_attrs[nodes_in_roi].position
96
+ print(" Positions of nodes in ROI:")
97
+ for i, (node_id, pos) in enumerate(zip(nodes_in_roi, node_positions)):
98
+ print(f" Node {node_id}: {pos}")
99
+ print()
100
+
101
+ # 9. Access edge attributes
102
+ print("9. Accessing edge attributes...")
103
+ if len(edges_in_roi) > 0:
104
+ edge_scores = graph.edge_attrs[edges_in_roi].score
105
+ print(" Scores of edges in ROI:")
106
+ for i, (edge_idx, score) in enumerate(zip(edges_in_roi, edge_scores)):
107
+ print(f" Edge index {edge_idx}: score = {score}")
108
+ print()
109
+
110
+ # 10. Graph statistics before removal
111
+ print("10. Graph statistics before node removal...")
112
+ print(f" Total nodes: {len(graph.nodes)}")
113
+ print(f" Total edges: {len(graph.edges)}")
114
+ print()
115
+
116
+ # 11. Remove some nodes
117
+ print("11. Removing nodes...")
118
+ nodes_to_remove = nodes[:2] # Remove first 2 nodes
119
+ print(f" Removing nodes: {nodes_to_remove}")
120
+ graph.remove_nodes(nodes_to_remove)
121
+ print(f" Nodes after removal: {len(graph.nodes)}")
122
+ print(f" Edges after removal: {len(graph.edges)}")
123
+ print()
124
+
125
+ # 12. Final query to show updated graph
126
+ print("12. Final query on updated graph...")
127
+ remaining_nodes = graph.query_nodes_in_roi(
128
+ np.array([[0.0, 0.0, 0.0], [1.0, 1.0, 1.0]])
129
+ )
130
+ print(f" Remaining nodes: {remaining_nodes}")
131
+
132
+ if len(remaining_nodes) > 0:
133
+ remaining_positions = graph.node_attrs[remaining_nodes].position
134
+ print(" Remaining node positions:")
135
+ for node_id, pos in zip(remaining_nodes, remaining_positions):
136
+ print(f" Node {node_id}: {pos}")
137
+
138
+ print("\n=== Example completed successfully! ===")
139
+
140
+
141
+ if __name__ == "__main__":
142
+ main()
@@ -0,0 +1,123 @@
1
+ # /// script
2
+ # requires-python = ">=3.13"
3
+ # dependencies = [
4
+ # "pyopengl",
5
+ # "pyqt6",
6
+ # "vispy",
7
+ # "spatial-graph",
8
+ # ]
9
+ # [tool.uv.sources]
10
+ # spatial-graph = { path = ".." }
11
+ # ///
12
+ from time import time
13
+
14
+ import numpy as np
15
+ from vispy import app, scene
16
+
17
+ from spatial_graph import SpatialGraph
18
+
19
+ canvas = scene.SceneCanvas(keys="interactive", size=(800, 600), show=True)
20
+ canvas.measure_fps()
21
+
22
+ view = canvas.central_widget.add_view()
23
+
24
+ camera = scene.cameras.FlyCamera(parent=view.scene, fov=60.0, name="Fly")
25
+ view.camera = camera
26
+
27
+ graph = SpatialGraph(
28
+ ndims=3,
29
+ node_dtype="uint64",
30
+ node_attr_dtypes={"position": "double[3]"},
31
+ edge_attr_dtypes={"score": "float32"},
32
+ position_attr="position",
33
+ directed=False,
34
+ )
35
+ nodes = np.arange(100_000, dtype="uint64")
36
+ graph.add_nodes(nodes, position=np.random.random((100_000, 3)))
37
+
38
+ highlight_markers = scene.visuals.Markers(size=20.0, scaling="scene", spherical=True)
39
+ highlight_markers.parent = view.scene
40
+ node_markers = scene.visuals.Markers(
41
+ pos=graph.node_attrs[nodes].position, size=10.0, scaling="scene", spherical=True
42
+ )
43
+ node_markers.parent = view.scene
44
+ axis_markers = scene.visuals.Markers(
45
+ pos=np.array(
46
+ [
47
+ [0, 0, 0],
48
+ [1, 0, 0],
49
+ [0, 1, 0],
50
+ [0, 0, 1],
51
+ ]
52
+ ),
53
+ face_color=np.array(
54
+ [
55
+ [0.5, 0.5, 0.5],
56
+ [1, 0, 0],
57
+ [0, 1, 0],
58
+ [0, 0, 1],
59
+ ]
60
+ ),
61
+ size=11,
62
+ scaling="scene",
63
+ spherical=True,
64
+ )
65
+ axis_markers.parent = view.scene
66
+
67
+ get_data_time = 0.0
68
+ set_data_time = 0.0
69
+ set_data_count = 0
70
+
71
+
72
+ @canvas.events.mouse_move.connect
73
+ def on_mouse_move(event):
74
+ global get_data_time
75
+ global set_data_time
76
+ global set_data_count
77
+ start = time()
78
+ positions = graph.node_attrs[nodes].position
79
+ get_data_time += time() - start
80
+ start = time()
81
+ node_markers.set_data(pos=positions, size=10)
82
+ set_data_time += time() - start
83
+ set_data_count += 1
84
+ if set_data_count > 100:
85
+ print(f"get_data(): {get_data_time / 100:.3f}s")
86
+ print(f"set_data(): {set_data_time / 100:.3f}s")
87
+ set_data_count = 0
88
+ get_data_time = 0.0
89
+ set_data_time = 0.0
90
+
91
+ x_pos = event.pos[0]
92
+ y_pos = event.pos[1]
93
+
94
+ transform = node_markers.transforms.get_transform(map_from="scene", map_to="canvas")
95
+ direction = transform.imap([x_pos, y_pos, 1.0])
96
+ direction = -((direction / direction[3])[:3])
97
+ direction /= np.linalg.norm(direction)
98
+ camera_center = np.array(camera.center)
99
+ z0_plane_intersection = (
100
+ camera_center - (camera_center[2] / direction[2]) * direction
101
+ )
102
+
103
+ # get closest nodes to mouse position
104
+ closest, distances = graph.query_nearest_nodes(
105
+ z0_plane_intersection, k=10_000, return_distances=True
106
+ )
107
+ positions = graph.node_attrs[closest].position
108
+ query = np.array([z0_plane_intersection])
109
+ max_distance = distances.max()
110
+ blend_coeffs = distances[:, np.newaxis] / max_distance
111
+ colors = (
112
+ np.tile([1.0, 0.5, 0.0], (len(positions), 1)) * (1.0 - blend_coeffs)
113
+ + np.ones((len(positions), 3)) * blend_coeffs
114
+ )
115
+ highlight_markers.set_data(
116
+ pos=np.concatenate((query, positions)),
117
+ size=np.concatenate(([14], 10.0 + (1.0 - distances / max_distance) * 2)),
118
+ face_color=np.concatenate(([[1.0, 0.5, 1.0]], colors)),
119
+ )
120
+
121
+
122
+ if __name__ == "__main__":
123
+ app.run()
@@ -0,0 +1,77 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [tool.hatch.version]
6
+ source = "vcs"
7
+
8
+
9
+ [project]
10
+ name = "spatial-graph"
11
+ dynamic = ["version"]
12
+ description = "A spatial graph datastructure for python."
13
+ readme = "README.md"
14
+ requires-python = ">=3.9"
15
+ license = { text = "MIT" }
16
+ authors = [
17
+ { email = "funkej@janelia.hhmi.org", name = "Jan Funke" },
18
+ { email = "talley.lambert@gmail.com", name = "Talley Lambert" },
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 3 - Alpha",
22
+ "Intended Audience :: Developers",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Typing :: Typed",
30
+ ]
31
+ dependencies = ["witty>=v0.2.1", "CT3>=3.3.3", "numpy", "setuptools>=75.8.0"]
32
+
33
+ [dependency-groups]
34
+ dev = [
35
+ "ipython>=8.18.1",
36
+ "mypy>=1.15.0",
37
+ "pre-commit>=4.2.0",
38
+ "pytest>=8.3.5",
39
+ "pytest-cov>=6.1.1",
40
+ "ruff>=0.11.10",
41
+ ]
42
+
43
+
44
+ [project.urls]
45
+ homepage = "https://github.com/funkelab/spatial_graph"
46
+ repository = "https://github.com/funkelab/spatial_graph"
47
+
48
+ [tool.ruff]
49
+ target-version = "py39"
50
+ line-length = 88
51
+
52
+ [tool.ruff.lint]
53
+ select = [
54
+ "E", # style errors
55
+ "F", # flakes
56
+ "W", # warnings
57
+ "I", # isort
58
+ "UP", # pyupgrade
59
+ "TC", # typing
60
+ "TID", # tidy imports
61
+ "RUF", # ruff
62
+ ]
63
+
64
+ [tool.ruff.format]
65
+ docstring-code-format = true
66
+
67
+ [tool.mypy]
68
+ files = "*.py"
69
+ strict = false
70
+ disallow_any_generics = false
71
+ disallow_subclassing_any = false
72
+ show_error_codes = true
73
+ pretty = true
74
+
75
+ [tool.pytest.ini_options]
76
+ addopts = "-v --color=yes"
77
+ filterwarnings = ["error", "ignore:'cgi' is deprecated"]
@@ -0,0 +1,13 @@
1
+ from importlib.metadata import PackageNotFoundError, version
2
+
3
+ try:
4
+ __version__ = version("spatial_graph")
5
+ except PackageNotFoundError:
6
+ __version__ = "unknown"
7
+
8
+
9
+ from .graph import Graph
10
+ from .rtree import LineRTree, PointRTree
11
+ from .spatial_graph import SpatialGraph
12
+
13
+ __all__ = ["Graph", "LineRTree", "PointRTree", "SpatialGraph"]