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.
Files changed (31) hide show
  1. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/LICENSE +1 -1
  2. {hiveplotlib-0.21/src/hiveplotlib.egg-info → hiveplotlib-0.23.0}/PKG-INFO +30 -3
  3. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/pyproject.toml +16 -4
  4. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/axis.py +22 -8
  5. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/datasets/__init__.py +101 -16
  6. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/hiveplot.py +459 -188
  7. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/node.py +21 -14
  8. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/p2cp.py +159 -91
  9. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/utils.py +20 -13
  10. hiveplotlib-0.23.0/src/hiveplotlib/viz/__init__.py +18 -0
  11. hiveplotlib-0.23.0/src/hiveplotlib/viz/base.py +61 -0
  12. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/viz/bokeh.py +366 -304
  13. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/viz/datashader.py +147 -98
  14. hiveplotlib-0.23.0/src/hiveplotlib/viz/input_checks.py +99 -0
  15. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/viz/matplotlib.py +338 -278
  16. hiveplotlib-0.23.0/src/hiveplotlib/viz/plotly.py +822 -0
  17. {hiveplotlib-0.21 → hiveplotlib-0.23.0/src/hiveplotlib.egg-info}/PKG-INFO +30 -3
  18. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/SOURCES.txt +3 -1
  19. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/requires.txt +4 -0
  20. hiveplotlib-0.21/src/hiveplotlib/viz/__init__.py +0 -16
  21. hiveplotlib-0.21/src/hiveplotlib/viz/input_checks.py +0 -30
  22. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/MANIFEST.in +0 -0
  23. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/README.md +0 -0
  24. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/setup.cfg +0 -0
  25. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/setup.py +0 -0
  26. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/__init__.py +0 -0
  27. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/converters.py +0 -0
  28. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/datasets/trade_data_harvard_growth_lab/international_exports_2019_8112.csv +0 -0
  29. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib/datasets/trade_data_harvard_growth_lab/international_exports_metadata_2019_8112.json +0 -0
  30. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/dependency_links.txt +0 -0
  31. {hiveplotlib-0.21 → hiveplotlib-0.23.0}/src/hiveplotlib.egg-info/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- Copyright (c) 2020 - 2022, Geometric Data Analytics, Inc.
1
+ Copyright (c) 2020 - 2023, Geometric Data Analytics, Inc.
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without modification,
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hiveplotlib
3
- Version: 0.21
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 - 2022, Geometric Data Analytics, Inc.
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
- License-File: LICENSE
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
  ![](https://geomdata.gitlab.io/hiveplotlib/_static/hiveplotlib.svg)
46
73
 
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "hiveplotlib"
10
- version = "0.21"
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
- ignore = [
89
+ extend_ignore = [
80
90
  "D200", # 1-line docstrings will be tolerated
81
- "E501" # can't check line-length and have long hyperlinks in the docs
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
- color = "always"
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__(self, axis_id: Hashable, start: float = 1, end: float = 5,
53
- angle: float = 0, long_name: Optional[Hashable] = None):
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=['x', 'y', 'unique_id', 'rho'])
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(self, x: List[float], y: List[float], node_ids: List[Hashable], rho: List[float]):
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 np.array(x).shape[0] == np.array(y).shape[0] == np.array(node_ids).shape[0] == np.array(rho).shape[0], \
112
- "Must provide the same number of x values, y values, and node IDs"
113
-
114
- self.node_placements = pd.DataFrame.from_dict({'x': x, 'y': y, 'unique_id': node_ids, 'rho': rho})
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(year: int = 2019, hs92_code: int = 8112,
27
- path: Optional[Union[str, Path]] = None) -> Tuple[pd.DataFrame, Dict]:
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 = [i.stem for i in sorted(internal_path.glob("international_exports*.csv"))]
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(np.c_[csv_years, csv_hs92], columns=["Year", "Trade Code"])
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(f"international_exports_metadata_{year}_{hs92_code}.json")
72
- assert data_path.exists() and metadata_path.exists(), \
73
- f"Could not find data and / or metadata under specified `path`. If you specified your own path, double check " \
74
- f"that the path is correct. Your file names should be " \
75
- f"If you are using `hiveplotlib` supported data, note that only the following `year`, " \
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, 'r') as openfile:
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(num_points: int = 50, noise: float = 0.5,
86
- random_seed: int = 0) -> pd.DataFrame:
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
- size=num_points * dim).reshape(num_points, dim)
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(np.row_stack([b_list[i] for i in corners_to_keep]),
127
- columns=feature_names)
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