Feranmii commited on
Commit
656773c
·
verified ·
1 Parent(s): e334d93

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +155 -226
app.py CHANGED
@@ -4,6 +4,7 @@ import joblib
4
  import pandas as pd
5
  import numpy as np
6
  import plotly.graph_objects as go
 
7
 
8
  os.environ["HOPSWORKS_API_KEY"] = "HLDlE8LYYNS4zTdX.GQvAhHVCPMDVOrXcbGK3IKrsUv2APbwSUzexJDgjhXHPRoC3aAjhOMKgkaM95UHt"
9
 
@@ -100,15 +101,14 @@ def predict_delay(carrier, arr_flights, arr_diverted, temperature, wind_speed, m
100
 
101
  import gradio as gr
102
 
103
- def create_3d_terminal_crowd(delay_minutes, n_passengers=200):
104
  # Normalize delay to determine crowd behavior
105
  # Assume delay range from -1 to 5 minutes
106
  normalized_delay = min(max((delay_minutes + 1) / 6, 0), 1) # 0 to 1 scale
107
 
108
  # Terminal layout dimensions
109
- terminal_length = 100 # x-axis
110
- terminal_width = 60 # y-axis
111
- terminal_height = 10 # z-axis
112
 
113
  # Calculate crowd parameters based on delay
114
  crowd_density = normalized_delay * 0.8 + 0.2 # 0.2 to 1.0
@@ -117,26 +117,26 @@ def create_3d_terminal_crowd(delay_minutes, n_passengers=200):
117
  # Generate passenger positions
118
  n_actual_passengers = int(n_passengers * crowd_density)
119
 
120
- # Create different passenger groups with 3D positions
121
  # 1. Seated passengers (at gates)
122
  # 2. Moving passengers (walking through terminal)
123
  # 3. Clustered passengers (at info desks, security, etc.)
124
 
125
- # Define gate areas (x, y, width, depth)
126
  gates = [
127
- [10, 5, 20, 15, "Gate A"],
128
- [40, 5, 20, 15, "Gate B"],
129
- [70, 5, 20, 15, "Gate C"],
130
- [10, 40, 20, 15, "Gate D"],
131
- [40, 40, 20, 15, "Gate E"],
132
- [70, 40, 20, 15, "Gate F"]
133
  ]
134
 
135
  # Define info desk/security areas (x, y, radius)
136
  service_points = [
137
- [50, 30, 6, "Information"],
138
- [25, 30, 4, "Security 1"],
139
- [75, 30, 4, "Security 2"]
140
  ]
141
 
142
  # Allocate passengers to different areas based on delay
@@ -151,7 +151,6 @@ def create_3d_terminal_crowd(delay_minutes, n_passengers=200):
151
  # Generate positions
152
  passenger_x = []
153
  passenger_y = []
154
- passenger_z = []
155
  passenger_colors = []
156
 
157
  # 1. Seated passengers (distributed across gates)
@@ -178,12 +177,8 @@ def create_3d_terminal_crowd(delay_minutes, n_passengers=200):
178
  x = max(min(x, gate[0] + gate[2]), gate[0])
179
  y = max(min(y, gate[1] + gate[3]), gate[1])
180
 
181
- # Z-coordinate (seated passengers are sitting)
182
- z = 1.5 # Average sitting height
183
-
184
  passenger_x.append(x)
185
  passenger_y.append(y)
186
- passenger_z.append(z)
187
  passenger_colors.append('blue') # Seated passengers are blue
188
 
189
  # 2. Service point passengers (clustered at info desks/security)
@@ -206,42 +201,34 @@ def create_3d_terminal_crowd(delay_minutes, n_passengers=200):
206
  y = point[1] + distance * np.sin(angle)
207
 
208
  # Keep within terminal bounds
209
- x = max(min(x, terminal_length), 0)
210
- y = max(min(y, terminal_width), 0)
211
-
212
- # Z-coordinate (standing passengers with some variation in height)
213
- z = 3 + np.random.uniform(-0.5, 0.5) # Standing height with variation
214
 
215
  passenger_x.append(x)
216
  passenger_y.append(y)
217
- passenger_z.append(z)
218
  passenger_colors.append('red') # Service point passengers are red (frustrated)
219
 
220
  # 3. Walking passengers (random paths in terminal)
221
- central_path_y = terminal_width / 2
222
  path_width = 20
223
 
224
  for i in range(n_walking):
225
  # With more delay, people tend to wander more randomly
226
  if normalized_delay < 0.4:
227
  # Mostly following the central path
228
- x = np.random.uniform(0, terminal_length)
229
  y = central_path_y + np.random.normal(0, path_width * 0.2)
230
  else:
231
  # More random movements
232
- x = np.random.uniform(0, terminal_length)
233
- y = np.random.uniform(0, terminal_width)
234
 
235
  # Keep within terminal bounds
236
- x = max(min(x, terminal_length), 0)
237
- y = max(min(y, terminal_width), 0)
238
-
239
- # Z-coordinate (walking passengers with some variation in height)
240
- z = 3 + np.random.uniform(-0.5, 0.5) # Standing height with variation
241
 
242
  passenger_x.append(x)
243
  passenger_y.append(y)
244
- passenger_z.append(z)
245
 
246
  # Color walking passengers by delay frustration level
247
  if normalized_delay < 0.3:
@@ -251,11 +238,11 @@ def create_3d_terminal_crowd(delay_minutes, n_passengers=200):
251
  else:
252
  passenger_colors.append('red') # High frustration
253
 
254
- return passenger_x, passenger_y, passenger_z, passenger_colors, normalized_delay, gates, service_points
255
 
256
  def predict_delay_interface(carrier, arr_flights, arr_diverted, temperature, wind_speed, month,
257
- arr_delay_lag1, arr_flights_lag2, weather_delay, security_delay,
258
- carrier_delay, arr_delay_lag1_lag2, arr_delay_lag1_lag3):
259
  # Get prediction
260
  delay_minutes = predict_delay(
261
  carrier, arr_flights, arr_diverted, temperature, wind_speed, month,
@@ -263,213 +250,155 @@ def predict_delay_interface(carrier, arr_flights, arr_diverted, temperature, win
263
  carrier_delay, arr_delay_lag1_lag2, arr_delay_lag1_lag3
264
  )
265
 
266
- # Create 3D airport terminal crowd simulation
267
- passenger_x, passenger_y, passenger_z, passenger_colors, normalized_delay, gates, service_points = create_3d_terminal_crowd(delay_minutes)
 
 
 
268
 
269
- # Create 3D plot
270
- fig = go.Figure()
 
271
 
272
- # Add floor of the terminal - slightly transparent
273
- x_floor = [0, 100, 100, 0, 0]
274
- y_floor = [0, 0, 60, 60, 0]
275
- z_floor = [0, 0, 0, 0, 0]
 
 
 
 
 
276
 
277
- fig.add_trace(go.Mesh3d(
278
- x=x_floor, y=y_floor, z=z_floor,
279
- i=[0, 0],
280
- j=[1, 2],
281
- k=[2, 3],
282
- opacity=0.7,
283
- color='lightgray',
284
- name='Terminal Floor'
285
- ))
286
 
287
- # Add gate areas
288
  for gate in gates:
289
- # Bottom face of gate area
290
- x = [gate[0], gate[0]+gate[2], gate[0]+gate[2], gate[0], gate[0]]
291
- y = [gate[1], gate[1], gate[1]+gate[3], gate[1]+gate[3], gate[1]]
292
- z = [0, 0, 0, 0, 0]
293
-
294
- fig.add_trace(go.Scatter3d(
295
- x=x, y=y, z=z,
296
- mode='lines',
297
- line=dict(color='blue', width=3),
298
- name=gate[4]
299
- ))
300
-
301
  # Add gate label
302
- fig.add_trace(go.Scatter3d(
303
- x=[gate[0] + gate[2]/2],
304
- y=[gate[1] + gate[3]/2],
305
- z=[1],
306
- mode='text',
307
- text=[gate[4]],
308
- textfont=dict(size=12, color='darkblue'),
309
- name=''
310
- ))
311
 
312
- # Add service points
313
- for point in service_points:
314
- # Create a circle of points for service desk
315
- theta = np.linspace(0, 2*np.pi, 20)
316
- x = point[0] + point[2] * np.cos(theta)
317
- y = point[1] + point[2] * np.sin(theta)
318
- z = np.zeros_like(theta)
319
-
320
- fig.add_trace(go.Scatter3d(
321
- x=x, y=y, z=z,
322
- mode='lines',
323
- line=dict(color='darkgray', width=3),
324
- name=point[3]
325
- ))
326
-
327
- # Add service point label
328
- fig.add_trace(go.Scatter3d(
329
- x=[point[0]],
330
- y=[point[1]],
331
- z=[1],
332
- mode='text',
333
- text=[point[3]],
334
- textfont=dict(size=12, color='darkred'),
335
- name=''
336
- ))
337
 
338
- # Add 3D passengers
339
- # We'll use a marker shape that looks like a person from above
340
- fig.add_trace(go.Scatter3d(
341
- x=passenger_x,
342
- y=passenger_y,
343
- z=passenger_z,
344
- mode='markers',
345
- marker=dict(
346
- size=5,
347
- color=passenger_colors,
348
- symbol='circle',
349
- opacity=0.8
350
- ),
351
- name='Passengers'
352
- ))
 
353
 
354
- # Calculate frustration metrics
355
- total_passengers = len(passenger_x)
356
- frustrated_passengers = passenger_colors.count('red') + passenger_colors.count('orange')
357
- frustration_percent = round(frustrated_passengers / total_passengers * 100)
 
 
 
 
 
 
 
 
 
358
 
359
- # Determine color for delay indication
 
360
  if delay_minutes < 0:
361
  delay_color = "green"
362
- delay_status = "Early by"
363
  elif delay_minutes < 1:
364
  delay_color = "green"
365
- delay_status = "On time (+"
366
  elif delay_minutes < 3:
367
  delay_color = "orange"
368
- delay_status = "Delayed by"
369
  else:
370
  delay_color = "red"
371
- delay_status = "Significantly delayed by"
372
 
373
- # Add text annotation for delay information
374
- fig.add_trace(go.Scatter3d(
375
- x=[50],
376
- y=[10],
377
- z=[8],
378
- mode='text',
379
- text=[f"{delay_status} {abs(delay_minutes):.1f} minutes"],
380
- textfont=dict(size=16, color=delay_color),
381
- name=''
382
- ))
 
 
 
383
 
384
- # Add text annotation for frustration level
385
- fig.add_trace(go.Scatter3d(
386
- x=[50],
387
- y=[50],
388
- z=[8],
389
- mode='text',
390
- text=[f"Terminal Occupancy: {total_passengers} | Frustration Level: {frustration_percent}%"],
391
- textfont=dict(size=14, color='black'),
392
- name=''
393
- ))
394
 
395
- # Add 3D people flow based on delay level
396
- if normalized_delay > 0.5:
397
- # With higher delays, show increased movement patterns
398
- # Generate flow lines between gates and service points
399
- for gate in gates:
400
- for point in service_points:
401
- # Number of flow lines based on delay severity
402
- num_flows = int(normalized_delay * 10)
403
- for _ in range(num_flows):
404
- # Starting point - random position within gate
405
- start_x = gate[0] + np.random.uniform(0, gate[2])
406
- start_y = gate[1] + np.random.uniform(0, gate[3])
407
-
408
- # Ending point - near service point
409
- end_x = point[0] + np.random.normal(0, point[2] * 0.5)
410
- end_y = point[1] + np.random.normal(0, point[2] * 0.5)
411
-
412
- # Create flow line with multiple points for curved effect
413
- curve_points = 5
414
- x_flow = np.linspace(start_x, end_x, curve_points)
415
- y_flow = np.linspace(start_y, end_y, curve_points)
416
-
417
- # Add slight randomness to path
418
- x_flow += np.random.normal(0, 3, curve_points)
419
- y_flow += np.random.normal(0, 3, curve_points)
420
-
421
- # Height varies along path (starting seated, ending standing)
422
- z_flow = np.linspace(1.5, 3, curve_points)
423
-
424
- # Add flow line
425
- fig.add_trace(go.Scatter3d(
426
- x=x_flow,
427
- y=y_flow,
428
- z=z_flow,
429
- mode='lines',
430
- line=dict(
431
- color='orange' if normalized_delay < 0.7 else 'red',
432
- width=2,
433
- dash='dot'
434
- ),
435
- opacity=0.5,
436
- name='Passenger Flow'
437
- ))
438
 
439
- # Customize 3D layout
440
  fig.update_layout(
441
- title=f"3D Airport Terminal Simulation - {carrier}",
442
- scene=dict(
443
- xaxis=dict(
444
- title='',
445
- range=[0, 100],
446
- showticklabels=False,
447
- showgrid=True,
448
- gridcolor='lightgray'
449
- ),
450
- yaxis=dict(
451
- title='',
452
- range=[0, 60],
453
- showticklabels=False,
454
- showgrid=True,
455
- gridcolor='lightgray'
456
- ),
457
- zaxis=dict(
458
- title='',
459
- range=[0, 10],
460
- showticklabels=False,
461
- showgrid=True,
462
- gridcolor='lightgray'
463
- ),
464
- aspectmode='manual',
465
- aspectratio=dict(x=1, y=0.6, z=0.3),
466
- camera=dict(
467
- eye=dict(x=0.8, y=-1.5, z=1.2),
468
- up=dict(x=0, y=0, z=1)
469
- )
470
- ),
471
  showlegend=False,
472
- margin=dict(l=0, r=0, t=30, b=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  )
474
 
475
  return fig
@@ -491,12 +420,12 @@ inputs = [
491
  gr.Slider(minimum=slider_ranges['arr_delay_lag1_lag3']['min'], maximum=slider_ranges['arr_delay_lag1_lag3']['max'], step=0.1, label="Arrival Delay 3 Months Ago (Scaled)")
492
  ]
493
 
494
- outputs = gr.Plot(label="3D Airport Terminal Simulation")
495
 
496
  gr.Interface(
497
  fn=predict_delay_interface,
498
  inputs=inputs,
499
  outputs=outputs,
500
- title="Flight Delay Prediction with 3D Terminal Crowd Simulation",
501
- description="Predict flight delays and visualize their impact in a 3D airport terminal environment. Passengers (colored dots) move between gates and service areas based on delay severity. Blue indicates calm passengers, orange shows mild frustration, and red represents high frustration. As delays increase, more movement patterns emerge between gates and information/security points."
502
- ).launch
 
4
  import pandas as pd
5
  import numpy as np
6
  import plotly.graph_objects as go
7
+ from plotly.subplots import make_subplots
8
 
9
  os.environ["HOPSWORKS_API_KEY"] = "HLDlE8LYYNS4zTdX.GQvAhHVCPMDVOrXcbGK3IKrsUv2APbwSUzexJDgjhXHPRoC3aAjhOMKgkaM95UHt"
10
 
 
101
 
102
  import gradio as gr
103
 
104
+ def create_terminal_crowd(delay_minutes, n_passengers=200):
105
  # Normalize delay to determine crowd behavior
106
  # Assume delay range from -1 to 5 minutes
107
  normalized_delay = min(max((delay_minutes + 1) / 6, 0), 1) # 0 to 1 scale
108
 
109
  # Terminal layout dimensions
110
+ terminal_width = 100
111
+ terminal_height = 60
 
112
 
113
  # Calculate crowd parameters based on delay
114
  crowd_density = normalized_delay * 0.8 + 0.2 # 0.2 to 1.0
 
117
  # Generate passenger positions
118
  n_actual_passengers = int(n_passengers * crowd_density)
119
 
120
+ # Create different passenger groups
121
  # 1. Seated passengers (at gates)
122
  # 2. Moving passengers (walking through terminal)
123
  # 3. Clustered passengers (at info desks, security, etc.)
124
 
125
+ # Define gate areas (x, y, width, height)
126
  gates = [
127
+ [10, 5, 20, 10], # Gate A
128
+ [40, 5, 20, 10], # Gate B
129
+ [70, 5, 20, 10], # Gate C
130
+ [10, 45, 20, 10], # Gate D
131
+ [40, 45, 20, 10], # Gate E
132
+ [70, 45, 20, 10] # Gate F
133
  ]
134
 
135
  # Define info desk/security areas (x, y, radius)
136
  service_points = [
137
+ [50, 30, 6], # Main info desk
138
+ [25, 30, 4], # Security point 1
139
+ [75, 30, 4] # Security point 2
140
  ]
141
 
142
  # Allocate passengers to different areas based on delay
 
151
  # Generate positions
152
  passenger_x = []
153
  passenger_y = []
 
154
  passenger_colors = []
155
 
156
  # 1. Seated passengers (distributed across gates)
 
177
  x = max(min(x, gate[0] + gate[2]), gate[0])
178
  y = max(min(y, gate[1] + gate[3]), gate[1])
179
 
 
 
 
180
  passenger_x.append(x)
181
  passenger_y.append(y)
 
182
  passenger_colors.append('blue') # Seated passengers are blue
183
 
184
  # 2. Service point passengers (clustered at info desks/security)
 
201
  y = point[1] + distance * np.sin(angle)
202
 
203
  # Keep within terminal bounds
204
+ x = max(min(x, terminal_width), 0)
205
+ y = max(min(y, terminal_height), 0)
 
 
 
206
 
207
  passenger_x.append(x)
208
  passenger_y.append(y)
 
209
  passenger_colors.append('red') # Service point passengers are red (frustrated)
210
 
211
  # 3. Walking passengers (random paths in terminal)
212
+ central_path_y = terminal_height / 2
213
  path_width = 20
214
 
215
  for i in range(n_walking):
216
  # With more delay, people tend to wander more randomly
217
  if normalized_delay < 0.4:
218
  # Mostly following the central path
219
+ x = np.random.uniform(0, terminal_width)
220
  y = central_path_y + np.random.normal(0, path_width * 0.2)
221
  else:
222
  # More random movements
223
+ x = np.random.uniform(0, terminal_width)
224
+ y = np.random.uniform(0, terminal_height)
225
 
226
  # Keep within terminal bounds
227
+ x = max(min(x, terminal_width), 0)
228
+ y = max(min(y, terminal_height), 0)
 
 
 
229
 
230
  passenger_x.append(x)
231
  passenger_y.append(y)
 
232
 
233
  # Color walking passengers by delay frustration level
234
  if normalized_delay < 0.3:
 
238
  else:
239
  passenger_colors.append('red') # High frustration
240
 
241
+ return passenger_x, passenger_y, passenger_colors, normalized_delay
242
 
243
  def predict_delay_interface(carrier, arr_flights, arr_diverted, temperature, wind_speed, month,
244
+ arr_delay_lag1, arr_flights_lag2, weather_delay, security_delay,
245
+ carrier_delay, arr_delay_lag1_lag2, arr_delay_lag1_lag3):
246
  # Get prediction
247
  delay_minutes = predict_delay(
248
  carrier, arr_flights, arr_diverted, temperature, wind_speed, month,
 
250
  carrier_delay, arr_delay_lag1_lag2, arr_delay_lag1_lag3
251
  )
252
 
253
+ # Create airport terminal crowd simulation
254
+ passenger_x, passenger_y, passenger_colors, normalized_delay = create_terminal_crowd(delay_minutes)
255
+
256
+ # Create terminal layout for visualization
257
+ fig = make_subplots(rows=1, cols=1)
258
 
259
+ # Add terminal background
260
+ terminal_width = 100
261
+ terminal_height = 60
262
 
263
+ # Draw terminal structure
264
+ # Main walking area
265
+ fig.add_shape(
266
+ type="rect",
267
+ x0=0, y0=0, x1=terminal_width, y1=terminal_height,
268
+ line=dict(width=2, color="gray"),
269
+ fillcolor="lightgray",
270
+ opacity=0.3
271
+ )
272
 
273
+ # Gates
274
+ gates = [
275
+ [10, 5, 20, 10, "Gate A"],
276
+ [40, 5, 20, 10, "Gate B"],
277
+ [70, 5, 20, 10, "Gate C"],
278
+ [10, 45, 20, 10, "Gate D"],
279
+ [40, 45, 20, 10, "Gate E"],
280
+ [70, 45, 20, 10, "Gate F"]
281
+ ]
282
 
 
283
  for gate in gates:
284
+ fig.add_shape(
285
+ type="rect",
286
+ x0=gate[0], y0=gate[1], x1=gate[0]+gate[2], y1=gate[1]+gate[3],
287
+ line=dict(width=1, color="blue"),
288
+ fillcolor="lightblue",
289
+ opacity=0.4
290
+ )
 
 
 
 
 
291
  # Add gate label
292
+ fig.add_annotation(
293
+ x=gate[0]+gate[2]/2, y=gate[1]+gate[3]/2,
294
+ text=gate[4],
295
+ showarrow=False,
296
+ font=dict(size=10)
297
+ )
 
 
 
298
 
299
+ # Info desk and security points
300
+ service_points = [
301
+ [50, 30, 6, "Information"],
302
+ [25, 30, 4, "Security 1"],
303
+ [75, 30, 4, "Security 2"]
304
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
 
306
+ for point in service_points:
307
+ fig.add_shape(
308
+ type="circle",
309
+ x0=point[0]-point[2], y0=point[1]-point[2],
310
+ x1=point[0]+point[2], y1=point[1]+point[2],
311
+ line=dict(width=1, color="darkgray"),
312
+ fillcolor="darkgray",
313
+ opacity=0.4
314
+ )
315
+ # Add label
316
+ fig.add_annotation(
317
+ x=point[0], y=point[1],
318
+ text=point[3],
319
+ showarrow=False,
320
+ font=dict(size=10, color="black")
321
+ )
322
 
323
+ # Add passengers as scatter points
324
+ fig.add_trace(
325
+ go.Scatter(
326
+ x=passenger_x, y=passenger_y,
327
+ mode='markers',
328
+ marker=dict(
329
+ size=7,
330
+ color=passenger_colors,
331
+ opacity=0.7
332
+ ),
333
+ name='Passengers'
334
+ )
335
+ )
336
 
337
+ # Add delay information
338
+ # Create color for delay text based on severity
339
  if delay_minutes < 0:
340
  delay_color = "green"
341
+ delay_text = "Early by"
342
  elif delay_minutes < 1:
343
  delay_color = "green"
344
+ delay_text = "On time (+"
345
  elif delay_minutes < 3:
346
  delay_color = "orange"
347
+ delay_text = "Delayed by"
348
  else:
349
  delay_color = "red"
350
+ delay_text = "Significantly delayed by"
351
 
352
+ # Add delay annotation
353
+ fig.add_annotation(
354
+ xref="paper", yref="paper",
355
+ x=0.5, y=0.97,
356
+ text=f"<b>{delay_text} {abs(delay_minutes):.1f} minutes</b>",
357
+ showarrow=False,
358
+ font=dict(size=16, color=delay_color),
359
+ align="center",
360
+ bgcolor="rgba(255, 255, 255, 0.8)",
361
+ bordercolor=delay_color,
362
+ borderwidth=2,
363
+ borderpad=4
364
+ )
365
 
366
+ # Add passenger count and frustration level
367
+ total_passengers = len(passenger_x)
368
+ frustrated_passengers = passenger_colors.count('red') + passenger_colors.count('orange')
369
+ frustration_percent = round(frustrated_passengers / total_passengers * 100)
 
 
 
 
 
 
370
 
371
+ fig.add_annotation(
372
+ xref="paper", yref="paper",
373
+ x=0.5, y=0.03,
374
+ text=f"Terminal occupancy: {total_passengers} passengers | Frustration level: {frustration_percent}%",
375
+ showarrow=False,
376
+ font=dict(size=12),
377
+ align="center",
378
+ bgcolor="rgba(255, 255, 255, 0.8)",
379
+ borderpad=4
380
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
 
382
+ # Customize layout
383
  fig.update_layout(
384
+ title=f"Airport Terminal Crowd Simulation - {carrier}",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  showlegend=False,
386
+ xaxis=dict(
387
+ range=[-5, terminal_width+5],
388
+ showgrid=False,
389
+ zeroline=False,
390
+ visible=False
391
+ ),
392
+ yaxis=dict(
393
+ range=[-5, terminal_height+5],
394
+ showgrid=False,
395
+ zeroline=False,
396
+ visible=False,
397
+ scaleanchor="x",
398
+ scaleratio=1
399
+ ),
400
+ margin=dict(l=20, r=20, t=50, b=20),
401
+ plot_bgcolor='white'
402
  )
403
 
404
  return fig
 
420
  gr.Slider(minimum=slider_ranges['arr_delay_lag1_lag3']['min'], maximum=slider_ranges['arr_delay_lag1_lag3']['max'], step=0.1, label="Arrival Delay 3 Months Ago (Scaled)")
421
  ]
422
 
423
+ outputs = gr.Plot(label="Airport Terminal Crowd Simulation")
424
 
425
  gr.Interface(
426
  fn=predict_delay_interface,
427
  inputs=inputs,
428
  outputs=outputs,
429
+ title="Flight Delay Prediction with Terminal Crowd Simulation",
430
+ description="Predict flight delays and visualize how they affect the airport terminal crowd. As delays increase, passengers shift from gates to information desks and security points, with increasing frustration levels (blue = calm, orange = mild frustration, red = high frustration)."
431
+ ).launch()