TahaRasouli commited on
Commit
bca6fdd
·
verified ·
1 Parent(s): c370335

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -93
app.py CHANGED
@@ -1,107 +1,157 @@
1
- import time
2
  import gradio as gr
3
- import matplotlib.pyplot as plt
4
  import networkx as nx
 
 
 
5
 
6
- # ---- Import generators (NO circular imports) ----
7
- from graphGen3 import NetworkGenerator as NetworkGenerator3
8
- from graphGen4 import NetworkGenerator as NetworkGenerator4
9
- from graphGen5 import NetworkGenerator as NetworkGenerator5
10
 
11
 
12
- # ---- Registry of available generators ----
13
- GENERATOR_MAP = {
14
- "graphGen3": NetworkGenerator3,
15
- "graphGen4": NetworkGenerator4,
16
- "graphGen5": NetworkGenerator5,
17
 
18
- }
19
-
20
-
21
- def generate_network(generator_name, size, variant, topology):
22
- """
23
- Gradio callback: generate a network using the selected generator.
24
- """
25
- GeneratorClass = GENERATOR_MAP[generator_name]
26
-
27
- generator = GeneratorClass(
28
- size=size,
29
- variant=variant,
30
- topology=topology
31
- )
32
-
33
- start = time.time()
34
- graph = generator.generate()
35
- elapsed = time.time() - start
36
-
37
- stats = (
38
- f"Generator: {generator_name}\n"
39
- f"Operation Time: {elapsed:.4f} seconds\n"
40
- f"Nodes: {len(graph.nodes())}\n"
41
- f"Edges: {len(graph.edges())}"
42
- )
43
-
44
- # ---- Plot ----
45
- fig, ax = plt.subplots(figsize=(8, 8))
46
- pos = {node: (node[1], -node[0]) for node in graph.nodes()}
47
- nx.draw(
48
- graph,
49
- pos,
50
- ax=ax,
51
- with_labels=True,
52
- node_size=300,
53
- font_size=8
54
- )
55
- ax.set_title(f"{generator_name} | {size}, {variant}, {topology}")
56
- ax.grid(True)
57
-
58
- return fig, stats
59
-
60
-
61
- # ---- Gradio UI ----
62
- with gr.Blocks(title="Network Generator") as demo:
63
- gr.Markdown("# Network Generator")
64
-
65
- with gr.Row():
66
- generator_choice = gr.Dropdown(
67
- choices=list(GENERATOR_MAP.keys()),
68
- value="graphGen3",
69
- label="Generator Logic"
70
- )
71
-
72
- with gr.Row():
73
- size = gr.Dropdown(
74
- choices=["S", "M", "L"],
75
- value="S",
76
- label="Size"
77
- )
78
- variant = gr.Dropdown(
79
- choices=["F", "R"],
80
- value="F",
81
- label="Variant"
82
  )
83
- topology = gr.Dropdown(
84
- choices=["highly_connected", "bottlenecks", "linear"],
85
- value="highly_connected",
86
- label="Topology"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  )
 
 
 
 
 
88
 
89
- generate_btn = gr.Button("Generate Network")
90
 
 
 
 
 
91
  with gr.Row():
