iplotx 0.0.1__py3-none-any.whl → 0.2.0__py3-none-any.whl
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.
- iplotx/__init__.py +22 -1
- iplotx/edge/__init__.py +882 -0
- iplotx/edge/arrow.py +220 -10
- iplotx/edge/ports.py +42 -0
- iplotx/groups.py +79 -41
- iplotx/ingest/__init__.py +155 -0
- iplotx/ingest/heuristics.py +209 -0
- iplotx/ingest/providers/network/igraph.py +96 -0
- iplotx/ingest/providers/network/networkx.py +133 -0
- iplotx/ingest/providers/tree/biopython.py +105 -0
- iplotx/ingest/providers/tree/cogent3.py +112 -0
- iplotx/ingest/providers/tree/ete4.py +112 -0
- iplotx/ingest/providers/tree/skbio.py +112 -0
- iplotx/ingest/typing.py +100 -0
- iplotx/label.py +127 -0
- iplotx/layout.py +139 -0
- iplotx/network.py +156 -375
- iplotx/plotting.py +157 -55
- iplotx/style.py +379 -0
- iplotx/tree.py +285 -0
- iplotx/typing.py +33 -38
- iplotx/utils/geometry.py +128 -81
- iplotx/utils/internal.py +3 -0
- iplotx/utils/matplotlib.py +58 -38
- iplotx/utils/style.py +1 -0
- iplotx/version.py +5 -1
- iplotx/vertex.py +250 -55
- iplotx-0.2.0.dist-info/METADATA +76 -0
- iplotx-0.2.0.dist-info/RECORD +30 -0
- {iplotx-0.0.1.dist-info → iplotx-0.2.0.dist-info}/WHEEL +0 -1
- iplotx/edge/common.py +0 -47
- iplotx/edge/directed.py +0 -149
- iplotx/edge/label.py +0 -50
- iplotx/edge/undirected.py +0 -447
- iplotx/heuristics.py +0 -114
- iplotx/importing.py +0 -13
- iplotx/styles.py +0 -186
- iplotx-0.0.1.dist-info/METADATA +0 -39
- iplotx-0.0.1.dist-info/RECORD +0 -20
iplotx/heuristics.py
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
from collections import defaultdict
|
|
2
|
-
import numpy as np
|
|
3
|
-
import pandas as pd
|
|
4
|
-
|
|
5
|
-
from .importing import igraph, networkx
|
|
6
|
-
from .typing import GraphType, GroupingType, LayoutType
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def network_library(
|
|
10
|
-
network: GraphType,
|
|
11
|
-
) -> str:
|
|
12
|
-
if igraph is not None and isinstance(network, igraph.Graph):
|
|
13
|
-
return "igraph"
|
|
14
|
-
if networkx is not None:
|
|
15
|
-
if isinstance(network, networkx.Graph):
|
|
16
|
-
return "networkx"
|
|
17
|
-
if isinstance(network, networkx.DiGraph):
|
|
18
|
-
return "networkx"
|
|
19
|
-
if isinstance(network, networkx.MultiGraph):
|
|
20
|
-
return "networkx"
|
|
21
|
-
if isinstance(network, networkx.MultiDiGraph):
|
|
22
|
-
return "networkx"
|
|
23
|
-
raise TypeError("Unsupported graph type. Supported types are igraph and networkx.")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def detect_directedness(
|
|
27
|
-
network: GraphType,
|
|
28
|
-
) -> np.ndarray:
|
|
29
|
-
"""Detect if the network is directed or not."""
|
|
30
|
-
if network_library(network) == "igraph":
|
|
31
|
-
return network.is_directed()
|
|
32
|
-
if isinstance(network, (networkx.DiGraph, networkx.MultiDiGraph)):
|
|
33
|
-
return True
|
|
34
|
-
return False
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def normalise_layout(layout):
|
|
38
|
-
"""Normalise the layout to a pandas.DataFrame."""
|
|
39
|
-
if layout is None:
|
|
40
|
-
return None
|
|
41
|
-
if isinstance(layout, dict):
|
|
42
|
-
layout = pd.DataFrame(layout).T
|
|
43
|
-
if isinstance(layout, str):
|
|
44
|
-
raise NotImplementedError("Layout as a string is not supported yet.")
|
|
45
|
-
if isinstance(layout, (list, tuple)):
|
|
46
|
-
return pd.DataFrame(np.array(layout))
|
|
47
|
-
if isinstance(layout, pd.DataFrame):
|
|
48
|
-
return layout
|
|
49
|
-
if isinstance(layout, np.ndarray):
|
|
50
|
-
return pd.DataFrame(layout)
|
|
51
|
-
raise TypeError(
|
|
52
|
-
"Layout must be a string, list, tuple, numpy array or pandas DataFrame."
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def normalise_grouping(
|
|
57
|
-
grouping: GroupingType,
|
|
58
|
-
layout: LayoutType,
|
|
59
|
-
) -> dict[set]:
|
|
60
|
-
|
|
61
|
-
if len(grouping) == 0:
|
|
62
|
-
return {}
|
|
63
|
-
|
|
64
|
-
if isinstance(grouping, dict):
|
|
65
|
-
val0 = next(iter(grouping.values()))
|
|
66
|
-
# If already the right data type or compatible, leave as is
|
|
67
|
-
if isinstance(val0, (set, frozenset)):
|
|
68
|
-
return grouping
|
|
69
|
-
|
|
70
|
-
# If a dict of integers or strings, assume each key is a vertex id and each value is a
|
|
71
|
-
# group, convert (i.e. invert the dict)
|
|
72
|
-
if isinstance(val0, (int, str)):
|
|
73
|
-
group_dic = defaultdict(set)
|
|
74
|
-
for key, val in grouping.items():
|
|
75
|
-
group_dic[val].add(key)
|
|
76
|
-
return group_dic
|
|
77
|
-
|
|
78
|
-
# If an igraph object, convert to a dict of sets
|
|
79
|
-
if igraph is not None:
|
|
80
|
-
if isinstance(grouping, igraph.clustering.Clustering):
|
|
81
|
-
layout = normalise_layout(layout)
|
|
82
|
-
group_dic = defaultdict(set)
|
|
83
|
-
for i, member in enumerate(grouping.membership):
|
|
84
|
-
group_dic[member].add(i)
|
|
85
|
-
return group_dic
|
|
86
|
-
|
|
87
|
-
if isinstance(grouping, igraph.clustering.Cover):
|
|
88
|
-
layout = normalise_layout(layout)
|
|
89
|
-
group_dic = defaultdict(set)
|
|
90
|
-
for i, members in enumerate(grouping.membership):
|
|
91
|
-
for member in members:
|
|
92
|
-
group_dic[member].add(i)
|
|
93
|
-
return group_dic
|
|
94
|
-
|
|
95
|
-
# Assume it's a sequence, so convert to list
|
|
96
|
-
grouping = list(grouping)
|
|
97
|
-
|
|
98
|
-
# If the values are already sets, assume group indices are integers
|
|
99
|
-
# and values are as is
|
|
100
|
-
if isinstance(grouping[0], set):
|
|
101
|
-
group_dic = {i: val for i, val in enumerate(grouping)}
|
|
102
|
-
return group_dic
|
|
103
|
-
|
|
104
|
-
# If the values are integers or strings, assume each key is a vertex id and each value is a
|
|
105
|
-
# group, convert to dict of sets
|
|
106
|
-
if isinstance(grouping[0], (int, str)):
|
|
107
|
-
group_dic = defaultdict(set)
|
|
108
|
-
for i, val in enumerate(grouping):
|
|
109
|
-
group_dic[val].add(i)
|
|
110
|
-
return group_dic
|
|
111
|
-
|
|
112
|
-
raise TypeError(
|
|
113
|
-
"Could not standardise grouping from object.",
|
|
114
|
-
)
|
iplotx/importing.py
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
try:
|
|
2
|
-
import igraph
|
|
3
|
-
except ImportError:
|
|
4
|
-
igraph = None
|
|
5
|
-
|
|
6
|
-
try:
|
|
7
|
-
import networkx
|
|
8
|
-
except ImportError:
|
|
9
|
-
networkx = None
|
|
10
|
-
|
|
11
|
-
if igraph is None and networkx is None:
|
|
12
|
-
raise ImportError("At least one of igraph or networkx must be installed to use this module.")
|
|
13
|
-
|
iplotx/styles.py
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
from typing import Union, Sequence, Hashable
|
|
2
|
-
from copy import deepcopy
|
|
3
|
-
from contextlib import contextmanager
|
|
4
|
-
import numpy as np
|
|
5
|
-
import pandas as pd
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
style_leaves = (
|
|
9
|
-
"edgecolor",
|
|
10
|
-
"facecolor",
|
|
11
|
-
"linewidth",
|
|
12
|
-
"linestyle",
|
|
13
|
-
"alpha",
|
|
14
|
-
"zorder",
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
default = {
|
|
19
|
-
"vertex": {
|
|
20
|
-
"size": 20,
|
|
21
|
-
"facecolor": "black",
|
|
22
|
-
"marker": "o",
|
|
23
|
-
"label": {
|
|
24
|
-
"horizontalalignment": "center",
|
|
25
|
-
"verticalalignment": "center",
|
|
26
|
-
"hpadding": 18,
|
|
27
|
-
"vpadding": 12,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
"edge": {
|
|
31
|
-
"linewidth": 1.5,
|
|
32
|
-
"linestyle": "-",
|
|
33
|
-
"color": "black",
|
|
34
|
-
"curved": False,
|
|
35
|
-
"offset": 3,
|
|
36
|
-
"tension": 1,
|
|
37
|
-
"label": {
|
|
38
|
-
"horizontalalignment": "center",
|
|
39
|
-
"verticalalignment": "center",
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
"arrow": {
|
|
43
|
-
"marker": "|>",
|
|
44
|
-
"width": 8,
|
|
45
|
-
"color": "black",
|
|
46
|
-
},
|
|
47
|
-
"grouping": {
|
|
48
|
-
"facecolor": ["grey", "steelblue", "tomato"],
|
|
49
|
-
"edgecolor": "black",
|
|
50
|
-
"linewidth": 1.5,
|
|
51
|
-
"alpha": 0.5,
|
|
52
|
-
"vertexpadding": 25,
|
|
53
|
-
},
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
hollow = deepcopy(default)
|
|
57
|
-
hollow["vertex"]["color"] = None
|
|
58
|
-
hollow["vertex"]["facecolor"] = "none"
|
|
59
|
-
hollow["vertex"]["edgecolor"] = "black"
|
|
60
|
-
hollow["vertex"]["linewidth"] = 1.5
|
|
61
|
-
hollow["vertex"]["marker"] = "r"
|
|
62
|
-
hollow["vertex"]["size"] = "label"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
styles = {
|
|
66
|
-
"default": default,
|
|
67
|
-
"hollow": hollow,
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
stylename = "default"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
current = deepcopy(styles["default"])
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def get_stylename():
|
|
78
|
-
"""Return the name of the current iplotx style."""
|
|
79
|
-
return str(stylename)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def get_style(name: str = ""):
|
|
83
|
-
namelist = name.split(".")
|
|
84
|
-
style = styles
|
|
85
|
-
for i, namei in enumerate(namelist):
|
|
86
|
-
if (i == 0) and (namei == ""):
|
|
87
|
-
style = current
|
|
88
|
-
else:
|
|
89
|
-
try:
|
|
90
|
-
style = style[namei]
|
|
91
|
-
except KeyError:
|
|
92
|
-
raise KeyError(f"Style not found: {name}")
|
|
93
|
-
|
|
94
|
-
style = deepcopy(style)
|
|
95
|
-
return style
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# The following is inspired by matplotlib's style library
|
|
99
|
-
# https://github.com/matplotlib/matplotlib/blob/v3.10.3/lib/matplotlib/style/core.py#L45
|
|
100
|
-
def use(style: Union[str, dict, Sequence]):
|
|
101
|
-
"""Use iplotx style setting for a style specification.
|
|
102
|
-
|
|
103
|
-
The style name of 'default' is reserved for reverting back to
|
|
104
|
-
the default style settings.
|
|
105
|
-
|
|
106
|
-
Parameters:
|
|
107
|
-
style: A style specification, currently either a name of an existing style
|
|
108
|
-
or a dict with specific parts of the style to override. The string
|
|
109
|
-
"default" resets the style to the default one. If this is a sequence,
|
|
110
|
-
each style is applied in order.
|
|
111
|
-
"""
|
|
112
|
-
global current
|
|
113
|
-
|
|
114
|
-
def _update(style: dict, current: dict):
|
|
115
|
-
for key, value in style.items():
|
|
116
|
-
if key not in current:
|
|
117
|
-
current[key] = value
|
|
118
|
-
continue
|
|
119
|
-
|
|
120
|
-
# Style leaves are by definition not to be recurred into
|
|
121
|
-
if isinstance(value, dict) and (key not in style_leaves):
|
|
122
|
-
_update(value, current[key])
|
|
123
|
-
elif value is None:
|
|
124
|
-
del current[key]
|
|
125
|
-
else:
|
|
126
|
-
current[key] = value
|
|
127
|
-
|
|
128
|
-
if isinstance(style, (dict, str)):
|
|
129
|
-
styles = [style]
|
|
130
|
-
else:
|
|
131
|
-
styles = style
|
|
132
|
-
|
|
133
|
-
for style in styles:
|
|
134
|
-
if style == "default":
|
|
135
|
-
reset()
|
|
136
|
-
else:
|
|
137
|
-
if isinstance(style, str):
|
|
138
|
-
current = get_style(style)
|
|
139
|
-
else:
|
|
140
|
-
_update(style, current)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def reset():
|
|
144
|
-
"""Reset to default style."""
|
|
145
|
-
global current
|
|
146
|
-
current = deepcopy(styles["default"])
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
@contextmanager
|
|
150
|
-
def stylecontext(style: Union[str, dict, Sequence]):
|
|
151
|
-
current = get_style()
|
|
152
|
-
try:
|
|
153
|
-
use(style)
|
|
154
|
-
yield
|
|
155
|
-
finally:
|
|
156
|
-
use(current)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def rotate_style(
|
|
160
|
-
style,
|
|
161
|
-
index: Union[int, None] = None,
|
|
162
|
-
id: Union[Hashable, None] = None,
|
|
163
|
-
props=style_leaves,
|
|
164
|
-
):
|
|
165
|
-
if (index is None) and (id is None):
|
|
166
|
-
raise ValueError(
|
|
167
|
-
"At least one of 'index' or 'id' must be provided to rotate_style."
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
style = deepcopy(style)
|
|
171
|
-
|
|
172
|
-
for prop in props:
|
|
173
|
-
val = style.get(prop, None)
|
|
174
|
-
if val is None:
|
|
175
|
-
continue
|
|
176
|
-
# NOTE: this assumes that these properties are leaves of the style tree
|
|
177
|
-
# Btw: dict includes defaultdict, Couter, etc.
|
|
178
|
-
if (id is not None) and isinstance(val, (dict, pd.Series)):
|
|
179
|
-
# This works on both dict-like and Series
|
|
180
|
-
style[prop] = val[id]
|
|
181
|
-
elif (index is not None) and isinstance(
|
|
182
|
-
val, (tuple, list, np.ndarray, pd.Index, pd.Series)
|
|
183
|
-
):
|
|
184
|
-
style[prop] = np.asarray(val)[index % len(val)]
|
|
185
|
-
|
|
186
|
-
return style
|
iplotx-0.0.1.dist-info/METADATA
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: iplotx
|
|
3
|
-
Version: 0.0.1
|
|
4
|
-
Summary: Plot networkx from igraph and networkx.
|
|
5
|
-
Project-URL: Homepage, https://github.com/fabilab/iplotx
|
|
6
|
-
Project-URL: Documentation, https://readthedocs.org/iplotx
|
|
7
|
-
Project-URL: Repository, https://github.com/fabilab/iplotx.git
|
|
8
|
-
Project-URL: Bug Tracker, https://github.com/fabilab/iplotx/issues
|
|
9
|
-
Project-URL: Changelog, https://github.com/fabilab/iplotx/blob/main/CHANGELOG.md
|
|
10
|
-
Author-email: Fabio Zanini <fabio.zanini@unsw.edu.au>
|
|
11
|
-
Maintainer-email: Fabio Zanini <fabio.zanini@unsw.edu.au>
|
|
12
|
-
License: MIT
|
|
13
|
-
Keywords: graph,network,plotting,visualisation
|
|
14
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
-
Classifier: Operating System :: OS Independent
|
|
16
|
-
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
-
Requires-Dist: matplotlib>=2.0.0
|
|
22
|
-
Requires-Dist: pandas>=2.0.0
|
|
23
|
-
Description-Content-Type: text/markdown
|
|
24
|
-
|
|
25
|
-
# iplotx
|
|
26
|
-
Plotting networks from igraph and networkx.
|
|
27
|
-
|
|
28
|
-
**NOTE**: This is currently pre-alpha quality software. The API and functionality will break constantly, so use at your own risk. That said, if you have things you would like to see improved, please open a GitHub issue.
|
|
29
|
-
|
|
30
|
-
## Roadmap
|
|
31
|
-
- Plot networks from igraph and networkx interchangeably, using matplotlib as a backend. ✅
|
|
32
|
-
- Support interactive plotting, e.g. zooming and panning after the plot is created. ✅
|
|
33
|
-
- Support storing the plot to disk thanks to the many matplotlib backends (SVG, PNG, PDF, etc.).
|
|
34
|
-
- Efficient plotting of large graphs using matplotlib's collection functionality. ✅ (partially)
|
|
35
|
-
- Support animations, e.g. showing the evolution of a network over time. 🏗️
|
|
36
|
-
- Support uni- and bi-directional communication between graph object and plot object.🏗️
|
|
37
|
-
|
|
38
|
-
## Authors
|
|
39
|
-
Fabio Zanini (https://fabilab.org)
|
iplotx-0.0.1.dist-info/RECORD
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
iplotx/__init__.py,sha256=VrbOJwPlhb_wEeyCU0OcfiNde_SJqYmHwa1Qh2trHvE,60
|
|
2
|
-
iplotx/groups.py,sha256=PplZgemEEg7b285fwV--08yIIomRTgg0xxyvvHeoBp8,4289
|
|
3
|
-
iplotx/heuristics.py,sha256=bnfetQRxZA-Ii2V61XH7VYnvvG6DyKqiH2iOsA5la9o,3810
|
|
4
|
-
iplotx/importing.py,sha256=GCzbQ4X8BAk0Cv9Nue-B-3vHiCmGHmF6pVPIVRUhGI8,267
|
|
5
|
-
iplotx/network.py,sha256=jipKjV6NtVteUoqeSTRc1kfkmRfTT0L8uEPCLt_ipJ4,18070
|
|
6
|
-
iplotx/plotting.py,sha256=Isdvxb8tAGhWPNHiEC-KG9TQb5C1_5s_F9C7NGP-p5Y,3389
|
|
7
|
-
iplotx/styles.py,sha256=lHn-NRQ0CkG7dWe-J1wuGa-rH8ut4dqBa8rLGbqk1Ig,4679
|
|
8
|
-
iplotx/typing.py,sha256=0RrZqEKsC9rSnPQIKg-br1g2w5wDVpTzrlx04rKnN0Y,1304
|
|
9
|
-
iplotx/version.py,sha256=sXLh7g3KC4QCFxcZGBTpG2scR7hmmBsMjq6LqRptkRg,22
|
|
10
|
-
iplotx/vertex.py,sha256=qP6V9eAoC6zb9uD00sxUlIWnEPbMxLeQRJoiKVCubLU,3485
|
|
11
|
-
iplotx/edge/arrow.py,sha256=gUvTXVFG8e9G0qeztljqHVTZwYSCrhIDj0HGq3anenk,3876
|
|
12
|
-
iplotx/edge/common.py,sha256=62CCsA_1z9qhKIgSEbnfxzj9elKxPDv0REbLewKnnqo,1445
|
|
13
|
-
iplotx/edge/directed.py,sha256=zUU0vJApasNcvIApNGYy_x0NDnVyStgCKJn5J6U3tW4,5059
|
|
14
|
-
iplotx/edge/label.py,sha256=rutePN_WEIT8IR7FSRrvsoIJw2WoFWDSHCh0dmHeJTI,1407
|
|
15
|
-
iplotx/edge/undirected.py,sha256=LfDHqUP5zEBuf69lyOhUU_tk5ZGCJyw5xL3eZnTk7OU,14799
|
|
16
|
-
iplotx/utils/geometry.py,sha256=3HIsH_Nek_m41vL7twvgmDYfhlJURYd5TbMaa15nyt8,7804
|
|
17
|
-
iplotx/utils/matplotlib.py,sha256=I4Lw6vMPIgKMyqcR6RQBiRPKnmi5ko_GAtG04cT5XPw,3972
|
|
18
|
-
iplotx-0.0.1.dist-info/METADATA,sha256=xG3Y-FukA2CGxLHBB5t33kxnT56rbxlpDpsfvZQ-J1A,1932
|
|
19
|
-
iplotx-0.0.1.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
20
|
-
iplotx-0.0.1.dist-info/RECORD,,
|