d3graph 2.9.0__tar.gz → 2.9.1__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.
- {d3graph-2.9.0/d3graph.egg-info → d3graph-2.9.1}/PKG-INFO +1 -1
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/__init__.py +1 -1
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/d3graph.py +123 -73
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/examples.py +16 -5
- {d3graph-2.9.0 → d3graph-2.9.1/d3graph.egg-info}/PKG-INFO +1 -1
- {d3graph-2.9.0 → d3graph-2.9.1}/LICENSE +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/MANIFEST.in +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/README.md +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/d3js/d3.v3.js +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/d3js/d3graphscript.js +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/d3js/index.html.j2 +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/d3js/style.css +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph/examples_docs.py +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph.egg-info/SOURCES.txt +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph.egg-info/dependency_links.txt +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph.egg-info/requires.txt +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/d3graph.egg-info/top_level.txt +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/pyproject.toml +0 -0
- {d3graph-2.9.0 → d3graph-2.9.1}/setup.cfg +0 -0
|
@@ -352,7 +352,7 @@ class d3graph:
|
|
|
352
352
|
return
|
|
353
353
|
|
|
354
354
|
if (not directed) and (marker_end is not None) or (marker_start is not None):
|
|
355
|
-
logger.info('Set directed=True to see the markers
|
|
355
|
+
logger.info('Markers not shown. Set directed=True to see the markers.')
|
|
356
356
|
|
|
357
357
|
# Get node color properties which is required to set the edge color
|
|
358
358
|
node_color_map = None
|
|
@@ -364,6 +364,7 @@ class d3graph:
|
|
|
364
364
|
self.config['edge_color'] = '#808080'
|
|
365
365
|
|
|
366
366
|
# Set the edge properties
|
|
367
|
+
logger.info('Set the edge properties')
|
|
367
368
|
self.edge_properties, self.adjmat = adjmat2dict(
|
|
368
369
|
self.adjmat,
|
|
369
370
|
filter_weight=0,
|
|
@@ -385,7 +386,7 @@ class d3graph:
|
|
|
385
386
|
node_color_map=node_color_map,
|
|
386
387
|
)
|
|
387
388
|
|
|
388
|
-
logger.
|
|
389
|
+
# logger.info(f'Number of edges: {len(self.edge_properties.keys())}')
|
|
389
390
|
|
|
390
391
|
def set_node_properties(self,
|
|
391
392
|
label=None,
|
|
@@ -710,7 +711,7 @@ class d3graph:
|
|
|
710
711
|
Parameters
|
|
711
712
|
----------
|
|
712
713
|
adjmat : pd.DataFrame()
|
|
713
|
-
Adjacency matrix (symmetric
|
|
714
|
+
Adjacency matrix (symmetric and Values > 0 are edges).
|
|
714
715
|
color : list of strings (default: 'cluster')
|
|
715
716
|
Coloring of the nodes.
|
|
716
717
|
* 'cluster' or None : Colours are based on the community distance clusters.
|
|
@@ -1153,21 +1154,23 @@ def adjmat2dict(adjmat: pd.DataFrame,
|
|
|
1153
1154
|
'tooltip': Text that is shown when hovering over the edge.
|
|
1154
1155
|
|
|
1155
1156
|
"""
|
|
1156
|
-
# Convert adjacency matrix into vector
|
|
1157
|
-
df = adjmat.stack().reset_index()
|
|
1158
|
-
# Set columns
|
|
1159
|
-
df.columns = ['source', 'target', 'weight']
|
|
1160
|
-
# Combine source-target values with weights
|
|
1161
|
-
df = create_unique_dataframe(df)
|
|
1162
|
-
# Remove self loops and no-connected edges
|
|
1163
|
-
Iloc = df['source'] != df['target']
|
|
1164
|
-
# Keep only edges with a minimum edge strength
|
|
1165
|
-
if filter_weight is not None:
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
df = df.loc[Iloc, :]
|
|
1170
|
-
df.reset_index(drop=True, inplace=True)
|
|
1157
|
+
# # Convert adjacency matrix into vector
|
|
1158
|
+
# df = adjmat.stack().reset_index()
|
|
1159
|
+
# # Set columns
|
|
1160
|
+
# df.columns = ['source', 'target', 'weight']
|
|
1161
|
+
# # Combine source-target values with weights
|
|
1162
|
+
# df = create_unique_dataframe(df)
|
|
1163
|
+
# # Remove self loops and no-connected edges
|
|
1164
|
+
# Iloc = df['source'] != df['target']
|
|
1165
|
+
# # Keep only edges with a minimum edge strength
|
|
1166
|
+
# if filter_weight is not None:
|
|
1167
|
+
# logger.info(f"Keep only edges with weight>{filter_weight}")
|
|
1168
|
+
# Iloc2 = df['weight'] > filter_weight
|
|
1169
|
+
# Iloc = Iloc & Iloc2
|
|
1170
|
+
# df = df.loc[Iloc, :]
|
|
1171
|
+
# df.reset_index(drop=True, inplace=True)
|
|
1172
|
+
|
|
1173
|
+
df = adjmat2vec(adjmat)
|
|
1171
1174
|
|
|
1172
1175
|
# Scale the weights for visualization purposes
|
|
1173
1176
|
if minmax_distance is not None:
|
|
@@ -1225,6 +1228,7 @@ def adjmat2dict(adjmat: pd.DataFrame,
|
|
|
1225
1228
|
source_target = list(zip(df['source'], df['target']))
|
|
1226
1229
|
if len(source_target)==0:
|
|
1227
1230
|
raise Exception('There are no links in the input data set that have unique source-target value with weight > 0')
|
|
1231
|
+
|
|
1228
1232
|
# Return
|
|
1229
1233
|
d = {edge: {'weight': df['weight'].iloc[i],
|
|
1230
1234
|
'weight_scaled': df['weight_scaled'].iloc[i],
|
|
@@ -1249,6 +1253,36 @@ def adjmat2dict(adjmat: pd.DataFrame,
|
|
|
1249
1253
|
|
|
1250
1254
|
|
|
1251
1255
|
# %% Create unique dataframe and update weights
|
|
1256
|
+
# def create_unique_dataframe(X, logger=None):
|
|
1257
|
+
# """Combine source-target into adjacency matrix with updated weights.
|
|
1258
|
+
|
|
1259
|
+
# Parameters
|
|
1260
|
+
# ----------
|
|
1261
|
+
# X : DataFrame
|
|
1262
|
+
# Data frame containing the columns [source, target, weight].
|
|
1263
|
+
# logger : Object, optional
|
|
1264
|
+
# Logger object. The default is None.
|
|
1265
|
+
|
|
1266
|
+
# Returns
|
|
1267
|
+
# -------
|
|
1268
|
+
# X : pd.DataFrame
|
|
1269
|
+
# Unique adjacency matrix containing with index as source and columns as target labels. Weights are in the matrix.
|
|
1270
|
+
|
|
1271
|
+
# References
|
|
1272
|
+
# ----------
|
|
1273
|
+
# * This function is similar to that of d3blocks.
|
|
1274
|
+
|
|
1275
|
+
# """
|
|
1276
|
+
# # Check whether labels are unique
|
|
1277
|
+
# if isinstance(X, pd.DataFrame):
|
|
1278
|
+
# Iloc = ismember(X.columns, ['source', 'target', 'weight'])[0]
|
|
1279
|
+
# X = X.loc[:, Iloc]
|
|
1280
|
+
# if 'weight' in X.columns: X['weight'] = X['weight'].astype(float)
|
|
1281
|
+
# # Groupby values and sum the weights
|
|
1282
|
+
# X = X.groupby(by=['source', 'target']).sum()
|
|
1283
|
+
# X.reset_index(drop=False, inplace=True)
|
|
1284
|
+
# return X
|
|
1285
|
+
|
|
1252
1286
|
def create_unique_dataframe(X, logger=None):
|
|
1253
1287
|
"""Combine source-target into adjacency matrix with updated weights.
|
|
1254
1288
|
|
|
@@ -1269,15 +1303,12 @@ def create_unique_dataframe(X, logger=None):
|
|
|
1269
1303
|
* This function is similar to that of d3blocks.
|
|
1270
1304
|
|
|
1271
1305
|
"""
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
X = X.groupby(by=['source', 'target']).sum()
|
|
1279
|
-
X.reset_index(drop=False, inplace=True)
|
|
1280
|
-
return X
|
|
1306
|
+
X = X[['source', 'target', 'weight']]
|
|
1307
|
+
return (
|
|
1308
|
+
X.groupby(['source', 'target'], sort=False, observed=True)
|
|
1309
|
+
.agg({'weight': 'sum'})
|
|
1310
|
+
.reset_index()
|
|
1311
|
+
)
|
|
1281
1312
|
|
|
1282
1313
|
|
|
1283
1314
|
# %% Convert dict with edges to graph (G) (also works with lower versions of networkx)
|
|
@@ -1580,61 +1611,80 @@ def vec2adjmat(source, target, weight=None, symmetric: bool = True, aggfunc='sum
|
|
|
1580
1611
|
|
|
1581
1612
|
|
|
1582
1613
|
# %% Convert adjacency matrix to vector
|
|
1614
|
+
# def adjmat2vec(adjmat, min_weight: float = 1.0) -> pd.DataFrame:
|
|
1615
|
+
# """Convert adjacency matrix into vector with source and target.
|
|
1616
|
+
|
|
1617
|
+
# Parameters
|
|
1618
|
+
# ----------
|
|
1619
|
+
# adjmat : pd.DataFrame()
|
|
1620
|
+
# Adjacency matrix.
|
|
1621
|
+
|
|
1622
|
+
# min_weight : float
|
|
1623
|
+
# edges are returned with a minimum weight.
|
|
1624
|
+
|
|
1625
|
+
# Returns
|
|
1626
|
+
# -------
|
|
1627
|
+
# pd.DataFrame()
|
|
1628
|
+
# nodes that are connected based on source and target
|
|
1629
|
+
|
|
1630
|
+
# Examples
|
|
1631
|
+
# --------
|
|
1632
|
+
# >>> source = ['Cloudy', 'Cloudy', 'Sprinkler', 'Rain']
|
|
1633
|
+
# >>> target = ['Sprinkler', 'Rain', 'Wet_Grass', 'Wet_Grass']
|
|
1634
|
+
# >>> adjmat = vec2adjmat(source, target, weight=[1, 2, 1, 3])
|
|
1635
|
+
# >>> vector = adjmat2vec(adjmat)
|
|
1636
|
+
|
|
1637
|
+
# """
|
|
1638
|
+
# # Convert adjacency matrix into vector
|
|
1639
|
+
# logger.info('Converting adjacency matrix into source-target..')
|
|
1640
|
+
# adjmat = adjmat.stack().reset_index()
|
|
1641
|
+
# # Set columns
|
|
1642
|
+
# adjmat.columns = ['source', 'target', 'weight']
|
|
1643
|
+
# # Remove self loops and no-connected edges
|
|
1644
|
+
# Iloc1 = adjmat['source'] != adjmat['target']
|
|
1645
|
+
# Iloc2 = adjmat['weight'] >= min_weight
|
|
1646
|
+
# Iloc = Iloc1 & Iloc2
|
|
1647
|
+
# # Take only connected nodes
|
|
1648
|
+
# adjmat = adjmat.loc[Iloc, :]
|
|
1649
|
+
# adjmat.reset_index(drop=True, inplace=True)
|
|
1650
|
+
# return adjmat
|
|
1651
|
+
|
|
1652
|
+
|
|
1583
1653
|
def adjmat2vec(adjmat, min_weight: float = 1.0) -> pd.DataFrame:
|
|
1584
|
-
"""
|
|
1654
|
+
"""
|
|
1655
|
+
Fast conversion of adjacency matrix → edge list.
|
|
1656
|
+
Removes self-loops and filters by min_weight.
|
|
1657
|
+
"""
|
|
1658
|
+
weights = adjmat.to_numpy(copy=False)
|
|
1585
1659
|
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
adjmat : pd.DataFrame()
|
|
1589
|
-
Adjacency matrix.
|
|
1660
|
+
# Mask of valid edges (stack() drops NaN, so we mimic that)
|
|
1661
|
+
mask = ~np.isnan(weights)
|
|
1590
1662
|
|
|
1591
|
-
|
|
1592
|
-
|
|
1663
|
+
# Extract coordinates of non-NaN entries
|
|
1664
|
+
row_idx, col_idx = np.nonzero(mask)
|
|
1593
1665
|
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
pd.DataFrame()
|
|
1597
|
-
nodes that are connected based on source and target
|
|
1666
|
+
index = adjmat.index.to_numpy()
|
|
1667
|
+
columns = adjmat.columns.to_numpy()
|
|
1598
1668
|
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1669
|
+
# Build edge list
|
|
1670
|
+
df = pd.DataFrame({
|
|
1671
|
+
'source': index[row_idx],
|
|
1672
|
+
'target': columns[col_idx],
|
|
1673
|
+
'weight': weights[row_idx, col_idx],
|
|
1674
|
+
})
|
|
1605
1675
|
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
logger.info('Converting adjacency matrix into source-target..')
|
|
1609
|
-
adjmat = adjmat.stack().reset_index()
|
|
1610
|
-
# Set columns
|
|
1611
|
-
adjmat.columns = ['source', 'target', 'weight']
|
|
1612
|
-
# Remove self loops and no-connected edges
|
|
1613
|
-
Iloc1 = adjmat['source'] != adjmat['target']
|
|
1614
|
-
Iloc2 = adjmat['weight'] >= min_weight
|
|
1615
|
-
Iloc = Iloc1 & Iloc2
|
|
1616
|
-
# Take only connected nodes
|
|
1617
|
-
adjmat = adjmat.loc[Iloc, :]
|
|
1618
|
-
adjmat.reset_index(drop=True, inplace=True)
|
|
1619
|
-
return adjmat
|
|
1676
|
+
# Remove self-loops
|
|
1677
|
+
df = df[df['source'] != df['target']]
|
|
1620
1678
|
|
|
1679
|
+
# Apply minimum weight filter
|
|
1680
|
+
if min_weight is not None:
|
|
1681
|
+
df = df[df['weight'] >= min_weight]
|
|
1682
|
+
|
|
1683
|
+
df.reset_index(drop=True, inplace=True)
|
|
1684
|
+
return df
|
|
1621
1685
|
|
|
1622
|
-
# def _check_hex_color(color, n=None, cmap='Set1'):
|
|
1623
|
-
# if isinstance(color, str) and len(color) != 7:
|
|
1624
|
-
# logger.warning('Input parameter [color] has wrong format. Must be like color="#000000" <auto-fixing>')
|
|
1625
|
-
# return get_hex_color(color, cmap=cmap)[0]
|
|
1626
|
-
# if isinstance(color, (list, np.ndarray, pd.Series, pd.Series, StringArray)) and len(color) == 0:
|
|
1627
|
-
# logger.warning('Input parameter [color] has wrong format and length. Must be like: color=["#000000", "...", "#000000"] <auto-fixing>')
|
|
1628
|
-
# return get_hex_color(color, cmap=cmap)[0]
|
|
1629
|
-
# if isinstance(color, (list, np.ndarray, pd.Series, pd.Series, StringArray)) and (not np.all(list(map(lambda x: len(x) == 7, color)))):
|
|
1630
|
-
# logger.warning('[color] contains incorrect hex-colors. Hex must be of length 7: ["#000000", "#000000", etc] <auto-fixing>')
|
|
1631
|
-
# return get_hex_color(color, cmap=cmap)[0]
|
|
1632
|
-
# if (n is not None) and isinstance(color, (list, np.ndarray, pd.Series, pd.Series, StringArray)) and len(color) != n:
|
|
1633
|
-
# logger.warning(f'Input parameter [color] has wrong length. Must be of length: {str(n)} <auto-fixing>')
|
|
1634
|
-
# return get_hex_color(color, cmap=cmap)[0]
|
|
1635
|
-
# # Return original input
|
|
1636
|
-
# return color
|
|
1637
1686
|
|
|
1687
|
+
# %%
|
|
1638
1688
|
def _check_hex_color(color, n=None, cmap='Set1'):
|
|
1639
1689
|
seq_types = (list, np.ndarray, pd.Series, StringArray)
|
|
1640
1690
|
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
# %%
|
|
2
2
|
from d3graph import d3graph, vec2adjmat, import_example
|
|
3
3
|
import pandas as pd
|
|
4
|
+
import time
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
df = pd.read_csv('https://github.com/d3blocks/d3blocks/files/11995798/Df.csv', sep=',', index_col=False)
|
|
6
8
|
del df['Unnamed: 0']
|
|
7
|
-
df = df[0:
|
|
9
|
+
df = df[0:10000]
|
|
8
10
|
adjmat = vec2adjmat(source=df['source'], target=df['target'], weight=df['weight'])
|
|
9
11
|
|
|
10
|
-
# sticky=False — classic spring-back behaviour
|
|
11
12
|
d3 = d3graph()
|
|
13
|
+
|
|
14
|
+
start = time.perf_counter()
|
|
12
15
|
d3.graph(adjmat)
|
|
16
|
+
end = time.perf_counter()
|
|
17
|
+
|
|
13
18
|
d3.show()
|
|
14
19
|
|
|
20
|
+
print(f"Elapsed: {end - start:.6f} seconds")
|
|
21
|
+
|
|
22
|
+
|
|
15
23
|
# %% SET PATH ISSUE https://github.com/erdogant/d3graph/issues/42
|
|
16
24
|
from pathlib import Path
|
|
17
25
|
from d3graph import d3graph, vec2adjmat, import_example
|
|
@@ -123,15 +131,18 @@ adjmat = vec2adjmat(source=df['source'], target=df['target'], weight=df['weight'
|
|
|
123
131
|
|
|
124
132
|
|
|
125
133
|
# sticky=True (default) — drag to pin, right-click to release
|
|
126
|
-
d3 = d3graph(
|
|
134
|
+
d3 = d3graph(sticky=True)
|
|
135
|
+
d3.graph(adjmat)
|
|
127
136
|
d3.show()
|
|
128
137
|
|
|
129
138
|
# sticky=False — classic spring-back behaviour
|
|
130
|
-
d3 = d3graph(
|
|
139
|
+
d3 = d3graph(sticky=False)
|
|
140
|
+
d3.graph(adjmat)
|
|
131
141
|
d3.show()
|
|
132
142
|
|
|
133
143
|
# Can also be overridden per-render:
|
|
134
|
-
d3.show(
|
|
144
|
+
d3.show(sticky=False)
|
|
145
|
+
d3.graph(adjmat)
|
|
135
146
|
d3.show()
|
|
136
147
|
|
|
137
148
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|