topologicpy 0.8.10__py3-none-any.whl → 0.8.12__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.
- topologicpy/Face.py +55 -0
- topologicpy/Graph.py +262 -299
- topologicpy/Matrix.py +211 -5
- topologicpy/Plotly.py +8 -9
- topologicpy/Topology.py +341 -397
- topologicpy/Vector.py +71 -22
- topologicpy/Vertex.py +57 -0
- topologicpy/Wire.py +0 -119
- topologicpy/version.py +1 -1
- {topologicpy-0.8.10.dist-info → topologicpy-0.8.12.dist-info}/METADATA +1 -1
- {topologicpy-0.8.10.dist-info → topologicpy-0.8.12.dist-info}/RECORD +14 -14
- {topologicpy-0.8.10.dist-info → topologicpy-0.8.12.dist-info}/LICENSE +0 -0
- {topologicpy-0.8.10.dist-info → topologicpy-0.8.12.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.10.dist-info → topologicpy-0.8.12.dist-info}/top_level.txt +0 -0
topologicpy/Graph.py
CHANGED
@@ -522,7 +522,7 @@ class Graph:
|
|
522
522
|
return adjDict
|
523
523
|
|
524
524
|
@staticmethod
|
525
|
-
def AdjacencyMatrix(graph, vertexKey=None, reverse=False, edgeKeyFwd=None, edgeKeyBwd=None, bidirKey=None, bidirectional=True, useEdgeIndex=False, useEdgeLength=False, tolerance=0.0001):
|
525
|
+
def AdjacencyMatrix(graph, vertexKey=None, reverse=False, edgeKeyFwd=None, edgeKeyBwd=None, bidirKey=None, bidirectional=True, useEdgeIndex=False, useEdgeLength=False, mantissa: int = 6, tolerance=0.0001):
|
526
526
|
"""
|
527
527
|
Returns the adjacency matrix of the input Graph. See https://en.wikipedia.org/wiki/Adjacency_matrix.
|
528
528
|
|
@@ -542,10 +542,12 @@ class Graph:
|
|
542
542
|
If set to True or False, this key in the connecting edge will be used to determine is the edge is supposed to be bidirectional or not. If set to None, the input variable bidrectional will be used instead. The default is None
|
543
543
|
bidirectional : bool , optional
|
544
544
|
If set to True, the edges in the graph that do not have a bidireKey in their dictionaries will be treated as being bidirectional. Otherwise, the start vertex and end vertex of the connecting edge will determine the direction. The default is True.
|
545
|
-
useEdgeIndex : bool ,
|
545
|
+
useEdgeIndex : bool , optional
|
546
546
|
If set to True, the adjacency matrix values will the index of the edge in Graph.Edges(graph). The default is False. Both useEdgeIndex, useEdgeLength should not be True at the same time. If they are, useEdgeLength will be used.
|
547
|
-
useEdgeLength : bool ,
|
547
|
+
useEdgeLength : bool , optional
|
548
548
|
If set to True, the adjacency matrix values will the length of the edge in Graph.Edges(graph). The default is False. Both useEdgeIndex, useEdgeLength should not be True at the same time. If they are, useEdgeLength will be used.
|
549
|
+
mantissa : int , optional
|
550
|
+
The desired length of the mantissa. The default is 6.
|
549
551
|
tolerance : float , optional
|
550
552
|
The desired tolerance. The default is 0.0001.
|
551
553
|
|
@@ -599,12 +601,16 @@ class Graph:
|
|
599
601
|
bidir = bidirectional
|
600
602
|
if edgeKeyFwd == None:
|
601
603
|
valueFwd = 1
|
604
|
+
elif "len" in edgeKeyFwd.lower() or "dis" in edgeKeyFwd.lower():
|
605
|
+
valueFwd = Edge.Length(edge, mantissa=mantissa)
|
602
606
|
else:
|
603
607
|
valueFwd = Dictionary.ValueAtKey(Topology.Dictionary(edge), edgeKeyFwd)
|
604
608
|
if valueFwd == None:
|
605
609
|
valueFwd = 1
|
606
610
|
if edgeKeyBwd == None:
|
607
611
|
valueBwd = 1
|
612
|
+
elif "len" in edgeKeyBwd.lower() or "dis" in edgeKeyBwd.lower():
|
613
|
+
valueBwd = Edge.Length(edge, mantissa=mantissa)
|
608
614
|
else:
|
609
615
|
valueBwd = Dictionary.ValueAtKey(Topology.Dictionary(edge), edgeKeyBwd)
|
610
616
|
if valueBwd == None:
|
@@ -613,8 +619,8 @@ class Graph:
|
|
613
619
|
valueFwd = i+1
|
614
620
|
valueBwd = i+1
|
615
621
|
if useEdgeLength:
|
616
|
-
valueFwd = Edge.Length(edge)
|
617
|
-
valueBwd = Edge.Length(edge)
|
622
|
+
valueFwd = Edge.Length(edge, mantissa=mantissa)
|
623
|
+
valueBwd = Edge.Length(edge, mantissa=mantissa)
|
618
624
|
if not svi == None and not evi == None:
|
619
625
|
matrix[svi][evi] = valueFwd
|
620
626
|
if bidir:
|
@@ -1352,7 +1358,7 @@ class Graph:
|
|
1352
1358
|
return bot_graph.serialize(format=format)
|
1353
1359
|
|
1354
1360
|
@staticmethod
|
1355
|
-
def BetweennessCentrality(graph, key: str = "betweenness_centrality",
|
1361
|
+
def BetweennessCentrality(graph, method: str = "vertex", weightKey="length", normalize: bool = False, nx: bool = False, key: str = "betweenness_centrality", colorKey="bc_color", colorScale="viridis", mantissa: int = 6, tolerance: float = 0.001, silent: bool = False):
|
1356
1362
|
"""
|
1357
1363
|
Returns the betweenness centrality of the input graph. The order of the returned list is the same as the order of vertices/edges. See https://en.wikipedia.org/wiki/Betweenness_centrality.
|
1358
1364
|
|
@@ -1360,10 +1366,23 @@ class Graph:
|
|
1360
1366
|
----------
|
1361
1367
|
graph : topologic_core.Graph
|
1362
1368
|
The input graph.
|
1363
|
-
key : str , optional
|
1364
|
-
The dictionary key under which to store the betweeness centrality score. The default is "betweenness_centrality".
|
1365
1369
|
method : str , optional
|
1366
1370
|
The method of computing the betweenness centrality. The options are "vertex" or "edge". The default is "vertex".
|
1371
|
+
weightKey : str , optional
|
1372
|
+
If specified, the value in the connected edges' dictionary specified by the weightKey string will be aggregated to calculate
|
1373
|
+
the shortest path. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
1374
|
+
This is used in weighted graphs. if weightKey is set to "Length" or "Distance", the length of the edge will be used as its weight.
|
1375
|
+
normalize : bool , optional
|
1376
|
+
If set to True, the values are normalized to be in the range 0 to 1. Otherwise they are not. The default is False.
|
1377
|
+
nx : bool , optional
|
1378
|
+
If set to True, and normalize input parameter is also set to True, the values are set to be identical to NetworkX values. Otherwise, they are normalized between 0 and 1. The default is False.
|
1379
|
+
key : str , optional
|
1380
|
+
The desired dictionary key under which to store the betweenness centrality score. The default is "betweenness_centrality".
|
1381
|
+
colorKey : str , optional
|
1382
|
+
The desired dictionary key under which to store the betweenness centrality color. The default is "betweenness_centrality".
|
1383
|
+
colorScale : str , optional
|
1384
|
+
The desired type of plotly color scales to use (e.g. "viridis", "plasma"). The default is "viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
|
1385
|
+
In addition to these, three color-blind friendly scales are included. These are "protanopia", "deuteranopia", and "tritanopia" for red, green, and blue colorblindness respectively.
|
1367
1386
|
mantissa : int , optional
|
1368
1387
|
The desired length of the mantissa. The default is 6.
|
1369
1388
|
tolerance : float , optional
|
@@ -1375,163 +1394,58 @@ class Graph:
|
|
1375
1394
|
The betweenness centrality of the input list of vertices within the input graph. The values are in the range 0 to 1.
|
1376
1395
|
|
1377
1396
|
"""
|
1378
|
-
|
1379
|
-
queue = [(source, [source])]
|
1380
|
-
while queue:
|
1381
|
-
(vertex, path) = queue.pop(0)
|
1382
|
-
for next in set(py_graph[vertex]) - set(path):
|
1383
|
-
queue.append((next, path + [next]))
|
1384
|
-
yield path + [next]
|
1385
|
-
|
1386
|
-
def shortest_paths_count(source):
|
1387
|
-
paths = list(bfs_paths(source))
|
1388
|
-
shortest_paths = {v: [] for v in py_graph}
|
1389
|
-
for path in paths:
|
1390
|
-
shortest_paths[path[-1]].append(path)
|
1391
|
-
return shortest_paths
|
1392
|
-
|
1393
|
-
def calculate_vertex_betweenness():
|
1394
|
-
betweenness = {v: 0.0 for v in py_graph}
|
1395
|
-
for s in py_graph:
|
1396
|
-
shortest_paths = shortest_paths_count(s)
|
1397
|
-
dependency = {v: 0.0 for v in py_graph}
|
1398
|
-
for t in py_graph:
|
1399
|
-
if t != s:
|
1400
|
-
for path in shortest_paths[t]:
|
1401
|
-
for v in path[1:-1]:
|
1402
|
-
dependency[v] += 1.0 / len(shortest_paths[t])
|
1403
|
-
for v in py_graph:
|
1404
|
-
if v != s:
|
1405
|
-
betweenness[v] += dependency[v]
|
1406
|
-
return betweenness
|
1407
|
-
|
1408
|
-
def calculate_edge_betweenness(graph_adj_matrix):
|
1409
|
-
n = len(graph_adj_matrix)
|
1410
|
-
edge_betweenness_scores = {}
|
1411
|
-
|
1412
|
-
# Iterate over all node pairs as source and target nodes
|
1413
|
-
for source in range(n):
|
1414
|
-
# Initialize the 'distance' and 'predecessors' for each node
|
1415
|
-
distance = [-1] * n
|
1416
|
-
predecessors = [[] for _ in range(n)]
|
1417
|
-
distance[source] = 0
|
1418
|
-
stack = []
|
1419
|
-
queue = [source]
|
1420
|
-
|
1421
|
-
# Breadth-first search to find shortest paths
|
1422
|
-
while queue:
|
1423
|
-
current_node = queue.pop(0)
|
1424
|
-
stack.append(current_node)
|
1425
|
-
for neighbor in range(n):
|
1426
|
-
if graph_adj_matrix[current_node][neighbor] == 1:
|
1427
|
-
if distance[neighbor] == -1: # First time visiting neighbor
|
1428
|
-
distance[neighbor] = distance[current_node] + 1
|
1429
|
-
queue.append(neighbor)
|
1430
|
-
if distance[neighbor] == distance[current_node] + 1: # Shortest path
|
1431
|
-
predecessors[neighbor].append(current_node)
|
1432
|
-
|
1433
|
-
# Initialize the dependency values for each node
|
1434
|
-
dependency = [0] * n
|
1435
|
-
|
1436
|
-
# Process the nodes in reverse order of discovery
|
1437
|
-
while stack:
|
1438
|
-
current_node = stack.pop()
|
1439
|
-
for pred in predecessors[current_node]:
|
1440
|
-
dependency[pred] += (1 + dependency[current_node]) / len(predecessors[current_node])
|
1441
|
-
|
1442
|
-
# Update edge betweenness scores
|
1443
|
-
if pred < current_node:
|
1444
|
-
edge = (pred, current_node)
|
1445
|
-
else:
|
1446
|
-
edge = (current_node, pred)
|
1447
|
-
|
1448
|
-
if edge not in edge_betweenness_scores:
|
1449
|
-
edge_betweenness_scores[edge] = 0
|
1450
|
-
edge_betweenness_scores[edge] += dependency[current_node]
|
1451
|
-
|
1452
|
-
# Normalize edge betweenness scores by dividing by 2 (since each edge is counted twice)
|
1453
|
-
for edge in edge_betweenness_scores:
|
1454
|
-
edge_betweenness_scores[edge] /= 2
|
1397
|
+
import warnings
|
1455
1398
|
|
1456
|
-
|
1399
|
+
try:
|
1400
|
+
import networkx as nx
|
1401
|
+
except:
|
1402
|
+
print("Graph.BetwennessCentrality - Information: Installing required networkx library.")
|
1403
|
+
try:
|
1404
|
+
os.system("pip install networkx")
|
1405
|
+
except:
|
1406
|
+
os.system("pip install networkx --user")
|
1407
|
+
try:
|
1408
|
+
import networkx as nx
|
1409
|
+
print("Graph.BetwennessCentrality - Infromation: networkx library installed correctly.")
|
1410
|
+
except:
|
1411
|
+
warnings.warn("Graph.BetwennessCentrality - Error: Could not import networkx. Please try to install networkx manually. Returning None.")
|
1412
|
+
return None
|
1457
1413
|
|
1458
|
-
from topologicpy.Topology import Topology
|
1459
1414
|
from topologicpy.Dictionary import Dictionary
|
1415
|
+
from topologicpy.Color import Color
|
1416
|
+
from topologicpy.Topology import Topology
|
1417
|
+
from topologicpy.Helper import Helper
|
1460
1418
|
|
1461
|
-
if
|
1462
|
-
if
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
vertex_betweenness = calculate_vertex_betweenness()
|
1481
|
-
for v in vertex_betweenness:
|
1482
|
-
vertex_betweenness[v] /= 2.0 # Each shortest path is counted twice
|
1483
|
-
|
1484
|
-
min_betweenness = min(vertex_betweenness.values())
|
1485
|
-
max_betweenness = max(vertex_betweenness.values())
|
1486
|
-
if (max_betweenness - min_betweenness) > 0:
|
1487
|
-
for v in vertex_betweenness:
|
1488
|
-
vertex_betweenness[v] = (vertex_betweenness[v] - min_betweenness)/ (max_betweenness - min_betweenness) # Normalize to [0, 1]
|
1489
|
-
|
1490
|
-
|
1491
|
-
vertex_betweenness_scores = [0]*len(vertices)
|
1492
|
-
for i, score in vertex_betweenness.items():
|
1493
|
-
vertex = vertices[int(i)]
|
1494
|
-
d = Topology.Dictionary(vertex)
|
1495
|
-
d = Dictionary.SetValueAtKey(d, key, round(score, mantissa))
|
1496
|
-
vertex = Topology.SetDictionary(vertex, d)
|
1497
|
-
vertex_betweenness_scores[int(i)] = round(score, mantissa)
|
1498
|
-
|
1499
|
-
return vertex_betweenness_scores
|
1419
|
+
if weightKey:
|
1420
|
+
if "len" in weightKey.lower() or "dis" in wireightKey.lower():
|
1421
|
+
weightKey = "length"
|
1422
|
+
nx_graph = Graph.NetworkXGraph(graph)
|
1423
|
+
if "vert" in method.lower():
|
1424
|
+
elements = Graph.Vertices(graph)
|
1425
|
+
elements_dict = nx.betweenness_centrality(nx_graph, normalized=normalize, weight=weightKey)
|
1426
|
+
values = list(elements_dict.values())
|
1427
|
+
else:
|
1428
|
+
elements = Graph.Edges(graph)
|
1429
|
+
elements_dict = nx.edge_betweenness_centrality(nx_graph, normalized=normalize, weight=weightKey)
|
1430
|
+
values = [round(value, mantissa) for value in list(elements_dict.values())]
|
1431
|
+
if nx == False:
|
1432
|
+
if mantissa > 0: # We cannot have values in the range 0 to 1 with a mantissa < 1
|
1433
|
+
values = [round(v, mantissa) for v in Helper.Normalize(values)]
|
1434
|
+
else:
|
1435
|
+
values = Helper.Normalize(values)
|
1436
|
+
min_value = 0
|
1437
|
+
max_value = 1
|
1500
1438
|
else:
|
1501
|
-
graph_edges = Graph.Edges(graph)
|
1502
|
-
adj_matrix = Graph.AdjacencyMatrix(graph)
|
1503
|
-
meshData = Graph.MeshData(graph)
|
1504
|
-
edges = meshData["edges"]
|
1505
|
-
if len(graph_edges) < 1:
|
1506
|
-
if not silent:
|
1507
|
-
print("Graph.BetweenessCentrality - Error: The input graph does not contain any edges. Returning None.")
|
1508
|
-
return None
|
1509
|
-
if len(graph_edges) == 1:
|
1510
|
-
d = Topology.Dictionary(graph_edges[0])
|
1511
|
-
d = Dictionary.SetValueAtKey(d, key, 1.0)
|
1512
|
-
graph_edges[0] = Topology.SetDictionary(graph_edges[0], d)
|
1513
|
-
return [1.0]
|
1514
|
-
|
1515
|
-
edge_betweenness = calculate_edge_betweenness(adj_matrix)
|
1516
|
-
keys = list(edge_betweenness.keys())
|
1517
|
-
values = list(edge_betweenness.values())
|
1518
1439
|
min_value = min(values)
|
1519
1440
|
max_value = max(values)
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
score = 0
|
1529
|
-
score = (score - min_value)/(max_value - min_value)
|
1530
|
-
edge_betweenness_scores.append(round(score, mantissa))
|
1531
|
-
d = Topology.Dictionary(graph_edges[i])
|
1532
|
-
d = Dictionary.SetValueAtKey(d, key, round(score, mantissa))
|
1533
|
-
graph_edges[i] = Topology.SetDictionary(graph_edges[i], d)
|
1534
|
-
return edge_betweenness_scores
|
1441
|
+
|
1442
|
+
for i, value in enumerate(values):
|
1443
|
+
d = Topology.Dictionary(elements[i])
|
1444
|
+
color = Color.AnyToHex(Color.ByValueInRange(value, minValue=min_value, maxValue=max_value, colorScale=colorScale))
|
1445
|
+
d = Dictionary.SetValuesAtKeys(d, [key, colorKey], [value, color])
|
1446
|
+
elements[i] = Topology.SetDictionary(elements[i], d)
|
1447
|
+
|
1448
|
+
return values
|
1535
1449
|
|
1536
1450
|
@staticmethod
|
1537
1451
|
def BetweennessPartition(graph, n=2, m=10, key="partition", tolerance=0.0001, silent=False):
|
@@ -4772,93 +4686,93 @@ class Graph:
|
|
4772
4686
|
return graph
|
4773
4687
|
|
4774
4688
|
@staticmethod
|
4775
|
-
def ClosenessCentrality(graph,
|
4689
|
+
def ClosenessCentrality(graph, weightKey="length", normalize: bool = False, nx: bool = True, key: str = "closeness_centrality", colorKey="cc_color", colorScale="viridis", mantissa: int = 6, tolerance: float = 0.001, silent: bool = False):
|
4776
4690
|
"""
|
4777
|
-
|
4691
|
+
Returns the closeness centrality of the input graph. The order of the returned list is the same as the order of vertices/edges. See https://en.wikipedia.org/wiki/Betweenness_centrality.
|
4778
4692
|
|
4779
4693
|
Parameters
|
4780
4694
|
----------
|
4781
4695
|
graph : topologic_core.Graph
|
4782
4696
|
The input graph.
|
4783
|
-
|
4784
|
-
|
4697
|
+
weightKey : str , optional
|
4698
|
+
If specified, the value in the connected edges' dictionary specified by the weightKey string will be aggregated to calculate
|
4699
|
+
the shortest path. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
4700
|
+
This is used in weighted graphs. if weightKey is set to "Length" or "Distance", the length of the edge will be used as its weight.
|
4701
|
+
normalize : bool , optional
|
4702
|
+
If set to True, the values are normalized to be in the range 0 to 1. Otherwise they are not. The default is False.
|
4703
|
+
nx : bool , optional
|
4704
|
+
If set to True, use networkX to scale by the fraction of nodes reachable. This gives the Wasserman and Faust improved formula.
|
4705
|
+
For single component graphs it is the same as the original formula.
|
4785
4706
|
key : str , optional
|
4786
|
-
The dictionary key under which to store the closeness centrality score. The default is "closeness_centrality".
|
4707
|
+
The desired dictionary key under which to store the closeness centrality score. The default is "closeness_centrality".
|
4708
|
+
colorKey : str , optional
|
4709
|
+
The desired dictionary key under which to store the closeness centrality color. The default is "cc_color".
|
4710
|
+
colorScale : str , optional
|
4711
|
+
The desired type of plotly color scales to use (e.g. "viridis", "plasma"). The default is "viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
|
4712
|
+
In addition to these, three color-blind friendly scales are included. These are "protanopia", "deuteranopia", and "tritanopia" for red, green, and blue colorblindness respectively.
|
4787
4713
|
mantissa : int , optional
|
4788
4714
|
The desired length of the mantissa. The default is 6.
|
4789
4715
|
tolerance : float , optional
|
4790
4716
|
The desired tolerance. The default is 0.0001.
|
4791
|
-
silent : bool , optional
|
4792
|
-
If set to True, no error and warning messages are printed. Otherwise, they are. The default is False.
|
4793
4717
|
|
4794
4718
|
Returns
|
4795
4719
|
-------
|
4796
4720
|
list
|
4797
|
-
The
|
4721
|
+
The betweenness centrality of the input list of vertices within the input graph. The values are in the range 0 to 1.
|
4798
4722
|
|
4799
4723
|
"""
|
4724
|
+
import warnings
|
4800
4725
|
|
4801
|
-
|
4802
|
-
|
4803
|
-
|
4804
|
-
|
4805
|
-
|
4806
|
-
|
4807
|
-
|
4808
|
-
|
4809
|
-
|
4810
|
-
|
4811
|
-
|
4812
|
-
|
4813
|
-
|
4814
|
-
|
4815
|
-
centralities = []
|
4816
|
-
for v in keys:
|
4817
|
-
total_distance = 0
|
4818
|
-
reachable_count = 0
|
4819
|
-
|
4820
|
-
for u in keys:
|
4821
|
-
if v != u:
|
4822
|
-
distance = Graph._topological_distance(g, v, u)
|
4823
|
-
if distance != None:
|
4824
|
-
total_distance += distance
|
4825
|
-
reachable_count += 1
|
4826
|
-
|
4827
|
-
if reachable_count > 0: # Avoid division by zero
|
4828
|
-
centrality = (reachable_count / total_distance)
|
4829
|
-
else:
|
4830
|
-
centrality = 0.0 # Isolated vertex
|
4831
|
-
|
4832
|
-
centralities.append(centrality)
|
4833
|
-
return centralities
|
4726
|
+
try:
|
4727
|
+
import networkx as nx
|
4728
|
+
except:
|
4729
|
+
print("Graph.ClosenessCentrality - Information: Installing required networkx library.")
|
4730
|
+
try:
|
4731
|
+
os.system("pip install networkx")
|
4732
|
+
except:
|
4733
|
+
os.system("pip install networkx --user")
|
4734
|
+
try:
|
4735
|
+
import networkx as nx
|
4736
|
+
print("Graph.ClosenessCentrality - Infromation: networkx library installed correctly.")
|
4737
|
+
except:
|
4738
|
+
warnings.warn("Graph.ClosenessCentrality - Error: Could not import networkx. Please try to install networkx manually. Returning None.")
|
4739
|
+
return None
|
4834
4740
|
|
4835
|
-
from topologicpy.Vertex import Vertex
|
4836
|
-
from topologicpy.Topology import Topology
|
4837
4741
|
from topologicpy.Dictionary import Dictionary
|
4742
|
+
from topologicpy.Color import Color
|
4743
|
+
from topologicpy.Topology import Topology
|
4838
4744
|
from topologicpy.Helper import Helper
|
4839
4745
|
|
4840
|
-
if not Topology.IsInstance(graph, "
|
4746
|
+
if not Topology.IsInstance(graph, "graph"):
|
4841
4747
|
if not silent:
|
4842
4748
|
print("Graph.ClosenessCentrality - Error: The input graph is not a valid graph. Returning None.")
|
4843
4749
|
return None
|
4844
|
-
|
4845
|
-
|
4846
|
-
|
4847
|
-
|
4848
|
-
|
4849
|
-
|
4850
|
-
|
4851
|
-
|
4852
|
-
|
4750
|
+
|
4751
|
+
if weightKey:
|
4752
|
+
if "len" in weightKey.lower() or "dis" in weightKey.lower():
|
4753
|
+
weightKey = "length"
|
4754
|
+
nx_graph = Graph.NetworkXGraph(graph)
|
4755
|
+
elements = Graph.Vertices(graph)
|
4756
|
+
elements_dict = nx.closeness_centrality(nx_graph, distance=weightKey, wf_improved=nx)
|
4757
|
+
values = [round(v, mantissa) for v in list(elements_dict.values())]
|
4758
|
+
if normalize == True:
|
4759
|
+
if mantissa > 0: # We cannot round numbers from 0 to 1 with a mantissa = 0.
|
4760
|
+
values = [round(v, mantissa) for v in Helper.Normalize(values)]
|
4761
|
+
else:
|
4762
|
+
values = Helper.Normalize(values)
|
4763
|
+
min_value = 0
|
4764
|
+
max_value = 1
|
4853
4765
|
else:
|
4854
|
-
|
4855
|
-
|
4856
|
-
|
4857
|
-
|
4858
|
-
|
4859
|
-
|
4860
|
-
|
4861
|
-
|
4766
|
+
min_value = min(values)
|
4767
|
+
max_value = max(values)
|
4768
|
+
|
4769
|
+
for i, value in enumerate(values):
|
4770
|
+
d = Topology.Dictionary(elements[i])
|
4771
|
+
color = Color.AnyToHex(Color.ByValueInRange(value, minValue=min_value, maxValue=max_value, colorScale=colorScale))
|
4772
|
+
d = Dictionary.SetValuesAtKeys(d, [key, colorKey], [value, color])
|
4773
|
+
elements[i] = Topology.SetDictionary(elements[i], d)
|
4774
|
+
|
4775
|
+
return values
|
4862
4776
|
|
4863
4777
|
@staticmethod
|
4864
4778
|
def Community(graph, key: str = "partition", mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
@@ -5026,7 +4940,7 @@ class Graph:
|
|
5026
4940
|
return graph
|
5027
4941
|
|
5028
4942
|
@staticmethod
|
5029
|
-
def Connectivity(graph, vertices=None, key: str = "connectivity",
|
4943
|
+
def Connectivity(graph, vertices=None, weightKey: str = None, normalize: bool = False, key: str = "connectivity", colorKey: str = "cn_color", colorScale="Viridis", mantissa: int = 6, tolerance = 0.0001, silent = False):
|
5030
4944
|
"""
|
5031
4945
|
Return the connectivity measure of the input list of vertices within the input graph. The order of the returned list is the same as the order of the input list of vertices. If no vertices are specified, the connectivity of all the vertices in the input graph is computed. See https://www.spacesyntax.online/term/connectivity/.
|
5032
4946
|
|
@@ -5035,15 +4949,22 @@ class Graph:
|
|
5035
4949
|
graph : topologic_core.Graph
|
5036
4950
|
The input graph.
|
5037
4951
|
vertices : list , optional
|
5038
|
-
The input list of vertices. The default is None.
|
4952
|
+
The input list of vertices. The default is None which means all graph vertices are computed.
|
4953
|
+
normalize : bool , optional
|
4954
|
+
If set to True, the values are normalized to be in the range 0 to 1. Otherwise they are not. The default is False.
|
4955
|
+
weightKey : str , optional
|
4956
|
+
If specified, the value in the connected edges' dictionary specified by the weightKey string will be aggregated to calculate
|
4957
|
+
the vertex degree. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
4958
|
+
This is used in weighted graphs. if weightKey is set to "Length" or "Distance", the length of the edge will be used as its weight.
|
5039
4959
|
key : str , optional
|
5040
4960
|
The dictionary key under which to store the connectivity score. The default is "connectivity".
|
5041
|
-
|
5042
|
-
|
5043
|
-
|
5044
|
-
|
5045
|
-
|
5046
|
-
|
4961
|
+
colorKey : str , optional
|
4962
|
+
The desired dictionary key under which to store the connectivity color. The default is "cn_color".
|
4963
|
+
colorScale : str , optional
|
4964
|
+
The desired type of plotly color scales to use (e.g. "viridis", "plasma"). The default is "viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
|
4965
|
+
In addition to these, three color-blind friendly scales are included. These are "protanopia", "deuteranopia", and "tritanopia" for red, green, and blue colorblindness respectively.
|
4966
|
+
mantissa : int , optional
|
4967
|
+
The desired length of the mantissa. The default is 6.
|
5047
4968
|
tolerance : float , optional
|
5048
4969
|
The desired tolerance. The default is 0.0001.
|
5049
4970
|
silent : bool , optional
|
@@ -5052,25 +4973,40 @@ class Graph:
|
|
5052
4973
|
Returns
|
5053
4974
|
-------
|
5054
4975
|
list
|
5055
|
-
The
|
4976
|
+
The connectivity score of the input list of vertices within the input graph. The values are in the range 0 to 1 if normalized.
|
5056
4977
|
|
5057
4978
|
"""
|
5058
4979
|
|
5059
4980
|
from topologicpy.Topology import Topology
|
5060
4981
|
from topologicpy.Dictionary import Dictionary
|
4982
|
+
from topologicpy.Helper import Helper
|
4983
|
+
from topologicpy.Color import Color
|
5061
4984
|
|
5062
4985
|
if not Topology.IsInstance(graph, "Graph"):
|
5063
4986
|
if not silent:
|
5064
|
-
print("Graph.
|
4987
|
+
print("Graph.Connectivity - Error: The input graph is not a valid graph. Returning None.")
|
5065
4988
|
return None
|
5066
4989
|
if vertices == None:
|
5067
4990
|
vertices = Graph.Vertices(graph)
|
5068
|
-
|
5069
|
-
|
5070
|
-
|
5071
|
-
|
5072
|
-
|
5073
|
-
|
4991
|
+
values = [Graph.VertexDegree(graph, v, weightKey=weightKey, mantissa=mantissa, tolerance=tolerance, silent=silent) for v in vertices]
|
4992
|
+
values = [round(v, mantissa) for v in values]
|
4993
|
+
if normalize == True:
|
4994
|
+
if mantissa > 0:
|
4995
|
+
values = [round(v, mantissa) for v in Helper.Normalize(values)]
|
4996
|
+
else:
|
4997
|
+
values = Helper.Normalize(values)
|
4998
|
+
min_value = 0
|
4999
|
+
max_value = 1
|
5000
|
+
else:
|
5001
|
+
min_value = min(values)
|
5002
|
+
max_value = max(values)
|
5003
|
+
|
5004
|
+
for i, value in enumerate(values):
|
5005
|
+
color = Color.AnyToHex(Color.ByValueInRange(value, minValue=min_value, maxValue=max_value, colorScale=colorScale))
|
5006
|
+
d = Topology.Dictionary(vertices[i])
|
5007
|
+
d = Dictionary.SetValuesAtKeys(d, [key, colorKey], [value, color])
|
5008
|
+
v = Topology.SetDictionary(vertices[i], d)
|
5009
|
+
return values
|
5074
5010
|
|
5075
5011
|
@staticmethod
|
5076
5012
|
def ContainsEdge(graph, edge, tolerance=0.0001):
|
@@ -5193,23 +5129,38 @@ class Graph:
|
|
5193
5129
|
vertex = Topology.SetDictionary(vertex, d)
|
5194
5130
|
|
5195
5131
|
return cut_vertices
|
5196
|
-
|
5132
|
+
|
5197
5133
|
@staticmethod
|
5198
|
-
def
|
5199
|
-
|
5200
|
-
|
5134
|
+
def DegreeCentrality(graph,
|
5135
|
+
vertices: list = None,
|
5136
|
+
weightKey: str= None,
|
5137
|
+
normalize: bool = False,
|
5138
|
+
key: str = "degree_centrality",
|
5139
|
+
colorKey="dc_color",
|
5140
|
+
colorScale="viridis",
|
5141
|
+
mantissa: int = 6,
|
5142
|
+
tolerance: float = 0.001,
|
5143
|
+
silent: bool = False):
|
5144
|
+
"""
|
5145
|
+
Returns the degree centrality of the input graph. The order of the returned list is the same as the order of vertices. See https://en.wikipedia.org/wiki/Degree_centrality.
|
5201
5146
|
|
5202
5147
|
Parameters
|
5203
5148
|
----------
|
5204
5149
|
graph : topologic_core.Graph
|
5205
5150
|
The input graph.
|
5206
|
-
|
5207
|
-
|
5151
|
+
weightKey : str , optional
|
5152
|
+
If specified, the value in the connected edges' dictionary specified by the weightKey string will be aggregated to calculate
|
5153
|
+
the vertex degree. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
5154
|
+
This is used in weighted graphs. if weightKey is set to "Length" or "Distance", the length of the edge will be used as its weight.
|
5155
|
+
normalize : bool , optional
|
5156
|
+
If set to True, the values are normalized to be in the range 0 to 1. Otherwise they are not. The default is False.
|
5208
5157
|
key : str , optional
|
5209
|
-
The dictionary key under which to store the
|
5210
|
-
|
5211
|
-
|
5212
|
-
|
5158
|
+
The desired dictionary key under which to store the degree centrality score. The default is "degree_centrality".
|
5159
|
+
colorKey : str , optional
|
5160
|
+
The desired dictionary key under which to store the degree centrality color. The default is "dc_color".
|
5161
|
+
colorScale : str , optional
|
5162
|
+
The desired type of plotly color scales to use (e.g. "viridis", "plasma"). The default is "viridis". For a full list of names, see https://plotly.com/python/builtin-colorscales/.
|
5163
|
+
In addition to these, three color-blind friendly scales are included. These are "protanopia", "deuteranopia", and "tritanopia" for red, green, and blue colorblindness respectively.
|
5213
5164
|
mantissa : int , optional
|
5214
5165
|
The desired length of the mantissa. The default is 6.
|
5215
5166
|
tolerance : float , optional
|
@@ -5218,35 +5169,30 @@ class Graph:
|
|
5218
5169
|
Returns
|
5219
5170
|
-------
|
5220
5171
|
list
|
5221
|
-
The
|
5172
|
+
The betweenness centrality of the input list of vertices within the input graph. The values are in the range 0 to 1.
|
5222
5173
|
|
5223
5174
|
"""
|
5224
|
-
|
5175
|
+
|
5225
5176
|
from topologicpy.Dictionary import Dictionary
|
5177
|
+
from topologicpy.Color import Color
|
5178
|
+
from topologicpy.Topology import Topology
|
5179
|
+
from topologicpy.Helper import Helper
|
5226
5180
|
|
5227
|
-
if not Topology.IsInstance(graph, "
|
5228
|
-
|
5229
|
-
|
5230
|
-
|
5231
|
-
|
5232
|
-
|
5233
|
-
|
5234
|
-
|
5235
|
-
|
5236
|
-
|
5237
|
-
|
5238
|
-
|
5239
|
-
|
5240
|
-
|
5241
|
-
|
5242
|
-
degree = Graph.VertexDegree(graph, v, edgeKey= edgeKey, tolerance = tolerance)
|
5243
|
-
if isinstance(degree, float):
|
5244
|
-
degree = round(degree, mantissa)
|
5245
|
-
d = Topology.Dictionary(v)
|
5246
|
-
d = Dictionary.SetValueAtKey(d, key, degree)
|
5247
|
-
v = Topology.SetDictionary(v, d)
|
5248
|
-
scores.append(degree)
|
5249
|
-
return scores
|
5181
|
+
if not Topology.IsInstance(graph, "graph"):
|
5182
|
+
if not silent:
|
5183
|
+
print("Graph.DegreeCentrality - Error: The input graph is not a valid graph. Returning None.")
|
5184
|
+
return None
|
5185
|
+
|
5186
|
+
return Graph.Connectivity(graph,
|
5187
|
+
vertices=vertices,
|
5188
|
+
weightKey=weightKey,
|
5189
|
+
normalize=normalize,
|
5190
|
+
key=key,
|
5191
|
+
colorKey=colorKey,
|
5192
|
+
colorScale=colorScale,
|
5193
|
+
mantissa=mantissa,
|
5194
|
+
tolerance=tolerance,
|
5195
|
+
silent=silent)
|
5250
5196
|
|
5251
5197
|
@staticmethod
|
5252
5198
|
def DegreeMatrix(graph):
|
@@ -8468,7 +8414,7 @@ class Graph:
|
|
8468
8414
|
return laplacian.tolist()
|
8469
8415
|
|
8470
8416
|
@staticmethod
|
8471
|
-
def Leaves(graph,
|
8417
|
+
def Leaves(graph, weightKey: str = None, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
8472
8418
|
"""
|
8473
8419
|
Returns a list of all vertices that have a degree of 1, also called leaf nodes.
|
8474
8420
|
|
@@ -8476,9 +8422,12 @@ class Graph:
|
|
8476
8422
|
----------
|
8477
8423
|
graph : topologic_core.Graph
|
8478
8424
|
The input graph.
|
8479
|
-
|
8480
|
-
If specified, the value in the connected edges' dictionary specified by the
|
8481
|
-
the vertex degree. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
8425
|
+
weightKey : str , optional
|
8426
|
+
If specified, the value in the connected edges' dictionary specified by the weightKey string will be aggregated to calculate
|
8427
|
+
the vertex degree. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
8428
|
+
This is used in weighted graphs. if weightKey is set to "Length" or "Distance", the length of the edge will be used as its weight.
|
8429
|
+
mantissa : int , optional
|
8430
|
+
The desired length of the mantissa. The default is 6.
|
8482
8431
|
tolerance : float , optional
|
8483
8432
|
The desired tolerance. The default is 0.0001.
|
8484
8433
|
silent : bool , optional
|
@@ -8496,7 +8445,7 @@ class Graph:
|
|
8496
8445
|
if not silent:
|
8497
8446
|
print("Graph.Leaves - Error: The input graph parameter is not a valid graph. Returning None.")
|
8498
8447
|
return None
|
8499
|
-
return [v for v in Graph.Vertices(graph) if Graph.VertexDegree(graph, v,
|
8448
|
+
return [v for v in Graph.Vertices(graph) if Graph.VertexDegree(graph, v, weightKey=weightKey, mantissa=mantissa, tolerance=tolerance, silent=silent) == 1]
|
8500
8449
|
|
8501
8450
|
@staticmethod
|
8502
8451
|
def LineGraph(graph, transferVertexDictionaries=False, transferEdgeDictionaries=False, tolerance=0.0001, silent=False):
|
@@ -9264,6 +9213,7 @@ class Graph:
|
|
9264
9213
|
from topologicpy.Vertex import Vertex
|
9265
9214
|
from topologicpy.Topology import Topology
|
9266
9215
|
from topologicpy.Dictionary import Dictionary
|
9216
|
+
import warnings
|
9267
9217
|
|
9268
9218
|
try:
|
9269
9219
|
import networkx as nx
|
@@ -9275,11 +9225,11 @@ class Graph:
|
|
9275
9225
|
os.system("pip install networkx --user")
|
9276
9226
|
try:
|
9277
9227
|
import networkx as nx
|
9278
|
-
print("Graph.NetworkXGraph -
|
9228
|
+
print("Graph.NetworkXGraph - Information: networkx library installed correctly.")
|
9279
9229
|
except:
|
9280
9230
|
warnings.warn("Graph - Error: Could not import networkx. Please try to install networkx manually. Returning None.")
|
9281
9231
|
return None
|
9282
|
-
|
9232
|
+
|
9283
9233
|
if not Topology.IsInstance(graph, "Graph"):
|
9284
9234
|
if not silent:
|
9285
9235
|
print("Graph.NetworkXGraph - Error: The input graph is not a valid graph. Returning None.")
|
@@ -9287,6 +9237,8 @@ class Graph:
|
|
9287
9237
|
|
9288
9238
|
nxGraph = nx.Graph()
|
9289
9239
|
vertices = Graph.Vertices(graph)
|
9240
|
+
edges = Graph.Edges(graph)
|
9241
|
+
mesh_data = Graph.MeshData(graph)
|
9290
9242
|
order = len(vertices)
|
9291
9243
|
nodes = []
|
9292
9244
|
for i in range(order):
|
@@ -9299,23 +9251,28 @@ class Graph:
|
|
9299
9251
|
values = Dictionary.Values(d)
|
9300
9252
|
if not values:
|
9301
9253
|
values = []
|
9302
|
-
keys += [xKey,yKey,zKey]
|
9254
|
+
keys += [xKey, yKey, zKey]
|
9303
9255
|
values += [Vertex.X(v, mantissa=mantissa), Vertex.Y(v, mantissa=mantissa), Vertex.Z(v, mantissa=mantissa)]
|
9304
|
-
d = Dictionary.ByKeysValues(keys,values)
|
9256
|
+
d = Dictionary.ByKeysValues(keys, values)
|
9305
9257
|
pythonD = Dictionary.PythonDictionary(d)
|
9306
9258
|
nodes.append((i, pythonD))
|
9307
9259
|
else:
|
9308
9260
|
nodes.append((i, {"name": str(i)}))
|
9309
9261
|
nxGraph.add_nodes_from(nodes)
|
9310
|
-
for i in range(order):
|
9311
|
-
v = vertices[i]
|
9312
|
-
adjVertices = Graph.AdjacentVertices(graph, vertices[i])
|
9313
|
-
for adjVertex in adjVertices:
|
9314
|
-
adjIndex = Vertex.Index(vertex=adjVertex, vertices=vertices, strict=True, tolerance=tolerance)
|
9315
|
-
if not adjIndex == None:
|
9316
|
-
nxGraph.add_edge(i,adjIndex, length=(Vertex.Distance(v, adjVertex, mantissa=mantissa)))
|
9317
9262
|
|
9318
|
-
|
9263
|
+
mesh_edges = mesh_data['edges']
|
9264
|
+
for i, mesh_edge in enumerate(mesh_edges):
|
9265
|
+
sv_i = mesh_edge[0]
|
9266
|
+
ev_i = mesh_edge[1]
|
9267
|
+
sv = vertices[sv_i]
|
9268
|
+
ev = vertices[ev_i]
|
9269
|
+
edge_length = Vertex.Distance(sv, ev, mantissa=mantissa)
|
9270
|
+
edge_dict = Topology.Dictionary(edges[i])
|
9271
|
+
edge_attributes = Dictionary.PythonDictionary(edge_dict) if edge_dict else {}
|
9272
|
+
edge_attributes['length'] = edge_length
|
9273
|
+
nxGraph.add_edge(sv_i, ev_i, **edge_attributes)
|
9274
|
+
|
9275
|
+
pos = nx.spring_layout(nxGraph, k=0.2)
|
9319
9276
|
nx.set_node_attributes(nxGraph, pos, "pos")
|
9320
9277
|
return nxGraph
|
9321
9278
|
|
@@ -10515,7 +10472,7 @@ class Graph:
|
|
10515
10472
|
return Graph.ByVerticesEdges(dictionary['vertices'], dictionary['edges'])
|
10516
10473
|
|
10517
10474
|
@staticmethod
|
10518
|
-
def VertexDegree(graph, vertex,
|
10475
|
+
def VertexDegree(graph, vertex, weightKey: str = None, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
10519
10476
|
"""
|
10520
10477
|
Returns the degree of the input vertex. See https://en.wikipedia.org/wiki/Degree_(graph_theory).
|
10521
10478
|
|
@@ -10525,9 +10482,12 @@ class Graph:
|
|
10525
10482
|
The input graph.
|
10526
10483
|
vertex : topologic_core.Vertex
|
10527
10484
|
The input vertex.
|
10528
|
-
|
10529
|
-
If specified, the value in the connected edges' dictionary specified by the
|
10530
|
-
the vertex degree. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
10485
|
+
weightKey : str , optional
|
10486
|
+
If specified, the value in the connected edges' dictionary specified by the weightKey string will be aggregated to calculate
|
10487
|
+
the vertex degree. If a numeric value cannot be retrieved from an edge, a value of 1 is used instead.
|
10488
|
+
This is used in weighted graphs. if weightKey is set to "Length" or "Distance", the length of the edge will be used as its weight.
|
10489
|
+
mantissa : int , optional
|
10490
|
+
The desired length of the mantissa. The default is 6.
|
10531
10491
|
tolerance : float , optional
|
10532
10492
|
The desired tolerance. The default is 0.0001.
|
10533
10493
|
silent : bool , optional
|
@@ -10539,6 +10499,7 @@ class Graph:
|
|
10539
10499
|
The degree of the input vertex.
|
10540
10500
|
|
10541
10501
|
"""
|
10502
|
+
from topologicpy.Edge import Edge
|
10542
10503
|
from topologicpy.Topology import Topology
|
10543
10504
|
from topologicpy.Dictionary import Dictionary
|
10544
10505
|
import numbers
|
@@ -10551,18 +10512,20 @@ class Graph:
|
|
10551
10512
|
if not silent:
|
10552
10513
|
print("Graph.VertexDegree - Error: The input vertex is not a valid vertex. Returning None.")
|
10553
10514
|
return None
|
10554
|
-
if not isinstance(edgeKey, str):
|
10555
|
-
edgeKey = ""
|
10556
10515
|
edges = Graph.Edges(graph, [vertex], tolerance=tolerance)
|
10557
10516
|
degree = 0
|
10558
10517
|
for edge in edges:
|
10559
|
-
|
10560
|
-
|
10561
|
-
|
10562
|
-
|
10518
|
+
if weightKey == None:
|
10519
|
+
value = 1
|
10520
|
+
elif "len" in weightKey.lower() or "dis" in weightKey.lower():
|
10521
|
+
value = Edge.Length(edge, mantissa=mantissa)
|
10563
10522
|
else:
|
10564
|
-
|
10565
|
-
|
10523
|
+
d = Topology.Dictionary(edge)
|
10524
|
+
value = Dictionary.ValueAtKey(d, weightKey)
|
10525
|
+
if not isinstance(value, numbers.Number):
|
10526
|
+
value = 1
|
10527
|
+
degree += value
|
10528
|
+
return round(degree, mantissa)
|
10566
10529
|
|
10567
10530
|
@staticmethod
|
10568
10531
|
def Vertices(graph, vertexKey=None, reverse=False):
|