hiveplotlib 0.21__tar.gz → 0.23.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.
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/LICENSE +1 -1
- {hiveplotlib-0.21/src/hiveplotlib.egg-info → hiveplotlib-0.23.0}/PKG-INFO +30 -3
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/pyproject.toml +16 -4
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/axis.py +22 -8
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/datasets/__init__.py +101 -16
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/hiveplot.py +459 -188
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/node.py +21 -14
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/p2cp.py +159 -91
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/utils.py +20 -13
- hiveplotlib-0.23.0/src/hiveplotlib/viz/__init__.py +18 -0
- hiveplotlib-0.23.0/src/hiveplotlib/viz/base.py +61 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/viz/bokeh.py +366 -304
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/viz/datashader.py +147 -98
- hiveplotlib-0.23.0/src/hiveplotlib/viz/input_checks.py +99 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/viz/matplotlib.py +338 -278
- hiveplotlib-0.23.0/src/hiveplotlib/viz/plotly.py +822 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0/src/hiveplotlib.egg-info}/PKG-INFO +30 -3
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/SOURCES.txt +3 -1
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/requires.txt +4 -0
- hiveplotlib-0.21/src/hiveplotlib/viz/__init__.py +0 -16
- hiveplotlib-0.21/src/hiveplotlib/viz/input_checks.py +0 -30
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/MANIFEST.in +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/README.md +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/setup.cfg +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/setup.py +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/__init__.py +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/converters.py +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/datasets/trade_data_harvard_growth_lab/international_exports_2019_8112.csv +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/datasets/trade_data_harvard_growth_lab/international_exports_metadata_2019_8112.json +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/dependency_links.txt +0 -0
- {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hiveplotlib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: Visualize Network Data with Hive Plots
|
|
5
5
|
Author-email: Gary Koplik <gary.koplik@geomdata.com>
|
|
6
|
-
License: Copyright (c) 2020 -
|
|
6
|
+
License: Copyright (c) 2020 - 2023, Geometric Data Analytics, Inc.
|
|
7
7
|
All rights reserved.
|
|
8
8
|
|
|
9
9
|
Redistribution and use in source and binary forms, with or without modification,
|
|
@@ -34,13 +34,40 @@ License: Copyright (c) 2020 - 2022, Geometric Data Analytics, Inc.
|
|
|
34
34
|
Project-URL: Documentation, https://geomdata.gitlab.io/hiveplotlib/
|
|
35
35
|
Project-URL: Source, https://gitlab.com/geomdata/hiveplotlib
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
|
+
License-File: LICENSE
|
|
38
|
+
Requires-Dist: matplotlib
|
|
39
|
+
Requires-Dist: numpy
|
|
40
|
+
Requires-Dist: pandas
|
|
37
41
|
Provides-Extra: bokeh
|
|
42
|
+
Requires-Dist: bokeh; extra == "bokeh"
|
|
38
43
|
Provides-Extra: datashader
|
|
44
|
+
Requires-Dist: datashader; extra == "datashader"
|
|
45
|
+
Requires-Dist: seaborn; extra == "datashader"
|
|
39
46
|
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: bokeh; extra == "dev"
|
|
48
|
+
Requires-Dist: datashader; extra == "dev"
|
|
49
|
+
Requires-Dist: jupyter; extra == "dev"
|
|
50
|
+
Requires-Dist: networkx; extra == "dev"
|
|
51
|
+
Requires-Dist: seaborn; extra == "dev"
|
|
52
|
+
Requires-Dist: tqdm; extra == "dev"
|
|
40
53
|
Provides-Extra: docs
|
|
54
|
+
Requires-Dist: nbsphinx; extra == "docs"
|
|
55
|
+
Requires-Dist: sphinx; extra == "docs"
|
|
56
|
+
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
|
57
|
+
Requires-Dist: toml; extra == "docs"
|
|
41
58
|
Provides-Extra: networkx
|
|
59
|
+
Requires-Dist: networkx; extra == "networkx"
|
|
60
|
+
Provides-Extra: plotly
|
|
61
|
+
Requires-Dist: plotly; extra == "plotly"
|
|
42
62
|
Provides-Extra: testing
|
|
43
|
-
|
|
63
|
+
Requires-Dist: black[jupyter]; extra == "testing"
|
|
64
|
+
Requires-Dist: flake8-docstrings; extra == "testing"
|
|
65
|
+
Requires-Dist: Flake8-pyproject; extra == "testing"
|
|
66
|
+
Requires-Dist: pytest; extra == "testing"
|
|
67
|
+
Requires-Dist: pytest-cov; extra == "testing"
|
|
68
|
+
Requires-Dist: pytest-html; extra == "testing"
|
|
69
|
+
Requires-Dist: pytest-timeout; extra == "testing"
|
|
70
|
+
Requires-Dist: pytest-xdist; extra == "testing"
|
|
44
71
|
|
|
45
72
|

|
|
46
73
|
|
|
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "hiveplotlib"
|
|
10
|
-
version = "0.
|
|
10
|
+
version = "0.23.0"
|
|
11
11
|
authors = [
|
|
12
12
|
{name="Gary Koplik", email="gary.koplik@geomdata.com"}
|
|
13
13
|
]
|
|
@@ -54,7 +54,12 @@ networkx = [
|
|
|
54
54
|
"networkx"
|
|
55
55
|
]
|
|
56
56
|
|
|
57
|
+
plotly = [
|
|
58
|
+
"plotly"
|
|
59
|
+
]
|
|
60
|
+
|
|
57
61
|
testing = [
|
|
62
|
+
"black[jupyter]",
|
|
58
63
|
"flake8-docstrings",
|
|
59
64
|
"Flake8-pyproject",
|
|
60
65
|
"pytest",
|
|
@@ -68,6 +73,11 @@ testing = [
|
|
|
68
73
|
where = ["src"]
|
|
69
74
|
include = ["hiveplotlib*"]
|
|
70
75
|
|
|
76
|
+
[tool.black]
|
|
77
|
+
line-length = 88
|
|
78
|
+
target-version = ["py311"]
|
|
79
|
+
include = '\.pyi?$|examples\/.*\.ipynb?$'
|
|
80
|
+
|
|
71
81
|
[tool.flake8]
|
|
72
82
|
exclude = [
|
|
73
83
|
"*_test.py",
|
|
@@ -76,10 +86,12 @@ exclude = [
|
|
|
76
86
|
"sandbox",
|
|
77
87
|
"setup.py",
|
|
78
88
|
]
|
|
79
|
-
|
|
89
|
+
extend_ignore = [
|
|
80
90
|
"D200", # 1-line docstrings will be tolerated
|
|
81
|
-
"
|
|
91
|
+
"E203", # https://black.readthedocs.io/en/stable/faq.html#why-are-flake8-s-e203-and-w503-violated
|
|
92
|
+
"W503" # docs literally say this should not be a thing https://www.flake8rules.com/rules/W504.html
|
|
82
93
|
]
|
|
83
|
-
|
|
94
|
+
# keeping a longer-allowed line-length on flake8 side for existing docs
|
|
95
|
+
max-line-length = 120
|
|
84
96
|
show-source = true
|
|
85
97
|
count = true
|
|
@@ -49,8 +49,14 @@ class Axis:
|
|
|
49
49
|
axis2 = Axis(axis_id="a2", start=1, end=5, angle=240, long_name="Axis 2")
|
|
50
50
|
"""
|
|
51
51
|
|
|
52
|
-
def __init__(
|
|
53
|
-
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
axis_id: Hashable,
|
|
55
|
+
start: float = 1,
|
|
56
|
+
end: float = 5,
|
|
57
|
+
angle: float = 0,
|
|
58
|
+
long_name: Optional[Hashable] = None,
|
|
59
|
+
):
|
|
54
60
|
"""
|
|
55
61
|
Initialize ``Axis`` object with start and end positions and angle. Default to axis normalized on [0, 1].
|
|
56
62
|
|
|
@@ -83,7 +89,7 @@ class Axis:
|
|
|
83
89
|
self.node_placement_label = None
|
|
84
90
|
|
|
85
91
|
# hold all the cartesian coordinates, polar rho, and corresponding labels in a pandas dataframe
|
|
86
|
-
self.node_placements = pd.DataFrame(columns=[
|
|
92
|
+
self.node_placements = pd.DataFrame(columns=["x", "y", "unique_id", "rho"])
|
|
87
93
|
|
|
88
94
|
def __repr__(self) -> str:
|
|
89
95
|
"""
|
|
@@ -91,7 +97,9 @@ class Axis:
|
|
|
91
97
|
"""
|
|
92
98
|
return f"hiveplotlib.Axis {self.axis_id}"
|
|
93
99
|
|
|
94
|
-
def _set_node_placements(
|
|
100
|
+
def _set_node_placements(
|
|
101
|
+
self, x: List[float], y: List[float], node_ids: List[Hashable], rho: List[float]
|
|
102
|
+
):
|
|
95
103
|
"""
|
|
96
104
|
Set ``Axis.node_placements`` to a ``pandas.DataFrame``.
|
|
97
105
|
|
|
@@ -108,10 +116,16 @@ class Axis:
|
|
|
108
116
|
:param rho: ``list-like`` of polar coordinate distance values corresponding to x, y, and unique ID values.
|
|
109
117
|
:return: ``None``.
|
|
110
118
|
"""
|
|
111
|
-
assert
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
119
|
+
assert (
|
|
120
|
+
np.array(x).shape[0]
|
|
121
|
+
== np.array(y).shape[0]
|
|
122
|
+
== np.array(node_ids).shape[0]
|
|
123
|
+
== np.array(rho).shape[0]
|
|
124
|
+
), "Must provide the same number of x values, y values, and node IDs"
|
|
125
|
+
|
|
126
|
+
self.node_placements = pd.DataFrame.from_dict(
|
|
127
|
+
{"x": x, "y": y, "unique_id": node_ids, "rho": rho}
|
|
128
|
+
)
|
|
115
129
|
|
|
116
130
|
return None
|
|
117
131
|
|
|
@@ -18,13 +18,15 @@ For Polar Parallel Coordinates Plots (P2CPs), many datasets are available throug
|
|
|
18
18
|
|
|
19
19
|
import json
|
|
20
20
|
import numpy as np
|
|
21
|
+
from hiveplotlib import hive_plot_n_axes, HivePlot, Node
|
|
21
22
|
import pandas as pd
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
from typing import Dict, Optional, Tuple, Union
|
|
24
25
|
|
|
25
26
|
|
|
26
|
-
def international_trade_data(
|
|
27
|
-
|
|
27
|
+
def international_trade_data(
|
|
28
|
+
year: int = 2019, hs92_code: int = 8112, path: Optional[Union[str, Path]] = None
|
|
29
|
+
) -> Tuple[pd.DataFrame, Dict]:
|
|
28
30
|
"""
|
|
29
31
|
Read in international trade data network from the Harvard Growth Lab.
|
|
30
32
|
|
|
@@ -61,29 +63,37 @@ def international_trade_data(year: int = 2019, hs92_code: int = 8112,
|
|
|
61
63
|
path = Path(path)
|
|
62
64
|
|
|
63
65
|
# grab the shipped year, hs92 values to present what's available on failure
|
|
64
|
-
csv_files = [
|
|
66
|
+
csv_files = [
|
|
67
|
+
i.stem for i in sorted(internal_path.glob("international_exports*.csv"))
|
|
68
|
+
]
|
|
65
69
|
csv_years = [i.split("_")[2] for i in csv_files]
|
|
66
70
|
csv_hs92 = [i.split("_")[-1] for i in csv_files]
|
|
67
|
-
hiveplotlib_supported_values = pd.DataFrame(
|
|
71
|
+
hiveplotlib_supported_values = pd.DataFrame(
|
|
72
|
+
np.c_[csv_years, csv_hs92], columns=["Year", "Trade Code"]
|
|
73
|
+
)
|
|
68
74
|
|
|
69
75
|
# check that our implied data and metadata files exist
|
|
70
76
|
data_path = path.joinpath(f"international_exports_{year}_{hs92_code}.csv")
|
|
71
|
-
metadata_path = path.joinpath(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
f"
|
|
77
|
+
metadata_path = path.joinpath(
|
|
78
|
+
f"international_exports_metadata_{year}_{hs92_code}.json"
|
|
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`, "
|
|
76
84
|
f"`hs29_code` values are supported:\n{hiveplotlib_supported_values}"
|
|
85
|
+
)
|
|
77
86
|
|
|
78
87
|
data = pd.read_csv(data_path)
|
|
79
|
-
with open(metadata_path,
|
|
88
|
+
with open(metadata_path, "r") as openfile:
|
|
80
89
|
metadata = json.load(openfile)
|
|
81
90
|
|
|
82
91
|
return data, metadata
|
|
83
92
|
|
|
84
93
|
|
|
85
|
-
def four_gaussian_blobs_3d(
|
|
86
|
-
|
|
94
|
+
def four_gaussian_blobs_3d(
|
|
95
|
+
num_points: int = 50, noise: float = 0.5, random_seed: int = 0
|
|
96
|
+
) -> pd.DataFrame:
|
|
87
97
|
"""
|
|
88
98
|
Generate a ``pandas`` dataframe of four Gaussian blobs in 3d.
|
|
89
99
|
|
|
@@ -113,8 +123,9 @@ def four_gaussian_blobs_3d(num_points: int = 50, noise: float = 0.5,
|
|
|
113
123
|
for i in [0, 5]:
|
|
114
124
|
for j in [0, 5]:
|
|
115
125
|
for k in [0, 5]:
|
|
116
|
-
b = rng.normal(scale=noise,
|
|
117
|
-
|
|
126
|
+
b = rng.normal(scale=noise, size=num_points * dim).reshape(
|
|
127
|
+
num_points, dim
|
|
128
|
+
)
|
|
118
129
|
b[:, 0] += i
|
|
119
130
|
b[:, 1] += j
|
|
120
131
|
b[:, 2] += k
|
|
@@ -123,8 +134,9 @@ def four_gaussian_blobs_3d(num_points: int = 50, noise: float = 0.5,
|
|
|
123
134
|
coords.append((i, j, k))
|
|
124
135
|
|
|
125
136
|
# put our 4 blobs of interest into a single dataframe
|
|
126
|
-
df = pd.DataFrame(
|
|
127
|
-
|
|
137
|
+
df = pd.DataFrame(
|
|
138
|
+
np.row_stack([b_list[i] for i in corners_to_keep]), columns=feature_names
|
|
139
|
+
)
|
|
128
140
|
|
|
129
141
|
# make the labels ints
|
|
130
142
|
df.Label = df.Label.astype(int)
|
|
@@ -132,3 +144,76 @@ def four_gaussian_blobs_3d(num_points: int = 50, noise: float = 0.5,
|
|
|
132
144
|
df.Label.values[df.Label.values == 4] = 3
|
|
133
145
|
|
|
134
146
|
return df
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def example_hive_plot(
|
|
150
|
+
num_nodes: int = 15,
|
|
151
|
+
num_edges: int = 30,
|
|
152
|
+
seed: int = 0,
|
|
153
|
+
**hive_plot_n_axes_kwargs,
|
|
154
|
+
) -> HivePlot:
|
|
155
|
+
"""
|
|
156
|
+
Generate example hive plot with ``"Low"``, ``"Medium"``, and ``"High"`` axes (plus repeat axes).
|
|
157
|
+
|
|
158
|
+
Nodes and edges will be generated and placed randomly.
|
|
159
|
+
|
|
160
|
+
:param num_nodes: number of nodes to generate.
|
|
161
|
+
:param num_edges: number of edges to generate.
|
|
162
|
+
:param seed: random seed to use when generating nodes and edges.
|
|
163
|
+
:param hive_plot_n_axes_kwargs: additional keyword arguments for the underlying
|
|
164
|
+
:py:func:`hiveplotlib.hive_plot.hive_plot_n_axes()` call.
|
|
165
|
+
:return: resulting ``HivePlot`` instance.
|
|
166
|
+
"""
|
|
167
|
+
color_dict = {
|
|
168
|
+
"Low": {"Low_repeat": "#006BA4", "High_repeat": "#FF800E"},
|
|
169
|
+
"High": {"Medium_repeat": "#ABABAB", "High_repeat": "#595959"},
|
|
170
|
+
"Medium": {"Medium_repeat": "#5F9ED1", "Low_repeat": "#C85200"},
|
|
171
|
+
"Low_repeat": {"Low": "#006BA4", "Medium": "#C85200"},
|
|
172
|
+
"Medium_repeat": {"Medium": "#5F9ED1", "High": "#ABABAB"},
|
|
173
|
+
"High_repeat": {"High": "#595959", "Low": "#FF800E"},
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
rng = np.random.default_rng(seed)
|
|
177
|
+
data = pd.DataFrame(
|
|
178
|
+
np.c_[
|
|
179
|
+
rng.uniform(low=0, high=10, size=num_nodes),
|
|
180
|
+
rng.uniform(low=10, high=20, size=num_nodes),
|
|
181
|
+
rng.uniform(low=20, high=30, size=num_nodes),
|
|
182
|
+
],
|
|
183
|
+
columns=["low", "med", "high"],
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
# convert into dict for later use
|
|
187
|
+
node_data = data.to_dict(orient="records")
|
|
188
|
+
|
|
189
|
+
# use the dataframe's index as unique id
|
|
190
|
+
node_ids = data.index.values
|
|
191
|
+
|
|
192
|
+
nodes = [
|
|
193
|
+
Node(unique_id=node_id, data=node_data[i]) for i, node_id in enumerate(node_ids)
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
edges = rng.choice(node_ids, size=num_edges * 2).reshape(-1, 2)
|
|
197
|
+
|
|
198
|
+
hp = hive_plot_n_axes(
|
|
199
|
+
node_list=nodes,
|
|
200
|
+
edges=edges,
|
|
201
|
+
axes_assignments=[
|
|
202
|
+
np.arange(num_nodes)[: num_nodes // 3],
|
|
203
|
+
np.arange(num_nodes)[num_nodes // 3 : 2 * num_nodes // 3],
|
|
204
|
+
np.arange(num_nodes)[2 * num_nodes // 3 :],
|
|
205
|
+
],
|
|
206
|
+
sorting_variables=["low", "med", "high"],
|
|
207
|
+
repeat_axes=[True, True, True],
|
|
208
|
+
axes_names=["Low", "Medium", "High"],
|
|
209
|
+
orient_angle=-30,
|
|
210
|
+
**hive_plot_n_axes_kwargs,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# set colors according to above-defined color dictionary
|
|
214
|
+
# (so we can replicate more easily in other viz later)
|
|
215
|
+
for e1 in color_dict:
|
|
216
|
+
for e2 in color_dict[e1]:
|
|
217
|
+
hp.add_edge_kwargs(axis_id_1=e1, axis_id_2=e2, color=color_dict[e1][e2])
|
|
218
|
+
|
|
219
|
+
return hp
|