hiveplotlib 0.22.0__tar.gz → 0.24.0__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 (31) hide show
  1. {hiveplotlib-0.22.0/src/hiveplotlib.egg-info → hiveplotlib-0.24.0}/PKG-INFO +10 -8
  2. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/README.md +3 -3
  3. hiveplotlib-0.24.0/pyproject.toml +147 -0
  4. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/setup.py +4 -0
  5. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/axis.py +7 -9
  6. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/converters.py +5 -3
  7. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/datasets/__init__.py +71 -17
  8. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/hiveplot.py +178 -147
  9. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/node.py +41 -44
  10. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/p2cp.py +46 -58
  11. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/utils.py +4 -7
  12. hiveplotlib-0.24.0/src/hiveplotlib/viz/base.py +62 -0
  13. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/viz/bokeh.py +198 -268
  14. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/viz/datashader.py +37 -53
  15. hiveplotlib-0.24.0/src/hiveplotlib/viz/input_checks.py +99 -0
  16. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/viz/matplotlib.py +241 -265
  17. hiveplotlib-0.24.0/src/hiveplotlib/viz/plotly.py +822 -0
  18. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0/src/hiveplotlib.egg-info}/PKG-INFO +10 -8
  19. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib.egg-info/SOURCES.txt +3 -1
  20. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib.egg-info/requires.txt +7 -3
  21. hiveplotlib-0.22.0/pyproject.toml +0 -94
  22. hiveplotlib-0.22.0/src/hiveplotlib/viz/input_checks.py +0 -30
  23. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/LICENSE +0 -0
  24. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/MANIFEST.in +0 -0
  25. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/setup.cfg +0 -0
  26. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/__init__.py +0 -0
  27. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/datasets/trade_data_harvard_growth_lab/international_exports_2019_8112.csv +0 -0
  28. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/datasets/trade_data_harvard_growth_lab/international_exports_metadata_2019_8112.json +0 -0
  29. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib/viz/__init__.py +0 -0
  30. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib.egg-info/dependency_links.txt +0 -0
  31. {hiveplotlib-0.22.0 → hiveplotlib-0.24.0}/src/hiveplotlib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hiveplotlib
3
- Version: 0.22.0
3
+ Version: 0.24.0
4
4
  Summary: Visualize Network Data with Hive Plots
5
5
  Author-email: Gary Koplik <gary.koplik@geomdata.com>
6
6
  License: Copyright (c) 2020 - 2023, Geometric Data Analytics, Inc.
@@ -31,7 +31,7 @@ License: Copyright (c) 2020 - 2023, Geometric Data Analytics, Inc.
31
31
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
32
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33
33
  THE POSSIBILITY OF SUCH DAMAGE.
34
- Project-URL: Documentation, https://geomdata.gitlab.io/hiveplotlib/
34
+ Project-URL: Documentation, https://hiveplotlib.readthedocs.io/stable/
35
35
  Project-URL: Source, https://gitlab.com/geomdata/hiveplotlib
36
36
  Description-Content-Type: text/markdown
37
37
  License-File: LICENSE
@@ -46,6 +46,7 @@ Requires-Dist: seaborn; extra == "datashader"
46
46
  Provides-Extra: dev
47
47
  Requires-Dist: bokeh; extra == "dev"
48
48
  Requires-Dist: datashader; extra == "dev"
49
+ Requires-Dist: flexitext; extra == "dev"
49
50
  Requires-Dist: jupyter; extra == "dev"
50
51
  Requires-Dist: networkx; extra == "dev"
51
52
  Requires-Dist: seaborn; extra == "dev"
@@ -57,17 +58,18 @@ Requires-Dist: sphinx-rtd-theme; extra == "docs"
57
58
  Requires-Dist: toml; extra == "docs"
58
59
  Provides-Extra: networkx
59
60
  Requires-Dist: networkx; extra == "networkx"
61
+ Provides-Extra: plotly
62
+ Requires-Dist: plotly; extra == "plotly"
63
+ Provides-Extra: ruff
64
+ Requires-Dist: ruff; extra == "ruff"
60
65
  Provides-Extra: testing
61
- Requires-Dist: black[jupyter]; extra == "testing"
62
- Requires-Dist: flake8-docstrings; extra == "testing"
63
- Requires-Dist: Flake8-pyproject; extra == "testing"
64
66
  Requires-Dist: pytest; extra == "testing"
65
67
  Requires-Dist: pytest-cov; extra == "testing"
66
68
  Requires-Dist: pytest-html; extra == "testing"
67
69
  Requires-Dist: pytest-timeout; extra == "testing"
