topologicpy 0.8.52__py3-none-any.whl → 0.8.54__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 +1 -3
- topologicpy/EnergyModel.py +111 -10
- topologicpy/Graph.py +285 -1
- topologicpy/Helper.py +57 -43
- topologicpy/Plotly.py +4 -2
- topologicpy/Topology.py +17 -0
- topologicpy/version.py +1 -1
- {topologicpy-0.8.52.dist-info → topologicpy-0.8.54.dist-info}/METADATA +1 -1
- {topologicpy-0.8.52.dist-info → topologicpy-0.8.54.dist-info}/RECORD +12 -12
- {topologicpy-0.8.52.dist-info → topologicpy-0.8.54.dist-info}/WHEEL +0 -0
- {topologicpy-0.8.52.dist-info → topologicpy-0.8.54.dist-info}/licenses/LICENSE +0 -0
- {topologicpy-0.8.52.dist-info → topologicpy-0.8.54.dist-info}/top_level.txt +0 -0
topologicpy/Cell.py
CHANGED
@@ -1552,7 +1552,6 @@ class Cell():
|
|
1552
1552
|
cluster = Cluster.ByTopologies(pentagons)
|
1553
1553
|
|
1554
1554
|
cluster2 = Topology.Rotate(cluster, origin=Vertex.Origin(), axis=[1, 0, 0], angle=180)
|
1555
|
-
#cluster2 = Topology.Rotate(cluster2, origin=Vertex.Origin(), axis=[0, 0, 1], angle=36)
|
1556
1555
|
vertices = Topology.Vertices(cluster)
|
1557
1556
|
zList = [Vertex.Z(v) for v in vertices]
|
1558
1557
|
zList = list(set(zList))
|
@@ -1566,9 +1565,8 @@ class Cell():
|
|
1566
1565
|
dodecahedron = Topology.Translate(dodecahedron, -Vertex.X(centroid), -Vertex.Y(centroid), -Vertex.Z(centroid))
|
1567
1566
|
vertices = Topology.Vertices(dodecahedron)
|
1568
1567
|
d = Vertex.Distance(Vertex.Origin(), vertices[0])
|
1568
|
+
# Make sure the distance from the origin to the vertices is equal to the radius.
|
1569
1569
|
dodecahedron = Topology.Scale(dodecahedron, origin=Vertex.Origin(), x=radius/d, y=radius/d, z=radius/d)
|
1570
|
-
verts = Topology.Vertices(dodecahedron)
|
1571
|
-
print("Dodec: Distance", Vertex.Distance(Vertex.Origin(), verts[0]))
|
1572
1570
|
if placement == "bottom":
|
1573
1571
|
dodecahedron = Topology.Translate(dodecahedron, 0, 0, radius)
|
1574
1572
|
elif placement == "lowerleft":
|
topologicpy/EnergyModel.py
CHANGED
@@ -201,6 +201,51 @@ class EnergyModel:
|
|
201
201
|
warnings.warn("EnergyModel.ByTopology - Error: Could not import openstudio.Please try to install openstudio manually. Returning None.")
|
202
202
|
return None
|
203
203
|
|
204
|
+
|
205
|
+
def load_openstudio_model(osm_path: str, allow_newer: bool = True):
|
206
|
+
"""
|
207
|
+
Load an OpenStudio .osm file and return an openstudio.model.Model.
|
208
|
+
Uses loadModelFromString to avoid SWIG path overload issues.
|
209
|
+
"""
|
210
|
+
import os
|
211
|
+
|
212
|
+
if not os.path.exists(osm_path):
|
213
|
+
raise FileNotFoundError(osm_path)
|
214
|
+
|
215
|
+
vt = openstudio.osversion.VersionTranslator()
|
216
|
+
if allow_newer:
|
217
|
+
vt.setAllowNewerVersions(True)
|
218
|
+
|
219
|
+
# 1) Robust path-agnostic route: read text and load from string
|
220
|
+
with open(osm_path, "r", encoding="utf-8") as f:
|
221
|
+
txt = f.read()
|
222
|
+
model_opt = vt.loadModelFromString(txt) # <- avoids path type mismatches
|
223
|
+
|
224
|
+
# 2) Fallback: try the filesystem-path overloads if needed
|
225
|
+
if (not model_opt) or (not model_opt.is_initialized()):
|
226
|
+
os_path = None
|
227
|
+
for maker in (
|
228
|
+
lambda s: getattr(openstudio, "path")(s),
|
229
|
+
lambda s: getattr(openstudio, "toPath")(s),
|
230
|
+
lambda s: getattr(openstudio.openstudioutilitiescore, "toPath")(s),
|
231
|
+
):
|
232
|
+
try:
|
233
|
+
os_path = maker(osm_path)
|
234
|
+
break
|
235
|
+
except Exception:
|
236
|
+
pass
|
237
|
+
if os_path is not None:
|
238
|
+
try:
|
239
|
+
model_opt = vt.loadModel(os_path)
|
240
|
+
except TypeError:
|
241
|
+
model_opt = openstudio.model.Model.load(os_path)
|
242
|
+
|
243
|
+
if (not model_opt) or (not model_opt.is_initialized()):
|
244
|
+
raise RuntimeError(f"Failed to load OpenStudio model from: {osm_path}")
|
245
|
+
|
246
|
+
model = model_opt.get()
|
247
|
+
return model
|
248
|
+
|
204
249
|
def getKeyName(d, keyName):
|
205
250
|
keys = d.Keys()
|
206
251
|
for key in keys:
|
@@ -243,21 +288,23 @@ class EnergyModel:
|
|
243
288
|
|
244
289
|
if not osModelPath:
|
245
290
|
import os
|
246
|
-
osModelPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "OSMTemplate-OfficeBuilding-3.
|
291
|
+
osModelPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "OSMTemplate-OfficeBuilding-3.10.0.osm")
|
247
292
|
if not weatherFilePath or not designDayFilePath:
|
248
293
|
import os
|
249
294
|
weatherFilePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "GBR_London.Gatwick.037760_IWEC.epw")
|
250
295
|
designDayFilePath = os.path.join(os.path.dirname(os.path.realpath(__file__)), "assets", "EnergyModel", "GBR_London.Gatwick.037760_IWEC.ddy")
|
251
|
-
|
296
|
+
|
297
|
+
#translator = openstudio.osversion.VersionTranslator()
|
252
298
|
# DEBUGGING
|
253
299
|
#osmFile = openstudio.openstudioutilitiescore.toPath(osModelPath)
|
254
300
|
#osModel = translator.loadModel(osmFile)
|
255
|
-
osModel = translator.loadModel(osModelPath)
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
301
|
+
#osModel = translator.loadModel(osModelPath)
|
302
|
+
osModel = load_openstudio_model(osModelPath, allow_newer=True)
|
303
|
+
# if osModel.isNull():
|
304
|
+
# print("EnergyModel.ByTopology - Error: The openstudio model is null. Returning None.")
|
305
|
+
# return None
|
306
|
+
# else:
|
307
|
+
# osModel = osModel.get()
|
261
308
|
# DEBUGGING
|
262
309
|
#osEPWFile = openstudio.openstudioutilitiesfiletypes.EpwFile.load(openstudio.toPath(weatherFilePath))
|
263
310
|
osEPWFile = openstudio.openstudioutilitiesfiletypes.EpwFile.load(weatherFilePath)
|
@@ -265,8 +312,8 @@ class EnergyModel:
|
|
265
312
|
osEPWFile = osEPWFile.get()
|
266
313
|
openstudio.model.WeatherFile.setWeatherFile(osModel, osEPWFile)
|
267
314
|
# DEBUGGING
|
268
|
-
|
269
|
-
ddyModel = openstudio.openstudioenergyplus.loadAndTranslateIdf(designDayFilePath)
|
315
|
+
ddyModel = openstudio.openstudioenergyplus.loadAndTranslateIdf(openstudio.toPath(designDayFilePath))
|
316
|
+
#ddyModel = openstudio.openstudioenergyplus.loadAndTranslateIdf(designDayFilePath)
|
270
317
|
if ddyModel.is_initialized():
|
271
318
|
ddyModel = ddyModel.get()
|
272
319
|
for ddy in ddyModel.getObjectsByType(openstudio.IddObjectType("OS:SizingPeriod:DesignDay")):
|
@@ -1195,3 +1242,57 @@ class EnergyModel:
|
|
1195
1242
|
return None
|
1196
1243
|
return units
|
1197
1244
|
|
1245
|
+
@staticmethod
|
1246
|
+
def Version(check: bool = True, silent: bool = False):
|
1247
|
+
"""
|
1248
|
+
Returns the OpenStudio SDK version number.
|
1249
|
+
|
1250
|
+
Parameters
|
1251
|
+
----------
|
1252
|
+
check : bool , optional
|
1253
|
+
if set to True, the version number is checked with the latest version on PyPi. Default is True.
|
1254
|
+
|
1255
|
+
silent : bool , optional
|
1256
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
1257
|
+
|
1258
|
+
Returns
|
1259
|
+
-------
|
1260
|
+
str
|
1261
|
+
The OpenStudio SDK version number.
|
1262
|
+
|
1263
|
+
"""
|
1264
|
+
from topologicpy.Helper import Helper
|
1265
|
+
try:
|
1266
|
+
import openstudio
|
1267
|
+
openstudio.Logger.instance().standardOutLogger().setLogLevel(openstudio.Fatal)
|
1268
|
+
except:
|
1269
|
+
if not silent:
|
1270
|
+
print("EnergyModel.Version - Information: Installing required openstudio library.")
|
1271
|
+
try:
|
1272
|
+
os.system("pip install openstudio")
|
1273
|
+
except:
|
1274
|
+
os.system("pip install openstudio --user")
|
1275
|
+
try:
|
1276
|
+
import openstudio
|
1277
|
+
openstudio.Logger.instance().standardOutLogger().setLogLevel(openstudio.Fatal)
|
1278
|
+
if not silent:
|
1279
|
+
print("EnergyModel.Version - Information: openstudio library installed correctly.")
|
1280
|
+
except:
|
1281
|
+
if not silent:
|
1282
|
+
print("EnergyModel.Version - Error: Could not import openstudio.Please try to install openstudio manually. Returning None.")
|
1283
|
+
return None
|
1284
|
+
import requests
|
1285
|
+
from packaging import version
|
1286
|
+
|
1287
|
+
result = getattr(openstudio, "openStudioVersion", None)
|
1288
|
+
if callable(result):
|
1289
|
+
result = result()
|
1290
|
+
else:
|
1291
|
+
if not silent:
|
1292
|
+
print("EnergyModel.Version - Error: Could not retrieve the openstudio SDK version number. Returning None.")
|
1293
|
+
return None
|
1294
|
+
if check == True:
|
1295
|
+
result = Helper.CheckVersion("openstudio", result, silent=silent)
|
1296
|
+
return result
|
1297
|
+
|
1298
|
+
|
topologicpy/Graph.py
CHANGED
@@ -784,7 +784,291 @@ class Graph:
|
|
784
784
|
return csv_buffer.getvalue()
|
785
785
|
except Exception as e:
|
786
786
|
return ""
|
787
|
-
|
787
|
+
|
788
|
+
@staticmethod
|
789
|
+
def AdjacencyMatrixFigure(graph,
|
790
|
+
vertexKey: str = None,
|
791
|
+
showZero: bool = False,
|
792
|
+
zeroChar: str = "·",
|
793
|
+
zeroColor: str = 'rgba(0,0,0,0)',
|
794
|
+
valueColor: str = 'rgba(0,0,0,0.05)',
|
795
|
+
diagonalHighlight: bool = True,
|
796
|
+
diagonalColor: str = 'rgba(0,0,0,0)',
|
797
|
+
title: str = None,
|
798
|
+
cellSize: int = 24,
|
799
|
+
fontFamily: str = "Arial",
|
800
|
+
fontSize: int = 12,
|
801
|
+
fontColor: str = 'rgba(0,0,0,0)',
|
802
|
+
backgroundColor: str = 'rgba(0,0,0,0)',
|
803
|
+
headerColor: str = 'rgba(0,0,0,0)',
|
804
|
+
reverse=False,
|
805
|
+
edgeKeyFwd=None,
|
806
|
+
edgeKeyBwd=None,
|
807
|
+
bidirKey=None,
|
808
|
+
bidirectional=True,
|
809
|
+
useEdgeIndex=False,
|
810
|
+
useEdgeLength=False,
|
811
|
+
mantissa: int = 6,
|
812
|
+
tolerance=0.0001,
|
813
|
+
silent: bool = False):
|
814
|
+
"""
|
815
|
+
Returns a Plotly table figure visualizing the adjacency matrix of a Graph.
|
816
|
+
|
817
|
+
Parameters
|
818
|
+
----------
|
819
|
+
graph : topologic_core.Graph
|
820
|
+
The input graph.
|
821
|
+
vertexKey : str , optional
|
822
|
+
If set, the returned list of vertices is sorted according to the dictionary values stored under this key. Default is None.
|
823
|
+
showZero : bool, optional
|
824
|
+
If True, show zeros as "0"; if False, show a subtle glyph (zero_char) or blank. Default is False.
|
825
|
+
zeroChar : str, optional
|
826
|
+
Character to display for zero entries when show_zero is False. Default is "·".
|
827
|
+
zeroColor : list or str , optional
|
828
|
+
The desired color to display for zero-valued cells. This can be any color list or plotly color string and may be specified as:
|
829
|
+
- An rgb list (e.g. [255,0,0])
|
830
|
+
- A cmyk list (e.g. [0.5, 0, 0.25, 0.2])
|
831
|
+
- A hex string (e.g. '#ff0000')
|
832
|
+
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
|
833
|
+
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
|
834
|
+
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
|
835
|
+
- A named CSS color.
|
836
|
+
The default is 'rgba(0,0,0,0)' (transparent).
|
837
|
+
valueColor : list or str , optional
|
838
|
+
The desired color to display for non-zero-valued cells. This can be any color list or plotly color string and may be specified as:
|
839
|
+
- An rgb list (e.g. [255,0,0])
|
840
|
+
- A cmyk list (e.g. [0.5, 0, 0.25, 0.2])
|
841
|
+
- A hex string (e.g. '#ff0000')
|
842
|
+
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
|
843
|
+
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
|
844
|
+
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
|
845
|
+
- A named CSS color.
|
846
|
+
The default is 'rgba(0,0,0,0.35)' (slight highlight).
|
847
|
+
diagonalHighlight : bool, optional
|
848
|
+
If True, lightly highlight diagonal cells. Default is True.
|
849
|
+
diagonalColor : list or str , optional
|
850
|
+
The desired diagonal highlight color. This can be any color list or plotly color string and may be specified as:
|
851
|
+
- An rgb list (e.g. [255,0,0])
|
852
|
+
- A cmyk list (e.g. [0.5, 0, 0.25, 0.2])
|
853
|
+
- A hex string (e.g. '#ff0000')
|
854
|
+
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
|
855
|
+
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
|
856
|
+
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
|
857
|
+
- A named CSS color.
|
858
|
+
The default is 'rgba(0,0,0,0)' (transparent).
|
859
|
+
title : str, optional
|
860
|
+
Optional figure title.
|
861
|
+
cellSize : int, optional
|
862
|
+
Approximate pixel height of each table row. Default is 24.
|
863
|
+
fontFamily : str, optional
|
864
|
+
Font family for table text. Default is "Arial".
|
865
|
+
fontSize : int, optional
|
866
|
+
Font size for table text. Default is 12.
|
867
|
+
fontColor : list or str , optional
|
868
|
+
The desired font color. This can be any color list or plotly color string and may be specified as:
|
869
|
+
- An rgb list (e.g. [255,0,0])
|
870
|
+
- A cmyk list (e.g. [0.5, 0, 0.25, 0.2])
|
871
|
+
- A hex string (e.g. '#ff0000')
|
872
|
+
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
|
873
|
+
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
|
874
|
+
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
|
875
|
+
- A named CSS color.
|
876
|
+
The default is 'rgba(0,0,0,0)' (transparent).
|
877
|
+
backgroundColor : list or str , optional
|
878
|
+
The desired background color. This can be any color list or plotly color string and may be specified as:
|
879
|
+
- An rgb list (e.g. [255,0,0])
|
880
|
+
- A cmyk list (e.g. [0.5, 0, 0.25, 0.2])
|
881
|
+
- A hex string (e.g. '#ff0000')
|
882
|
+
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
|
883
|
+
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
|
884
|
+
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
|
885
|
+
- A named CSS color.
|
886
|
+
The default is 'rgba(0,0,0,0)' (transparent).
|
887
|
+
headerColor : list or str , optional
|
888
|
+
The desired header color. This can be any color list or plotly color string and may be specified as:
|
889
|
+
- An rgb list (e.g. [255,0,0])
|
890
|
+
- A cmyk list (e.g. [0.5, 0, 0.25, 0.2])
|
891
|
+
- A hex string (e.g. '#ff0000')
|
892
|
+
- An rgb/rgba string (e.g. 'rgb(255,0,0)')
|
893
|
+
- An hsl/hsla string (e.g. 'hsl(0,100%,50%)')
|
894
|
+
- An hsv/hsva string (e.g. 'hsv(0,100%,100%)')
|
895
|
+
- A named CSS color.
|
896
|
+
The default is 'rgba(0,0,0,0)' (transparent).
|
897
|
+
reverse : bool , optional
|
898
|
+
If set to True, the vertices are sorted in reverse order (only if vertexKey is set). Otherwise, they are not. Default is False.
|
899
|
+
edgeKeyFwd : str , optional
|
900
|
+
If set, the value at this key in the connecting edge from start vertex to end vertex (forward) will be used instead of the value 1. Default is None. useEdgeIndex and useEdgeLength override this setting.
|
901
|
+
edgeKeyBwd : str , optional
|
902
|
+
If set, the value at this key in the connecting edge from end vertex to start vertex (backward) will be used instead of the value 1. Default is None. useEdgeIndex and useEdgeLength override this setting.
|
903
|
+
bidirKey : bool , optional
|
904
|
+
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. Default is None
|
905
|
+
bidirectional : bool , optional
|
906
|
+
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. Default is True.
|
907
|
+
useEdgeIndex : bool , optional
|
908
|
+
If set to True, the adjacency matrix values will the index of the edge in Graph.Edges(graph). Default is False. Both useEdgeIndex, useEdgeLength should not be True at the same time. If they are, useEdgeLength will be used.
|
909
|
+
useEdgeLength : bool , optional
|
910
|
+
If set to True, the adjacency matrix values will the length of the edge in Graph.Edges(graph). Default is False. Both useEdgeIndex, useEdgeLength should not be True at the same time. If they are, useEdgeLength will be used.
|
911
|
+
mantissa : int , optional
|
912
|
+
The number of decimal places to round the result to. Default is 6.
|
913
|
+
tolerance : float , optional
|
914
|
+
The desired tolerance. Default is 0.0001.
|
915
|
+
silent : bool, optional
|
916
|
+
If True, suppresses warning messages. Default is False.
|
917
|
+
|
918
|
+
Returns
|
919
|
+
-------
|
920
|
+
plotly.graph_objs._figure.Figure
|
921
|
+
A Plotly table figure containing the adjacency matrix table.
|
922
|
+
"""
|
923
|
+
|
924
|
+
from topologicpy.Topology import Topology
|
925
|
+
from topologicpy.Graph import Graph
|
926
|
+
from topologicpy.Dictionary import Dictionary
|
927
|
+
import plotly.graph_objects as go
|
928
|
+
|
929
|
+
if not Topology.IsInstance(graph, "Graph"):
|
930
|
+
if not silent:
|
931
|
+
print("Plotly.AdjacencyMatrixTable - Error: The input is not a valid Graph. Returning None.")
|
932
|
+
return None
|
933
|
+
|
934
|
+
# Build adjacency matrix
|
935
|
+
adj = Graph.AdjacencyMatrix(graph,
|
936
|
+
vertexKey=vertexKey,
|
937
|
+
reverse=reverse,
|
938
|
+
edgeKeyFwd=edgeKeyFwd,
|
939
|
+
edgeKeyBwd=edgeKeyBwd,
|
940
|
+
bidirKey=bidirKey,
|
941
|
+
bidirectional=bidirectional,
|
942
|
+
useEdgeIndex=useEdgeIndex,
|
943
|
+
useEdgeLength=useEdgeLength,
|
944
|
+
mantissa=mantissa,
|
945
|
+
tolerance=tolerance)
|
946
|
+
|
947
|
+
if adj is None or not isinstance(adj, list) or len(adj) == 0:
|
948
|
+
if not silent:
|
949
|
+
print("Plotly.AdjacencyMatrixTable - Warning: Empty adjacency matrix. Returning None.")
|
950
|
+
return None
|
951
|
+
|
952
|
+
n = len(adj)
|
953
|
+
# Validate squareness
|
954
|
+
if any((not isinstance(row, list) or len(row) != n) for row in adj):
|
955
|
+
if not silent:
|
956
|
+
print("Plotly.AdjacencyMatrixTable - Error: Adjacency matrix must be square. Returning None.")
|
957
|
+
return None
|
958
|
+
|
959
|
+
# Derive labels
|
960
|
+
verts = Graph.Vertices(graph)
|
961
|
+
labels = [Dictionary.ValueAtKey(Topology.Dictionary(v), vertexKey, str(i)) for i, v in enumerate(verts)]
|
962
|
+
if len(labels) > 0 and not vertexKey == None:
|
963
|
+
labels.sort()
|
964
|
+
if reverse == True:
|
965
|
+
labels.reverse()
|
966
|
+
# Build display matrix (strings) while keeping a parallel style mask for diagonal
|
967
|
+
display_matrix = []
|
968
|
+
diag_mask = []
|
969
|
+
for r in range(n):
|
970
|
+
row_vals = []
|
971
|
+
row_diag = []
|
972
|
+
for c in range(n):
|
973
|
+
v = adj[r][c]
|
974
|
+
if v == 0:
|
975
|
+
row_vals.append("0" if showZero else (zeroChar if zeroChar else ""))
|
976
|
+
else:
|
977
|
+
# Keep integers unpadded for clarity; cast others nicely
|
978
|
+
row_vals.append(str(int(v)) if isinstance(v, (int, float)) and float(v).is_integer() else str(v))
|
979
|
+
row_diag.append(r == c)
|
980
|
+
display_matrix.append(row_vals)
|
981
|
+
diag_mask.append(row_diag)
|
982
|
+
|
983
|
+
# Construct header and cells for Plotly Table
|
984
|
+
# Header: blank corner + column labels
|
985
|
+
header_values = [""] + labels
|
986
|
+
|
987
|
+
# Body: first column is row labels, then matrix cells as strings
|
988
|
+
# Plotly Table expects columns as lists; we need to transpose
|
989
|
+
columns = []
|
990
|
+
# Column 0: row labels
|
991
|
+
columns.append(labels)
|
992
|
+
# Subsequent columns: for each c, collect display_matrix[r][c]
|
993
|
+
for c in range(n):
|
994
|
+
columns.append([display_matrix[r][c] for r in range(n)])
|
995
|
+
|
996
|
+
# Flatten cell fill_colors to highlight diagonal subtly.
|
997
|
+
# Plotly Table allows per-cell fillcolor via a 2D list matching the table shape for 'cells'.
|
998
|
+
# Our cells shape is n rows x (n+1) cols (including row label column).
|
999
|
+
|
1000
|
+
fill_colors = []
|
1001
|
+
# Column 0: row labels (no highlight)
|
1002
|
+
fill_colors.append([headerColor] * n)
|
1003
|
+
|
1004
|
+
# Columns 1..n: highlight diagonal where row index r == (column_index-1)
|
1005
|
+
for c in range(1, n + 1):
|
1006
|
+
col_colors = []
|
1007
|
+
for r in range(n):
|
1008
|
+
if diagonalHighlight and r == (c - 1):
|
1009
|
+
col_colors.append(diagonalColor)
|
1010
|
+
elif columns[c][r] == "0" or columns[c][r] == zeroChar:
|
1011
|
+
col_colors.append(zeroColor)
|
1012
|
+
else:
|
1013
|
+
col_colors.append(valueColor)
|
1014
|
+
fill_colors.append(col_colors)
|
1015
|
+
|
1016
|
+
# Minimal line style
|
1017
|
+
line_color = "rgba(0,0,0,0.12)"
|
1018
|
+
# --- Sizing to prevent cropped text ---
|
1019
|
+
# Heuristic widths (pixels)
|
1020
|
+
max_label_len = max(len(str(x)) for x in labels) if labels else 1
|
1021
|
+
row_label_px = max(120, min(320, 8 * max_label_len)) # scale with label length
|
1022
|
+
cell_px = 36 if n <= 30 else (30 if n <= 50 else 24) # narrower cells for very wide matrices
|
1023
|
+
|
1024
|
+
# Adaptive cell font size for many columns
|
1025
|
+
fontSize = max(fontSize, 3)
|
1026
|
+
cell_font_size = fontSize if n <= 35 else (fontSize-1 if n <= 60 else fontSize-2)
|
1027
|
+
|
1028
|
+
# Figure width: row label column + all matrix columns
|
1029
|
+
fig_width = row_label_px + n * cell_px
|
1030
|
+
fig_width = max(600, min(2400, fig_width)) # clamp to reasonable bounds
|
1031
|
+
|
1032
|
+
# Increase row height a bit for readability
|
1033
|
+
cellSize = max(cellSize, 26)
|
1034
|
+
|
1035
|
+
# Column widths in px (Plotly Table accepts pixel widths)
|
1036
|
+
columnwidth = [row_label_px] + [cell_px] * n
|
1037
|
+
fig = go.Figure(
|
1038
|
+
data=[
|
1039
|
+
go.Table(
|
1040
|
+
header=dict(
|
1041
|
+
values=header_values,
|
1042
|
+
align="center",
|
1043
|
+
font=dict(family=fontFamily, size=cell_font_size, color=fontColor),
|
1044
|
+
fill_color=headerColor,
|
1045
|
+
line_color=line_color,
|
1046
|
+
height=cellSize + 4 # a touch taller for the header
|
1047
|
+
),
|
1048
|
+
cells=dict(
|
1049
|
+
values=columns,
|
1050
|
+
align=["right"] + ["center"] * n,
|
1051
|
+
font=dict(family=fontFamily, size=cell_font_size, color=fontColor),
|
1052
|
+
fill_color=fill_colors,
|
1053
|
+
line_color=line_color,
|
1054
|
+
height=cellSize
|
1055
|
+
),
|
1056
|
+
columnorder=list(range(n + 1)),
|
1057
|
+
columnwidth=columnwidth
|
1058
|
+
)
|
1059
|
+
]
|
1060
|
+
)
|
1061
|
+
|
1062
|
+
# Layout: generous margins, white background, optional title
|
1063
|
+
fig.update_layout(
|
1064
|
+
title=dict(text=title, x=0.5, xanchor="center") if title else None,
|
1065
|
+
paper_bgcolor="white",
|
1066
|
+
plot_bgcolor=backgroundColor,
|
1067
|
+
margin=dict(l=20, r=20, t=40 if title else 10, b=20)
|
1068
|
+
)
|
1069
|
+
|
1070
|
+
return fig
|
1071
|
+
|
788
1072
|
@staticmethod
|
789
1073
|
def AdjacencyList(graph, vertexKey=None, reverse=True, tolerance=0.0001):
|
790
1074
|
"""
|
topologicpy/Helper.py
CHANGED
@@ -90,6 +90,53 @@ class Helper:
|
|
90
90
|
|
91
91
|
return sorted(bin_averages)
|
92
92
|
|
93
|
+
def CheckVersion(library: str = None, version: str = None, silent: bool = False):
|
94
|
+
"""
|
95
|
+
Compare an input version with the latest version of a Python library on PyPI.
|
96
|
+
|
97
|
+
Parameters
|
98
|
+
----------
|
99
|
+
library : str
|
100
|
+
The input software library name. Default is None.
|
101
|
+
version : str
|
102
|
+
The input software version number to compare. Default is None.
|
103
|
+
silent : bool , optional
|
104
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
105
|
+
|
106
|
+
Returns:
|
107
|
+
str: A message indicating whether the input version is less than,
|
108
|
+
equal to, or greater than the latest version on PyPI.
|
109
|
+
"""
|
110
|
+
import requests
|
111
|
+
from packaging import version as ver
|
112
|
+
|
113
|
+
try:
|
114
|
+
# Fetch library data from PyPI
|
115
|
+
url = f"https://pypi.org/pypi/{library}/json"
|
116
|
+
response = requests.get(url)
|
117
|
+
response.raise_for_status()
|
118
|
+
|
119
|
+
# Extract the latest version from the JSON response
|
120
|
+
data = response.json()
|
121
|
+
latest_version = data['info']['version']
|
122
|
+
|
123
|
+
# Compare versions using the packaging library
|
124
|
+
if ver.parse(version) < ver.parse(latest_version):
|
125
|
+
return (f"The version that you are using ({version}) is OLDER than the latest version ({latest_version}) from PyPI. Please consider upgrading to the latest version.")
|
126
|
+
elif ver.parse(version) == ver.parse(latest_version):
|
127
|
+
return (f"The version that you are using ({version}) is EQUAL TO the latest version available on PyPI.")
|
128
|
+
else:
|
129
|
+
return (f"The version that you are using ({version}) is NEWER than the latest version ({latest_version}) available from PyPI.")
|
130
|
+
|
131
|
+
except requests.exceptions.RequestException as e:
|
132
|
+
if not silent:
|
133
|
+
print("Helper.CheckVersion - Error: Could not fetch data from PyPI. Returning None")
|
134
|
+
return None
|
135
|
+
except KeyError:
|
136
|
+
if not silent:
|
137
|
+
print("Helper.CheckVersion - Error: Could not fetch data from PyPI. Returning None")
|
138
|
+
return None
|
139
|
+
|
93
140
|
@staticmethod
|
94
141
|
def ClosestMatch(item, listA):
|
95
142
|
"""
|
@@ -788,58 +835,25 @@ class Helper:
|
|
788
835
|
return returnList
|
789
836
|
|
790
837
|
@staticmethod
|
791
|
-
def Version():
|
838
|
+
def Version(check: bool = True, silent: bool = False):
|
792
839
|
"""
|
793
840
|
Returns the current version of the software.
|
794
841
|
|
795
842
|
Parameters
|
796
843
|
----------
|
797
|
-
|
844
|
+
check : bool , optional
|
845
|
+
if set to True, the version number is checked with the latest version on PyPi. Default is True.
|
846
|
+
silent : bool , optional
|
847
|
+
If set to True, error and warning messages are suppressed. Default is False.
|
848
|
+
|
798
849
|
Returns
|
799
850
|
-------
|
800
851
|
str
|
801
|
-
The current version of the software.
|
852
|
+
The current version of the software. Optionally, includes a check with PyPi.
|
802
853
|
|
803
854
|
"""
|
804
855
|
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
def compare_version_with_pypi(library_name, input_version):
|
809
|
-
"""
|
810
|
-
Compare an input version with the latest version of a Python library on PyPI.
|
811
|
-
|
812
|
-
Args:
|
813
|
-
library_name (str): The name of the Python library on PyPI.
|
814
|
-
input_version (str): The version number to compare (e.g., "0.7.58").
|
815
|
-
|
816
|
-
Returns:
|
817
|
-
str: A message indicating whether the input version is less than,
|
818
|
-
equal to, or greater than the latest version on PyPI.
|
819
|
-
"""
|
820
|
-
try:
|
821
|
-
# Fetch library data from PyPI
|
822
|
-
url = f"https://pypi.org/pypi/{library_name}/json"
|
823
|
-
response = requests.get(url)
|
824
|
-
response.raise_for_status()
|
825
|
-
|
826
|
-
# Extract the latest version from the JSON response
|
827
|
-
data = response.json()
|
828
|
-
latest_version = data['info']['version']
|
829
|
-
|
830
|
-
# Compare versions using the packaging library
|
831
|
-
if version.parse(input_version) < version.parse(latest_version):
|
832
|
-
return (f"The version that you are using ({input_version}) is OLDER than the latest version {latest_version} from PyPI. Please consider upgrading to the latest version.")
|
833
|
-
elif version.parse(input_version) == version.parse(latest_version):
|
834
|
-
return (f"The version that you are using ({input_version}) is the latest version available on PyPI.")
|
835
|
-
else:
|
836
|
-
return (f"The version that you are using ({input_version}) is NEWER than the latest version ({latest_version}) available from PyPI.")
|
837
|
-
|
838
|
-
except requests.exceptions.RequestException as e:
|
839
|
-
return f"Error fetching data from PyPI: {e}"
|
840
|
-
except KeyError:
|
841
|
-
return "Error: Unable to find the latest version in the PyPI response."
|
842
|
-
|
843
|
-
current_version = topologicpy.__version__
|
844
|
-
result = compare_version_with_pypi("topologicpy", current_version)
|
856
|
+
result = topologicpy.__version__
|
857
|
+
if check == True:
|
858
|
+
result = Helper.CheckVersion("topologicpy", result, silent=silent)
|
845
859
|
return result
|
topologicpy/Plotly.py
CHANGED
@@ -1447,8 +1447,10 @@ class Plotly:
|
|
1447
1447
|
----------
|
1448
1448
|
matrix : list or numpy.array
|
1449
1449
|
The matrix to display.
|
1450
|
-
|
1451
|
-
The list of categories to use on the X
|
1450
|
+
xCategories : list
|
1451
|
+
The list of categories to use on the X axis.
|
1452
|
+
yCategories : list
|
1453
|
+
The list of categories to use on the Y axis.
|
1452
1454
|
minValue : float , optional
|
1453
1455
|
The desired minimum value to use for the color scale. If set to None, the minmum value found in the input matrix will be used. Default is None.
|
1454
1456
|
maxValue : float , optional
|
topologicpy/Topology.py
CHANGED
@@ -8699,6 +8699,23 @@ class Topology():
|
|
8699
8699
|
if showFigure:
|
8700
8700
|
Plotly.Show(figure=figure, renderer=renderer, camera=camera, center=center, up=up, projection=projection)
|
8701
8701
|
return None
|
8702
|
+
if "ortho" in projection.lower():
|
8703
|
+
camera_settings = dict(eye=dict(x=camera[0], y=camera[1], z=camera[2]),
|
8704
|
+
center=dict(x=center[0], y=center[1], z=center[2]),
|
8705
|
+
up=dict(x=up[0], y=up[1], z=up[2]),
|
8706
|
+
projection=dict(type="orthographic"))
|
8707
|
+
else:
|
8708
|
+
camera_settings = dict(eye=dict(x=camera[0], y=camera[1], z=camera[2]),
|
8709
|
+
center=dict(x=center[0], y=center[1], z=center[2]),
|
8710
|
+
up=dict(x=up[0], y=up[1], z=up[2]),
|
8711
|
+
projection=dict(type="perspective"))
|
8712
|
+
|
8713
|
+
figure.update_layout(
|
8714
|
+
scene_camera = camera_settings,
|
8715
|
+
scene=dict(aspectmode="data"),
|
8716
|
+
autosize=True,
|
8717
|
+
margin=dict(l=40, r=40, t=40, b=40)
|
8718
|
+
)
|
8702
8719
|
return figure
|
8703
8720
|
|
8704
8721
|
@staticmethod
|
topologicpy/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = '0.8.
|
1
|
+
__version__ = '0.8.54'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: topologicpy
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.54
|
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=ndrfovjwEEQTJ0B5DuthuCBDdVg9-1i_MX8Dtj-wD4E,177330
|
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
|
@@ -10,29 +10,29 @@ topologicpy/Context.py,sha256=G3CwMvN8Jw2rnQRwB-n4MaQq_wLS0vPimbXKwsdMJ80,3055
|
|
10
10
|
topologicpy/DGL.py,sha256=O7r22ss0tgak4kWaACkyExhR_rZ46O_bqIBpxAcwJkw,138918
|
11
11
|
topologicpy/Dictionary.py,sha256=Z4YQ88tONWd-0X0dENQ8IZqIOa9mbBqhJkTBsHmft2g,44619
|
12
12
|
topologicpy/Edge.py,sha256=DifItuyabFDUFC7CVMlt2DeMFMNaGOqCg43iU9CPP0A,74029
|
13
|
-
topologicpy/EnergyModel.py,sha256=
|
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=Oa0oOrPoOSUGL5fvJYHBH_r6kRZ944wk-P828GyAjk4,705757
|
16
16
|
topologicpy/Grid.py,sha256=3OsBMyHh4w8gpFOTMKHMNTpo62V0CwRNu5cwm87yDUA,18421
|
17
|
-
topologicpy/Helper.py,sha256=
|
17
|
+
topologicpy/Helper.py,sha256=Nr6pyzl0sZm4Cu11wOqoYKu6yYal5N6A9jErXnaZBJc,31765
|
18
18
|
topologicpy/Honeybee.py,sha256=C7Am0kCK3a5rt7Jpu2EIgqeR114ZJWtsx4_DBcr5hQA,21716
|
19
19
|
topologicpy/Matrix.py,sha256=bOofT34G3YHu9aMIWx60YHAJga4R0GbDjsZBUD4Hu_k,22706
|
20
20
|
topologicpy/Neo4j.py,sha256=J8jU_mr5-mWC0Lg_D2dMjMlx1rY_eh8ks_aubUuTdWw,22319
|
21
|
-
topologicpy/Plotly.py,sha256=
|
21
|
+
topologicpy/Plotly.py,sha256=kF7JwBMWJQAuGezaJYI6Cq7ErNwEtcKzaExOfdGPIMc,123003
|
22
22
|
topologicpy/Polyskel.py,sha256=oVfM4lqSMPTjnkHfsRU9VI8Blt6Vf0LVPkD9ebz7Wmw,27082
|
23
23
|
topologicpy/PyG.py,sha256=wOsoBFxMgwZYWjj86OMkz_PJuQ02locV_djhSDD6dVc,109644
|
24
24
|
topologicpy/ShapeGrammar.py,sha256=KYsKDLXWdflAcYMAIz84AUF-GMkbTmaBDd2-ovbilqU,23336
|
25
25
|
topologicpy/Shell.py,sha256=ioO4raCJfXtYldQg-adpcLVeJPEA6od6cAA5ro7t6r4,96792
|
26
26
|
topologicpy/Speckle.py,sha256=-eiTqJugd7pHiHpD3pDUcDO6CGhVyPV14HFRzaqEoaw,18187
|
27
27
|
topologicpy/Sun.py,sha256=8S6dhCKfOhUGVny-jEk87Q08anLYMB1JEBKRGCklvbQ,36670
|
28
|
-
topologicpy/Topology.py,sha256=
|
28
|
+
topologicpy/Topology.py,sha256=R5Ac3V_ADDRDZjhpcNvhM3AvDOLU6ORvB3yILyEkxnI,472559
|
29
29
|
topologicpy/Vector.py,sha256=pEC8YY3TeHGfGdeNgvdHjgMDwxGabp5aWjwYC1HSvMk,42236
|
30
30
|
topologicpy/Vertex.py,sha256=0f6HouARKaCuxhdxsUEYi8T9giJycnWhQ8Cn70YILBA,84885
|
31
31
|
topologicpy/Wire.py,sha256=gjgQUGHdBdXUIijgZc_VIW0E39w-smaVhhdl0jF63fQ,230466
|
32
32
|
topologicpy/__init__.py,sha256=RMftibjgAnHB1vdL-muo71RwMS4972JCxHuRHOlU428,928
|
33
|
-
topologicpy/version.py,sha256=
|
34
|
-
topologicpy-0.8.
|
35
|
-
topologicpy-0.8.
|
36
|
-
topologicpy-0.8.
|
37
|
-
topologicpy-0.8.
|
38
|
-
topologicpy-0.8.
|
33
|
+
topologicpy/version.py,sha256=4rZKb5aqUqZkGV-bsREBGvAbGTFOte68oezCn9q__NM,23
|
34
|
+
topologicpy-0.8.54.dist-info/licenses/LICENSE,sha256=FK0vJ73LuE8PYJAn7LutsReWR47-Ooovw2dnRe5yV6Q,681
|
35
|
+
topologicpy-0.8.54.dist-info/METADATA,sha256=mfbs0io_WTGxQzjuphNKxMpb12yRIYEt43sfj9gSVc4,10535
|
36
|
+
topologicpy-0.8.54.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
37
|
+
topologicpy-0.8.54.dist-info/top_level.txt,sha256=J30bDzW92Ob7hw3zA8V34Jlp-vvsfIkGzkr8sqvb4Uw,12
|
38
|
+
topologicpy-0.8.54.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|