helios-network 0.10.1__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.
- helios_network-0.10.1/PKG-INFO +239 -0
- helios_network-0.10.1/README.md +225 -0
- helios_network-0.10.1/docs/API.md +142 -0
- helios_network-0.10.1/docs/PYDOC.md +77 -0
- helios_network-0.10.1/examples/attributes.py +16 -0
- helios_network-0.10.1/examples/basic_usage.py +14 -0
- helios_network-0.10.1/examples/conversions.py +27 -0
- helios_network-0.10.1/examples/generate_umap_example_networks.py +244 -0
- helios_network-0.10.1/examples/saving_loading.py +15 -0
- helios_network-0.10.1/examples/selectors.py +22 -0
- helios_network-0.10.1/examples/toroidal_dimensions_plot.py +216 -0
- helios_network-0.10.1/examples/toroidal_dimensions_table.py +110 -0
- helios_network-0.10.1/examples/toroidal_methods_order2_plot.py +418 -0
- helios_network-0.10.1/examples/toroidal_order2_method_average_fivex_r40.png +0 -0
- helios_network-0.10.1/examples/toroidal_order2_method_average_large.png +0 -0
- helios_network-0.10.1/examples/toroidal_order2_method_average_tenx_r40.png +0 -0
- helios_network-0.10.1/examples/toroidal_order2_method_average_xlarge.png +0 -0
- helios_network-0.10.1/examples/toroidal_order2_method_average_xlarge_r40.png +0 -0
- helios_network-0.10.1/examples/toroidal_order2_method_average_xxlarge_r40.png +0 -0
- helios_network-0.10.1/meson.build +96 -0
- helios_network-0.10.1/pyproject.toml +28 -0
- helios_network-0.10.1/src/helios_network/__init__.py +291 -0
- helios_network-0.10.1/src/helios_network/_conversions.py +272 -0
- helios_network-0.10.1/src/helios_network/_core.c +3675 -0
- helios_network-0.10.1/src/helios_network/_node_link_json.py +313 -0
- helios_network-0.10.1/src/helios_network/_wrapper.py +2419 -0
- helios_network-0.10.1/src/helios_network/umap.py +556 -0
- helios_network-0.10.1/tests/test_conversions.py +56 -0
- helios_network-0.10.1/tests/test_network.py +869 -0
- helios_network-0.10.1/tests/test_umap.py +216 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: helios-network
|
|
3
|
+
Version: 0.10.1
|
|
4
|
+
Summary: Helios Network Python bindings
|
|
5
|
+
Author: Helios
|
|
6
|
+
License: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Provides-Extra: umap
|
|
9
|
+
Requires-Dist: numpy>=1.23; extra == "umap"
|
|
10
|
+
Requires-Dist: scipy>=1.10; extra == "umap"
|
|
11
|
+
Requires-Dist: umap-learn>=0.5.7; extra == "umap"
|
|
12
|
+
Requires-Dist: pynndescent>=0.5.12; extra == "umap"
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# Helios Network (Python)
|
|
16
|
+
|
|
17
|
+
Python bindings for the Helios Network C core.
|
|
18
|
+
|
|
19
|
+
## Quick start
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from helios_network import AttributeScope, AttributeType, Network
|
|
23
|
+
|
|
24
|
+
network = Network(directed=False)
|
|
25
|
+
node_ids = network.add_nodes(3)
|
|
26
|
+
network.add_edges([(node_ids[0], node_ids[1])])
|
|
27
|
+
|
|
28
|
+
network.define_attribute(AttributeScope.Node, "weight", AttributeType.Double, 1)
|
|
29
|
+
network.nodes["weight"] = 1.0
|
|
30
|
+
|
|
31
|
+
# Auto-define attributes on assignment
|
|
32
|
+
network.nodes["score"] = 2.5
|
|
33
|
+
|
|
34
|
+
network.define_attribute(AttributeScope.Network, "title", AttributeType.String, 1)
|
|
35
|
+
network.network["title"] = "demo"
|
|
36
|
+
print(network.graph["title"])
|
|
37
|
+
network["title"] = "demo2"
|
|
38
|
+
|
|
39
|
+
# Node access
|
|
40
|
+
print(network.nodes[node_ids[0]]["weight"])
|
|
41
|
+
network.nodes[[node_ids[0], node_ids[1]]]["weight"] = [2.0, 3.0]
|
|
42
|
+
|
|
43
|
+
for node in network.nodes:
|
|
44
|
+
node["weight"] = 4.0
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Selectors
|
|
48
|
+
|
|
49
|
+
- `network.nodes[id]` returns a node view
|
|
50
|
+
- `network.nodes[[id1, id2]]` returns a selector for active nodes
|
|
51
|
+
- `network.nodes["attr"]` returns a list of attribute values for active nodes
|
|
52
|
+
- `network.nodes["attr"] = value` assigns a constant to all active nodes
|
|
53
|
+
- `network.nodes[[id1, id2]]["attr"] = [v1, v2]` assigns per-node values
|
|
54
|
+
|
|
55
|
+
Edge access mirrors node access via `network.edges`, with `network.edges.pairs()` yielding `(source, target)` tuples.
|
|
56
|
+
|
|
57
|
+
For large generated graphs, avoid materializing Python `(source, target)` tuples:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from array import array
|
|
61
|
+
|
|
62
|
+
network.add_nodes(1_000_000)
|
|
63
|
+
network.add_edges_from_arrays(
|
|
64
|
+
array("I", sources),
|
|
65
|
+
array("I", targets),
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Network Generators
|
|
70
|
+
|
|
71
|
+
The Python package exposes native generators as module-level constructors:
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
from helios_network import generate_watts_strogatz
|
|
75
|
+
|
|
76
|
+
network = generate_watts_strogatz(
|
|
77
|
+
5_000,
|
|
78
|
+
neighbor_level=2,
|
|
79
|
+
rewiring_probability=0.01,
|
|
80
|
+
seed=1,
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Available generators include `generate_stochastic_block_model`,
|
|
85
|
+
`generate_barabasi_albert`, `generate_watts_strogatz`,
|
|
86
|
+
`generate_random_geometric`, `generate_waxman`,
|
|
87
|
+
`generate_configuration_model`, and `generate_lattice_2d`.
|
|
88
|
+
|
|
89
|
+
### Edge indices
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
for edge_id, (source, target) in network.edges.with_indices():
|
|
93
|
+
print(edge_id, source, target)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Measurements and Community Detection
|
|
97
|
+
|
|
98
|
+
The Python wrapper exposes the native measurement APIs:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
degree = network.measure_degree(direction="both")
|
|
102
|
+
components = network.measure_connected_components(mode="weak")
|
|
103
|
+
leiden = network.leiden_modularity(
|
|
104
|
+
resolution=1.0,
|
|
105
|
+
seed=42,
|
|
106
|
+
out_node_community_attribute="community",
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`leiden_modularity(...)` is an alias for `measure_leiden_modularity(...)`. It
|
|
111
|
+
writes an unsigned-integer node attribute and returns `community_count`,
|
|
112
|
+
`modularity`, and `values_by_node`.
|
|
113
|
+
|
|
114
|
+
To label only major components for filtering or visualization:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
major = network.label_major_components(
|
|
118
|
+
mode="weak",
|
|
119
|
+
max_components=3,
|
|
120
|
+
min_size=100,
|
|
121
|
+
out_node_component_attribute="major_component",
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Selected components receive rank labels `1..N` by decreasing size. Other nodes
|
|
126
|
+
receive `0` by default.
|
|
127
|
+
|
|
128
|
+
The Leiden comparison harness in `research/benchmarks/leiden_compare/` uses a
|
|
129
|
+
conda environment file:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
conda env create -f research/benchmarks/leiden_compare/environment.yml
|
|
133
|
+
conda run -n helios-leiden-compare python -m pip install -e python --no-build-isolation
|
|
134
|
+
conda run -n helios-leiden-compare python research/benchmarks/leiden_compare/compare_leiden.py
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Installation
|
|
138
|
+
|
|
139
|
+
Standard install:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
python -m pip install ./python --upgrade
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Editable install (recommended during development):
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
python -m pip install -e python --no-build-isolation
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`mesonpy` editable builds require `--no-build-isolation`.
|
|
152
|
+
|
|
153
|
+
If editable install fails, install build tools in the active environment:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
python -m pip install meson ninja meson-python
|
|
157
|
+
python -m pip install -e python --no-build-isolation
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Optional conversions
|
|
161
|
+
|
|
162
|
+
NetworkX and igraph conversions are optional. Install when needed:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
python -m pip install networkx
|
|
166
|
+
python -m pip install igraph
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## UMAP export
|
|
170
|
+
|
|
171
|
+
Install the optional UMAP stack when you want a Helios-ready fuzzy graph or
|
|
172
|
+
kNN graph export:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
python -m pip install ./python[umap]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from helios_network import HeliosUMAP
|
|
180
|
+
|
|
181
|
+
umap_export = HeliosUMAP(
|
|
182
|
+
n_neighbors=15,
|
|
183
|
+
min_dist=0.1,
|
|
184
|
+
build_knn_network=True,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
network = umap_export.fit_network(X)
|
|
188
|
+
network.save_bxnet("embedding.bxnet")
|
|
189
|
+
|
|
190
|
+
# Optional directed kNN export
|
|
191
|
+
umap_export.knn_network_.save_zxnet("embedding-knn.zxnet")
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
If you want only the UMAP graph construction output for `helios-web-next`
|
|
195
|
+
to lay out from scratch, use the graph-only export path instead:
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
graph_network = umap_export.fit_graph_network(X)
|
|
199
|
+
graph_network.save_zxnet("umap-graph.zxnet")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The fit graph export writes:
|
|
203
|
+
|
|
204
|
+
- node attributes: `umap_embedding`, `_helios_visuals_position`, `umap_mass`
|
|
205
|
+
- edge attribute: `umap_weight`
|
|
206
|
+
- network attributes that let `helios-web-next` auto-enable UMAP force mode on import
|
|
207
|
+
|
|
208
|
+
The graph-only export writes the same UMAP edge weights and graph metadata, but
|
|
209
|
+
omits `umap_embedding` and `_helios_visuals_position` so `helios-web-next` can
|
|
210
|
+
start its own realtime UMAP-like layout from scratch.
|
|
211
|
+
|
|
212
|
+
## Examples
|
|
213
|
+
|
|
214
|
+
From `python/`:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
python examples/basic_usage.py
|
|
218
|
+
python examples/toroidal_dimensions_table.py
|
|
219
|
+
python examples/toroidal_dimensions_plot.py --skip-plot
|
|
220
|
+
python examples/toroidal_dimensions_plot.py
|
|
221
|
+
python examples/toroidal_dimensions_plot.py --large --skip-plot
|
|
222
|
+
python examples/generate_umap_example_networks.py --sizes 200 2000 20000
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`toroidal_dimensions_plot.py` uses `matplotlib` for plotting local dimension curves. Install it with:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
python -m pip install matplotlib
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Vector attributes
|
|
232
|
+
|
|
233
|
+
Attributes with dimension > 1 accept vector assignments:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
network.define_attribute(AttributeScope.Node, "i3", AttributeType.Integer, 3)
|
|
237
|
+
network.nodes["i3"] = [1, 2, 3] # broadcast to all nodes
|
|
238
|
+
network.nodes[[0, 1]]["i3"] = [[4, 5, 6], [7, 8, 9]]
|
|
239
|
+
```
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Helios Network (Python)
|
|
2
|
+
|
|
3
|
+
Python bindings for the Helios Network C core.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from helios_network import AttributeScope, AttributeType, Network
|
|
9
|
+
|
|
10
|
+
network = Network(directed=False)
|
|
11
|
+
node_ids = network.add_nodes(3)
|
|
12
|
+
network.add_edges([(node_ids[0], node_ids[1])])
|
|
13
|
+
|
|
14
|
+
network.define_attribute(AttributeScope.Node, "weight", AttributeType.Double, 1)
|
|
15
|
+
network.nodes["weight"] = 1.0
|
|
16
|
+
|
|
17
|
+
# Auto-define attributes on assignment
|
|
18
|
+
network.nodes["score"] = 2.5
|
|
19
|
+
|
|
20
|
+
network.define_attribute(AttributeScope.Network, "title", AttributeType.String, 1)
|
|
21
|
+
network.network["title"] = "demo"
|
|
22
|
+
print(network.graph["title"])
|
|
23
|
+
network["title"] = "demo2"
|
|
24
|
+
|
|
25
|
+
# Node access
|
|
26
|
+
print(network.nodes[node_ids[0]]["weight"])
|
|
27
|
+
network.nodes[[node_ids[0], node_ids[1]]]["weight"] = [2.0, 3.0]
|
|
28
|
+
|
|
29
|
+
for node in network.nodes:
|
|
30
|
+
node["weight"] = 4.0
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Selectors
|
|
34
|
+
|
|
35
|
+
- `network.nodes[id]` returns a node view
|
|
36
|
+
- `network.nodes[[id1, id2]]` returns a selector for active nodes
|
|
37
|
+
- `network.nodes["attr"]` returns a list of attribute values for active nodes
|
|
38
|
+
- `network.nodes["attr"] = value` assigns a constant to all active nodes
|
|
39
|
+
- `network.nodes[[id1, id2]]["attr"] = [v1, v2]` assigns per-node values
|
|
40
|
+
|
|
41
|
+
Edge access mirrors node access via `network.edges`, with `network.edges.pairs()` yielding `(source, target)` tuples.
|
|
42
|
+
|
|
43
|
+
For large generated graphs, avoid materializing Python `(source, target)` tuples:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from array import array
|
|
47
|
+
|
|
48
|
+
network.add_nodes(1_000_000)
|
|
49
|
+
network.add_edges_from_arrays(
|
|
50
|
+
array("I", sources),
|
|
51
|
+
array("I", targets),
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Network Generators
|
|
56
|
+
|
|
57
|
+
The Python package exposes native generators as module-level constructors:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from helios_network import generate_watts_strogatz
|
|
61
|
+
|
|
62
|
+
network = generate_watts_strogatz(
|
|
63
|
+
5_000,
|
|
64
|
+
neighbor_level=2,
|
|
65
|
+
rewiring_probability=0.01,
|
|
66
|
+
seed=1,
|
|
67
|
+
)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Available generators include `generate_stochastic_block_model`,
|
|
71
|
+
`generate_barabasi_albert`, `generate_watts_strogatz`,
|
|
72
|
+
`generate_random_geometric`, `generate_waxman`,
|
|
73
|
+
`generate_configuration_model`, and `generate_lattice_2d`.
|
|
74
|
+
|
|
75
|
+
### Edge indices
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
for edge_id, (source, target) in network.edges.with_indices():
|
|
79
|
+
print(edge_id, source, target)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Measurements and Community Detection
|
|
83
|
+
|
|
84
|
+
The Python wrapper exposes the native measurement APIs:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
degree = network.measure_degree(direction="both")
|
|
88
|
+
components = network.measure_connected_components(mode="weak")
|
|
89
|
+
leiden = network.leiden_modularity(
|
|
90
|
+
resolution=1.0,
|
|
91
|
+
seed=42,
|
|
92
|
+
out_node_community_attribute="community",
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`leiden_modularity(...)` is an alias for `measure_leiden_modularity(...)`. It
|
|
97
|
+
writes an unsigned-integer node attribute and returns `community_count`,
|
|
98
|
+
`modularity`, and `values_by_node`.
|
|
99
|
+
|
|
100
|
+
To label only major components for filtering or visualization:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
major = network.label_major_components(
|
|
104
|
+
mode="weak",
|
|
105
|
+
max_components=3,
|
|
106
|
+
min_size=100,
|
|
107
|
+
out_node_component_attribute="major_component",
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Selected components receive rank labels `1..N` by decreasing size. Other nodes
|
|
112
|
+
receive `0` by default.
|
|
113
|
+
|
|
114
|
+
The Leiden comparison harness in `research/benchmarks/leiden_compare/` uses a
|
|
115
|
+
conda environment file:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
conda env create -f research/benchmarks/leiden_compare/environment.yml
|
|
119
|
+
conda run -n helios-leiden-compare python -m pip install -e python --no-build-isolation
|
|
120
|
+
conda run -n helios-leiden-compare python research/benchmarks/leiden_compare/compare_leiden.py
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Installation
|
|
124
|
+
|
|
125
|
+
Standard install:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
python -m pip install ./python --upgrade
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Editable install (recommended during development):
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
python -m pip install -e python --no-build-isolation
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`mesonpy` editable builds require `--no-build-isolation`.
|
|
138
|
+
|
|
139
|
+
If editable install fails, install build tools in the active environment:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
python -m pip install meson ninja meson-python
|
|
143
|
+
python -m pip install -e python --no-build-isolation
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Optional conversions
|
|
147
|
+
|
|
148
|
+
NetworkX and igraph conversions are optional. Install when needed:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
python -m pip install networkx
|
|
152
|
+
python -m pip install igraph
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## UMAP export
|
|
156
|
+
|
|
157
|
+
Install the optional UMAP stack when you want a Helios-ready fuzzy graph or
|
|
158
|
+
kNN graph export:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
python -m pip install ./python[umap]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from helios_network import HeliosUMAP
|
|
166
|
+
|
|
167
|
+
umap_export = HeliosUMAP(
|
|
168
|
+
n_neighbors=15,
|
|
169
|
+
min_dist=0.1,
|
|
170
|
+
build_knn_network=True,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
network = umap_export.fit_network(X)
|
|
174
|
+
network.save_bxnet("embedding.bxnet")
|
|
175
|
+
|
|
176
|
+
# Optional directed kNN export
|
|
177
|
+
umap_export.knn_network_.save_zxnet("embedding-knn.zxnet")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
If you want only the UMAP graph construction output for `helios-web-next`
|
|
181
|
+
to lay out from scratch, use the graph-only export path instead:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
graph_network = umap_export.fit_graph_network(X)
|
|
185
|
+
graph_network.save_zxnet("umap-graph.zxnet")
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The fit graph export writes:
|
|
189
|
+
|
|
190
|
+
- node attributes: `umap_embedding`, `_helios_visuals_position`, `umap_mass`
|
|
191
|
+
- edge attribute: `umap_weight`
|
|
192
|
+
- network attributes that let `helios-web-next` auto-enable UMAP force mode on import
|
|
193
|
+
|
|
194
|
+
The graph-only export writes the same UMAP edge weights and graph metadata, but
|
|
195
|
+
omits `umap_embedding` and `_helios_visuals_position` so `helios-web-next` can
|
|
196
|
+
start its own realtime UMAP-like layout from scratch.
|
|
197
|
+
|
|
198
|
+
## Examples
|
|
199
|
+
|
|
200
|
+
From `python/`:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
python examples/basic_usage.py
|
|
204
|
+
python examples/toroidal_dimensions_table.py
|
|
205
|
+
python examples/toroidal_dimensions_plot.py --skip-plot
|
|
206
|
+
python examples/toroidal_dimensions_plot.py
|
|
207
|
+
python examples/toroidal_dimensions_plot.py --large --skip-plot
|
|
208
|
+
python examples/generate_umap_example_networks.py --sizes 200 2000 20000
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`toroidal_dimensions_plot.py` uses `matplotlib` for plotting local dimension curves. Install it with:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
python -m pip install matplotlib
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Vector attributes
|
|
218
|
+
|
|
219
|
+
Attributes with dimension > 1 accept vector assignments:
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
network.define_attribute(AttributeScope.Node, "i3", AttributeType.Integer, 3)
|
|
223
|
+
network.nodes["i3"] = [1, 2, 3] # broadcast to all nodes
|
|
224
|
+
network.nodes[[0, 1]]["i3"] = [[4, 5, 6], [7, 8, 9]]
|
|
225
|
+
```
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Helios Network Python API
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Python bindings expose a high-level `Network` class with convenient node/edge/network selectors. Attributes are backed by the native Helios core and can be created explicitly or implicitly.
|
|
6
|
+
|
|
7
|
+
Key concepts:
|
|
8
|
+
- `network.nodes`, `network.edges`: active-only selectors that allow iteration and batch attribute assignment.
|
|
9
|
+
- `network.network` / `network.graph`: network-scope attribute access (single record).
|
|
10
|
+
- `network["attr"]`: shorthand for network-scope attribute access.
|
|
11
|
+
|
|
12
|
+
## Creating Networks
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from helios_network import Network
|
|
16
|
+
|
|
17
|
+
network = Network(directed=False)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Constructor
|
|
21
|
+
|
|
22
|
+
`Network(directed: bool = False, node_capacity: int | None = None, edge_capacity: int | None = None)`
|
|
23
|
+
|
|
24
|
+
- `directed`: If `True`, edges are directed.
|
|
25
|
+
- `node_capacity`, `edge_capacity`: Optional initial capacities.
|
|
26
|
+
|
|
27
|
+
## Nodes and Edges
|
|
28
|
+
|
|
29
|
+
### Iteration
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
for node in network.nodes:
|
|
33
|
+
print(node.id)
|
|
34
|
+
|
|
35
|
+
for edge in network.edges:
|
|
36
|
+
print(edge.id, edge.endpoints)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Edge pairs
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
for source, target in network.edges.pairs():
|
|
43
|
+
print(source, target)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Edge indices + endpoints
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
for edge_id, (source, target) in network.edges.with_indices():
|
|
50
|
+
print(edge_id, source, target)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Attributes
|
|
54
|
+
|
|
55
|
+
### Auto-definition
|
|
56
|
+
|
|
57
|
+
Assigning to an unknown attribute name will create it automatically based on the assigned value.
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
network.nodes["weight"] = 1.0 # creates Double attribute, dimension 1
|
|
61
|
+
network.nodes["i3"] = [1, 2, 3] # creates Integer attribute, dimension 3
|
|
62
|
+
network.edges["weight"] = 0.5 # creates Double attribute on edges
|
|
63
|
+
network["title"] = "demo" # creates String attribute on network scope
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Explicit definition
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from helios_network import AttributeScope, AttributeType
|
|
70
|
+
|
|
71
|
+
network.define_attribute(AttributeScope.Node, "score", AttributeType.Double, 1)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Collection helpers
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
network.nodes.define_attribute("score", float)
|
|
78
|
+
network.edges.define_attribute("weight", AttributeType.Double)
|
|
79
|
+
network.network.define_attribute("title", str)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Attribute access
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
# Single node
|
|
86
|
+
network.nodes[node_id]["score"] = 1.5
|
|
87
|
+
value = network.nodes[node_id]["score"]
|
|
88
|
+
|
|
89
|
+
# Selector
|
|
90
|
+
network.nodes[[id1, id2]]["score"] = [1.0, 2.0]
|
|
91
|
+
values = network.nodes[[id1, id2]]["score"]
|
|
92
|
+
|
|
93
|
+
# All nodes
|
|
94
|
+
network.nodes["score"] = 2.0
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Vector attributes (dimension > 1)
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
network.nodes["i3"] = [1, 2, 3] # broadcast
|
|
101
|
+
network.nodes[[id1, id2]]["i3"] = [[1, 2, 3], [4, 5, 6]]
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
NumPy arrays with shape `(dim,)` or `(count, dim)` are supported when NumPy is installed.
|
|
105
|
+
|
|
106
|
+
## Categorical attributes
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
network.nodes["label"] = ["a", "b", "a"]
|
|
110
|
+
network.categorize_attribute(AttributeScope.Node, "label")
|
|
111
|
+
|
|
112
|
+
mapping = network.get_category_dictionary(AttributeScope.Node, "label")
|
|
113
|
+
# mapping: {"a": 0, "b": 1, ...}
|
|
114
|
+
|
|
115
|
+
network.set_category_dictionary(AttributeScope.Node, "label", {"x": 10, "y": 11}, remap_existing=True)
|
|
116
|
+
network.decategorize_attribute(AttributeScope.Node, "label")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Serialization
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
network.save_xnet("graph.xnet")
|
|
123
|
+
network.save_bxnet("graph.bxnet")
|
|
124
|
+
network.save_zxnet("graph.zxnet")
|
|
125
|
+
network.save_gml("graph.gml")
|
|
126
|
+
network.save_node_link_json("graph.json")
|
|
127
|
+
|
|
128
|
+
loaded = read_xnet("graph.xnet")
|
|
129
|
+
loaded_gml = read_gml("graph.gml")
|
|
130
|
+
loaded_json = read_node_link_json("graph.json")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Conversions
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from helios_network import to_networkx, from_networkx
|
|
137
|
+
|
|
138
|
+
nx_graph = to_networkx(network)
|
|
139
|
+
network2 = from_networkx(nx_graph)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`to_igraph` / `from_igraph` are available when `igraph` is installed.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Helios Network Python Docstrings
|
|
2
|
+
|
|
3
|
+
Below is a summary of the main classes and methods exposed in the Python API.
|
|
4
|
+
This complements the inline docstrings and `python/docs/API.md`.
|
|
5
|
+
|
|
6
|
+
## Network
|
|
7
|
+
|
|
8
|
+
`Network(directed=False, node_capacity=None, edge_capacity=None)`
|
|
9
|
+
|
|
10
|
+
- Creates a network wrapper around the native core.
|
|
11
|
+
- Properties:
|
|
12
|
+
- `nodes`, `edges`: active selectors
|
|
13
|
+
- `network`, `graph`, `attributes`: network-scope selectors
|
|
14
|
+
- `__getitem__(name)` / `__setitem__(name, value)`: network-scope shorthand
|
|
15
|
+
|
|
16
|
+
### Common methods
|
|
17
|
+
|
|
18
|
+
- `node_count() -> int`
|
|
19
|
+
- `edge_count() -> int`
|
|
20
|
+
- `add_nodes(count) -> list[int]`
|
|
21
|
+
- `remove_nodes(indices) -> bool`
|
|
22
|
+
- `add_edges([(from, to), ...]) -> list[int]`
|
|
23
|
+
- `remove_edges(indices) -> bool`
|
|
24
|
+
- `node_indices() -> list[int]`
|
|
25
|
+
- `edge_indices() -> list[int]`
|
|
26
|
+
- `edges_with_indices() -> list[(edge_id, (source, target))]`
|
|
27
|
+
|
|
28
|
+
### Attribute methods
|
|
29
|
+
|
|
30
|
+
- `define_attribute(scope, name, type, dimension=1) -> bool`
|
|
31
|
+
- `nodes.define_attribute(name, type, dimension=1) -> bool`
|
|
32
|
+
- `edges.define_attribute(name, type, dimension=1) -> bool`
|
|
33
|
+
- `network.define_attribute(name, type, dimension=1) -> bool`
|
|
34
|
+
- `attribute_info(scope, name) -> dict`
|
|
35
|
+
- `set_attribute_value(scope, name, index, value) -> bool`
|
|
36
|
+
- `get_attribute_value(scope, name, index)`
|
|
37
|
+
|
|
38
|
+
### Categorical helpers
|
|
39
|
+
|
|
40
|
+
- `categorize_attribute(scope, name, sort_order=None, missing_label=None) -> bool`
|
|
41
|
+
- `decategorize_attribute(scope, name, missing_label=None) -> bool`
|
|
42
|
+
- `get_category_dictionary(scope, name) -> dict[label, id]`
|
|
43
|
+
- `set_category_dictionary(scope, name, mapping_or_pairs, remap_existing=True) -> bool`
|
|
44
|
+
|
|
45
|
+
### Serialization
|
|
46
|
+
|
|
47
|
+
- `save_xnet(path)`
|
|
48
|
+
- `save_bxnet(path)`
|
|
49
|
+
- `save_zxnet(path, compression=6)`
|
|
50
|
+
- `save_gml(path)`
|
|
51
|
+
- `save_node_link_json(path)`
|
|
52
|
+
- `read_gml(path)`
|
|
53
|
+
- `read_node_link_json(path)`
|
|
54
|
+
|
|
55
|
+
## NodeCollection / EdgeCollection
|
|
56
|
+
|
|
57
|
+
Selectors for active nodes/edges. Support iteration and vectorized assignment.
|
|
58
|
+
|
|
59
|
+
### Common behaviors
|
|
60
|
+
|
|
61
|
+
- `collection[id]` -> `NodeView` / `EdgeView`
|
|
62
|
+
- `collection[[ids]]` -> selector for multiple items
|
|
63
|
+
- `collection["attr"]` -> list of values
|
|
64
|
+
- `collection["attr"] = value` -> broadcast or per-item assignment
|
|
65
|
+
|
|
66
|
+
### Convenience
|
|
67
|
+
|
|
68
|
+
- `nodes.define_attribute(name, type, dimension=1)`
|
|
69
|
+
- `edges.define_attribute(name, type, dimension=1)`
|
|
70
|
+
- `network.define_attribute(name, type, dimension=1)`
|
|
71
|
+
|
|
72
|
+
## NodeView / EdgeView / NetworkView
|
|
73
|
+
|
|
74
|
+
Simple wrappers around a single item (node, edge, network).
|
|
75
|
+
|
|
76
|
+
- `node["attr"]` / `edge["attr"]` / `network["attr"]`
|
|
77
|
+
- `edge.endpoints -> (source, target)`
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from helios_network import AttributeScope, AttributeType, Network
|
|
2
|
+
|
|
3
|
+
network = Network(directed=True)
|
|
4
|
+
node_ids = network.add_nodes(3)
|
|
5
|
+
|
|
6
|
+
network.define_attribute(AttributeScope.Node, "weight", AttributeType.Double, 1)
|
|
7
|
+
network.define_attribute(AttributeScope.Node, "label", AttributeType.String, 1)
|
|
8
|
+
|
|
9
|
+
network.nodes["weight"] = 1.0
|
|
10
|
+
network.nodes["label"] = [f"node-{idx}" for idx in range(len(node_ids))]
|
|
11
|
+
|
|
12
|
+
network.nodes[[node_ids[0], node_ids[2]]]["weight"] = [2.5, 3.5]
|
|
13
|
+
|
|
14
|
+
for node in network.nodes:
|
|
15
|
+
print(node)
|
|
16
|
+
print(node.id, node["weight"], node["label"])
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from helios_network import Network
|
|
2
|
+
|
|
3
|
+
network = Network(directed=False)
|
|
4
|
+
node_ids = network.add_nodes(4)
|
|
5
|
+
edge_ids = network.add_edges([
|
|
6
|
+
(node_ids[0], node_ids[1]),
|
|
7
|
+
(node_ids[1], node_ids[2]),
|
|
8
|
+
(node_ids[2], node_ids[3]),
|
|
9
|
+
])
|
|
10
|
+
|
|
11
|
+
print("nodes:", node_ids)
|
|
12
|
+
print("edges:", edge_ids)
|
|
13
|
+
print("node_count:", network.node_count())
|
|
14
|
+
print("edge_count:", network.edge_count())
|