68
70
  Requires-Dist: pytest-xdist; extra == "testing"
69
71
 
70
- ![](https://geomdata.gitlab.io/hiveplotlib/_static/hiveplotlib.svg)
72
+ ![](https://hiveplotlib.readthedocs.io/stable/_static/hiveplotlib.svg)
71
73
 
72
74
  A plotting package for generating and visualizing static Hive Plots in `matplotlib`.
73
75
 
@@ -94,7 +96,7 @@ For more on contributing to the project, see [CONTRIBUTING.md](https://gitlab.co
94
96
  # How to Use and Examples
95
97
 
96
98
  For more on how to use the software and examples, see the
97
- [docs](https://geomdata.gitlab.io/hiveplotlib/index.html).
99
+ [docs](https://hiveplotlib.readthedocs.io/stable/index.html).
98
100
 
99
101
  All the example notebooks are available for download as `jupyter` notebooks in the repository under the
100
102
  [examples](https://gitlab.com/geomdata/hiveplotlib/-/tree/master/examples) directory.
@@ -112,7 +114,7 @@ $ bash install.sh
112
114
  # More on Hive Plots
113
115
 
114
116
  For more on Hive Plots, see our
115
- [Introduction to Hive Plots](https://geomdata.gitlab.io/hiveplotlib/introduction_to_hive_plots.html).
117
+ [Introduction to Hive Plots](https://hiveplotlib.readthedocs.io/stable/introduction_to_hive_plots.html).
116
118
 
117
119
  For additional resources, see:
118
120
 
@@ -1,4 +1,4 @@
1
- ![](https://geomdata.gitlab.io/hiveplotlib/_static/hiveplotlib.svg)
1
+ ![](https://hiveplotlib.readthedocs.io/stable/_static/hiveplotlib.svg)
2
2
 
3
3
  A plotting package for generating and visualizing static Hive Plots in `matplotlib`.
4
4
 
@@ -25,7 +25,7 @@ For more on contributing to the project, see [CONTRIBUTING.md](https://gitlab.co
25
25
  # How to Use and Examples
26
26
 
27
27
  For more on how to use the software and examples, see the
28
- [docs](https://geomdata.gitlab.io/hiveplotlib/index.html).
28
+ [docs](https://hiveplotlib.readthedocs.io/stable/index.html).
29
29
 
30
30
  All the example notebooks are available for download as `jupyter` notebooks in the repository under the
31
31
  [examples](https://gitlab.com/geomdata/hiveplotlib/-/tree/master/examples) directory.
@@ -43,7 +43,7 @@ $ bash install.sh
43
43
  # More on Hive Plots
44
44
 
45
45
  For more on Hive Plots, see our
46
- [Introduction to Hive Plots](https://geomdata.gitlab.io/hiveplotlib/introduction_to_hive_plots.html).
46
+ [Introduction to Hive Plots](https://hiveplotlib.readthedocs.io/stable/introduction_to_hive_plots.html).
47
47
 
48
48
  For additional resources, see:
49
49
 
@@ -0,0 +1,147 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools",
4
+ "wheel"
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "hiveplotlib"
10
+ version = "0.24.0"
11
+ authors = [
12
+ {name="Gary Koplik", email="gary.koplik@geomdata.com"}
13
+ ]
14
+ description = "Visualize Network Data with Hive Plots"
15
+ readme = "README.md"
16
+ license = {file = "LICENSE"}
17
+ urls = {Documentation="https://hiveplotlib.readthedocs.io/stable/", Source="https://gitlab.com/geomdata/hiveplotlib" }
18
+
19
+
20
+ dependencies = [
21
+ "matplotlib",
22
+ "numpy",
23
+ "pandas"
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+
28
+ bokeh = [
29
+ "bokeh"
30
+ ]
31
+
32
+ datashader = [
33
+ "datashader",
34
+ "seaborn"
35
+ ]
36
+
37
+ # developer dependencies
38
+ dev = [
39
+ "bokeh",
40
+ "datashader",
41
+ "flexitext",
42
+ "jupyter",
43
+ "networkx",
44
+ "seaborn",
45
+ "tqdm",
46
+ ]
47
+
48
+ # for building documentation
49
+ docs = [
50
+ "nbsphinx",
51
+ "sphinx",
52
+ "sphinx-rtd-theme",
53
+ "toml"
54
+ ]
55
+
56
+ networkx = [
57
+ "networkx"
58
+ ]
59
+
60
+ plotly = [
61
+ "plotly"
62
+ ]
63
+
64
+ # ruff code hygeine checks
65
+ ruff = [
66
+ "ruff"
67
+ ]
68
+
69
+ testing = [
70
+ "pytest",
71
+ "pytest-cov",
72
+ "pytest-html",
73
+ "pytest-timeout",
74
+ "pytest-xdist"
75
+ ]
76
+
77
+ [tool.setuptools.packages.find]
78
+ where = ["src"]
79
+ include = ["hiveplotlib*"]
80
+
81
+ [tool.ruff]
82
+ # ruff performs our linting and formatting.
83
+ # if you receive an error you don't understand, you can run `ruff rule <error code>` to learn more.
84
+ # the full list of ruff rules are here: https://docs.astral.sh/ruff/rules/
85
+ extend-include = ["*.ipynb", "*.pyi"]
86
+
87
+ # Add files here to be completely skipped by ruff.
88
+ extend-exclude = [
89
+ "docs",
90
+ "sandbox"
91
+ ]
92
+
93
+ line-length = 88
94
+ indent-width = 4
95
+
96
+ output-format = "full"
97
+ target-version = "py311"
98
+
99
+ [tool.ruff.lint]
100
+ extend-ignore = [
101
+ "ANN101", # typing `self` being deprecated (and not particularly useful)
102
+ "ANN003", # don't require type hints on kwargs (too many possible types to be useful)
103
+ "D200", # 1-line docstrings will be tolerated
104
+ "D203", # don't require blank line before class docstring.
105
+ "D212", # require Docstring text starts on the next line after the triple quotes.
106
+ "E203", # https://black.readthedocs.io/en/stable/faq.html#why-are-flake8-s-e203-and-w503-violated
107
+ "PD901", # generic `df` name for pandas dataframes will be tolerated
108
+ ]
109
+
110
+ extend-select = [
111
+ "A", # use flake8-builtins (check if variable name shadows python builtin names)
112
+ "ANN", # use flake8-annotations (checks type annotations)
113
+ "ARG", # use flake8-unused-arguments (checks for unused arguments)
114
+ # "B", # use flake8-bugbear (nice for cleaner code, but appears to only work when min Python constraint is 3.9)
115
+ "C4", # use flake8-comprehensions (remove unnecessary literals, generators, lists, etc.)
116
+ "D", # use pydoc style rules
117
+ "E", # use pycodestyle warnings
118
+ "I", # use isort rules
119
+ "ICN", # use flake-import-conventions (checks that imports use standard names)
120
+ "N", # use pep8 naming
121
+ "NPY", # numpy-specific rules
122
+ "PERF", # linter focused on avoiding performance anti-patterns
123
+ "PIE", # use flake8-pie (some misc additional linting)
124
+ "PD", # write pandas code more in line with pd recommendations
125
+ "PT", # use flake8-pytest-style (linting specifically for pytest)
126
+ "RET", # use flake8-return (linting on return / raise)
127
+ "SIM", # use flake8-simplify (helps simplify logic in code)
128
+ "TID", # use flake8-tidy-imports (to prevent relative imports)
129
+ "W", # use pycodestyle warnings
130
+ ]
131
+
132
+ [tool.ruff.lint.pycodestyle]
133
+ # allow docstrings to go longer
134
+ max-line-length = 120
135
+
136
+ [tool.ruff.format]
137
+ # like Black, use double quotes for strings.
138
+ quote-style = "double"
139
+
140
+ # like Black, indent with spaces, rather than tabs.
141
+ indent-style = "space"
142
+
143
+ # like Black, respect magic trailing commas.
144
+ skip-magic-trailing-comma = false
145
+
146
+ # like Black, automatically detect the appropriate line ending.
147
+ line-ending = "auto"
@@ -1,3 +1,7 @@
1
+ """
2
+ Setup.
3
+ """
4
+
1
5
  import setuptools
2
6
 
3
7
  if __name__ == "__main__":
@@ -4,10 +4,12 @@
4
4
  Definition of ``Axis`` instance and helper static methods for generating and working with ``Axis`` instances.
5
5
  """
6
6
 
7
- from hiveplotlib.utils import polar2cartesian
7
+ from typing import Hashable, List, Optional
8
+
8
9
  import numpy as np
9
10
  import pandas as pd
10
- from typing import Hashable, List, Optional
11
+
12
+ from hiveplotlib.utils import polar2cartesian
11
13
 
12
14
 
13
15
  class Axis:
@@ -56,7 +58,7 @@ class Axis:
56
58
  end: float = 5,
57
59
  angle: float = 0,
58
60
  long_name: Optional[Hashable] = None,
59
- ):
61
+ ) -> None:
60
62
  """
61
63
  Initialize ``Axis`` object with start and end positions and angle. Default to axis normalized on [0, 1].
62
64
 
@@ -99,7 +101,7 @@ class Axis:
99
101
 
100
102
  def _set_node_placements(
101
103
  self, x: List[float], y: List[float], node_ids: List[Hashable], rho: List[float]
102
- ):
104
+ ) -> None:
103
105
  """
104
106
  Set ``Axis.node_placements`` to a ``pandas.DataFrame``.
105
107
 
@@ -127,9 +129,7 @@ class Axis:
127
129
  {"x": x, "y": y, "unique_id": node_ids, "rho": rho}
128
130
  )
129
131
 
130
- return None
131
-
132
- def _set_node_placement_label(self, label: Hashable):
132
+ def _set_node_placement_label(self, label: Hashable) -> None:
133
133
  """
134
134
  Set which scalar variable in each ``Node`` instance will be used to place each node on the axis when plotting.
135
135
 
@@ -141,5 +141,3 @@ class Axis:
141
141
  :return: ``None``.
142
142
  """
143
143
  self.node_placement_label = label
144
-
145
- return None
@@ -5,15 +5,17 @@ Converters from various data structures to ``hiveplotlib``-ready structures.
5
5
  """
6
6
 
7
7
 
8
- from hiveplotlib import Node
9
- import numpy as np
10
8
  from typing import List, Tuple
11
9
 
10
+ import numpy as np
11
+
12
+ from hiveplotlib import Node
13
+
12
14
  # say the graph type instead of calling `nx.Graph` to keep networkx dep out of this file.
13
15
  NetworkXGraph = "networkx.classes.graph.Graph instance"
14
16
 
15
17
 
16
- def networkx_to_nodes_edges(graph: NetworkXGraph) -> Tuple[List[Node], np.ndarray]:
18
+ def networkx_to_nodes_edges(graph: NetworkXGraph) -> Tuple[List[Node], np.ndarray]: # type: ignore
17
19
  """
18
20
  Take a ``networkx`` graph and return ``hiveplotlib``-friendly data structures.
19
21
 
@@ -17,11 +17,14 @@ For Polar Parallel Coordinates Plots (P2CPs), many datasets are available throug
17
17
  """
18
18
 
19
19
  import json
20
+ from pathlib import Path
21
+ from typing import Dict, Hashable, List, Optional, Tuple, Union
22
+
20
23
  import numpy as np
21
- from hiveplotlib import hive_plot_n_axes, HivePlot, Node
22
24
  import pandas as pd
23
- from pathlib import Path
24
- from typing import Dict, Optional, Tuple, Union
25
+
26
+ from hiveplotlib import HivePlot, Node, hive_plot_n_axes
27
+ from hiveplotlib.node import dataframe_to_node_list
25
28
 
26
29
 
27
30
  def international_trade_data(
@@ -57,10 +60,7 @@ def international_trade_data(
57
60
  # path when grabbing files shipped with hiveplotlib
58
61
  internal_path = Path(__path__[0]).joinpath("trade_data_harvard_growth_lab")
59
62
 
60
- if path is None:
61
- path = internal_path
62
- else:
63
- path = Path(path)
63
+ path = internal_path if path is None else Path(path)
64
64
 
65
65
  # grab the shipped year, hs92 values to present what's available on failure
66
66
  csv_files = [
@@ -77,12 +77,14 @@ def international_trade_data(
77
77
  metadata_path = path.joinpath(
78
78
  f"international_exports_metadata_{year}_{hs92_code}.json"
79
79
  )
80
- assert data_path.exists() and metadata_path.exists(), (
81
- f"Could not find data and / or metadata under specified `path`. If you specified your own path, double check "
82
- f"that the path is correct. Your file names should be "
83
- f"If you are using `hiveplotlib` supported data, note that only the following `year`, "
84
- f"`hs29_code` values are supported:\n{hiveplotlib_supported_values}"
85
- )
80
+
81
+ if not (data_path.exists() and metadata_path.exists()):
82
+ raise ValueError(
83
+ "Could not find data and / or metadata under specified `path`. If you specified your own path, double "
84
+ "check that the path is correct. Your file names should be "
85
+ "If you are using `hiveplotlib` supported data, note that only the following `year`, "
86
+ f"`hs29_code` values are supported:\n{hiveplotlib_supported_values}"
87
+ )
86
88
 
87
89
  data = pd.read_csv(data_path)
88
90
  with open(metadata_path, "r") as openfile:
@@ -141,13 +143,16 @@ def four_gaussian_blobs_3d(
141
143
  # make the labels ints
142
144
  df.Label = df.Label.astype(int)
143
145
  # replace the 4s with 3s so our labels are just range(4)
144
- df.Label.values[df.Label.values == 4] = 3
146
+ df.Label.to_numpy()[df.Label.to_numpy() == 4] = 3
145
147
 
146
148
  return df
147
149
 
148
150
 
149
151
  def example_hive_plot(
150
- num_nodes: int = 15, num_edges: int = 30, seed: int = 0
152
+ num_nodes: int = 15,
153
+ num_edges: int = 30,
154
+ seed: int = 0,
155
+ **hive_plot_n_axes_kwargs,
151
156
  ) -> HivePlot:
152
157
  """
153
158
  Generate example hive plot with ``"Low"``, ``"Medium"``, and ``"High"`` axes (plus repeat axes).
@@ -157,6 +162,8 @@ def example_hive_plot(
157
162
  :param num_nodes: number of nodes to generate.
158
163
  :param num_edges: number of edges to generate.
159
164
  :param seed: random seed to use when generating nodes and edges.
165
+ :param hive_plot_n_axes_kwargs: additional keyword arguments for the underlying
166
+ :py:func:`hiveplotlib.hive_plot.hive_plot_n_axes()` call.
160
167
  :return: resulting ``HivePlot`` instance.
161
168
  """
162
169
  color_dict = {
@@ -182,7 +189,7 @@ def example_hive_plot(
182
189
  node_data = data.to_dict(orient="records")
183
190
 
184
191
  # use the dataframe's index as unique id
185
- node_ids = data.index.values
192
+ node_ids = data.index.to_numpy()
186
193
 
187
194
  nodes = [
188
195
  Node(unique_id=node_id, data=node_data[i]) for i, node_id in enumerate(node_ids)
@@ -202,7 +209,7 @@ def example_hive_plot(
202
209
  repeat_axes=[True, True, True],
203
210
  axes_names=["Low", "Medium", "High"],
204
211
  orient_angle=-30,
205
- all_edge_kwargs=dict(alpha=1),
212
+ **hive_plot_n_axes_kwargs,
206
213
  )
207
214
 
208
215
  # set colors according to above-defined color dictionary
@@ -212,3 +219,50 @@ def example_hive_plot(
212
219
  hp.add_edge_kwargs(axis_id_1=e1, axis_id_2=e2, color=color_dict[e1][e2])
213
220
 
214
221
  return hp
222
+
223
+
224
+ def example_nodes_and_edges(
225
+ num_nodes: int = 100,
226
+ num_edges: int = 200,
227
+ num_axes: int = 3,
228
+ seed: int = 0,
229
+ ) -> Tuple[List[Node], List[List[Hashable]], np.ndarray]:
230
+ """
231
+ Generate example nodes, node splits (one list of nodes per intended axis), and edges.
232
+
233
+ Each node will have a ``"low"``, ``"med"``, and ``"high"`` value, where these values are randomly generated, and as
234
+ the names suggest, for the resulting values of each node, ``"low"`` < ``"med"`` < ``"high"``.
235
+
236
+ :param num_nodes: how many nodes to randomly generate. Node unique IDs will be the integers 0, 1, ... ,
237
+ ``num_nodes - 1``.
238
+ :param num_edges: how many edges to randomly generate.
239
+ :param num_axes: how many axes into which to partition the randomly generated nodes.
240
+ :param seed: random seed to use when randomly generating node and edge data.
241
+ :return: list of generated ``Node`` instances, a list of ``num_axes`` lists that evenly split the node IDs to be
242
+ allocated to their own axes, and a ``(num_edges, 2)`` shaped array of random edges between nodes.
243
+ """
244
+ rng = np.random.default_rng(seed)
245
+
246
+ # example data
247
+ data = pd.DataFrame(
248
+ np.c_[
249
+ rng.uniform(low=0, high=9.99, size=num_nodes),
250
+ rng.uniform(low=10, high=19.99, size=num_nodes),
251
+ rng.uniform(low=20, high=29.99, size=num_nodes),
252
+ ],
253
+ columns=["low", "med", "high"],
254
+ )
255
+ # make indices a column
256
+ data = data.reset_index()
257
+
258
+ node_list = dataframe_to_node_list(data, unique_id_column="index")
259
+ node_ids = data["index"].to_numpy()
260
+
261
+ # split node allocation equally among planned axes
262
+ node_ids_per_axis = np.split(node_ids, num_axes)
263
+ # coax to list of lists
264
+ node_ids_per_axis = [i.tolist() for i in node_ids_per_axis]
265
+
266
+ edges = rng.choice(node_ids, size=num_edges * 2).reshape(-1, 2)
267
+
268
+ return node_list, node_ids_per_axis, edges