92
- plot_out = gr.Plot(label="Generated Graph")
93
- stats_out = gr.Textbox(
94
- label="Statistics",
95
- lines=6,
96
- interactive=False
97
- )
98
-
99
- generate_btn.click(
100
- fn=generate_network,
101
- inputs=[generator_choice, size, variant, topology],
102
- outputs=[plot_out, stats_out]
103
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
 
106
  if __name__ == "__main__":
107
- demo.launch()
 
 
1
  import gradio as gr
 
2
  import networkx as nx
3
+ import matplotlib.pyplot as plt
4
+ import random
5
+ import time
6
 
 
 
 
 
7
 
8
 
9
+ def get_preset_dims(preset_mode, topology):
10
+ """Calculates dimensions based on preset and topology."""
11
+ if preset_mode == "Custom":
12
+ # Enable inputs, keep current values (passed via state in UI, but here we just return interaction update)
13
+ return gr.update(interactive=True), gr.update(interactive=True)
14
 
15
+ # Preset Logic
16
+ if topology == "linear":
17
+ if preset_mode == "Small": dims = (4, 4)
18
+ elif preset_mode == "Medium": dims = (6, 11)
19
+ else: dims = (10, 26)
20
+ else: # Highly Connected / Bottlenecks
21
+ if preset_mode == "Small": dims = (4, 4)
22
+ elif preset_mode == "Medium": dims = (8, 8)
23
+ else: dims = (16, 16)
24
+
25
+ return gr.update(value=dims[0], interactive=False), gr.update(value=dims[1], interactive=False)
26
+
27
+ def update_void_settings(variant, width, height):
28
+ """Calculates void fraction based on variant logic."""
29
+ if variant == "Custom":
30
+ return gr.update(interactive=True)
31
+
32
+ # Fixed Logic
33
+ area = width * height
34
+ val = 0.60 if area <= 20 else 0.35
35
+ return gr.update(value=val, interactive=False)
36
+
37
+ def generate_network_viz(topology, width, height, variant, void_frac):
38
+ try:
39
+ variant_code = "F" if variant == "Fixed" else "R"
40
+
41
+ generator = NetworkGenerator(
42
+ width=width,
43
+ height=height,
44
+ variant=variant_code,
45
+ topology=topology,
46
+ node_drop_fraction=void_frac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  )
48
+
49
+ start = time.time()
50
+ graph = generator.generate()
51
+ end = time.time()
52
+
53
+ # Plotting
54
+ fig, ax = plt.subplots(figsize=(8, 8))
55
+ pos = {node: (node[0], node[1]) for node in graph.nodes()}
56
+
57
+ nx.draw_networkx_edges(graph, pos, ax=ax, width=2, alpha=0.6, edge_color="#333")
58
+ nx.draw_networkx_nodes(graph, pos, ax=ax, node_size=350, node_color="#4F46E5", edgecolors="white", linewidths=1.5)
59
+ nx.draw_networkx_labels(graph, pos, ax=ax, font_size=7, font_color="white", font_weight="bold")
60
+
61
+ ax.set_xlim(-1, width + 1)
62
+ ax.set_ylim(-1, height + 1)
63
+ ax.invert_yaxis() # Camera looks top-down (0 at top)
64
+ ax.grid(True, linestyle=':', alpha=0.3)
65
+ ax.set_axis_on()
66
+ ax.tick_params(left=True, bottom=True, labelleft=False, labelbottom=False)
67
+ ax.set_title(f"{topology.upper()} | {width}x{height} | Voids: {int(void_frac*100)}%")
68
+
69
+ # Metrics
70
+ info_text = (
71
+ f"**Nodes:** {len(graph.nodes())} | "
72
+ f"**Edges:** {len(graph.edges())} | "
73
+ f"**Density:** {nx.density(graph):.2f} | "
74
+ f"**Time:** {end - start:.3f}s"
75
  )
76
+
77
+ return fig, info_text
78
+
79
+ except Exception as e:
80
+ return None, f"Error: {str(e)}"
81
 
 
82
 
83
+ with gr.Blocks(title="Spatial Network Generator") as demo:
84
+ gr.Markdown("# Spatial Network Generator")
85
+ gr.Markdown("Generate procedural room-like graphs with topological constraints.")
86
+
87
  with gr.Row():
88
+ # --- LEFT COLUMN: CONTROLS ---
89
+ with gr.Column(scale=1):
90
+ topology_dd = gr.Dropdown(
91
+ choices=["highly_connected", "bottlenecks", "linear"],
92
+ value="highly_connected",
93
+ label="Topology"
94
+ )
95
+
96
+ preset_radio = gr.Radio(
97
+ choices=["Small", "Medium", "Large", "Custom"],
98
+ value="Medium",
99
+ label="Preset Size"
100
+ )
101
+
102
+ with gr.Row():
103
+ width_num = gr.Number(value=8, label="Width (X)", precision=0, interactive=False)
104
+ height_num = gr.Number(value=8, label="Height (Y)", precision=0, interactive=False)
105
+
106
+ gr.Markdown("---")
107
+
108
+ variant_dd = gr.Dropdown(
109
+ choices=["Fixed", "Custom"],
110
+ value="Fixed",
111
+ label="Variant",
112
+ info="Fixed = Standard density. Custom = Random density."
113
+ )
114
+
115
+ void_slider = gr.Slider(
116
+ minimum=0.0, maximum=0.9, value=0.35, step=0.05,
117
+ label="Void Fraction",
118
+ interactive=False,
119
+ info="Percentage of grid to leave empty."
120
+ )
121
+
122
+ gen_btn = gr.Button("Generate Network", variant="primary")
123
+
124
+ # --- RIGHT COLUMN: VISUALIZATION ---
125
+ with gr.Column(scale=2):
126
+ metrics_out = gr.Markdown("Click Generate to see metrics...")
127
+ plot_out = gr.Plot(label="Network Visualization")
128
+
129
+ # ==========================================
130
+ # EVENT LISTENERS
131
+ # ==========================================
132
+
133
+ # 1. Update Dimensions when Preset or Topology changes
134
+ # Note: We pass inputs to calculate new dims, and output to width/height inputs
135
+ input_group_dims = [preset_radio, topology_dd]
136
+ output_group_dims = [width_num, height_num]
137
+
138
+ preset_radio.change(fn=get_preset_dims, inputs=input_group_dims, outputs=output_group_dims)
139
+ topology_dd.change(fn=get_preset_dims, inputs=input_group_dims, outputs=output_group_dims)
140
 
141
+ # 2. Update Void Settings when Variant or Dimensions change
142
+ # (If user switches to Fixed, we lock slider. If dimensions change while Fixed, we recalc 0.60 vs 0.35)
143
+ input_group_void = [variant_dd, width_num, height_num]
144
+
145
+ variant_dd.change(fn=update_void_settings, inputs=input_group_void, outputs=void_slider)
146
+ width_num.change(fn=update_void_settings, inputs=input_group_void, outputs=void_slider)
147
+ height_num.change(fn=update_void_settings, inputs=input_group_void, outputs=void_slider)
148
+
149
+ # 3. Main Generation
150
+ input_group_gen = [topology_dd, width_num, height_num, variant_dd, void_slider]
151
+ output_group_gen = [plot_out, metrics_out]
152
+
153
+ gen_btn.click(fn=generate_network_viz, inputs=input_group_gen, outputs=output_group_gen)
154
 
155
+ # Launch
156
  if __name__ == "__main__":
157
+ demo.launch()