immunobiotech commited on
Commit
44668bc
·
verified ·
1 Parent(s): 6f3cec6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -34
app.py CHANGED
@@ -8,10 +8,27 @@ import time
8
  import branca.colormap as cm
9
  import numpy as np
10
  import io
 
 
 
11
 
12
  # OpenSky API URL
13
  BASE_URL = "https://opensky-network.org/api"
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def get_states(bounds=None):
16
  """Get current aircraft states from OpenSky Network"""
17
  params = {}
@@ -31,9 +48,60 @@ def get_states(bounds=None):
31
  print(f"Error fetching data: {e}")
32
  return None
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  def create_map(region="world"):
35
  """Create aircraft tracking map"""
36
- # Default bounds for different regions
37
  bounds = {
38
  "world": None,
39
  "europe": [35.0, -15.0, 60.0, 40.0],
@@ -41,51 +109,46 @@ def create_map(region="world"):
41
  "asia": [10.0, 60.0, 50.0, 150.0]
42
  }
43
 
44
- # Get aircraft data
45
  data = get_states(bounds.get(region))
46
 
47
  if not data or 'states' not in data:
48
- return None, "Failed to fetch aircraft data"
49
 
50
- # Create base map
51
  m = folium.Map(
52
  location=[30, 0],
53
  zoom_start=3,
54
  tiles='CartoDB dark_matter'
55
  )
56
 
57
- # Create aircraft icon
58
- aircraft_icon = folium.CustomIcon(
59
- 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-blue.png',
60
- icon_size=(25, 41)
61
- )
62
-
63
- # Create heatmap data
64
  heat_data = []
65
 
66
  # Add aircraft markers
67
  for state in data['states']:
68
- if state[6] and state[5]: # If latitude and longitude exist
69
  lat, lon = state[6], state[5]
70
  callsign = state[1] if state[1] else 'N/A'
71
  altitude = state[7] if state[7] else 'N/A'
72
  velocity = state[9] if state[9] else 'N/A'
 
73
 
74
- # Add to heatmap data
75
  heat_data.append([lat, lon, 1])
76
 
77
- # Create popup content
 
 
78
  popup_content = f"""
79
- <div style="font-family: Arial; width: 200px;">
80
  <h4 style="color: #4a90e2;">Flight Information</h4>
 
81
  <p><b>Callsign:</b> {callsign}</p>
 
82
  <p><b>Altitude:</b> {altitude}m</p>
83
  <p><b>Velocity:</b> {velocity}m/s</p>
84
  <p><b>Origin:</b> {state[2]}</p>
 
85
  </div>
86
  """
87
 
88
- # Add marker
89
  folium.Marker(
90
  location=[lat, lon],
91
  popup=folium.Popup(popup_content, max_width=300),
@@ -97,28 +160,31 @@ def create_map(region="world"):
97
  )
98
  ).add_to(m)
99
 
100
- # Add heatmap layer
101
  plugins.HeatMap(heat_data, radius=15).add_to(m)
102
-
103
- # Add layer control
104
  folium.LayerControl().add_to(m)
105
 
106
- # Save map to HTML string
107
- html_string = m._repr_html_()
108
 
109
  # Create statistics
110
  total_aircraft = len(data['states'])
111
  countries = len(set(state[2] for state in data['states'] if state[2]))
112
  avg_altitude = np.mean([state[7] for state in data['states'] if state[7]]) if data['states'] else 0
 
 
113
 
114
  stats = f"""
115
- 📊 Statistics:
116
  • Total Aircraft: {total_aircraft}
 
 
117
  • Countries: {countries}
118
  • Average Altitude: {avg_altitude:.0f}m
 
 
119
  """
120
 
121
- return html_string, stats
122
 
123
  # Custom CSS
124
  custom_css = """
@@ -143,6 +209,11 @@ custom_css = """
143
  margin-bottom: 0.5em !important;
144
  text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
145
  }
 
 
 
 
 
