Skip to content

Commit 597666d

Browse files
authored
Merge pull request #32 from graphgeeks-lab/gf-31
31: Graph Export Feature to GraphML
2 parents 57f0f92 + c451b34 commit 597666d

File tree

2 files changed

+49
-6
lines changed

2 files changed

+49
-6
lines changed

graphfaker/cli.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,19 @@ def gen(
5050
None,
5151
help="Year, Month and day range (YYYY-MM-DD,YYYY-MM-DD) for flight data. e.g. '2024-01-01,2024-01-15'.",
5252
),
53+
54+
# common
55+
export: str = typer.Option("graph.graphml", help="File path to export GraphML"),
5356
):
5457
"""Generate a graph using GraphFaker."""
5558
gf = GraphFaker()
5659

5760
if fetcher == FetcherType.FAKER:
5861

5962
g = gf.generate_graph(total_nodes=total_nodes, total_edges=total_edges)
60-
print(g)
61-
return g
63+
logger.info(
64+
f"Generated random graph with {g.number_of_nodes()} nodes and {g.number_of_edges()} edges."
65+
)
6266

6367
elif fetcher == FetcherType.OSM:
6468
# parse bbox string if provided
@@ -75,8 +79,9 @@ def gen(
7579
retain_all=retain_all,
7680
dist=dist,
7781
)
78-
print(g)
79-
return g
82+
logger.info(
83+
f"Fetched OSM graph with {g.number_of_nodes()} nodes and {g.number_of_edges()} edges."
84+
)
8085
else:
8186
# Flight fetcher
8287
parsed_date_range = parse_date_range(date_range) if date_range else None
@@ -101,8 +106,13 @@ def gen(
101106
)
102107

103108
g = FlightGraphFetcher.build_graph(airlines_df, airports_df, flights_df)
104-
print(g)
105-
return g
109+
110+
logger.info(
111+
f"Generated flight graph with {g.number_of_nodes()} nodes and {g.number_of_edges()} edges."
112+
)
113+
114+
gf.export_graph(g, export)
115+
logger.info(f"exported graph to {export}, with {g.number_of_nodes()} nodes and {g.number_of_edges()} edges.")
106116

107117

108118
if __name__ == "__main__":

graphfaker/core.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
A multi-domain network connecting entities across social, geographical, and commercial dimensions.
33
"""
44

5+
import os
56
from typing import Optional
67
import networkx as nx
78
import random
@@ -318,3 +319,35 @@ def generate_graph(
318319
)
319320
else:
320321
raise ValueError(f"Unknown source '{source}'. Use 'random' or 'osm'.")
322+
323+
def export_graph(self, G: nx.Graph = None, path: str = "graph.graphml"):
324+
"""
325+
Export the graph to a GraphML format.
326+
327+
args:
328+
G: Optional Networkx graph. If None, uses self.G.
329+
path: Destination file path for .graphml output.
330+
331+
Notes:
332+
GraphML is useful for visualization in tools like G.V(), Gephi or Cytoscape.
333+
It supports node and edge attributes but may not handle complex types like tuples.
334+
"""
335+
import os
336+
337+
if G is None:
338+
G = self.G
339+
if G is None:
340+
raise ValueError("No graph available to export.")
341+
342+
# Sanitize attributes that are not GraphML-friendly
343+
for _, data in G.nodes(data=True):
344+
if 'coordinates' in data and isinstance(data['coordinates'], tuple):
345+
lat, lon = data['coordinates']
346+
data['coordinates'] = f"{lat},{lon}"
347+
348+
# Ensure directory exists
349+
abs_path = os.path.abspath(path)
350+
os.makedirs(os.path.dirname(abs_path) or ".", exist_ok=True)
351+
352+
nx.write_graphml(G, path)
353+
print(f"✅ Graph exported to: {path}")

0 commit comments

Comments
 (0)