topologicpy 0.8.59__py3-none-any.whl → 0.8.61__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/Cell.py +5 -2
- topologicpy/Graph.py +660 -42
- topologicpy/Kuzu.py +1 -1
- topologicpy/Topology.py +50 -26
- topologicpy/version.py +1 -1
- {topologicpy-0.8.59.dist-info → topologicpy-0.8.61.dist-info}/METADATA +1 -1
- {topologicpy-0.8.59.dist-info → topologicpy-0.8.61.dist-info}/RECORD +10 -10
- {topologicpy-0.8.59.dist-info → topologicpy-0.8.61.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.59.dist-info → topologicpy-0.8.61.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.59.dist-info → topologicpy-0.8.61.dist-info}/top_level.txt +0 -0
topologicpy/Cell.py
CHANGED
@@ -226,7 +226,7 @@ class Cell():
|
|
226
226
|
return new_cell
|
227
227
|
|
228
228
|
@staticmethod
|
229
|
-
def ByShell(shell, planarize: bool = False, tolerance: float = 0.0001):
|
229
|
+
def ByShell(shell, planarize: bool = False, tolerance: float = 0.0001, silent: bool = False):
|
230
230
|
"""
|
231
231
|
Creates a cell from the input shell.
|
232
232
|
|
@@ -238,6 +238,8 @@ class Cell():
|
|
238
238
|
If set to True, the input faces of the input shell are planarized before building the cell. Otherwise, they are not. Default is False.
|
239
239
|
tolerance : float , optional
|
240
240
|
The desired tolerance. Default is 0.0001.
|
241
|
+
silent : bool , optional
|
242
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
241
243
|
|
242
244
|
Returns
|
243
245
|
-------
|
@@ -248,7 +250,8 @@ class Cell():
|
|
248
250
|
from topologicpy.Topology import Topology
|
249
251
|
|
250
252
|
if not Topology.IsInstance(shell, "Shell"):
|
251
|
-
|
253
|
+
if not silent:
|
254
|
+
print("Cell.ByShell - Error: The input shell parameter is not a valid topologic shell. Returning None.")
|
252
255
|
return None
|
253
256
|
faces = Topology.SubTopologies(shell, subTopologyType="face")
|
254
257
|
return Cell.ByFaces(faces, planarize=planarize, tolerance=tolerance)
|
topologicpy/Graph.py
CHANGED
@@ -64,20 +64,6 @@ except:
|
|
64
64
|
print("Graph - tqdm library installed correctly.")
|
65
65
|
except:
|
66
66
|
warnings.warn("Graph - Error: Could not import tqdm.")
|
67
|
-
|
68
|
-
try:
|
69
|
-
from graphviz import Digraph
|
70
|
-
except:
|
71
|
-
print("Graph - Installing required graphviz library.")
|
72
|
-
try:
|
73
|
-
os.system("pip install graphviz")
|
74
|
-
except:
|
75
|
-
os.system("pip install graphviz --user")
|
76
|
-
try:
|
77
|
-
from graphviz import Digraph
|
78
|
-
print("Graph - graphviz library installed correctly.")
|
79
|
-
except:
|
80
|
-
warnings.warn("Graph - Error: Could not import graphviz.")
|
81
67
|
|
82
68
|
GraphQueueItem = namedtuple('GraphQueueItem', ['edges'])
|
83
69
|
|
@@ -4060,6 +4046,380 @@ class Graph:
|
|
4060
4046
|
removeCoplanarFaces=removeCoplanarFaces,
|
4061
4047
|
xMin=xMin, yMin=yMin, zMin=zMin, xMax=xMax, yMax=yMax, zMax=zMax)
|
4062
4048
|
|
4049
|
+
@staticmethod
|
4050
|
+
def ByJSONDictionary(
|
4051
|
+
jsonDictionary: dict,
|
4052
|
+
xKey: str = "x",
|
4053
|
+
yKey: str = "y",
|
4054
|
+
zKey: str = "z",
|
4055
|
+
vertexIDKey: str = None,
|
4056
|
+
edgeSourceKey: str = "source",
|
4057
|
+
edgeTargetKey: str = "target",
|
4058
|
+
edgeIDKey: str = None,
|
4059
|
+
graphPropsKey: str = "properties",
|
4060
|
+
verticesKey: str = "vertices",
|
4061
|
+
edgesKey: str = "edges",
|
4062
|
+
mantissa: int = 6,
|
4063
|
+
tolerance: float = 0.0001,
|
4064
|
+
silent: bool = False,
|
4065
|
+
):
|
4066
|
+
"""
|
4067
|
+
Loads a Graph from a JSON file and attaches graph-, vertex-, and edge-level dictionaries.
|
4068
|
+
|
4069
|
+
Parameters
|
4070
|
+
----------
|
4071
|
+
path : str
|
4072
|
+
Path to a JSON file containing:
|
4073
|
+
- graph-level properties under `graphPropsKey` (default "properties"),
|
4074
|
+
- a vertex dict under `verticesKey` (default "vertices") keyed by vertex IDs,
|
4075
|
+
- an edge dict under `edgesKey` (default "edges") keyed by edge IDs.
|
4076
|
+
xKey: str , optional
|
4077
|
+
JSON key used to read vertex's x coordinate. Default is "x".
|
4078
|
+
yKey: str , optional
|
4079
|
+
JSON key used to read vertex's y coordinate. Default is "y".
|
4080
|
+
zKey: str , optional
|
4081
|
+
JSON key used to read vertex's z coordinate. Default is "z".
|
4082
|
+
vertexIDKey : str , optional
|
4083
|
+
If not None, the vertex dictionary key under which to store the JSON vertex id. Default is "id".
|
4084
|
+
edgeSourceKey: str , optional
|
4085
|
+
JSON key used to read edge's start vertex. Default is "source".
|
4086
|
+
edgeTargetKey: str , optional
|
4087
|
+
JSON key used to read edge's end vertex. Default is "target".
|
4088
|
+
edgeIDKey : str , optional
|
4089
|
+
If not None, the edge dictionary key under which to store the JSON edge id. Default is "id".
|
4090
|
+
graphPropsKey: str , optional
|
4091
|
+
JSON key for the graph properties section. Default is "properties".
|
4092
|
+
verticesKey: str , optional
|
4093
|
+
JSON key for the vertices section. Default is "vertices".
|
4094
|
+
edgesKey: str , optional
|
4095
|
+
JSON key for the edges section. Default is "edges".
|
4096
|
+
mantissa : int , optional
|
4097
|
+
The desired length of the mantissa. Default is 6.
|
4098
|
+
tolerance : float , optional
|
4099
|
+
The desired tolerance. Default is 0.0001.
|
4100
|
+
silent : bool , optional
|
4101
|
+
If set to True, no warnings or error messages are displayed. Default is False.
|
4102
|
+
|
4103
|
+
Returns
|
4104
|
+
-------
|
4105
|
+
topologic_core.Graph
|
4106
|
+
"""
|
4107
|
+
# --- Imports kept local by request ---
|
4108
|
+
import json
|
4109
|
+
import math
|
4110
|
+
from typing import Any, Iterable
|
4111
|
+
|
4112
|
+
# TopologicPy imports
|
4113
|
+
from topologicpy.Graph import Graph
|
4114
|
+
from topologicpy.Vertex import Vertex
|
4115
|
+
from topologicpy.Edge import Edge
|
4116
|
+
from topologicpy.Topology import Topology
|
4117
|
+
from topologicpy.Dictionary import Dictionary
|
4118
|
+
|
4119
|
+
# --- Helper functions kept local by request ---
|
4120
|
+
def _to_plain(value: Any) -> Any:
|
4121
|
+
"Convert numpy/pandas-ish scalars/arrays and nested containers to plain Python."
|
4122
|
+
try:
|
4123
|
+
import numpy as _np # optional
|
4124
|
+
if isinstance(value, _np.generic):
|
4125
|
+
return value.item()
|
4126
|
+
if isinstance(value, _np.ndarray):
|
4127
|
+
return [_to_plain(v) for v in value.tolist()]
|
4128
|
+
except Exception:
|
4129
|
+
pass
|
4130
|
+
if isinstance(value, (list, tuple)):
|
4131
|
+
return [_to_plain(v) for v in value]
|
4132
|
+
if isinstance(value, dict):
|
4133
|
+
return {str(k): _to_plain(v) for k, v in value.items()}
|
4134
|
+
if isinstance(value, float):
|
4135
|
+
if not math.isfinite(value):
|
4136
|
+
return 0.0
|
4137
|
+
# normalize -0.0
|
4138
|
+
return 0.0 if abs(value) < tolerance else float(value)
|
4139
|
+
return value
|
4140
|
+
|
4141
|
+
def _round_num(x: Any, m: int) -> float:
|
4142
|
+
"Safe float conversion + rounding + tolerance clamp."
|
4143
|
+
try:
|
4144
|
+
xf = float(x)
|
4145
|
+
except Exception:
|
4146
|
+
return 0.0
|
4147
|
+
if not math.isfinite(xf):
|
4148
|
+
return 0.0
|
4149
|
+
# clamp tiny values to zero to avoid -0.0 drift and floating trash
|
4150
|
+
if abs(xf) < tolerance:
|
4151
|
+
xf = 0.0
|
4152
|
+
return round(xf, max(0, int(m)))
|
4153
|
+
|
4154
|
+
def _dict_from(obj: dict, drop_keys: Iterable[str] = ()):
|
4155
|
+
"Create a Topologic Dictionary from a Python dict (optionally dropping some keys)."
|
4156
|
+
data = {k: _to_plain(v) for k, v in obj.items() if k not in drop_keys}
|
4157
|
+
if not data:
|
4158
|
+
return None
|
4159
|
+
keys = list(map(str, data.keys()))
|
4160
|
+
vals = list(data.values())
|
4161
|
+
try:
|
4162
|
+
return Dictionary.ByKeysValues(keys, vals)
|
4163
|
+
except Exception:
|
4164
|
+
# As a last resort, stringify nested types
|
4165
|
+
import json as _json
|
4166
|
+
vals2 = [_json.dumps(v) if isinstance(v, (list, dict)) else v for v in vals]
|
4167
|
+
return Dictionary.ByKeysValues(keys, vals2)
|
4168
|
+
|
4169
|
+
# --- Load JSON ---
|
4170
|
+
if not isinstance(jsonDictionary, dict):
|
4171
|
+
if not silent:
|
4172
|
+
print(f"Graph.ByJSONDictionary - Error: The input JSON Dictionary parameter is not a valid python dictionary. Returning None.")
|
4173
|
+
return None
|
4174
|
+
|
4175
|
+
gprops = jsonDictionary.get(graphPropsKey, {}) or {}
|
4176
|
+
verts = jsonDictionary.get(verticesKey, {}) or {}
|
4177
|
+
edges = jsonDictionary.get(edgesKey, {}) or {}
|
4178
|
+
|
4179
|
+
# --- Build vertices ---
|
4180
|
+
id_to_vertex = {}
|
4181
|
+
vertex_list = []
|
4182
|
+
for v_id, v_rec in verts.items():
|
4183
|
+
x = _round_num(v_rec.get(xKey, 0.0), mantissa)
|
4184
|
+
y = _round_num(v_rec.get(yKey, 0.0), mantissa)
|
4185
|
+
z = _round_num(v_rec.get(zKey, 0.0), mantissa)
|
4186
|
+
try:
|
4187
|
+
v = Vertex.ByCoordinates(x, y, z)
|
4188
|
+
except Exception as e:
|
4189
|
+
if not silent:
|
4190
|
+
print(f"Graph.ByJSONDictionary - Warning: failed to create Vertex {v_id} at ({x},{y},{z}): {e}")
|
4191
|
+
continue
|
4192
|
+
|
4193
|
+
# Attach vertex dictionary with all attributes except raw coords
|
4194
|
+
v_dict_py = dict(v_rec)
|
4195
|
+
if vertexIDKey:
|
4196
|
+
v_dict_py[vertexIDKey] = v_id
|
4197
|
+
v_dict = _dict_from(v_dict_py, drop_keys={xKey, yKey, zKey})
|
4198
|
+
if v_dict:
|
4199
|
+
v = Topology.SetDictionary(v, v_dict)
|
4200
|
+
|
4201
|
+
id_to_vertex[str(v_id)] = v
|
4202
|
+
vertex_list.append(v)
|
4203
|
+
|
4204
|
+
# --- Build edges ---
|
4205
|
+
edge_list = []
|
4206
|
+
for e_id, e_rec in edges.items():
|
4207
|
+
s_id = e_rec.get(edgeSourceKey)
|
4208
|
+
t_id = e_rec.get(edgeTargetKey)
|
4209
|
+
if s_id is None or t_id is None:
|
4210
|
+
if not silent:
|
4211
|
+
print(f"Graph.ByJSONDictionary - Warning: skipping Edge {e_id}: missing '{edgeSourceKey}' or '{edgeTargetKey}'.")
|
4212
|
+
continue
|
4213
|
+
s_id = str(s_id)
|
4214
|
+
t_id = str(t_id)
|
4215
|
+
if s_id not in id_to_vertex or t_id not in id_to_vertex:
|
4216
|
+
if not silent:
|
4217
|
+
print(f"Graph.ByJSONDictionary - Warning: skipping Edge {e_id}: unknown endpoint(s) {s_id}->{t_id}.")
|
4218
|
+
continue
|
4219
|
+
u = id_to_vertex[s_id]
|
4220
|
+
v = id_to_vertex[t_id]
|
4221
|
+
try:
|
4222
|
+
e = Edge.ByVertices(u, v)
|
4223
|
+
except Exception as ee:
|
4224
|
+
if not silent:
|
4225
|
+
print(f"Graph.ByJSONDictionary - Warning: failed to create Edge {e_id}: {ee}")
|
4226
|
+
continue
|
4227
|
+
|
4228
|
+
# Attach full edge record as dictionary (including source/target keys)
|
4229
|
+
e_dict = _dict_from(dict(e_rec), drop_keys=())
|
4230
|
+
if edgeIDKey:
|
4231
|
+
Dictionary.SetValueAtKey(e_dict, edgeIDKey, e_id)
|
4232
|
+
if e_dict:
|
4233
|
+
e = Topology.SetDictionary(e, e_dict)
|
4234
|
+
edge_list.append(e)
|
4235
|
+
|
4236
|
+
# --- Assemble graph ---
|
4237
|
+
try:
|
4238
|
+
g = Graph.ByVerticesEdges(vertex_list, edge_list)
|
4239
|
+
except Exception:
|
4240
|
+
# Fallback: create empty, then add
|
4241
|
+
g = Graph.ByVerticesEdges([], [])
|
4242
|
+
for v in vertex_list:
|
4243
|
+
try:
|
4244
|
+
g = Graph.AddVertex(g, v)
|
4245
|
+
except Exception:
|
4246
|
+
pass
|
4247
|
+
for e in edge_list:
|
4248
|
+
try:
|
4249
|
+
g = Graph.AddEdge(g, e)
|
4250
|
+
except Exception:
|
4251
|
+
pass
|
4252
|
+
|
4253
|
+
# --- Graph-level dictionary ---
|
4254
|
+
g_dict = _dict_from(dict(gprops), drop_keys=())
|
4255
|
+
if g_dict:
|
4256
|
+
g = Topology.SetDictionary(g, g_dict)
|
4257
|
+
|
4258
|
+
return g
|
4259
|
+
|
4260
|
+
@staticmethod
|
4261
|
+
def ByJSONFile(file,
|
4262
|
+
xKey: str = "x",
|
4263
|
+
yKey: str = "y",
|
4264
|
+
zKey: str = "z",
|
4265
|
+
vertexIDKey: str = "id",
|
4266
|
+
edgeSourceKey: str = "source",
|
4267
|
+
edgeTargetKey: str = "target",
|
4268
|
+
edgeIDKey: str = "id",
|
4269
|
+
graphPropsKey: str = "properties",
|
4270
|
+
verticesKey: str = "vertices",
|
4271
|
+
edgesKey: str = "edges",
|
4272
|
+
mantissa: int = 6,
|
4273
|
+
tolerance: float = 0.0001,
|
4274
|
+
silent: bool = False):
|
4275
|
+
"""
|
4276
|
+
Imports the graph from a JSON file.
|
4277
|
+
|
4278
|
+
Parameters
|
4279
|
+
----------
|
4280
|
+
file : file object
|
4281
|
+
The input JSON file.
|
4282
|
+
xKey: str , optional
|
4283
|
+
JSON key used to read vertex's x coordinate. Default is "x".
|
4284
|
+
yKey: str , optional
|
4285
|
+
JSON key used to read vertex's y coordinate. Default is "y".
|
4286
|
+
zKey: str , optional
|
4287
|
+
JSON key used to read vertex's z coordinate. Default is "z".
|
4288
|
+
vertexIDKey : str , optional
|
4289
|
+
If not None, the vertex dictionary key under which to store the JSON vertex id. Default is "id".
|
4290
|
+
edgeSourceKey: str , optional
|
4291
|
+
JSON key used to read edge's start vertex. Default is "source".
|
4292
|
+
edgeTargetKey: str , optional
|
4293
|
+
JSON key used to read edge's end vertex. Default is "target".
|
4294
|
+
edgeIDKey : str , optional
|
4295
|
+
If not None, the edge dictionary key under which to store the JSON edge id. Default is "id".
|
4296
|
+
graphPropsKey: str , optional
|
4297
|
+
JSON key for the graph properties section. Default is "properties".
|
4298
|
+
verticesKey: str , optional
|
4299
|
+
JSON key for the vertices section. Default is "vertices".
|
4300
|
+
edgesKey: str , optional
|
4301
|
+
JSON key for the edges section. Default is "edges".
|
4302
|
+
mantissa : int , optional
|
4303
|
+
The desired length of the mantissa. Default is 6.
|
4304
|
+
tolerance : float , optional
|
4305
|
+
The desired tolerance. Default is 0.0001.
|
4306
|
+
silent : bool , optional
|
4307
|
+
If set to True, no warnings or error messages are displayed. Default is False.
|
4308
|
+
|
4309
|
+
Returns
|
4310
|
+
-------
|
4311
|
+
topologic_graph
|
4312
|
+
the imported graph.
|
4313
|
+
|
4314
|
+
"""
|
4315
|
+
import json
|
4316
|
+
if not file:
|
4317
|
+
if not silent:
|
4318
|
+
print("Topology.ByJSONFile - Error: the input file parameter is not a valid file. Returning None.")
|
4319
|
+
return None
|
4320
|
+
try:
|
4321
|
+
json_dict = json.load(file)
|
4322
|
+
except Exception as e:
|
4323
|
+
if not silent:
|
4324
|
+
print("Graph.ByJSONFile - Error: Could not load the JSON file: {e}. Returning None.")
|
4325
|
+
return None
|
4326
|
+
return Graph.ByJSONDictionary(json_dict,
|
4327
|
+
xKey=xKey,
|
4328
|
+
yKey=yKey,
|
4329
|
+
zKey=zKey,
|
4330
|
+
vertexIDKey=vertexIDKey,
|
4331
|
+
edgeSourceKey=edgeSourceKey,
|
4332
|
+
edgeTargetKey=edgeTargetKey,
|
4333
|
+
edgeIDKey=edgeIDKey,
|
4334
|
+
graphPropsKey=graphPropsKey,
|
4335
|
+
verticesKey=verticesKey,
|
4336
|
+
edgesKey=edgesKey,
|
4337
|
+
mantissa=mantissa,
|
4338
|
+
tolerance=tolerance,
|
4339
|
+
silent=silent)
|
4340
|
+
|
4341
|
+
@staticmethod
|
4342
|
+
def ByJSONPath(path,
|
4343
|
+
xKey: str = "x",
|
4344
|
+
yKey: str = "y",
|
4345
|
+
zKey: str = "z",
|
4346
|
+
vertexIDKey: str = "id",
|
4347
|
+
edgeSourceKey: str = "source",
|
4348
|
+
edgeTargetKey: str = "target",
|
4349
|
+
edgeIDKey: str = "id",
|
4350
|
+
graphPropsKey: str = "properties",
|
4351
|
+
verticesKey: str = "vertices",
|
4352
|
+
edgesKey: str = "edges",
|
4353
|
+
mantissa: int = 6,
|
4354
|
+
tolerance: float = 0.0001,
|
4355
|
+
silent: bool = False):
|
4356
|
+
"""
|
4357
|
+
Imports the graph from a JSON file.
|
4358
|
+
|
4359
|
+
Parameters
|
4360
|
+
----------
|
4361
|
+
path : str
|
4362
|
+
The file path to the json file.
|
4363
|
+
xKey: str , optional
|
4364
|
+
JSON key used to read vertex's x coordinate. Default is "x".
|
4365
|
+
yKey: str , optional
|
4366
|
+
JSON key used to read vertex's y coordinate. Default is "y".
|
4367
|
+
zKey: str , optional
|
4368
|
+
JSON key used to read vertex's z coordinate. Default is "z".
|
4369
|
+
vertexIDKey : str , optional
|
4370
|
+
If not None, the vertex dictionary key under which to store the JSON vertex id. Default is "id".
|
4371
|
+
edgeSourceKey: str , optional
|
4372
|
+
JSON key used to read edge's start vertex. Default is "source".
|
4373
|
+
edgeTargetKey: str , optional
|
4374
|
+
JSON key used to read edge's end vertex. Default is "target".
|
4375
|
+
edgeIDKey : str , optional
|
4376
|
+
If not None, the edge dictionary key under which to store the JSON edge id. Default is "id".
|
4377
|
+
graphPropsKey: str , optional
|
4378
|
+
JSON key for the graph properties section. Default is "properties".
|
4379
|
+
verticesKey: str , optional
|
4380
|
+
JSON key for the vertices section. Default is "vertices".
|
4381
|
+
edgesKey: str , optional
|
4382
|
+
JSON key for the edges section. Default is "edges".
|
4383
|
+
mantissa : int , optional
|
4384
|
+
The desired length of the mantissa. Default is 6.
|
4385
|
+
tolerance : float , optional
|
4386
|
+
The desired tolerance. Default is 0.0001.
|
4387
|
+
silent : bool , optional
|
4388
|
+
If set to True, no warnings or error messages are displayed. Default is False.
|
4389
|
+
|
4390
|
+
Returns
|
4391
|
+
-------
|
4392
|
+
list
|
4393
|
+
The list of imported topologies.
|
4394
|
+
|
4395
|
+
"""
|
4396
|
+
import json
|
4397
|
+
if not path:
|
4398
|
+
if not silent:
|
4399
|
+
print("Graph.ByJSONPath - Error: the input path parameter is not a valid path. Returning None.")
|
4400
|
+
return None
|
4401
|
+
try:
|
4402
|
+
with open(path) as file:
|
4403
|
+
json_dict = json.load(file)
|
4404
|
+
except Exception as e:
|
4405
|
+
if not silent:
|
4406
|
+
print(f"Graph.ByJSONPath - Error: Could not load file: {e}. Returning None.")
|
4407
|
+
return None
|
4408
|
+
return Graph.ByJSONDictionary(json_dict,
|
4409
|
+
xKey=xKey,
|
4410
|
+
yKey=yKey,
|
4411
|
+
zKey=zKey,
|
4412
|
+
vertexIDKey=vertexIDKey,
|
4413
|
+
edgeSourceKey=edgeSourceKey,
|
4414
|
+
edgeTargetKey=edgeTargetKey,
|
4415
|
+
edgeIDKey=edgeIDKey,
|
4416
|
+
graphPropsKey=graphPropsKey,
|
4417
|
+
verticesKey=verticesKey,
|
4418
|
+
edgesKey=edgesKey,
|
4419
|
+
mantissa=mantissa,
|
4420
|
+
tolerance=tolerance,
|
4421
|
+
silent=silent)
|
4422
|
+
|
4063
4423
|
@staticmethod
|
4064
4424
|
def ByMeshData(vertices, edges, vertexDictionaries=None, edgeDictionaries=None, tolerance=0.0001):
|
4065
4425
|
"""
|
@@ -4119,7 +4479,7 @@ class Graph:
|
|
4119
4479
|
return Graph.ByVerticesEdges(g_vertices, g_edges)
|
4120
4480
|
|
4121
4481
|
@staticmethod
|
4122
|
-
def ByNetworkXGraph(nxGraph, xKey="x", yKey="y", zKey="z",
|
4482
|
+
def ByNetworkXGraph(nxGraph, xKey="x", yKey="y", zKey="z", coordsKey='coords', randomRange=(-1, 1), mantissa: int = 6, tolerance: float = 0.0001):
|
4123
4483
|
"""
|
4124
4484
|
Converts the input NetworkX graph into a topologic Graph. See http://networkx.org
|
4125
4485
|
|
@@ -4133,8 +4493,10 @@ class Graph:
|
|
4133
4493
|
The dictionary key under which to find the Y-Coordinate of the vertex. Default is 'y'.
|
4134
4494
|
zKey : str , optional
|
4135
4495
|
The dictionary key under which to find the Z-Coordinate of the vertex. Default is 'z'.
|
4136
|
-
|
4137
|
-
The
|
4496
|
+
coordsKey : str , optional
|
4497
|
+
The dictionary key under which to find the list of the coordinates vertex. Default is 'coords'.
|
4498
|
+
randomRange : tuple , optional
|
4499
|
+
The range to use for random position coordinates if no values are found in the dictionaries. Default is (-1,1)
|
4138
4500
|
mantissa : int , optional
|
4139
4501
|
The number of decimal places to round the result to. Default is 6.
|
4140
4502
|
tolerance : float , optional
|
@@ -4153,38 +4515,221 @@ class Graph:
|
|
4153
4515
|
|
4154
4516
|
import random
|
4155
4517
|
import numpy as np
|
4518
|
+
import math
|
4519
|
+
import torch
|
4520
|
+
from collections.abc import Mapping, Sequence
|
4521
|
+
|
4522
|
+
def _is_iterable_but_not_str(x):
|
4523
|
+
return isinstance(x, Sequence) and not isinstance(x, (str, bytes, bytearray))
|
4524
|
+
|
4525
|
+
def _to_python_scalar(x):
|
4526
|
+
"""Return a plain Python scalar if x is a numpy/pandas/Decimal/torch scalar; otherwise return x."""
|
4527
|
+
# numpy scalar
|
4528
|
+
if np is not None and isinstance(x, np.generic):
|
4529
|
+
return x.item()
|
4530
|
+
# pandas NA
|
4531
|
+
if pd is not None and x is pd.NA:
|
4532
|
+
return None
|
4533
|
+
# pandas Timestamp/Timedelta
|
4534
|
+
if pd is not None and isinstance(x, (pd.Timestamp, pd.Timedelta)):
|
4535
|
+
return x.isoformat()
|
4536
|
+
# torch scalar tensor
|
4537
|
+
if torch is not None and isinstance(x, torch.Tensor) and x.dim() == 0:
|
4538
|
+
return _to_python_scalar(x.item())
|
4539
|
+
# decimal
|
4540
|
+
try:
|
4541
|
+
from decimal import Decimal
|
4542
|
+
if isinstance(x, Decimal):
|
4543
|
+
return float(x)
|
4544
|
+
except Exception:
|
4545
|
+
pass
|
4546
|
+
return x
|
4547
|
+
|
4548
|
+
def _to_python_list(x):
|
4549
|
+
"""Convert arrays/series/tensors/sets/tuples to Python lists (recursively)."""
|
4550
|
+
if torch is not None and isinstance(x, torch.Tensor):
|
4551
|
+
x = x.detach().cpu().tolist()
|
4552
|
+
elif np is not None and isinstance(x, (np.ndarray,)):
|
4553
|
+
x = x.tolist()
|
4554
|
+
elif pd is not None and isinstance(x, (pd.Series, pd.Index)):
|
4555
|
+
x = x.tolist()
|
4556
|
+
elif isinstance(x, (set, tuple)):
|
4557
|
+
x = list(x)
|
4558
|
+
return x
|
4559
|
+
|
4560
|
+
def _round_number(x, mantissa):
|
4561
|
+
"""Round finite floats; keep ints; sanitize NaNs/Infs to None."""
|
4562
|
+
if isinstance(x, bool): # bool is int subclass; keep as bool
|
4563
|
+
return x
|
4564
|
+
if isinstance(x, int):
|
4565
|
+
return x
|
4566
|
+
# try float conversion
|
4567
|
+
try:
|
4568
|
+
xf = float(x)
|
4569
|
+
except Exception:
|
4570
|
+
return x # not a number
|
4571
|
+
if math.isfinite(xf):
|
4572
|
+
return round(xf, mantissa)
|
4573
|
+
return None # NaN/Inf -> None
|
4574
|
+
|
4575
|
+
def clean_value(value, mantissa):
|
4576
|
+
"""
|
4577
|
+
Recursively convert value into TopologicPy-friendly types:
|
4578
|
+
- numbers rounded to mantissa
|
4579
|
+
- sequences -> lists (cleaned)
|
4580
|
+
- mappings -> dicts (cleaned)
|
4581
|
+
- datetime -> isoformat
|
4582
|
+
- other objects -> str(value)
|
4583
|
+
"""
|
4584
|
+
# First, normalize common library wrappers
|
4585
|
+
value = _to_python_scalar(value)
|
4586
|
+
|
4587
|
+
# Datetime from stdlib
|
4588
|
+
import datetime
|
4589
|
+
if isinstance(value, (datetime.datetime, datetime.date, datetime.time)):
|
4590
|
+
try:
|
4591
|
+
return value.isoformat()
|
4592
|
+
except Exception:
|
4593
|
+
return str(value)
|
4594
|
+
|
4595
|
+
# Mapping (dict-like)
|
4596
|
+
if isinstance(value, Mapping):
|
4597
|
+
return {str(k): clean_value(v, mantissa) for k, v in value.items()}
|
4598
|
+
|
4599
|
+
# Sequences / arrays / tensors -> list
|
4600
|
+
if _is_iterable_but_not_str(value) or (
|
4601
|
+
(np is not None and isinstance(value, (np.ndarray,))) or
|
4602
|
+
(torch is not None and isinstance(value, torch.Tensor)) or
|
4603
|
+
(pd is not None and isinstance(value, (pd.Series, pd.Index)))
|
4604
|
+
):
|
4605
|
+
value = _to_python_list(value)
|
4606
|
+
return [clean_value(v, mantissa) for v in value]
|
4607
|
+
|
4608
|
+
# Strings stay as-is
|
4609
|
+
if isinstance(value, (str, bytes, bytearray)):
|
4610
|
+
return value.decode() if isinstance(value, (bytes, bytearray)) else value
|
4611
|
+
|
4612
|
+
# Numbers (or things that can be safely treated as numbers)
|
4613
|
+
out = _round_number(value, mantissa)
|
4614
|
+
# If rounder didn't change type and it's still a weird object, stringify it
|
4615
|
+
if out is value and not isinstance(out, (type(None), bool, int, float, str)):
|
4616
|
+
return str(out)
|
4617
|
+
return out
|
4618
|
+
|
4619
|
+
def coerce_xyz(val, mantissa, default=0.0):
|
4620
|
+
"""
|
4621
|
+
Coerce a candidate XYZ value into a float:
|
4622
|
+
- if mapping with 'x' or 'value' -> try those
|
4623
|
+
- if sequence -> use first element
|
4624
|
+
- if string -> try float
|
4625
|
+
- arrays/tensors -> first element
|
4626
|
+
- fallback to default
|
4627
|
+
"""
|
4628
|
+
if val is None:
|
4629
|
+
return round(float(default), mantissa)
|
4630
|
+
# library scalars
|
4631
|
+
val = _to_python_scalar(val)
|
4632
|
+
|
4633
|
+
# Mapping with common keys
|
4634
|
+
if isinstance(val, Mapping):
|
4635
|
+
for k in ("x", "value", "val", "coord", "0"):
|
4636
|
+
if k in val:
|
4637
|
+
return coerce_xyz(val[k], mantissa, default)
|
4638
|
+
# otherwise try to take first value
|
4639
|
+
try:
|
4640
|
+
first = next(iter(val.values()))
|
4641
|
+
return coerce_xyz(first, mantissa, default)
|
4642
|
+
except Exception:
|
4643
|
+
return round(float(default), mantissa)
|
4644
|
+
|
4645
|
+
# Sequence / array / tensor
|
4646
|
+
if _is_iterable_but_not_str(val) or \
|
4647
|
+
(np is not None and isinstance(val, (np.ndarray,))) or \
|
4648
|
+
(torch is not None and isinstance(val, torch.Tensor)) or \
|
4649
|
+
(pd is not None and isinstance(val, (pd.Series, pd.Index))):
|
4650
|
+
lst = _to_python_list(val)
|
4651
|
+
if len(lst) == 0:
|
4652
|
+
return round(float(default), mantissa)
|
4653
|
+
return coerce_xyz(lst[0], mantissa, default)
|
4654
|
+
|
4655
|
+
# String
|
4656
|
+
if isinstance(val, str):
|
4657
|
+
try:
|
4658
|
+
return round(float(val), mantissa)
|
4659
|
+
except Exception:
|
4660
|
+
return round(float(default), mantissa)
|
4661
|
+
|
4662
|
+
# Numeric
|
4663
|
+
try:
|
4664
|
+
return _round_number(val, mantissa)
|
4665
|
+
except Exception:
|
4666
|
+
return round(float(default), mantissa)
|
4156
4667
|
|
4157
|
-
|
4158
|
-
|
4668
|
+
# Create a mapping from NetworkX nodes to TopologicPy vertices
|
4669
|
+
nx_to_topologic_vertex = {}
|
4159
4670
|
|
4160
4671
|
# Create TopologicPy vertices for each node in the NetworkX graph
|
4161
4672
|
vertices = []
|
4162
4673
|
for node, data in nxGraph.nodes(data=True):
|
4163
|
-
#
|
4164
|
-
x = round(data.get(xKey, random.uniform(*range)), mantissa)
|
4165
|
-
y = round(data.get(yKey, random.uniform(*range)), mantissa)
|
4166
|
-
z = round(data.get(zKey, 0), mantissa) # If there are no Z values, this is probably a flat graph.
|
4167
|
-
# Create a TopologicPy vertex with the node data dictionary
|
4168
|
-
vertex = Vertex.ByCoordinates(x,y,z)
|
4674
|
+
# Clean the node dictionary
|
4169
4675
|
cleaned_values = []
|
4170
|
-
|
4171
|
-
|
4172
|
-
|
4173
|
-
cleaned_values.append(
|
4174
|
-
|
4175
|
-
|
4676
|
+
cleaned_keys = []
|
4677
|
+
for k, v in data.items():
|
4678
|
+
cleaned_keys.append(str(k))
|
4679
|
+
cleaned_values.append(clean_value(v, mantissa))
|
4680
|
+
data = dict(zip(cleaned_keys, cleaned_values))
|
4681
|
+
# Defensive defaults for coordinates
|
4682
|
+
x_raw = y_raw = z_raw = None
|
4683
|
+
try:
|
4684
|
+
x_raw = data.get(xKey, None)
|
4685
|
+
y_raw = data.get(yKey, None)
|
4686
|
+
z_raw = data.get(zKey, None)
|
4687
|
+
except Exception:
|
4688
|
+
x_raw = y_raw = z_raw = None
|
4689
|
+
|
4690
|
+
if x_raw == None:
|
4691
|
+
coords = data.get(coordsKey, None)
|
4692
|
+
if coords:
|
4693
|
+
coords = clean_value(coords, mantissa)
|
4694
|
+
if isinstance(coords, list):
|
4695
|
+
if len(coords) == 2:
|
4696
|
+
x_raw = coords[0]
|
4697
|
+
y_raw = coords[1]
|
4698
|
+
z_raw = 0
|
4699
|
+
elif len(coords) == 3:
|
4700
|
+
x_raw = coords[0]
|
4701
|
+
y_raw = coords[1]
|
4702
|
+
z_raw = coords[2]
|
4703
|
+
|
4704
|
+
# Fall back to random only if missing / invalid
|
4705
|
+
x = coerce_xyz(x_raw, mantissa, default=random.uniform(*randomRange))
|
4706
|
+
y = coerce_xyz(y_raw, mantissa, default=random.uniform(*randomRange))
|
4707
|
+
z = coerce_xyz(z_raw, mantissa, default=0.0)
|
4708
|
+
|
4709
|
+
# Create vertex
|
4710
|
+
vertex = Vertex.ByCoordinates(x, y, z)
|
4711
|
+
|
4712
|
+
# Build and attach TopologicPy dictionary
|
4713
|
+
node_dict = Dictionary.ByKeysValues(cleaned_keys, cleaned_values)
|
4176
4714
|
vertex = Topology.SetDictionary(vertex, node_dict)
|
4177
|
-
|
4715
|
+
|
4716
|
+
#nx_to_topologic_vertex[node] = vertex
|
4178
4717
|
vertices.append(vertex)
|
4179
4718
|
|
4180
4719
|
# Create TopologicPy edges for each edge in the NetworkX graph
|
4181
4720
|
edges = []
|
4182
4721
|
for u, v, data in nxGraph.edges(data=True):
|
4183
|
-
start_vertex =
|
4184
|
-
end_vertex =
|
4722
|
+
start_vertex = vertices[u]
|
4723
|
+
end_vertex = vertices[v]
|
4185
4724
|
|
4186
4725
|
# Create a TopologicPy edge with the edge data dictionary
|
4187
|
-
|
4726
|
+
# Clean the node dictionary
|
4727
|
+
cleaned_values = []
|
4728
|
+
cleaned_keys = []
|
4729
|
+
for k, v in data.items():
|
4730
|
+
cleaned_keys.append(str(k))
|
4731
|
+
cleaned_values.append(clean_value(v, mantissa))
|
4732
|
+
edge_dict = Dictionary.ByKeysValues(cleaned_keys, cleaned_values)
|
4188
4733
|
edge = Edge.ByVertices([start_vertex, end_vertex], tolerance=tolerance)
|
4189
4734
|
edge = Topology.SetDictionary(edge, edge_dict)
|
4190
4735
|
edges.append(edge)
|
@@ -8015,13 +8560,13 @@ class Graph:
|
|
8015
8560
|
1 for validate, and 2 for test. If no key is found, the ratio of train/validate/test will be used. Default is "mask".
|
8016
8561
|
nodeTrainRatio : float , optional
|
8017
8562
|
The desired ratio of the node data to use for training. The number must be between 0 and 1. Default is 0.8 which means 80% of the data will be used for training.
|
8018
|
-
This value is ignored if an nodeMaskKey is
|
8563
|
+
This value is ignored if an nodeMaskKey is found.
|
8019
8564
|
nodeValidateRatio : float , optional
|
8020
8565
|
The desired ratio of the node data to use for validation. The number must be between 0 and 1. Default is 0.1 which means 10% of the data will be used for validation.
|
8021
|
-
This value is ignored if an nodeMaskKey is
|
8566
|
+
This value is ignored if an nodeMaskKey is found.
|
8022
8567
|
nodeTestRatio : float , optional
|
8023
8568
|
The desired ratio of the node data to use for testing. The number must be between 0 and 1. Default is 0.1 which means 10% of the data will be used for testing.
|
8024
|
-
This value is ignored if an nodeMaskKey is
|
8569
|
+
This value is ignored if an nodeMaskKey is found.
|
8025
8570
|
mantissa : int , optional
|
8026
8571
|
The number of decimal places to round the result to. Default is 6.
|
8027
8572
|
tolerance : float , optional
|
@@ -8888,7 +9433,7 @@ class Graph:
|
|
8888
9433
|
return False
|
8889
9434
|
|
8890
9435
|
@staticmethod
|
8891
|
-
def ExportToJSON(graph, path, verticesKey="vertices", edgesKey="edges", vertexLabelKey="", edgeLabelKey="", xKey="x", yKey="y", zKey="z", indent=4, sortKeys=False, mantissa=6, overwrite=False):
|
9436
|
+
def ExportToJSON(graph, path, propertiesKey="properties", verticesKey="vertices", edgesKey="edges", vertexLabelKey="", edgeLabelKey="", xKey="x", yKey="y", zKey="z", indent=4, sortKeys=False, mantissa=6, overwrite=False):
|
8892
9437
|
"""
|
8893
9438
|
Exports the input graph to a JSON file.
|
8894
9439
|
|
@@ -8898,6 +9443,8 @@ class Graph:
|
|
8898
9443
|
The input graph.
|
8899
9444
|
path : str
|
8900
9445
|
The path to the JSON file.
|
9446
|
+
propertiesKey : str , optional
|
9447
|
+
The desired key name to call graph properties. Default is "properties".
|
8901
9448
|
verticesKey : str , optional
|
8902
9449
|
The desired key name to call vertices. Default is "vertices".
|
8903
9450
|
edgesKey : str , optional
|
@@ -8947,7 +9494,7 @@ class Graph:
|
|
8947
9494
|
except:
|
8948
9495
|
raise Exception("Graph.ExportToJSON - Error: Could not create a new file at the following location: "+path)
|
8949
9496
|
if (f):
|
8950
|
-
jsondata = Graph.JSONData(graph, verticesKey=verticesKey, edgesKey=edgesKey, vertexLabelKey=vertexLabelKey, edgeLabelKey=edgeLabelKey, xKey=xKey, yKey=yKey, zKey=zKey, mantissa=mantissa)
|
9497
|
+
jsondata = Graph.JSONData(graph, propertiesKey=propertiesKey, verticesKey=verticesKey, edgesKey=edgesKey, vertexLabelKey=vertexLabelKey, edgeLabelKey=edgeLabelKey, xKey=xKey, yKey=yKey, zKey=zKey, mantissa=mantissa)
|
8951
9498
|
if jsondata != None:
|
8952
9499
|
json.dump(jsondata, f, indent=indent, sort_keys=sortKeys)
|
8953
9500
|
f.close()
|
@@ -10467,8 +11014,26 @@ class Graph:
|
|
10467
11014
|
The created GraphViz graph.
|
10468
11015
|
"""
|
10469
11016
|
|
10470
|
-
|
10471
|
-
|
11017
|
+
import os
|
11018
|
+
import warnings
|
11019
|
+
|
11020
|
+
try:
|
11021
|
+
from graphviz import Digraph
|
11022
|
+
from graphviz import Graph as Udgraph
|
11023
|
+
|
11024
|
+
except:
|
11025
|
+
print("Graph - Installing required graphviz library.")
|
11026
|
+
try:
|
11027
|
+
os.system("pip install graphviz")
|
11028
|
+
except:
|
11029
|
+
os.system("pip install graphviz --user")
|
11030
|
+
try:
|
11031
|
+
from graphviz import Digraph
|
11032
|
+
from graphviz import Graph as Udgraph
|
11033
|
+
print("Graph - graphviz library installed correctly.")
|
11034
|
+
except:
|
11035
|
+
warnings.warn("Graph - Error: Could not import graphviz.")
|
11036
|
+
|
10472
11037
|
from topologicpy.Graph import Graph
|
10473
11038
|
from topologicpy.Topology import Topology
|
10474
11039
|
from topologicpy.Dictionary import Dictionary
|
@@ -11662,6 +12227,7 @@ class Graph:
|
|
11662
12227
|
|
11663
12228
|
@staticmethod
|
11664
12229
|
def JSONData(graph,
|
12230
|
+
propertiesKey: str = "properties",
|
11665
12231
|
verticesKey: str = "vertices",
|
11666
12232
|
edgesKey: str = "edges",
|
11667
12233
|
vertexLabelKey: str = "",
|
@@ -11681,6 +12247,8 @@ class Graph:
|
|
11681
12247
|
----------
|
11682
12248
|
graph : topologic_core.Graph
|
11683
12249
|
The input graph.
|
12250
|
+
propertiesKey : str , optional
|
12251
|
+
The desired key name to call the graph properties. Default is "properties".
|
11684
12252
|
verticesKey : str , optional
|
11685
12253
|
The desired key name to call vertices. Default is "vertices".
|
11686
12254
|
edgesKey : str , optional
|
@@ -11720,8 +12288,10 @@ class Graph:
|
|
11720
12288
|
from topologicpy.Dictionary import Dictionary
|
11721
12289
|
from topologicpy.Helper import Helper
|
11722
12290
|
|
12291
|
+
graph_d = Dictionary.PythonDictionary(Topology.Dictionary(graph))
|
11723
12292
|
vertices = Graph.Vertices(graph)
|
11724
12293
|
j_data = {}
|
12294
|
+
j_data[propertiesKey] = graph_d
|
11725
12295
|
j_data[verticesKey] = {}
|
11726
12296
|
j_data[edgesKey] = {}
|
11727
12297
|
n = max(len(str(len(vertices))), 4)
|
@@ -14266,6 +14836,54 @@ class Graph:
|
|
14266
14836
|
_ = graph.RemoveEdges([edge], tolerance) # Hook to Core
|
14267
14837
|
return graph
|
14268
14838
|
|
14839
|
+
@staticmethod
|
14840
|
+
def RemoveIsolatedEdges(graph, removeVertices: bool = True, tolerance: float = 0.0001, silent: bool = False):
|
14841
|
+
"""
|
14842
|
+
Removes all isolated edges from the input graph.
|
14843
|
+
Isolated edges are those whose vertices are not connected to any other edges.
|
14844
|
+
That is, they have a degree of 1.
|
14845
|
+
|
14846
|
+
Parameters
|
14847
|
+
----------
|
14848
|
+
graph : topologic_core.Graph
|
14849
|
+
The input graph.
|
14850
|
+
removeVertices : bool , optional
|
14851
|
+
If set to True, the end vertices of the edges are also removed. Default is True.
|
14852
|
+
tolerance : float , optional
|
14853
|
+
The desired tolerance. Default is 0.0001.
|
14854
|
+
silent : bool , optional
|
14855
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
14856
|
+
|
14857
|
+
Returns
|
14858
|
+
-------
|
14859
|
+
topologic_core.Graph
|
14860
|
+
The input graph with all isolated vertices removed.
|
14861
|
+
|
14862
|
+
"""
|
14863
|
+
from topologicpy.Topology import Topology
|
14864
|
+
from topologicpy.Edge import Edge
|
14865
|
+
|
14866
|
+
|
14867
|
+
if not Topology.IsInstance(graph, "graph"):
|
14868
|
+
if not silent:
|
14869
|
+
print("Graph.RemoveIsolatedEdges - Error: The input graph parameter is not a valid graph. Returning None.")
|
14870
|
+
return None
|
14871
|
+
|
14872
|
+
edges = Graph.Edges(graph)
|
14873
|
+
if removeVertices == True:
|
14874
|
+
for edge in edges:
|
14875
|
+
va, vb = Edge.Vertices(edge)
|
14876
|
+
if Graph.VertexDegree(graph, va, tolerance=tolerance, silent=silent) == 1 and Graph.VertexDegree(graph, vb, tolerance=tolerance, silent=silent) == 1:
|
14877
|
+
graph = Graph.RemoveEdge(graph, edge, tolerance=tolerance)
|
14878
|
+
graph = Graph.RemoveVertex(graph, va, tolerance=tolerance)
|
14879
|
+
graph = Graph.RemoveVertex(graph, vb, tolerance=tolerance)
|
14880
|
+
else:
|
14881
|
+
for edge in edges:
|
14882
|
+
va, vb = Edge.Vertices(edge)
|
14883
|
+
if Graph.VertexDegree(graph, va, tolerance=tolerance, silent=silent) == 1 and Graph.VertexDegree(graph, vb, tolerance=tolerance, silent=silent) == 1:
|
14884
|
+
graph = Graph.RemoveEdge(graph, edge, tolerance=tolerance)
|
14885
|
+
return graph
|
14886
|
+
|
14269
14887
|
@staticmethod
|
14270
14888
|
def RemoveIsolatedVertices(graph, tolerance=0.0001):
|
14271
14889
|
"""
|
topologicpy/Kuzu.py
CHANGED
topologicpy/Topology.py
CHANGED
@@ -2390,7 +2390,7 @@ class Topology():
|
|
2390
2390
|
return topology
|
2391
2391
|
'''
|
2392
2392
|
@staticmethod
|
2393
|
-
def ByJSONFile(file, tolerance=0.0001):
|
2393
|
+
def ByJSONFile(file, tolerance: float = 0.0001, silent: bool = False):
|
2394
2394
|
"""
|
2395
2395
|
Imports the topology from a JSON file.
|
2396
2396
|
|
@@ -2400,6 +2400,8 @@ class Topology():
|
|
2400
2400
|
The input JSON file.
|
2401
2401
|
tolerance : float , optional
|
2402
2402
|
The desired tolerance. Default is 0.0001.
|
2403
|
+
silent : bool , optional
|
2404
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
2403
2405
|
|
2404
2406
|
Returns
|
2405
2407
|
-------
|
@@ -2407,14 +2409,21 @@ class Topology():
|
|
2407
2409
|
The list of imported topologies (Warning: the list could contain 0, 1, or many topologies, but this method will always return a list)
|
2408
2410
|
|
2409
2411
|
"""
|
2412
|
+
import json
|
2410
2413
|
if not file:
|
2411
|
-
|
2414
|
+
if not silent:
|
2415
|
+
print("Topology.ByJSONFile - Error: the input file parameter is not a valid file. Returning None.")
|
2416
|
+
return None
|
2417
|
+
try:
|
2418
|
+
json_dict = json.load(file)
|
2419
|
+
except Exception as e:
|
2420
|
+
if not silent:
|
2421
|
+
print("Topology.ByJSONFile - Error: Could not load the JSON file: {e}. Returning None.")
|
2412
2422
|
return None
|
2413
|
-
json_dict =
|
2414
|
-
return Topology.ByJSONDictionary(json_dict, tolerance=tolerance)
|
2423
|
+
return Topology.ByJSONDictionary(json_dict, tolerance=tolerance, silent=silent)
|
2415
2424
|
|
2416
2425
|
@staticmethod
|
2417
|
-
def ByJSONPath(path, tolerance=0.0001):
|
2426
|
+
def ByJSONPath(path, tolerance: float = 0.0001, silent: bool = False):
|
2418
2427
|
"""
|
2419
2428
|
Imports the topology from a JSON file.
|
2420
2429
|
|
@@ -2424,6 +2433,8 @@ class Topology():
|
|
2424
2433
|
The file path to the json file.
|
2425
2434
|
tolerance : float , optional
|
2426
2435
|
The desired tolerance. Default is 0.0001.
|
2436
|
+
silent : bool , optional
|
2437
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
2427
2438
|
|
2428
2439
|
Returns
|
2429
2440
|
-------
|
@@ -2433,15 +2444,20 @@ class Topology():
|
|
2433
2444
|
"""
|
2434
2445
|
import json
|
2435
2446
|
if not path:
|
2436
|
-
|
2447
|
+
if not silent:
|
2448
|
+
print("Topology.ByJSONPath - Error: the input path parameter is not a valid path. Returning None.")
|
2437
2449
|
return None
|
2438
|
-
|
2439
|
-
|
2440
|
-
|
2441
|
-
|
2450
|
+
try:
|
2451
|
+
with open(path) as file:
|
2452
|
+
json_dict = json.load(file)
|
2453
|
+
except Exception as e:
|
2454
|
+
if not silent:
|
2455
|
+
print("Topology.ByJSONPath - Error: Could not load file: {e}. Returning None.")
|
2456
|
+
return None
|
2457
|
+
return Topology.ByJSONDictionary(json_dict, tolerance=tolerance, silent=silent)
|
2442
2458
|
|
2443
2459
|
@staticmethod
|
2444
|
-
def ByJSONDictionary(jsonDictionary, tolerance=0.0001):
|
2460
|
+
def ByJSONDictionary(jsonDictionary: dict, tolerance: float = 0.0001, silent: bool = False):
|
2445
2461
|
"""
|
2446
2462
|
Imports the topology from a JSON dictionary.
|
2447
2463
|
|
@@ -2451,6 +2467,8 @@ class Topology():
|
|
2451
2467
|
The input JSON dictionary.
|
2452
2468
|
tolerance : float , optional
|
2453
2469
|
The desired tolerance. Default is 0.0001.
|
2470
|
+
silent : bool , optional
|
2471
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
2454
2472
|
|
2455
2473
|
Returns
|
2456
2474
|
-------
|
@@ -2489,41 +2507,41 @@ class Topology():
|
|
2489
2507
|
# Create basic topological entities
|
2490
2508
|
if entity_type == 'Vertex':
|
2491
2509
|
parent_entity = Vertex.ByCoordinates(*entity['coordinates'])
|
2492
|
-
parent_entity = Topology.SetDictionary(parent_entity, entity_dict)
|
2510
|
+
parent_entity = Topology.SetDictionary(parent_entity, entity_dict, silent=silent)
|
2493
2511
|
vertices[entity['uuid']] = parent_entity
|
2494
2512
|
|
2495
2513
|
elif entity_type == 'Edge':
|
2496
2514
|
vertex1 = vertices[entity['vertices'][0]]
|
2497
2515
|
vertex2 = vertices[entity['vertices'][1]]
|
2498
|
-
parent_entity = Edge.ByVertices([vertex1, vertex2])
|
2499
|
-
parent_entity = Topology.SetDictionary(parent_entity, entity_dict)
|
2516
|
+
parent_entity = Edge.ByVertices([vertex1, vertex2], tolerance=tolerance, silent=silent)
|
2517
|
+
parent_entity = Topology.SetDictionary(parent_entity, entity_dict, silent=silent)
|
2500
2518
|
edges[entity['uuid']] = parent_entity
|
2501
2519
|
|
2502
2520
|
elif entity_type == 'Wire':
|
2503
2521
|
wire_edges = [edges[uuid] for uuid in entity['edges']]
|
2504
|
-
parent_entity = Wire.ByEdges(wire_edges)
|
2505
|
-
parent_entity = Topology.SetDictionary(parent_entity, entity_dict)
|
2522
|
+
parent_entity = Wire.ByEdges(wire_edges, tolerance=tolerance, silent=silent)
|
2523
|
+
parent_entity = Topology.SetDictionary(parent_entity, entity_dict, silent=silent)
|
2506
2524
|
wires[entity['uuid']] = parent_entity
|
2507
2525
|
|
2508
2526
|
elif entity_type == 'Face':
|
2509
2527
|
face_wires = [wires[uuid] for uuid in entity['wires']]
|
2510
2528
|
if len(face_wires) > 1:
|
2511
|
-
parent_entity = Face.ByWires(face_wires[0], face_wires[1:])
|
2529
|
+
parent_entity = Face.ByWires(face_wires[0], face_wires[1:], tolerance=tolerance, silent=silent)
|
2512
2530
|
else:
|
2513
|
-
parent_entity = Face.ByWire(face_wires[0])
|
2514
|
-
parent_entity = Topology.SetDictionary(parent_entity, entity_dict)
|
2531
|
+
parent_entity = Face.ByWire(face_wires[0], tolerance=tolerance, silent=silent)
|
2532
|
+
parent_entity = Topology.SetDictionary(parent_entity, entity_dict, silent=silent)
|
2515
2533
|
faces[entity['uuid']] = parent_entity
|
2516
2534
|
|
2517
2535
|
elif entity_type == 'Shell':
|
2518
2536
|
shell_faces = [faces[uuid] for uuid in entity['faces']]
|
2519
|
-
parent_entity = Shell.ByFaces(shell_faces)
|
2520
|
-
parent_entity = Topology.SetDictionary(parent_entity, entity_dict)
|
2537
|
+
parent_entity = Shell.ByFaces(shell_faces, tolerance=tolerance, silent=silent)
|
2538
|
+
parent_entity = Topology.SetDictionary(parent_entity, entity_dict, silent=silent)
|
2521
2539
|
shells[entity['uuid']] = parent_entity
|
2522
2540
|
|
2523
2541
|
elif entity_type == 'Cell':
|
2524
2542
|
cell_shells = [shells[uuid] for uuid in entity['shells']]
|
2525
2543
|
if len(cell_shells) > 1:
|
2526
|
-
parent_entity = Cell.ByShells(cell_shells[0], cell_shells[1:])
|
2544
|
+
parent_entity = Cell.ByShells(cell_shells[0], cell_shells[1:], tolerance=tolerance, silent=silent)
|
2527
2545
|
else:
|
2528
2546
|
parent_entity = Cell.ByShell(cell_shells[0])
|
2529
2547
|
parent_entity = Topology.SetDictionary(parent_entity, entity_dict)
|
@@ -2649,7 +2667,7 @@ class Topology():
|
|
2649
2667
|
return top_level_list
|
2650
2668
|
|
2651
2669
|
@staticmethod
|
2652
|
-
def ByJSONString(string, tolerance=0.0001):
|
2670
|
+
def ByJSONString(string: str, tolerance: float = 0.0001, silent: bool = False):
|
2653
2671
|
"""
|
2654
2672
|
Imports the topology from a JSON string.
|
2655
2673
|
|
@@ -2659,6 +2677,8 @@ class Topology():
|
|
2659
2677
|
The input JSON string.
|
2660
2678
|
tolerance : float , optional
|
2661
2679
|
The desired tolerance. Default is 0.0001.
|
2680
|
+
silent : bool , optional
|
2681
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
2662
2682
|
|
2663
2683
|
Returns
|
2664
2684
|
-------
|
@@ -2666,9 +2686,13 @@ class Topology():
|
|
2666
2686
|
The list of imported topologies (Warning: the list could contain 0, 1, or many topologies, but this method will always return a list)
|
2667
2687
|
|
2668
2688
|
"""
|
2669
|
-
|
2670
|
-
|
2671
|
-
|
2689
|
+
try:
|
2690
|
+
json_dict = json.loads(string)
|
2691
|
+
except Exception as e:
|
2692
|
+
if not silent:
|
2693
|
+
print(f"Topology.ByJSONString - Error: Could not read the input string: {e}. Returning None.")
|
2694
|
+
return None
|
2695
|
+
return Topology.ByJSONDictionary(json_dict, tolerance=tolerance, silent=silent)
|
2672
2696
|
|
2673
2697
|
@staticmethod
|
2674
2698
|
def ByMeshData(dictionary, transferDictionaries: bool = False, mantissa: int = 6, tolerance: float = 0.0001, silent: bool = False):
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.8.
|
1
|
+
__version__ = '0.8.61'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.61
|
4
4
|
Summary: An AI-Powered Spatial Modelling and Analysis Software Library for Architecture, Engineering, and Construction.
|
5
5
|
Author-email: Wassim Jabi <wassim.jabi@gmail.com>
|
6
6
|
License: AGPL v3 License
|
@@ -2,7 +2,7 @@ topologicpy/ANN.py,sha256=gpflv4lFypOW789vO7mSkMLaMF_ZftVOCqCvtGr6-JA,47873
|
|
2
2
|
topologicpy/Aperture.py,sha256=wNn5miB_IrGCBYuQ18HXQYRva20dUC3id4AJCulL7to,2723
|
3
3
|
topologicpy/BVH.py,sha256=JA4bb-9hgMfVZ_syzmSmTL3ueCq-0vMUGMPZxNcawAY,13023
|
4
4
|
topologicpy/CSG.py,sha256=09la1-xzS9vr-WnV7tpJ0I-mkZ-XY0MRSd5iB50Nfgw,15556
|
5
|
-
topologicpy/Cell.py,sha256=
|
5
|
+
topologicpy/Cell.py,sha256=xkt9lfutgSwr_1lah1U5n48UnrLIggznNKUmEe2FA2g,177505
|
6
6
|
topologicpy/CellComplex.py,sha256=Kbz63rGeE08bJfMXFvB-AptoKHiaCK5OtiV1wz8Y-Fk,68081
|
7
7
|
topologicpy/Cluster.py,sha256=G49AuhJHQ1s819cB5MtVdmAGgkag19IC3dRP1ub1Wh4,58608
|
8
8
|
topologicpy/Color.py,sha256=hzSmgBWhiuYc55RSipkQNIgGtgyhC5BqY8AakNYEK-U,24486
|
@@ -12,11 +12,11 @@ topologicpy/Dictionary.py,sha256=Z4YQ88tONWd-0X0dENQ8IZqIOa9mbBqhJkTBsHmft2g,446
|
|
12
12
|
topologicpy/Edge.py,sha256=DifItuyabFDUFC7CVMlt2DeMFMNaGOqCg43iU9CPP0A,74029
|
13
13
|
topologicpy/EnergyModel.py,sha256=hB1aiJe45gdDMFm1AhkBr-1djjtXSzn24iRpQMk43-4,57749
|
14
14
|
topologicpy/Face.py,sha256=aX9EcR3JGbLITElhd25J0Z8m9U8KkmbYivGg3oZN-Uw,202296
|
15
|
-
topologicpy/Graph.py,sha256=
|
15
|
+
topologicpy/Graph.py,sha256=ytXl9VLj243o9LhY0A8P_gp4_Ce_VrHW5oaC2WK6Mbc,782718
|
16
16
|
topologicpy/Grid.py,sha256=3OsBMyHh4w8gpFOTMKHMNTpo62V0CwRNu5cwm87yDUA,18421
|
17
17
|
topologicpy/Helper.py,sha256=Nr6pyzl0sZm4Cu11wOqoYKu6yYal5N6A9jErXnaZBJc,31765
|
18
18
|
topologicpy/Honeybee.py,sha256=DzaG9wpkJdcDWcjOGXhuN5X0gCqypmZGBa1y5E2MkjU,48964
|
19
|
-
topologicpy/Kuzu.py,sha256=
|
19
|
+
topologicpy/Kuzu.py,sha256=fxaDPWM5Xam7Tot0olPZsazS_7xgE_Vo-jf0Sbv3VZE,36298
|
20
20
|
topologicpy/Matrix.py,sha256=bOofT34G3YHu9aMIWx60YHAJga4R0GbDjsZBUD4Hu_k,22706
|
21
21
|
topologicpy/Neo4j.py,sha256=J8jU_mr5-mWC0Lg_D2dMjMlx1rY_eh8ks_aubUuTdWw,22319
|
22
22
|
topologicpy/Plotly.py,sha256=OQvCzAXqu_QYn8iY0rjc8ZB4XwwK70pWjnnoMzDdcc0,123167
|
@@ -26,14 +26,14 @@ topologicpy/ShapeGrammar.py,sha256=KYsKDLXWdflAcYMAIz84AUF-GMkbTmaBDd2-ovbilqU,2
|
|
26
26
|
topologicpy/Shell.py,sha256=ioO4raCJfXtYldQg-adpcLVeJPEA6od6cAA5ro7t6r4,96792
|
27
27
|
topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
|
28
28
|
topologicpy/Sun.py,sha256=8S6dhCKfOhUGVny-jEk87Q08anLYMB1JEBKRGCklvbQ,36670
|
29
|
-
topologicpy/Topology.py,sha256=
|
29
|
+
topologicpy/Topology.py,sha256=O3K4B47K0ic4jMj4OC9ZuqDPV6I7QRZ6r7Q9SHPEqaI,474206
|
30
30
|
topologicpy/Vector.py,sha256=pEC8YY3TeHGfGdeNgvdHjgMDwxGabp5aWjwYC1HSvMk,42236
|
31
31
|
topologicpy/Vertex.py,sha256=r_3cicgpino96ymm1ANptfOuqE59b99YWwksxyPOYK4,85914
|
32
32
|
topologicpy/Wire.py,sha256=gjgQUGHdBdXUIijgZc_VIW0E39w-smaVhhdl0jF63fQ,230466
|
33
33
|
topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
|
34
|
-
topologicpy/version.py,sha256=
|
35
|
-
topologicpy-0.8.
|
36
|
-
topologicpy-0.8.
|
37
|
-
topologicpy-0.8.
|
38
|
-
topologicpy-0.8.
|
39
|
-
topologicpy-0.8.
|
34
|
+
topologicpy/version.py,sha256=v9RYfeFVriaSopTI1WMyzj0QSU9vvxnXtU_efzx9Iek,23
|
35
|
+
topologicpy-0.8.61.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
36
|
+
topologicpy-0.8.61.dist-info/METADATA,sha256=AUdc_jfqI7o0MlB6Izlr_BIUcpjbN71DLKCHBY1UYsA,10535
|
37
|
+
topologicpy-0.8.61.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
38
|
+
topologicpy-0.8.61.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
39
|
+
topologicpy-0.8.61.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|