matplotlib-sankey 0.3.0__tar.gz → 0.3.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.
- {matplotlib_sankey-0.3.0 → matplotlib_sankey-0.3.2}/PKG-INFO +42 -35
- {matplotlib_sankey-0.3.0 → matplotlib_sankey-0.3.2}/README.md +15 -4
- matplotlib_sankey-0.3.2/pyproject.toml +89 -0
- matplotlib_sankey-0.3.2/src/matplotlib_sankey/__init__.py +5 -0
- {matplotlib_sankey-0.3.0 → matplotlib_sankey-0.3.2/src}/matplotlib_sankey/_colors.py +5 -5
- {matplotlib_sankey-0.3.0 → matplotlib_sankey-0.3.2/src}/matplotlib_sankey/_plotting.py +60 -26
- {matplotlib_sankey-0.3.0 → matplotlib_sankey-0.3.2/src}/matplotlib_sankey/_utils.py +9 -4
- matplotlib_sankey-0.3.2/src/matplotlib_sankey/_version.py +3 -0
- matplotlib_sankey-0.3.0/.editorconfig +0 -15
- matplotlib_sankey-0.3.0/.gitignore +0 -164
- matplotlib_sankey-0.3.0/CITATION.cff +0 -11
- matplotlib_sankey-0.3.0/LICENSE +0 -21
- matplotlib_sankey-0.3.0/matplotlib_sankey/__init__.py +0 -5
- matplotlib_sankey-0.3.0/matplotlib_sankey/_version.py +0 -1
- matplotlib_sankey-0.3.0/pyproject.toml +0 -160
- matplotlib_sankey-0.3.0/requirements.txt +0 -133
- matplotlib_sankey-0.3.0/tests/test_colors.py +0 -25
- matplotlib_sankey-0.3.0/tests/test_sankey_plot.py +0 -23
- matplotlib_sankey-0.3.0/tests/test_utils.py +0 -40
- {matplotlib_sankey-0.3.0 → matplotlib_sankey-0.3.2/src}/matplotlib_sankey/_patches.py +0 -0
- {matplotlib_sankey-0.3.0 → matplotlib_sankey-0.3.2/src}/matplotlib_sankey/_types.py +0 -0
- /matplotlib_sankey-0.3.0/tests/__init__.py → /matplotlib_sankey-0.3.2/src/matplotlib_sankey/py.typed +0 -0
|
@@ -1,49 +1,46 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: matplotlib-sankey
|
|
3
|
-
Version: 0.3.
|
|
4
|
-
Summary: Sankey
|
|
3
|
+
Version: 0.3.2
|
|
4
|
+
Summary: Create Sankey diagrams with Matplotlib.
|
|
5
5
|
Author: harryhaller001
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
6
|
+
Author-email: harryhaller001 <harryhaller001@gmail.com>
|
|
7
|
+
License-Expression: MIT
|
|
9
8
|
Classifier: Development Status :: 3 - Alpha
|
|
10
|
-
Classifier: Framework :: Matplotlib
|
|
11
9
|
Classifier: Intended Audience :: Science/Research
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
10
|
Classifier: Natural Language :: English
|
|
14
11
|
Classifier: Operating System :: OS Independent
|
|
15
12
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
17
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
18
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
19
15
|
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
17
|
Classifier: Typing :: Typed
|
|
21
|
-
License-File: LICENSE
|
|
22
18
|
Requires-Dist: matplotlib
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-Dist:
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist:
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist:
|
|
37
|
-
Requires-Dist:
|
|
38
|
-
Requires-Dist:
|
|
39
|
-
Requires-Dist:
|
|
40
|
-
Requires-Dist:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
19
|
+
Requires-Dist: ipython ; extra == 'docs'
|
|
20
|
+
Requires-Dist: myst-parser ; extra == 'docs'
|
|
21
|
+
Requires-Dist: nbsphinx ; extra == 'docs'
|
|
22
|
+
Requires-Dist: sphinx ; extra == 'docs'
|
|
23
|
+
Requires-Dist: sphinx-autoapi ; extra == 'docs'
|
|
24
|
+
Requires-Dist: sphinx-autodoc-typehints ; extra == 'docs'
|
|
25
|
+
Requires-Dist: sphinx-book-theme ; extra == 'docs'
|
|
26
|
+
Requires-Dist: coverage ; extra == 'test'
|
|
27
|
+
Requires-Dist: ipykernel ; extra == 'test'
|
|
28
|
+
Requires-Dist: ipython ; extra == 'test'
|
|
29
|
+
Requires-Dist: ipywidgets ; extra == 'test'
|
|
30
|
+
Requires-Dist: pre-commit ; extra == 'test'
|
|
31
|
+
Requires-Dist: pytest ; extra == 'test'
|
|
32
|
+
Requires-Dist: responses ; extra == 'test'
|
|
33
|
+
Requires-Dist: ruff ; extra == 'test'
|
|
34
|
+
Requires-Dist: twine ; extra == 'test'
|
|
35
|
+
Requires-Dist: ty>=0.0.16 ; extra == 'test'
|
|
36
|
+
Requires-Dist: types-requests ; extra == 'test'
|
|
37
|
+
Maintainer: harryhaller001
|
|
38
|
+
Maintainer-email: harryhaller001 <harryhaller001@gmail.com>
|
|
39
|
+
Requires-Python: >=3.11
|
|
44
40
|
Project-URL: Source, https://github.com/harryhaller001/matplotlib-sankey
|
|
45
41
|
Provides-Extra: docs
|
|
46
42
|
Provides-Extra: test
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
47
44
|
|
|
48
45
|
# matplotlib-sankey
|
|
49
46
|
|
|
@@ -51,6 +48,7 @@ Provides-Extra: test
|
|
|
51
48
|
[](https://pypi.org/project/matplotlib-sankey/)
|
|
52
49
|

|
|
53
50
|

|
|
51
|
+
[](https://doi.org/10.5281/zenodo.15420062)
|
|
54
52
|
|
|
55
53
|
[Documentation](https://harryhaller001.github.io/matplotlib-sankey/) | [PyPI](https://pypi.org/project/matplotlib-sankey/) | [Github repository](https://github.com/harryhaller001/matplotlib-sankey) | [Codecov](https://codecov.io/gh/harryhaller001/matplotlib-sankey)
|
|
56
54
|
|
|
@@ -58,16 +56,20 @@ Sankey plot for matplotlib
|
|
|
58
56
|
|
|
59
57
|
### Installation
|
|
60
58
|
|
|
61
|
-
Install with pip
|
|
59
|
+
Install with `pip`:
|
|
62
60
|
|
|
63
61
|
`pip install matplotlib-sankey`
|
|
64
62
|
|
|
63
|
+
Install with `uv`:
|
|
64
|
+
|
|
65
|
+
`uv add matplotlib-sankey`
|
|
66
|
+
|
|
65
67
|
Install from source:
|
|
66
68
|
|
|
67
69
|
```bash
|
|
68
70
|
git clone https://github.com/harryhaller001/matplotlib-sankey
|
|
69
71
|
cd matplotlib-sankey
|
|
70
|
-
pip install .
|
|
72
|
+
pip install -e .
|
|
71
73
|
```
|
|
72
74
|
|
|
73
75
|
|
|
@@ -99,10 +101,15 @@ sankey(
|
|
|
99
101
|
### Development
|
|
100
102
|
|
|
101
103
|
```bash
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
git clone https://github.com/harryhaller001/matplotlib-sankey
|
|
105
|
+
cd matplotlib-sankey
|
|
106
|
+
|
|
107
|
+
# Create virtual env with uv
|
|
108
|
+
uv venv
|
|
104
109
|
|
|
105
110
|
# Install dev dependencies
|
|
106
111
|
make install
|
|
107
|
-
```
|
|
108
112
|
|
|
113
|
+
# Run all checks
|
|
114
|
+
make check
|
|
115
|
+
```
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[](https://pypi.org/project/matplotlib-sankey/)
|
|
5
5
|

|
|
6
6
|

|
|
7
|
+
[](https://doi.org/10.5281/zenodo.15420062)
|
|
7
8
|
|
|
8
9
|
[Documentation](https://harryhaller001.github.io/matplotlib-sankey/) | [PyPI](https://pypi.org/project/matplotlib-sankey/) | [Github repository](https://github.com/harryhaller001/matplotlib-sankey) | [Codecov](https://codecov.io/gh/harryhaller001/matplotlib-sankey)
|
|
9
10
|
|
|
@@ -11,16 +12,20 @@ Sankey plot for matplotlib
|
|
|
11
12
|
|
|
12
13
|
### Installation
|
|
13
14
|
|
|
14
|
-
Install with pip
|
|
15
|
+
Install with `pip`:
|
|
15
16
|
|
|
16
17
|
`pip install matplotlib-sankey`
|
|
17
18
|
|
|
19
|
+
Install with `uv`:
|
|
20
|
+
|
|
21
|
+
`uv add matplotlib-sankey`
|
|
22
|
+
|
|
18
23
|
Install from source:
|
|
19
24
|
|
|
20
25
|
```bash
|
|
21
26
|
git clone https://github.com/harryhaller001/matplotlib-sankey
|
|
22
27
|
cd matplotlib-sankey
|
|
23
|
-
pip install .
|
|
28
|
+
pip install -e .
|
|
24
29
|
```
|
|
25
30
|
|
|
26
31
|
|
|
@@ -52,9 +57,15 @@ sankey(
|
|
|
52
57
|
### Development
|
|
53
58
|
|
|
54
59
|
```bash
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
git clone https://github.com/harryhaller001/matplotlib-sankey
|
|
61
|
+
cd matplotlib-sankey
|
|
62
|
+
|
|
63
|
+
# Create virtual env with uv
|
|
64
|
+
uv venv
|
|
57
65
|
|
|
58
66
|
# Install dev dependencies
|
|
59
67
|
make install
|
|
68
|
+
|
|
69
|
+
# Run all checks
|
|
70
|
+
make check
|
|
60
71
|
```
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "uv_build"
|
|
3
|
+
requires = [ "uv-build>=0.9.28,<0.10" ]
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "matplotlib-sankey"
|
|
7
|
+
version = "0.3.2"
|
|
8
|
+
description = "Create Sankey diagrams with Matplotlib."
|
|
9
|
+
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
|
+
license = "MIT"
|
|
11
|
+
maintainers = [ { name = "harryhaller001", email = "harryhaller001@gmail.com" } ]
|
|
12
|
+
authors = [ { name = "harryhaller001", email = "harryhaller001@gmail.com" } ]
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Science/Research",
|
|
17
|
+
"Natural Language :: English",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [ "matplotlib" ]
|
|
27
|
+
optional-dependencies.docs = [
|
|
28
|
+
"ipython", # Required for syntax highlighing (https://github.com/spatialaudio/nbsphinx/issues/24)
|
|
29
|
+
"myst-parser",
|
|
30
|
+
"nbsphinx",
|
|
31
|
+
"sphinx",
|
|
32
|
+
"sphinx-autoapi",
|
|
33
|
+
"sphinx-autodoc-typehints",
|
|
34
|
+
"sphinx-book-theme",
|
|
35
|
+
]
|
|
36
|
+
optional-dependencies.test = [
|
|
37
|
+
"coverage",
|
|
38
|
+
"ipykernel",
|
|
39
|
+
"ipython",
|
|
40
|
+
"ipywidgets",
|
|
41
|
+
"pre-commit",
|
|
42
|
+
"pytest",
|
|
43
|
+
"responses",
|
|
44
|
+
"ruff",
|
|
45
|
+
"twine",
|
|
46
|
+
"ty>=0.0.16",
|
|
47
|
+
"types-requests",
|
|
48
|
+
]
|
|
49
|
+
urls.Source = "https://github.com/harryhaller001/matplotlib-sankey"
|
|
50
|
+
|
|
51
|
+
[tool.ruff]
|
|
52
|
+
line-length = 120
|
|
53
|
+
extend-include = [ "*.ipynb" ]
|
|
54
|
+
format.docstring-code-format = true
|
|
55
|
+
lint.select = [ "B", "BLE", "C4", "D", "E", "F", "I", "RUF100", "TID", "UP", "W" ]
|
|
56
|
+
lint.ignore = [ "B008", "C408", "D100", "D104", "D105", "D107", "D203", "D213", "D400", "D401", "E501", "E731", "E741" ]
|
|
57
|
+
lint.per-file-ignores."*/__init__.py" = [ "F401" ]
|
|
58
|
+
lint.per-file-ignores."docs/*" = [ "I" ]
|
|
59
|
+
lint.per-file-ignores."test/*" = [ "D" ]
|
|
60
|
+
lint.pydocstyle.convention = "google"
|
|
61
|
+
|
|
62
|
+
[tool.pyproject-fmt]
|
|
63
|
+
column_width = 120 # after how many column width split arrays/dicts into multiple lines, 1 will force always
|
|
64
|
+
indent = 4
|
|
65
|
+
keep_full_version = false # if false will remove unnecessary trailing ``.0``'s from version specifiers
|
|
66
|
+
max_supported_python = "3.14" # maximum Python version to use when generating version specifiers
|
|
67
|
+
|
|
68
|
+
[tool.pytest]
|
|
69
|
+
ini_options.minversion = "7.0"
|
|
70
|
+
ini_options.log_format = "%(asctime)s %(levelname)s %(message)s"
|
|
71
|
+
ini_options.log_date_format = "%Y-%m-%d %H:%M:%S"
|
|
72
|
+
ini_options.log_level = "INFO"
|
|
73
|
+
ini_options.log_cli = true
|
|
74
|
+
ini_options.python_files = "test_*.py"
|
|
75
|
+
ini_options.testpaths = [ "tests" ]
|
|
76
|
+
ini_options.xfail_strict = true
|
|
77
|
+
ini_options.addopts = [
|
|
78
|
+
"--import-mode=importlib", # allow using test files with same name
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[tool.coverage]
|
|
82
|
+
run.omit = [ "*/tests/*" ]
|
|
83
|
+
run.source = [ "src/matplotlib_sankey" ]
|
|
84
|
+
report.exclude_lines = [ "raise" ]
|
|
85
|
+
report.ignore_errors = true
|
|
86
|
+
html.directory = "coverage_report"
|
|
87
|
+
|
|
88
|
+
[tool.uv]
|
|
89
|
+
package = true
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
from typing import Any
|
|
2
1
|
import re
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from ._utils import isinstance_list_of
|
|
6
|
-
from ._types import ColorTuple
|
|
2
|
+
from typing import Any
|
|
7
3
|
|
|
8
4
|
from matplotlib import colormaps
|
|
5
|
+
from matplotlib.colors import Normalize, get_named_colors_mapping, to_rgb
|
|
6
|
+
|
|
7
|
+
from matplotlib_sankey._types import ColorTuple
|
|
8
|
+
from matplotlib_sankey._utils import isinstance_list_of
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def is_colormap(name: str) -> bool:
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
|
-
from typing import Literal,
|
|
2
|
+
from typing import Any, Literal, cast
|
|
3
3
|
|
|
4
4
|
import matplotlib.pyplot as plt
|
|
5
5
|
from matplotlib.axes import Axes
|
|
6
|
-
from matplotlib.patches import Rectangle, PathPatch, Patch
|
|
7
|
-
from matplotlib.ticker import FixedLocator
|
|
8
6
|
from matplotlib.colors import Colormap
|
|
7
|
+
from matplotlib.patches import Patch, PathPatch, Rectangle
|
|
8
|
+
from matplotlib.ticker import FixedLocator
|
|
9
9
|
|
|
10
|
-
from .
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
13
|
-
from .
|
|
10
|
+
from matplotlib_sankey._colors import colormap_to_list, is_color, is_colormap, unify_color
|
|
11
|
+
from matplotlib_sankey._patches import patch_curve3, patch_curve4, patch_line
|
|
12
|
+
from matplotlib_sankey._types import ColorTuple, CurveType
|
|
13
|
+
from matplotlib_sankey._utils import _clean_axis, is_light_color
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def sankey(
|
|
@@ -27,7 +27,10 @@ def sankey(
|
|
|
27
27
|
| Sequence[Colormap]
|
|
28
28
|
| str
|
|
29
29
|
| Sequence[tuple[float, float, float]]
|
|
30
|
-
| Sequence[tuple[float, float, float, float]]
|
|
30
|
+
| Sequence[tuple[float, float, float, float]]
|
|
31
|
+
| Sequence[
|
|
32
|
+
str | Sequence[str] | Colormap | tuple[float, float, float] | tuple[float, float, float, float]
|
|
33
|
+
] = "tab10",
|
|
31
34
|
curve_type: CurveType = "curve4",
|
|
32
35
|
ribbon_alpha: float = 0.2,
|
|
33
36
|
ribbon_color: str = "black",
|
|
@@ -38,6 +41,7 @@ def sankey(
|
|
|
38
41
|
column_labels: list[str] | None = None,
|
|
39
42
|
annotate_columns_font_kwargs: dict[str, Any] | None = None,
|
|
40
43
|
annotate_columns_font_color: Literal["auto"] | ColorTuple | str = "auto",
|
|
44
|
+
column_item_totals: list[dict[int | str, float | int]] | None = None,
|
|
41
45
|
) -> Axes:
|
|
42
46
|
"""Sankey plot.
|
|
43
47
|
|
|
@@ -60,6 +64,7 @@ def sankey(
|
|
|
60
64
|
column_labels (list[str] | None, optional): Labels for columns. Defaults to `None`.
|
|
61
65
|
annotate_columns_font_kwargs (dict[str, Any] | None, optional): Extra arguments for column `ax.text` method of column annotation. Defaults to `None`.
|
|
62
66
|
annotate_columns_font_color (Literal["auto"] | ColorTuple | str, optional): Color of column annotation text. Defaults to `"auto"`, thereby automatically selectes text color based on background color.
|
|
67
|
+
column_item_totals (list[dict[int | str, float | int]] | None, optional): Total values for each column item. If provided, column items are sized based on these totals instead of the sum of ribbon weights. Ribbons are adjusted proportionally within the column items. Defaults to `None`.
|
|
63
68
|
|
|
64
69
|
Returns:
|
|
65
70
|
Matplotlib axes instance.
|
|
@@ -108,6 +113,24 @@ def sankey(
|
|
|
108
113
|
column_weights[frame_index + 1].get(target_index, 0) + weight
|
|
109
114
|
)
|
|
110
115
|
|
|
116
|
+
# Validate column_item_totals if provided
|
|
117
|
+
if column_item_totals is not None:
|
|
118
|
+
assert len(column_item_totals) == ncols, f"column_item_totals must have {ncols} entries, one for each column."
|
|
119
|
+
for col_index in range(ncols):
|
|
120
|
+
for item_key in column_weights[col_index].keys():
|
|
121
|
+
if item_key not in column_item_totals[col_index]:
|
|
122
|
+
raise ValueError(
|
|
123
|
+
f"Column {col_index}, item '{item_key}' has ribbons but no total value provided in column_item_totals."
|
|
124
|
+
)
|
|
125
|
+
if column_item_totals[col_index][item_key] < column_weights[col_index][item_key]:
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"Column {col_index}, item '{item_key}': total value {column_item_totals[col_index][item_key]} "
|
|
128
|
+
f"is less than sum of ribbon weights {column_weights[col_index][item_key]}."
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Use totals for rectangle sizing if provided, otherwise use calculated weights
|
|
132
|
+
column_display_weights = column_item_totals if column_item_totals is not None else column_weights
|
|
133
|
+
|
|
111
134
|
# Total number of column rects
|
|
112
135
|
total_rects: int = sum([len(col.keys()) for col in column_weights])
|
|
113
136
|
|
|
@@ -139,23 +162,36 @@ def sankey(
|
|
|
139
162
|
raise ValueError("If cmap argument is a string, please provide color name, hex code or name of colormap.")
|
|
140
163
|
|
|
141
164
|
elif isinstance(color, list | tuple | set):
|
|
142
|
-
|
|
165
|
+
# Type narrowing: at this point we know color is a sequence
|
|
166
|
+
color_seq = cast(Sequence[Any], color)
|
|
167
|
+
assert len(color_seq) == ncols
|
|
143
168
|
# process column wise definition of color
|
|
144
169
|
for col_index in range(len(column_rect_counts)):
|
|
145
170
|
new_column = []
|
|
171
|
+
col_color = color_seq[col_index]
|
|
146
172
|
|
|
147
|
-
if is_colormap(
|
|
173
|
+
if isinstance(col_color, str) and is_colormap(col_color):
|
|
148
174
|
for rect_index in range(column_rect_counts[col_index]):
|
|
149
175
|
new_column.append(
|
|
150
176
|
colormap_to_list(
|
|
151
|
-
name=
|
|
177
|
+
name=col_color,
|
|
152
178
|
num=len(column_weights[col_index].keys()),
|
|
153
179
|
rollover=True,
|
|
154
180
|
)[rect_index]
|
|
155
181
|
)
|
|
156
|
-
elif is_color(
|
|
182
|
+
elif is_color(col_color):
|
|
157
183
|
for _ in range(column_rect_counts[col_index]):
|
|
158
|
-
new_column.append(unify_color(
|
|
184
|
+
new_column.append(unify_color(col_color))
|
|
185
|
+
|
|
186
|
+
elif isinstance(col_color, list | tuple | set):
|
|
187
|
+
# List of list -> individual definition of column rect color
|
|
188
|
+
col_color_seq = cast(Sequence[Any], col_color)
|
|
189
|
+
assert all(is_color(c) for c in col_color_seq), "All items must be a color."
|
|
190
|
+
assert len(col_color_seq) == column_rect_counts[col_index]
|
|
191
|
+
|
|
192
|
+
for rect_index in range(column_rect_counts[col_index]):
|
|
193
|
+
new_column.append(unify_color(col_color_seq[rect_index]))
|
|
194
|
+
|
|
159
195
|
color_matrix.append(new_column)
|
|
160
196
|
|
|
161
197
|
else:
|
|
@@ -168,14 +204,14 @@ def sankey(
|
|
|
168
204
|
legend_handles: list[tuple[str, ColorTuple]] = []
|
|
169
205
|
|
|
170
206
|
for frame_index in range(ncols):
|
|
171
|
-
column_total_weight = sum(
|
|
207
|
+
column_total_weight = sum(column_display_weights[frame_index].values())
|
|
172
208
|
column_prev_weight = 0.0
|
|
173
209
|
|
|
174
|
-
column_n_spacing = len(
|
|
210
|
+
column_n_spacing = len(column_display_weights[frame_index].values()) - 1
|
|
175
211
|
|
|
176
212
|
spacing_scale_factor = 1 - (spacing * column_n_spacing)
|
|
177
213
|
|
|
178
|
-
for column_index, (column_key, weights) in enumerate(
|
|
214
|
+
for column_index, (column_key, weights) in enumerate(column_display_weights[frame_index].items()):
|
|
179
215
|
rect_x = frame_index - (rel_column_width / 2)
|
|
180
216
|
rect_y = column_prev_weight / column_total_weight + (column_index * spacing)
|
|
181
217
|
rect_height = (weights * spacing_scale_factor) / column_total_weight
|
|
@@ -272,25 +308,23 @@ def sankey(
|
|
|
272
308
|
ribbon_offset: float = 0.0
|
|
273
309
|
|
|
274
310
|
for target_index, ribbon_weight in column_targets.items():
|
|
275
|
-
# Start coords
|
|
276
|
-
|
|
277
|
-
|
|
311
|
+
# Start coords - use actual ribbon weights for positioning within source rectangle
|
|
312
|
+
source_item_total = column_display_weights[frame_index][column_key]
|
|
313
|
+
y1_start = rect_y + (rect_height * (ribbon_offset / source_item_total))
|
|
314
|
+
y2_end = rect_y + (rect_height * ((ribbon_offset + ribbon_weight) / source_item_total))
|
|
278
315
|
|
|
279
316
|
ribbon_offset += ribbon_weight
|
|
280
317
|
|
|
281
318
|
_, target_rect_y, _, target_rect_height = column_rects[frame_index + 1][target_index]
|
|
282
319
|
|
|
283
|
-
# End coords
|
|
320
|
+
# End coords - use actual ribbon weights for positioning within target rectangle
|
|
321
|
+
target_item_total = column_display_weights[frame_index + 1][target_index]
|
|
284
322
|
y1_end = target_rect_y + (
|
|
285
|
-
target_rect_height
|
|
286
|
-
* (target_ribbon_offset.get(target_index, 0) / column_weights[frame_index + 1][target_index])
|
|
323
|
+
target_rect_height * (target_ribbon_offset.get(target_index, 0) / target_item_total)
|
|
287
324
|
)
|
|
288
325
|
y2_start = target_rect_y + (
|
|
289
326
|
target_rect_height
|
|
290
|
-
* (
|
|
291
|
-
(ribbon_weight + target_ribbon_offset.get(target_index, 0))
|
|
292
|
-
/ column_weights[frame_index + 1][target_index]
|
|
293
|
-
)
|
|
327
|
+
* ((ribbon_weight + target_ribbon_offset.get(target_index, 0)) / target_item_total)
|
|
294
328
|
)
|
|
295
329
|
|
|
296
330
|
target_ribbon_offset[target_index] = target_ribbon_offset.get(target_index, 0) + ribbon_weight
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from collections.abc import Sequence
|
|
2
|
-
from typing import Any, Literal
|
|
3
2
|
from types import UnionType
|
|
3
|
+
from typing import Any, Literal
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
from matplotlib import colormaps
|
|
7
7
|
from matplotlib.axes import Axes
|
|
8
|
-
from matplotlib.colors import Colormap, ListedColormap
|
|
8
|
+
from matplotlib.colors import Colormap, ListedColormap, to_rgb
|
|
9
9
|
|
|
10
|
-
from ._types import AcceptedColors, ColorTuple
|
|
10
|
+
from matplotlib_sankey._types import AcceptedColors, ColorTuple
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def _clean_axis(
|
|
@@ -51,7 +51,12 @@ def _generate_cmap(value: AcceptedColors, nrows: int) -> Colormap:
|
|
|
51
51
|
return _convert_sequential_cmap_to_listed(colormaps.get_cmap(value))
|
|
52
52
|
|
|
53
53
|
elif isinstance(value, Sequence):
|
|
54
|
-
|
|
54
|
+
# Convert color names/strings to RGB tuples for ListedColormap
|
|
55
|
+
rgb_colors: list[tuple[float, float, float]] = [
|
|
56
|
+
to_rgb(c) if isinstance(c, str) else tuple(c) # type: ignore[arg-type]
|
|
57
|
+
for c in value
|
|
58
|
+
]
|
|
59
|
+
return ListedColormap(rgb_colors)
|
|
55
60
|
|
|
56
61
|
elif isinstance(value, Colormap):
|
|
57
62
|
return _convert_sequential_cmap_to_listed(value)
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
root = true
|
|
2
|
-
|
|
3
|
-
[*]
|
|
4
|
-
indent_style = space
|
|
5
|
-
indent_size = 4
|
|
6
|
-
end_of_line = lf
|
|
7
|
-
charset = utf-8
|
|
8
|
-
trim_trailing_whitespace = true
|
|
9
|
-
insert_final_newline = true
|
|
10
|
-
|
|
11
|
-
[{*.{yml,yaml,toml},.cruft.json}]
|
|
12
|
-
indent_size = 2
|
|
13
|
-
|
|
14
|
-
[Makefile]
|
|
15
|
-
indent_style = tab
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
/docs/coverage_report
|
|
2
|
-
|
|
3
|
-
# Byte-compiled / optimized / DLL files
|
|
4
|
-
__pycache__/
|
|
5
|
-
*.py[cod]
|
|
6
|
-
*$py.class
|
|
7
|
-
|
|
8
|
-
# C extensions
|
|
9
|
-
*.so
|
|
10
|
-
|
|
11
|
-
# Distribution / packaging
|
|
12
|
-
.Python
|
|
13
|
-
build/
|
|
14
|
-
develop-eggs/
|
|
15
|
-
dist/
|
|
16
|
-
downloads/
|
|
17
|
-
eggs/
|
|
18
|
-
.eggs/
|
|
19
|
-
lib/
|
|
20
|
-
lib64/
|
|
21
|
-
parts/
|
|
22
|
-
sdist/
|
|
23
|
-
var/
|
|
24
|
-
wheels/
|
|
25
|
-
share/python-wheels/
|
|
26
|
-
*.egg-info/
|
|
27
|
-
.installed.cfg
|
|
28
|
-
*.egg
|
|
29
|
-
MANIFEST
|
|
30
|
-
|
|
31
|
-
# PyInstaller
|
|
32
|
-
# Usually these files are written by a python script from a template
|
|
33
|
-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
34
|
-
*.manifest
|
|
35
|
-
*.spec
|
|
36
|
-
|
|
37
|
-
# Installer logs
|
|
38
|
-
pip-log.txt
|
|
39
|
-
pip-delete-this-directory.txt
|
|
40
|
-
|
|
41
|
-
# Unit test / coverage reports
|
|
42
|
-
htmlcov/
|
|
43
|
-
.tox/
|
|
44
|
-
.nox/
|
|
45
|
-
.coverage
|
|
46
|
-
.coverage.*
|
|
47
|
-
.cache
|
|
48
|
-
nosetests.xml
|
|
49
|
-
coverage.xml
|
|
50
|
-
*.cover
|
|
51
|
-
*.py,cover
|
|
52
|
-
.hypothesis/
|
|
53
|
-
.pytest_cache/
|
|
54
|
-
cover/
|
|
55
|
-
|
|
56
|
-
# Translations
|
|
57
|
-
*.mo
|
|
58
|
-
*.pot
|
|
59
|
-
|
|
60
|
-
# Django stuff:
|
|
61
|
-
*.log
|
|
62
|
-
local_settings.py
|
|
63
|
-
db.sqlite3
|
|
64
|
-
db.sqlite3-journal
|
|
65
|
-
|
|
66
|
-
# Flask stuff:
|
|
67
|
-
instance/
|
|
68
|
-
.webassets-cache
|
|
69
|
-
|
|
70
|
-
# Scrapy stuff:
|
|
71
|
-
.scrapy
|
|
72
|
-
|
|
73
|
-
# Sphinx documentation
|
|
74
|
-
docs/_build/
|
|
75
|
-
|
|
76
|
-
# PyBuilder
|
|
77
|
-
.pybuilder/
|
|
78
|
-
target/
|
|
79
|
-
|
|
80
|
-
# Jupyter Notebook
|
|
81
|
-
.ipynb_checkpoints
|
|
82
|
-
|
|
83
|
-
# IPython
|
|
84
|
-
profile_default/
|
|
85
|
-
ipython_config.py
|
|
86
|
-
|
|
87
|
-
# pyenv
|
|
88
|
-
# For a library or package, you might want to ignore these files since the code is
|
|
89
|
-
# intended to run in multiple environments; otherwise, check them in:
|
|
90
|
-
# .python-version
|
|
91
|
-
|
|
92
|
-
# pipenv
|
|
93
|
-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
94
|
-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
95
|
-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
96
|
-
# install all needed dependencies.
|
|
97
|
-
#Pipfile.lock
|
|
98
|
-
|
|
99
|
-
# poetry
|
|
100
|
-
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
101
|
-
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
102
|
-
# commonly ignored for libraries.
|
|
103
|
-
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
104
|
-
#poetry.lock
|
|
105
|
-
|
|
106
|
-
# pdm
|
|
107
|
-
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
108
|
-
#pdm.lock
|
|
109
|
-
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
110
|
-
# in version control.
|
|
111
|
-
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
|
112
|
-
.pdm.toml
|
|
113
|
-
.pdm-python
|
|
114
|
-
.pdm-build/
|
|
115
|
-
|
|
116
|
-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
117
|
-
__pypackages__/
|
|
118
|
-
|
|
119
|
-
# Celery stuff
|
|
120
|
-
celerybeat-schedule
|
|
121
|
-
celerybeat.pid
|
|
122
|
-
|
|
123
|
-
# SageMath parsed files
|
|
124
|
-
*.sage.py
|
|
125
|
-
|
|
126
|
-
# Environments
|
|
127
|
-
.env
|
|
128
|
-
.venv
|
|
129
|
-
env/
|
|
130
|
-
venv/
|
|
131
|
-
ENV/
|
|
132
|
-
env.bak/
|
|
133
|
-
venv.bak/
|
|
134
|
-
|
|
135
|
-
# Spyder project settings
|
|
136
|
-
.spyderproject
|
|
137
|
-
.spyproject
|
|
138
|
-
|
|
139
|
-
# Rope project settings
|
|
140
|
-
.ropeproject
|
|
141
|
-
|
|
142
|
-
# mkdocs documentation
|
|
143
|
-
/site
|
|
144
|
-
|
|
145
|
-
# mypy
|
|
146
|
-
.mypy_cache/
|
|
147
|
-
.dmypy.json
|
|
148
|
-
dmypy.json
|
|
149
|
-
|
|
150
|
-
# Pyre type checker
|
|
151
|
-
.pyre/
|
|
152
|
-
|
|
153
|
-
# pytype static type analyzer
|
|
154
|
-
.pytype/
|
|
155
|
-
|
|
156
|
-
# Cython debug symbols
|
|
157
|
-
cython_debug/
|
|
158
|
-
|
|
159
|
-
# PyCharm
|
|
160
|
-
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
161
|
-
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
162
|
-
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
163
|
-
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
164
|
-
#.idea/
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
cff-version: 1.2.0
|
|
2
|
-
message: "If you use matplotlib-sankey, please cite it as below."
|
|
3
|
-
authors:
|
|
4
|
-
- family-names: "Hellmig"
|
|
5
|
-
given-names: "Malte"
|
|
6
|
-
- family-names: "Krebs"
|
|
7
|
-
given-names: "Christian F."
|
|
8
|
-
title: "matplotlib-sankey"
|
|
9
|
-
version: 0.3.0
|
|
10
|
-
date-released: 2025-05-11
|
|
11
|
-
url: "https://github.com/harryhaller001/matplotlib-sankey"
|
matplotlib_sankey-0.3.0/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2024 harryhaller001
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.3.0"
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
# Package build system
|
|
3
|
-
build-backend = "flit_core.buildapi"
|
|
4
|
-
requires = [ "flit-core>=3.2,<4" ]
|
|
5
|
-
|
|
6
|
-
[project]
|
|
7
|
-
name = "matplotlib-sankey"
|
|
8
|
-
description = "Sankey plot for matplotlib"
|
|
9
|
-
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
|
-
|
|
11
|
-
license = { file = "LICENSE" }
|
|
12
|
-
|
|
13
|
-
maintainers = [ { name = "harryhaller001", email = "harryhaller001@gmail.com" } ]
|
|
14
|
-
authors = [ { name = "harryhaller001" } ]
|
|
15
|
-
|
|
16
|
-
requires-python = ">=3.10"
|
|
17
|
-
|
|
18
|
-
classifiers = [
|
|
19
|
-
"Development Status :: 3 - Alpha",
|
|
20
|
-
"Framework :: Matplotlib",
|
|
21
|
-
"Intended Audience :: Science/Research",
|
|
22
|
-
"License :: OSI Approved :: MIT License",
|
|
23
|
-
"Natural Language :: English",
|
|
24
|
-
"Operating System :: OS Independent",
|
|
25
|
-
"Programming Language :: Python :: 3 :: Only",
|
|
26
|
-
"Programming Language :: Python :: 3.10",
|
|
27
|
-
"Programming Language :: Python :: 3.11",
|
|
28
|
-
"Programming Language :: Python :: 3.12",
|
|
29
|
-
"Programming Language :: Python :: 3.13",
|
|
30
|
-
"Typing :: Typed",
|
|
31
|
-
]
|
|
32
|
-
dynamic = [ "version" ]
|
|
33
|
-
|
|
34
|
-
dependencies = [ "matplotlib", "numpy" ]
|
|
35
|
-
|
|
36
|
-
optional-dependencies.docs = [
|
|
37
|
-
"ipykernel",
|
|
38
|
-
"ipython",
|
|
39
|
-
"ipywidgets",
|
|
40
|
-
"myst-parser",
|
|
41
|
-
"nbsphinx",
|
|
42
|
-
"networkx[default]",
|
|
43
|
-
"sphinx>=4",
|
|
44
|
-
"sphinx-autoapi",
|
|
45
|
-
"sphinx-autodoc-typehints",
|
|
46
|
-
"sphinx-book-theme>=1",
|
|
47
|
-
]
|
|
48
|
-
optional-dependencies.test = [
|
|
49
|
-
"coverage",
|
|
50
|
-
"flit",
|
|
51
|
-
"mypy",
|
|
52
|
-
"pre-commit",
|
|
53
|
-
"pytest",
|
|
54
|
-
"ruff",
|
|
55
|
-
"setuptools",
|
|
56
|
-
"twine>=4.0.2",
|
|
57
|
-
]
|
|
58
|
-
|
|
59
|
-
# https://docs.pypi.org/project_metadata/#project-urls
|
|
60
|
-
urls.Documentation = "https://harryhaller001.github.io/matplotlib-sankey/"
|
|
61
|
-
urls.Homepage = "https://github.com/harryhaller001/matplotlib-sankey"
|
|
62
|
-
urls.Source = "https://github.com/harryhaller001/matplotlib-sankey"
|
|
63
|
-
|
|
64
|
-
[tool.flit.sdist]
|
|
65
|
-
include = [ "matplotlib_sankey/", "tests/" ]
|
|
66
|
-
exclude = [
|
|
67
|
-
"docs/",
|
|
68
|
-
"coverage",
|
|
69
|
-
".git/",
|
|
70
|
-
".github/",
|
|
71
|
-
".pre-commit-config.yaml",
|
|
72
|
-
"Makefile",
|
|
73
|
-
".python-version",
|
|
74
|
-
# "requirements.txt",
|
|
75
|
-
".vscode/",
|
|
76
|
-
"dev/",
|
|
77
|
-
]
|
|
78
|
-
|
|
79
|
-
[tool.ruff]
|
|
80
|
-
line-length = 120
|
|
81
|
-
extend-include = [ "*.ipynb" ]
|
|
82
|
-
|
|
83
|
-
format.docstring-code-format = true
|
|
84
|
-
|
|
85
|
-
lint.select = [
|
|
86
|
-
"B", # flake8-bugbear
|
|
87
|
-
"BLE", # flake8-blind-except
|
|
88
|
-
"C4", # flake8-comprehensions
|
|
89
|
-
"D", # pydocstyle
|
|
90
|
-
"E", # Error detected by Pycodestyle
|
|
91
|
-
"F", # Errors detected by Pyflakes
|
|
92
|
-
"I", # isort
|
|
93
|
-
"RUF100", # Report unused noqa directives
|
|
94
|
-
"TID", # flake8-tidy-imports
|
|
95
|
-
"UP", # pyupgrade
|
|
96
|
-
"W", # Warning detected by Pycodestyle
|
|
97
|
-
]
|
|
98
|
-
lint.ignore = [
|
|
99
|
-
"B008", # Errors from function calls in argument defaults. These are fine when the result is immutable.
|
|
100
|
-
"D100", # Missing docstring in public module
|
|
101
|
-
"D104", # Missing docstring in public package
|
|
102
|
-
"D105", # __magic__ methods are often self-explanatory, allow missing docstrings
|
|
103
|
-
"D107", # Missing docstring in __init__
|
|
104
|
-
# Disable one in each pair of mutually incompatible rules
|
|
105
|
-
"D203", # We don’t want a blank line before a class docstring
|
|
106
|
-
"D213", # <> We want docstrings to start immediately after the opening triple quote
|
|
107
|
-
"D400", # first line should end with a period [Bug: doesn’t work with single-line docstrings]
|
|
108
|
-
"D401", # First line should be in imperative mood; try rephrasing
|
|
109
|
-
"E501", # line too long -> we accept long comment lines; formatter gets rid of long code lines
|
|
110
|
-
"E731", # Do not assign a lambda expression, use a def -> lambda expression assignments are convenient
|
|
111
|
-
"E741", # allow I, O, l as variable names -> I is the identity matrix
|
|
112
|
-
"I001",
|
|
113
|
-
]
|
|
114
|
-
|
|
115
|
-
[tool.pyproject-fmt]
|
|
116
|
-
column_width = 120 # after how many column width split arrays/dicts into multiple lines, 1 will force always
|
|
117
|
-
indent = 4
|
|
118
|
-
keep_full_version = false # if false will remove unnecessary trailing ``.0``'s from version specifiers
|
|
119
|
-
max_supported_python = "3.13" # maximum Python version to use when generating version specifiers
|
|
120
|
-
|
|
121
|
-
[tool.pytest.ini_options]
|
|
122
|
-
# Pytest config
|
|
123
|
-
minversion = "7.0"
|
|
124
|
-
|
|
125
|
-
log_format = "%(asctime)s %(levelname)s %(message)s"
|
|
126
|
-
log_date_format = "%Y-%m-%d %H:%M:%S"
|
|
127
|
-
log_level = "INFO"
|
|
128
|
-
log_cli = true
|
|
129
|
-
|
|
130
|
-
python_files = "test_*.py"
|
|
131
|
-
testpaths = [ "tests" ]
|
|
132
|
-
|
|
133
|
-
xfail_strict = true
|
|
134
|
-
addopts = [
|
|
135
|
-
"--import-mode=importlib", # allow using test files with same name
|
|
136
|
-
]
|
|
137
|
-
|
|
138
|
-
[tool.coverage.run]
|
|
139
|
-
# Coverage config
|
|
140
|
-
source = [ "matplotlib_sankey" ]
|
|
141
|
-
omit = [ "*/tests/*" ]
|
|
142
|
-
|
|
143
|
-
[tool.coverage.report]
|
|
144
|
-
exclude_lines = [ "raise" ]
|
|
145
|
-
ignore_errors = true
|
|
146
|
-
|
|
147
|
-
[tool.coverage.html]
|
|
148
|
-
directory = "docs/coverage_report"
|
|
149
|
-
|
|
150
|
-
[tool.mypy]
|
|
151
|
-
# Mypy config (https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml-file)
|
|
152
|
-
python_version = "3.10"
|
|
153
|
-
warn_return_any = true
|
|
154
|
-
warn_unused_configs = true
|
|
155
|
-
|
|
156
|
-
# Ignore libs which are not PEP 561 compliant
|
|
157
|
-
# [[tool.mypy.overrides]]
|
|
158
|
-
# module = [
|
|
159
|
-
# ]
|
|
160
|
-
# ignore_missing_imports = true
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
accessible-pygments==0.0.5
|
|
2
|
-
alabaster==1.0.0
|
|
3
|
-
astroid==3.3.9
|
|
4
|
-
asttokens==3.0.0
|
|
5
|
-
attrs==25.3.0
|
|
6
|
-
babel==2.17.0
|
|
7
|
-
backports.tarfile==1.2.0
|
|
8
|
-
beautifulsoup4==4.13.4
|
|
9
|
-
bleach==6.2.0
|
|
10
|
-
certifi==2025.4.26
|
|
11
|
-
cffi==1.17.1
|
|
12
|
-
cfgv==3.4.0
|
|
13
|
-
charset-normalizer==3.4.1
|
|
14
|
-
comm==0.2.2
|
|
15
|
-
contourpy==1.3.2
|
|
16
|
-
coverage==7.8.0
|
|
17
|
-
cryptography==44.0.2
|
|
18
|
-
cycler==0.12.1
|
|
19
|
-
debugpy==1.8.14
|
|
20
|
-
decorator==5.2.1
|
|
21
|
-
defusedxml==0.7.1
|
|
22
|
-
distlib==0.3.9
|
|
23
|
-
docutils==0.21.2
|
|
24
|
-
exceptiongroup==1.2.2
|
|
25
|
-
executing==2.2.0
|
|
26
|
-
fastjsonschema==2.21.1
|
|
27
|
-
filelock==3.18.0
|
|
28
|
-
flit==3.12.0
|
|
29
|
-
flit_core==3.12.0
|
|
30
|
-
fonttools==4.57.0
|
|
31
|
-
id==1.5.0
|
|
32
|
-
identify==2.6.10
|
|
33
|
-
idna==3.10
|
|
34
|
-
imagesize==1.4.1
|
|
35
|
-
importlib_metadata==8.6.1
|
|
36
|
-
iniconfig==2.1.0
|
|
37
|
-
ipykernel==6.29.5
|
|
38
|
-
ipython==8.36.0
|
|
39
|
-
ipywidgets==8.1.6
|
|
40
|
-
jaraco.classes==3.4.0
|
|
41
|
-
jaraco.context==6.0.1
|
|
42
|
-
jaraco.functools==4.1.0
|
|
43
|
-
jedi==0.19.2
|
|
44
|
-
jeepney==0.9.0
|
|
45
|
-
Jinja2==3.1.6
|
|
46
|
-
jsonschema==4.23.0
|
|
47
|
-
jsonschema-specifications==2025.4.1
|
|
48
|
-
jupyter_client==8.6.3
|
|
49
|
-
jupyter_core==5.7.2
|
|
50
|
-
jupyterlab_pygments==0.3.0
|
|
51
|
-
jupyterlab_widgets==3.0.14
|
|
52
|
-
keyring==25.6.0
|
|
53
|
-
kiwisolver==1.4.8
|
|
54
|
-
markdown-it-py==3.0.0
|
|
55
|
-
MarkupSafe==3.0.2
|
|
56
|
-
matplotlib==3.10.3
|
|
57
|
-
matplotlib-inline==0.1.7
|
|
58
|
-
mdit-py-plugins==0.4.2
|
|
59
|
-
mdurl==0.1.2
|
|
60
|
-
mistune==3.1.3
|
|
61
|
-
more-itertools==10.7.0
|
|
62
|
-
mypy==1.15.0
|
|
63
|
-
mypy_extensions==1.1.0
|
|
64
|
-
myst-parser==4.0.1
|
|
65
|
-
nbclient==0.10.2
|
|
66
|
-
nbconvert==7.16.6
|
|
67
|
-
nbformat==5.10.4
|
|
68
|
-
nbsphinx==0.9.7
|
|
69
|
-
nest-asyncio==1.6.0
|
|
70
|
-
networkx==3.4.2
|
|
71
|
-
nh3==0.2.21
|
|
72
|
-
nodeenv==1.9.1
|
|
73
|
-
numpy==2.2.5
|
|
74
|
-
packaging==25.0
|
|
75
|
-
pandas==2.2.3
|
|
76
|
-
pandocfilters==1.5.1
|
|
77
|
-
parso==0.8.4
|
|
78
|
-
pexpect==4.9.0
|
|
79
|
-
pillow==11.2.1
|
|
80
|
-
platformdirs==4.3.7
|
|
81
|
-
pluggy==1.5.0
|
|
82
|
-
pre_commit==4.2.0
|
|
83
|
-
prompt_toolkit==3.0.51
|
|
84
|
-
psutil==7.0.0
|
|
85
|
-
ptyprocess==0.7.0
|
|
86
|
-
pure_eval==0.2.3
|
|
87
|
-
pycparser==2.22
|
|
88
|
-
pydata-sphinx-theme==0.15.4
|
|
89
|
-
Pygments==2.19.1
|
|
90
|
-
pyparsing==3.2.3
|
|
91
|
-
pytest==8.3.5
|
|
92
|
-
python-dateutil==2.9.0.post0
|
|
93
|
-
pytz==2025.2
|
|
94
|
-
PyYAML==6.0.2
|
|
95
|
-
pyzmq==26.4.0
|
|
96
|
-
readme_renderer==44.0
|
|
97
|
-
referencing==0.36.2
|
|
98
|
-
requests==2.32.3
|
|
99
|
-
requests-toolbelt==1.0.0
|
|
100
|
-
rfc3986==2.0.0
|
|
101
|
-
rich==14.0.0
|
|
102
|
-
rpds-py==0.24.0
|
|
103
|
-
ruff==0.11.9
|
|
104
|
-
scipy==1.15.2
|
|
105
|
-
SecretStorage==3.3.3
|
|
106
|
-
six==1.17.0
|
|
107
|
-
snowballstemmer==2.2.0
|
|
108
|
-
soupsieve==2.7
|
|
109
|
-
Sphinx==8.1.3
|
|
110
|
-
sphinx-autoapi==3.6.0
|
|
111
|
-
sphinx-autodoc-typehints==3.0.1
|
|
112
|
-
sphinx-book-theme==1.1.4
|
|
113
|
-
sphinxcontrib-applehelp==2.0.0
|
|
114
|
-
sphinxcontrib-devhelp==2.0.0
|
|
115
|
-
sphinxcontrib-htmlhelp==2.1.0
|
|
116
|
-
sphinxcontrib-jsmath==1.0.1
|
|
117
|
-
sphinxcontrib-qthelp==2.0.0
|
|
118
|
-
sphinxcontrib-serializinghtml==2.0.0
|
|
119
|
-
stack-data==0.6.3
|
|
120
|
-
tinycss2==1.4.0
|
|
121
|
-
tomli==2.2.1
|
|
122
|
-
tomli_w==1.2.0
|
|
123
|
-
tornado==6.4.2
|
|
124
|
-
traitlets==5.14.3
|
|
125
|
-
twine==6.1.0
|
|
126
|
-
typing_extensions==4.13.2
|
|
127
|
-
tzdata==2025.2
|
|
128
|
-
urllib3==2.4.0
|
|
129
|
-
virtualenv==20.30.0
|
|
130
|
-
wcwidth==0.2.13
|
|
131
|
-
webencodings==0.5.1
|
|
132
|
-
widgetsnbextension==4.0.14
|
|
133
|
-
zipp==3.21.0
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from matplotlib_sankey._colors import is_color, is_colormap, colormap_to_list, is_hex_color, unify_color
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def test_color_utils() -> None:
|
|
5
|
-
"""Testing color utils."""
|
|
6
|
-
assert all(
|
|
7
|
-
[
|
|
8
|
-
is_color("blue"),
|
|
9
|
-
is_color("tab:red"),
|
|
10
|
-
is_color("#3456ad"),
|
|
11
|
-
is_color([1, 0.4, 0.2]),
|
|
12
|
-
is_color([255, 60, 60]),
|
|
13
|
-
]
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
assert is_hex_color("#345") is False
|
|
17
|
-
assert is_hex_color("test") is False
|
|
18
|
-
assert is_hex_color([255, 60, 60]) is False
|
|
19
|
-
|
|
20
|
-
assert unify_color("#FFFFFF") == (1, 1, 1)
|
|
21
|
-
|
|
22
|
-
assert is_colormap("tab10")
|
|
23
|
-
assert is_colormap("blue") is False
|
|
24
|
-
|
|
25
|
-
assert len(colormap_to_list("Reds", 20)) == 20
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import matplotlib.pyplot as plt
|
|
2
|
-
from matplotlib_sankey import sankey
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def test_sankey_simple_plot():
|
|
6
|
-
"""Testing simple sankey plot."""
|
|
7
|
-
data = [
|
|
8
|
-
[(0, 2, 20), (0, 1, 10), (3, 4, 15), (3, 2, 10), (5, 1, 5), (5, 2, 50)],
|
|
9
|
-
[(2, 6, 40), (1, 6, 15), (2, 7, 40), (4, 6, 15)],
|
|
10
|
-
[(7, 8, 5), (7, 9, 5), (7, 10, 20), (7, 11, 10), (6, 11, 55), (6, 8, 15)],
|
|
11
|
-
]
|
|
12
|
-
sankey(data, frameon=True)
|
|
13
|
-
sankey(data, curve_type="curve3")
|
|
14
|
-
sankey(data, curve_type="line")
|
|
15
|
-
sankey(data, title="test", annotate_columns="index")
|
|
16
|
-
sankey(data, color="Reds", annotate_columns="weight")
|
|
17
|
-
sankey(data, color="tab:red", annotate_columns="weight_percent", annotate_columns_font_color="white")
|
|
18
|
-
sankey(data, color=["tab:red", "Reds", (0.1, 0.4, 1.0), "viridis"])
|
|
19
|
-
sankey(data, show_legend=True)
|
|
20
|
-
sankey(data, color="tab:red", column_labels=["A", "B", "C", "D"], show=False)
|
|
21
|
-
|
|
22
|
-
_, ax = plt.subplots()
|
|
23
|
-
sankey(data, ax=ax)
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
from matplotlib import colormaps
|
|
2
|
-
from matplotlib.colors import Colormap
|
|
3
|
-
|
|
4
|
-
from matplotlib_sankey._utils import _generate_cmap, from_matrix, isinstance_list_of, is_light_color
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_utils_cmap() -> None:
|
|
8
|
-
"""Testing utils function to generate cmap."""
|
|
9
|
-
assert isinstance(_generate_cmap("tab10", 4), Colormap)
|
|
10
|
-
assert isinstance(_generate_cmap("viridis", 4), Colormap)
|
|
11
|
-
assert _generate_cmap("viridis", 4).N == 4
|
|
12
|
-
assert isinstance(_generate_cmap(["#ec4899", "#0284c7", "#16a34a", "#f59e0b"], 4), Colormap)
|
|
13
|
-
assert isinstance(_generate_cmap([(0.4, 0.1, 0.9), (0.1, 0.1, 0.7)], 4), Colormap)
|
|
14
|
-
assert isinstance(_generate_cmap(colormaps["tab10"], 4), Colormap)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_from_matrix() -> None:
|
|
18
|
-
"""Testing from matrix helper function."""
|
|
19
|
-
assert len(from_matrix([[0, 0], [0, 0]])) == 0
|
|
20
|
-
|
|
21
|
-
assert len(from_matrix([[0, 0], [0, 0]], source_indicies=["A", "B"], target_indicies=["C", "D"])) == 0
|
|
22
|
-
|
|
23
|
-
assert len(from_matrix([[0, 1], [0, 0]])) == 1
|
|
24
|
-
|
|
25
|
-
assert len(from_matrix([[0, 1], [0, 1]], source_indicies=["A", "B"], target_indicies=["C", "D"])) == 2
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def test_isinstance_list_of() -> None:
|
|
29
|
-
"""Testing is instance list of type."""
|
|
30
|
-
assert isinstance_list_of(["A", "b", "c"], str)
|
|
31
|
-
assert isinstance_list_of([1, 2, 3, 4], int)
|
|
32
|
-
assert isinstance_list_of(["A", "b", 1], str) is False
|
|
33
|
-
assert isinstance_list_of("test", str) is False
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def test_luminance() -> None:
|
|
37
|
-
"""Testing is light color function."""
|
|
38
|
-
assert is_light_color((1, 1, 1)) is True
|
|
39
|
-
assert is_light_color((0, 0, 0)) is False
|
|
40
|
-
assert is_light_color((255, 255, 255), color_range_max=255) is True
|
|
File without changes
|
|
File without changes
|
/matplotlib_sankey-0.3.0/tests/__init__.py → /matplotlib_sankey-0.3.2/src/matplotlib_sankey/py.typed
RENAMED
|
File without changes
|