topologicpy 0.8.54__py3-none-any.whl → 0.8.57__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/Graph.py CHANGED
@@ -448,6 +448,67 @@ class Graph:
448
448
  new_graph = Graph.ByVerticesEdges(graph_vertices, graph_edges)
449
449
  return new_graph
450
450
 
451
+ @staticmethod
452
+ def AddEdgeByIndex(graph, index: list = None, dictionary = None, silent: bool = False):
453
+ """
454
+ Creates an edge in the input Graph by connecting the two vertices specified by their indices (e.g., [5, 6] connects the 4th and 6th vertices).
455
+
456
+ Parameters
457
+ ----------
458
+ graph : topologic_core.Graph
459
+ The input graph.
460
+ index : list or tuple
461
+ The input list of vertex indices (e.g. [4, 6]).
462
+ dictionary : topologic_core.Dictionary , optional
463
+ The input edge dictionary.
464
+ silent : bool , optional
465
+ If set to True, error and warning messages are suppressed. Default is False.
466
+
467
+ Returns
468
+ -------
469
+ topologic_core.Graph
470
+ The input graph with the input edge added to it.
471
+
472
+ """
473
+ from topologicpy.Edge import Edge
474
+ from topologicpy.Topology import Topology
475
+
476
+ if not Topology.IsInstance(graph, "Graph"):
477
+ if not silent:
478
+ print("Graph.AddEdgeIndex - Error: The input graph parameter is not a valid graph. Returning None.")
479
+ return None
480
+ if dictionary:
481
+ if not Topology.IsInstance(dictionary, "Dictionary"):
482
+ if not silent:
483
+ print("Graph.AddEdgeIndex - Error: The input dictionary parameter is not a valid dictionary. Returning None.")
484
+ return None
485
+ if not isinstance(index, list):
486
+ if not silent:
487
+ print("Graph.AddEdgeIndex - Error: The input index parameter is not a valid list. Returning None.")
488
+ return None
489
+ index = [x for x in index if isinstance(x, int)]
490
+ if not len(index) == 2:
491
+ if not silent:
492
+ print("Graph.AddEdgeIndex - Error: The input index parameter should only contain two integer numbers. Returning None.")
493
+ return None
494
+ vertices = Graph.Vertices(graph)
495
+ n = len(vertices)
496
+ if index[0] < 0 or index[0] > n-1:
497
+ if not silent:
498
+ print("Graph.AddEdgeIndex - Error: The first integer in the input index parameter does not exist in the input graph. Returning None.")
499
+ return None
500
+ if index[1] < 0 or index[1] > n-1:
501
+ if not silent:
502
+ print("Graph.AddEdgeIndex - Error: The second integer in the input index parameter does not exist in the input graph. Returning None.")
503
+ return None
504
+ sv = vertices[index[0]]
505
+ ev = vertices[index[1]]
506
+ edge = Edge.ByVertices(sv, ev)
507
+ if dictionary:
508
+ edge = Topology.SetDictionary(edge, dictionary)
509
+ graph = Graph.AddEdge(graph,edge)
510
+ return graph
511
+
451
512
  @staticmethod
452
513
  def AddVertex(graph, vertex, tolerance: float = 0.0001, silent: bool = False):