146
  """
147
 
148
  # Gradio interface
@@ -154,15 +225,24 @@ with gr.Blocks(css=custom_css) as demo:
154
  )
155
 
156
  with gr.Row():
157
- region_select = gr.Dropdown(
158
- choices=["world", "europe", "north_america", "asia"],
159
- value="world",
160
- label="Select Region"
161
- )
162
- refresh_btn = gr.Button("🔄 Refresh")
 
 
 
 
 
 
 
 
 
163
 
164
- map_html = gr.HTML()
165
- stats_text = gr.Textbox(label="Statistics", lines=4)
166
 
167
  def update_map(region):
168
  return create_map(region)
@@ -170,16 +250,25 @@ with gr.Blocks(css=custom_css) as demo:
170
  refresh_btn.click(
171
  fn=update_map,
172
  inputs=[region_select],
173
- outputs=[map_html, stats_text]
174
  )
175
 
176
  region_select.change(
177
  fn=update_map,
178
  inputs=[region_select],
179
- outputs=[map_html, stats_text]
180
  )
181
 
 
 
 
 
 
 
 
 
 
182
  # Initial map load
183
- map_html, stats_text = create_map("world")
184
 
185
  demo.launch()
 
8
  import branca.colormap as cm
9
  import numpy as np
10
  import io
11
+ from PIL import Image
12
+ import plotly.graph_objects as go
13
+ from plotly.subplots import make_subplots
14
 
15
  # OpenSky API URL
16
  BASE_URL = "https://opensky-network.org/api"
17
 
18
+ # Aircraft photos API (예시 - 실제 구현시에는 적절한 API로 대체 필요)
19
+ AIRCRAFT_PHOTOS_API = "https://api.planespotters.net/pub/photos/hex/{icao24}"
20
+
21
+ def get_aircraft_photo(icao24):
22
+ """Get aircraft photo from Planespotters API"""
23
+ try:
24
+ response = requests.get(AIRCRAFT_PHOTOS_API.format(icao24=icao24))
25
+ data = response.json()
26
+ if data.get('photos'):
27
+ return data['photos'][0]['thumbnail_large']['src']
28
+ except:
29
+ # 기본 항공기 이미지 URL 반환
30
+ return "https://example.com/default-aircraft.jpg"
31
+
32
  def get_states(bounds=None):
33
  """Get current aircraft states from OpenSky Network"""
34
  params = {}
 
48
  print(f"Error fetching data: {e}")
49
  return None
50
 
51
+ def create_monitoring_dashboard(data):
52
+ """Create monitoring dashboard using Plotly"""
53
+ if not data or 'states' not in data:
54
+ return None
55
+
56
+ states = data['states']
57
+
58
+ # Create subplots
59
+ fig = make_subplots(
60
+ rows=2, cols=2,
61
+ subplot_titles=('Altitude Distribution', 'Speed Distribution',
62
+ 'Aircraft by Country', 'Aircraft Categories')
63
+ )
64
+
65
+ # Altitude distribution
66
+ altitudes = [state[7] for state in states if state[7]]
67
+ fig.add_trace(
68
+ go.Histogram(x=altitudes, name="Altitude"),
69
+ row=1, col=1
70
+ )
71
+
72
+ # Speed distribution
73
+ speeds = [state[9] for state in states if state[9]]
74
+ fig.add_trace(
75
+ go.Histogram(x=speeds, name="Speed"),
76
+ row=1, col=2
77
+ )
78
+
79
+ # Aircraft by country
80
+ countries = pd.Series([state[2] for state in states if state[2]]).value_counts()
81
+ fig.add_trace(
82
+ go.Bar(x=countries.index[:10], y=countries.values[:10], name="Countries"),
83
+ row=2, col=1
84
+ )
85
+
86
+ # Aircraft categories
87
+ categories = pd.Series([state[17] for state in states if state[17]]).value_counts()
88
+ fig.add_trace(
89
+ go.Pie(labels=categories.index, values=categories.values, name="Categories"),
90
+ row=2, col=2
91
+ )
92
+
93
+ fig.update_layout(
94
+ height=800,
95
+ showlegend=False,
96
+ template="plotly_dark",
97
+ paper_bgcolor='rgba(0,0,0,0)',
98
+ plot_bgcolor='rgba(0,0,0,0)'
99
+ )
100
+
101
+ return fig
102
+
103
  def create_map(region="world"):
104
  """Create aircraft tracking map"""
 
105
  bounds = {
106
  "world": None,
107
  "europe": [35.0, -15.0, 60.0, 40.0],
 
109
  "asia": [10.0, 60.0, 50.0, 150.0]
110
  }
111
 
 
112
  data = get_states(bounds.get(region))
113
 
114
  if not data or 'states' not in data:
115
+ return None, None, "Failed to fetch aircraft data"
116
 
 
117
  m = folium.Map(
118
  location=[30, 0],
119
  zoom_start=3,
120
  tiles='CartoDB dark_matter'
121
  )
122
 
 
 
 
 
 
 
 
123
  heat_data = []
124
 
125
  # Add aircraft markers
126
  for state in data['states']:
127
+ if state[6] and state[5]:
128
  lat, lon = state[6], state[5]
129
  callsign = state[1] if state[1] else 'N/A'
130
  altitude = state[7] if state[7] else 'N/A'
131
  velocity = state[9] if state[9] else 'N/A'
132
+ icao24 = state[0]
133
 
 
134
  heat_data.append([lat, lon, 1])
135
 
136
+ # Get aircraft photo
137
+ photo_url = get_aircraft_photo(icao24)
138
+
139
  popup_content = f"""