453
514
  """
@@ -2835,6 +2896,158 @@ class Graph:
2835
2896
  graphs.append(Graph.ByVerticesEdges(vertices, edges))
2836
2897
  return {'graphs':graphs, 'labels':labels}
2837
2898
 
2899
+ @staticmethod
2900
+ def ByDictionaries(graphDictionary, vertexDictionaries, edgeDictionaries, vertexKey: str = None, edgeKey: str = None, silent: bool = False, tolerance: float = 0.0001):
2901
+ """
2902
+ Creates a graph from input python dictionaries.
2903
+
2904
+ Rules:
2905
+ All vertex dictionaries must contain at least the vertexKey.
2906
+ All edge dictionaries must contain at least the edgeKey.
2907
+ The edgeKey must be a tuple or list of two str values.
2908
+ x,y,z coordinates are optional. However, if a vertex dictionary contains x,y,z coordinates then all vertex dictionaries must contain x,y,z coordinates.
2909
+ If vertex dictionaries contain x,y,z coordinates they must not overlap and be separated by a distance greater than tolerance.
2910
+ Keys and values are case sensitive.
2911
+ x,y,z keys, if present must be lowercase.
2912
+
2913
+ Example:
2914
+ graphDictionary = {"name": "Small Apartment", "location": "123 Main Street"}
2915
+ vertexDictionaries = [
2916
+ {"name":"Entry", "type":"Circulation", "x":1, "y":4, "z":0, "area":5},
2917
+ {"name":"Living Room", "type":"Living Room", "x":3, "y":4 , "z":0, "area":24},
2918
+ {"name":"Dining Room", "type":"Dining Room", "x":5, "y":2, "z":0, "area":18},
2919
+ {"name":"Kitchen", "type":"Kitchen", "x":1, "y":2, "z":0, "area":15},
2920
+ {"name":"Bathroom", "type":"Bathroom", "x":3, "y":6, "z":0, "area":9},
2921
+ {"name":"Bedroom", "type":"Bedroom", "x":5, "y":4, "z":0, "area":16}
2922
+ ]
2923
+ edgeDictionaries = [
2924
+ {"connects": ("Entry","Living Room"), "relationship": "adjacent_to"},
2925
+ {"connects": ("Living Room","Kitchen"), "relationship": "adjacent_to"},
2926
+ {"connects": ("Dining Room","Kitchen"), "relationship": "adjacent_to"},
2927
+ {"connects": ("Living Room","Dining Room"), "relationship": "adjacent_to"},
2928
+ {"connects": ("Living Room","Bedroom"), "relationship": "adjacent_to"},
2929
+ {"connects": ("Living Room","Bathroom"), "relationship": "adjacent_to"}
2930
+ ]
2931
+ vertexKey = "name"
2932
+ edgeKey = "connects"
2933
+
2934
+ Parameters
2935
+ ----------
2936
+ graphDictionary : dict
2937
+ The python dictionary to associate with the resulting graph
2938
+ vertexDictionaries : list
2939
+ The input list of vertex dictionaries. These must contain the vertexKey. X,Y,Z coordinates are optional.
2940
+ edgeDictionaries : list
2941
+ The input list of edge dictionaries. These must have the edgeKey to specify the two vertices they connect (by using the vertexKey)
2942
+ vertexKey: str
2943
+ The vertex key used to identify which vertices and edge connects.
2944
+ edgeKey: str
2945
+ The edge key under which the pair of vertex keys are listed as a tuple or list.
2946
+ tolerance: float , optional
2947
+ The desired tolerance. The default is 0.0001
2948
+ silent : bool , optional
2949
+ If set to True, error and warning messages are suppressed. Default is False.
2950
+
2951
+ Returns
2952
+ -------
2953
+ topologic_core.Graph
2954
+ The resulting graph
2955
+
2956
+ """
2957
+ from topologicpy.Vertex import Vertex
2958
+ from topologicpy.Edge import Edge
2959
+ from topologicpy.Cluster import Cluster
2960
+ from topologicpy.Topology import Topology
2961
+ from topologicpy.Dictionary import Dictionary
2962
+
2963
+ def _set_dict(obj, kv: dict):
2964
+ keys = list(kv.keys())
2965
+ vals = list(kv.values())
2966
+ d = Dictionary.ByKeysValues(keys, vals)
2967
+ Topology.SetDictionary(obj, d)
2968
+ return obj
2969
+
2970
+ def _vertex(vertexDictionary, vertices, vertexKey, tolerance=0.0001, silent=False):
2971
+ x = vertexDictionary.get("x", 0)
2972
+ y = vertexDictionary.get("y", 0)
2973
+ z = vertexDictionary.get("z", 0)
2974
+ v = Vertex.ByCoordinates(x, y, z)
2975
+ v = _set_dict(v, vertexDictionary)
2976
+ if "x" in vertexDictionary.keys(): # Check for overlap only if coords are given.
2977
+ if len(vertices) > 0:
2978
+ nv = Vertex.NearestVertex(v, Cluster.ByTopologies(vertices))
2979
+ d = Topology.Dictionary(nv)
2980
+ nv_name = Dictionary.ValueAtKey(d, vertexKey, "Unknown")
2981
+ if Vertex.Distance(v, nv) < tolerance:
2982
+ if not silent:
2983
+ v_name = vertexDictionary[vertexKey]
2984
+ print(f"Graph.ByDictionaries - Warning: Vertices {v_name} and {nv_name} overlap.")
2985
+ return v
2986
+
2987
+
2988
+ if graphDictionary:
2989
+ if not isinstance(graphDictionary, dict):
2990
+ if not silent:
2991
+ print("Graph.ByDictionaries - Error: The input graphDictionary parameter is not a valid python dictionary. Returning None.")
2992
+ return None
2993
+
2994
+ if not isinstance(vertexDictionaries, list):
2995
+ if not silent:
2996
+ print("Graph.ByDictionaries - Error: The input vertexDictionaries parameter is not a valid list. Returning None.")
2997
+ return None
2998
+
2999
+ if not isinstance(edgeDictionaries, list):
3000
+ if not silent:
3001
+ print("Graph.ByDictionaries - Error: The input edgeDictionaries parameter is not a valid list. Returning None.")
3002
+ return None
3003
+
3004
+ name_to_vertex = {}
3005
+ vertices = []
3006
+ for vd in vertexDictionaries:
3007
+ v = _vertex(vd, vertices, vertexKey=vertexKey, tolerance=tolerance, silent=silent)
3008
+ if v:
3009
+ vertices.append(v)
3010
+
3011
+ # If coordinates are not present, make sure you separate the vertices to allow edges to be created.
3012
+ if "x" not in vertexDictionaries[0].keys():
3013
+ vertices = Vertex.Separate(vertices, minDistance=max(1, tolerance))
3014
+
3015
+ for i, v in enumerate(vertices):
3016
+ vd = vertexDictionaries[i]
3017
+ name_to_vertex[vd[vertexKey]] = v
3018
+
3019
+ # Create adjacency edges (undirected: one edge per pair)
3020
+ edges = []
3021
+ for d in edgeDictionaries:
3022
+ a, b = d[edgeKey]
3023
+ va = name_to_vertex.get(a, None)
3024
+ vb = name_to_vertex.get(b, None)
3025
+ if not va and not vb:
3026
+ if not silent:
3027
+ print(f"Graph.ByDictionaries - Warning: vertices '{a}' and '{b}' are missing. Could not create an edge between them.")
3028
+ continue
3029
+ if not va:
3030
+ if not silent:
3031
+ print(f"Graph.ByDictionaries - Warning: vertex '{a}' is missing. Could not create an edge between '{a}' and '{b}'.")
3032
+ continue
3033
+ if not vb:
3034
+ if not silent:
3035
+ print(f"Graph.ByDictionaries - Warning: vertex '{b}' is missing. Could not create an edge between '{a}' and '{b}'.")
3036
+ continue
3037
+ e = Edge.ByStartVertexEndVertex(va, vb, silent=True)
3038
+ if not e:
3039
+ if not silent:
3040
+ print(f"Graph.ByDictionaries - Warning: Could not create an edge between '{a}' and '{b}'. Check if the distance betwen '{a}' and '{b}' is kess than the input tolerance.")
3041
+ continue
3042
+ edges.append(e)
3043
+ # Build graph
3044
+ g = Graph.ByVerticesEdges(vertices, edges)
3045
+
3046
+ # Attach graph-level metadata
3047
+ if graphDictionary:
3048
+ _set_dict(g, graphDictionary)
3049
+ return g
3050
+
2838
3051
  @staticmethod
2839
3052
  def ByIFCFile(file,
2840
3053
  includeTypes: list = [],
@@ -9117,8 +9330,6 @@ class Graph:
9117
9330
 
9118
9331
  return pos
9119
9332
 
9120
-
9121
-
9122
9333
  def radial_layout_2d(edge_list, root_index=0):
9123
9334
  import numpy as np
9124
9335
  from collections import deque
@@ -9270,9 +9481,15 @@ class Graph:
9270
9481
 
9271
9482
  if not Topology.IsInstance(graph, "Graph"):
9272
9483
  if not silent:
9273
- print("Graph.Flatten - Error: The input graph is not a valid topologic graph. Returning None.")
9484
+ print("Graph.Reshape - Error: The input graph is not a valid topologic graph. Returning None.")
9274
9485
  return None
9275
9486
 
9487
+ vertices = Graph.Vertices(graph)
9488
+ if len(vertices) < 2:
9489
+ if not silent:
9490
+ print("Graph.Reshape - Warning: The graph has less than two vertices. It cannot be rehsaped. Returning the original input graph.")
9491
+ return graph
9492
+
9276
9493
  if 'circ' in shape.lower():
9277
9494
  return circle_layout_2d(graph, radius=size/2, sides=sides)
9278
9495
  elif 'lin' in shape.lower():