140
+ <div style="font-family: Arial; width: 300px;">
141
  <h4 style="color: #4a90e2;">Flight Information</h4>
142
+ <img src="{photo_url}" style="width: 100%; max-height: 200px; object-fit: cover; margin-bottom: 10px;">
143
  <p><b>Callsign:</b> {callsign}</p>
144
+ <p><b>ICAO24:</b> {icao24}</p>
145
  <p><b>Altitude:</b> {altitude}m</p>
146
  <p><b>Velocity:</b> {velocity}m/s</p>
147
  <p><b>Origin:</b> {state[2]}</p>
148
+ <p><b>Status:</b> {'On Ground' if state[8] else 'In Air'}</p>
149
  </div>
150
  """
151
 
 
152
  folium.Marker(
153
  location=[lat, lon],
154
  popup=folium.Popup(popup_content, max_width=300),
 
160
  )
161
  ).add_to(m)
162
 
 
163
  plugins.HeatMap(heat_data, radius=15).add_to(m)
 
 
164
  folium.LayerControl().add_to(m)
165
 
166
+ # Create monitoring dashboard
167
+ dashboard = create_monitoring_dashboard(data)
168
 
169
  # Create statistics
170
  total_aircraft = len(data['states'])
171
  countries = len(set(state[2] for state in data['states'] if state[2]))
172
  avg_altitude = np.mean([state[7] for state in data['states'] if state[7]]) if data['states'] else 0
173
+ in_air = sum(1 for state in data['states'] if not state[8])
174
+ on_ground = sum(1 for state in data['states'] if state[8])
175
 
176
  stats = f"""
177
+ 📊 Real-time Statistics:
178
  • Total Aircraft: {total_aircraft}
179
+ • Aircraft in Air: {in_air}
180
+ • Aircraft on Ground: {on_ground}
181
  • Countries: {countries}
182
  • Average Altitude: {avg_altitude:.0f}m
183
+
184
+ 🔄 Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
185
  """
186
 
187
+ return m._repr_html_(), dashboard, stats
188
 
189
  # Custom CSS
190
  custom_css = """
 
209
  margin-bottom: 0.5em !important;
210
  text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
211
  }
212
+ .dashboard {
213
+ background: rgba(0, 0, 0, 0.3) !important;
214
+ border-radius: 10px !important;
215
+ padding: 20px !important;
216
+ }
217
  """
218
 
219
  # Gradio interface
 
225
  )
226
 
227
  with gr.Row():
228
+ with gr.Column(scale=2):
229
+ region_select = gr.Dropdown(
230
+ choices=["world", "europe", "north_america", "asia"],
231
+ value="world",
232
+ label="Select Region"
233
+ )
234
+ with gr.Column(scale=1):
235
+ refresh_btn = gr.Button("🔄 Refresh")
236
+ auto_refresh = gr.Checkbox(label="Auto Refresh (30s)", value=False)
237
+
238
+ with gr.Row():
239
+ with gr.Column(scale=2):
240
+ map_html = gr.HTML()
241
+ with gr.Column(scale=1):
242
+ stats_text = gr.Textbox(label="Statistics", lines=8)
243
 
244
+ with gr.Row():
245
+ dashboard_plot = gr.Plot(label="Monitoring Dashboard")
246
 
247
  def update_map(region):
248
  return create_map(region)
 
250
  refresh_btn.click(
251
  fn=update_map,
252
  inputs=[region_select],
253
+ outputs=[map_html, dashboard_plot, stats_text]
254
  )
255
 
256
  region_select.change(
257
  fn=update_map,
258
  inputs=[region_select],
259
+ outputs=[map_html, dashboard_plot, stats_text]
260
  )
261
 
262
+ # Auto refresh
263
+ if auto_refresh:
264
+ demo.load(
265
+ fn=update_map,
266
+ inputs=[region_select],
267
+ outputs=[map_html, dashboard_plot, stats_text],
268
+ every=30
269
+ )
270
+
271
  # Initial map load
272
+ map_html, dashboard_plot, stats_text = create_map("world")
273
 
274
  demo.launch()