Shreya Mendi commited on
Commit
723cf28
·
1 Parent(s): b29efb9

new features

Browse files
src/__pycache__/fetchapi.cpython-310.pyc ADDED
Binary file (3.53 kB). View file
 
src/fetchapi.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import requests
3
+ import pandas as pd
4
+ from datetime import datetime
5
+ from dotenv import load_dotenv
6
+ import os
7
+ import time
8
+ from dotenv import load_dotenv
9
+
10
+ OPENSKY_URL = "https://opensky-network.org/api/states/all"
11
+ OPENSKY_URL_DEPARTURES = "https://opensky-network.org/api/flights/departure"
12
+
13
+ def fetch_opensky_snapshot() -> pd.DataFrame:
14
+ """
15
+ Fetches a snapshot of current flights from the OpenSky API.
16
+ Returns a pandas DataFrame of flight state vectors.
17
+ """
18
+ r = requests.get(OPENSKY_URL, timeout=20)
19
+ if r.status_code != 200:
20
+ raise RuntimeError(f"Failed to fetch OpenSky data: {r.status_code} {r.reason} -> {r.text[:200]}")
21
+
22
+
23
+ data = r.json()
24
+ states = data.get("states", [])
25
+ timestamp = data.get("time", datetime.utcnow().timestamp())
26
+
27
+ cols = [
28
+ "icao24", "callsign", "origin_country", "time_position", "last_contact",
29
+ "longitude", "latitude", "baro_altitude", "on_ground", "velocity",
30
+ "true_track", "vertical_rate", "sensors", "geo_altitude", "squawk",
31
+ "spi", "position_source"
32
+ ]
33
+ df = pd.DataFrame(states, columns=cols)
34
+ df["last_contact"] = pd.to_datetime(df["last_contact"], unit="s")
35
+ df.attrs["timestamp"] = datetime.utcfromtimestamp(timestamp)
36
+ return df
37
+
38
+ def fetch_aviation_API_airlines_endpoint():
39
+ """
40
+ Fetches airline data from the AviationStack API airlines endpoint.
41
+
42
+ Parameters:
43
+ - None
44
+
45
+ Returns:
46
+ - dict: The JSON response from the AviationStack API containing the airline data.
47
+ """
48
+ #api_key = os.environ.get("AVIATION_KEY") # Retrieve the API key (when running on HuggingFace)
49
+ # Comment the line above and uncomment the two lines below if you are running the app locally (not on HuggingFace) and have a .env file with the AviationStack API key
50
+ load_dotenv()
51
+ api_key = os.getenv("AVIATION_KEY") # Retrieve the API key
52
+ url = f"https://api.aviationstack.com/v1/airlines?access_key={api_key}"
53
+ response = requests.get(url)
54
+ return response.json()
55
+
56
+ def fetch_rdu_departures(hours=6) -> pd.DataFrame:
57
+ """
58
+ Fetch recent departures from RDU (KRDU) within the last n hours (default is 6).
59
+ Returns a pandas DataFrame.
60
+ """
61
+ end = int(time.time())
62
+ begin = end - hours * 3600
63
+ params = {
64
+ "airport": "KRDU",
65
+ "begin": begin,
66
+ "end": end
67
+ }
68
+
69
+ response = requests.get(OPENSKY_URL_DEPARTURES, params=params, timeout=20)
70
+ if response.status_code != 200:
71
+ raise RuntimeError(f"Failed to fetch data, {response.headers}")
72
+
73
+ data = response.json()
74
+ columns = [
75
+ "icao24", "firstSeen", "estDepartureAirport", "lastSeen", "estArrivalAirport", "callsign",
76
+ "estDepartureAirportHorizDistance", "estDepartureAirportVertDistance", "estArrivalAirportHorizDistance",
77
+ "estArrivalAirportVertDistance", "departureAirportCandidatesCount", "arrivalAirportCandidatesCount"
78
+ ]
79
+ data_df = pd.DataFrame(data, columns=columns)
80
+
81
+ flights = []
82
+ for _, flight in data_df.iterrows():
83
+ flights.append({
84
+ "icao24": flight["icao24"],
85
+ "callsign": flight["callsign"],
86
+ "departure": flight["estDepartureAirport"],
87
+ "arrival": flight["estArrivalAirport"]
88
+ })
89
+ return pd.DataFrame(flights)
90
+
91
+ def fetch_aviation_API_airlines_endpoint():
92
+ """
93
+ Fetches airline data from the AviationStack API airlines endpoint.
94
+
95
+ Parameters:
96
+ - None
97
+
98
+ Returns:
99
+ - dict: The JSON response from the AviationStack API containing the airline data.
100
+ """
101
+ #api_key = os.environ.get("AVIATION_KEY") # Retrieve the API key (when running on HuggingFace)
102
+ # Comment the line above and uncomment the two lines below if you are running the app locally (not on HuggingFace) and have a .env file with the AviationStack API key
103
+ load_dotenv()
104
+ api_key = os.getenv("AVIATION_KEY") # Retrieve the API key
105
+ url = f"https://api.aviationstack.com/v1/airlines?access_key={api_key}"
106
+ response = requests.get(url)
107
+ return response.json()
108
+
109
+
110
+ if __name__ == "__main__":
111
+ print("Fetching live flight data from OpenSky…")
112
+ try:
113
+ df = fetch_opensky_snapshot()
114
+ print(f"Fetched {len(df)} flights at {df.attrs['timestamp']}")
115
+ print(df.head())
116
+
117
+ df_2 = fetch_rdu_departures(hours=6)
118
+ print(f"Fetched {len(df)} flights at {df.attrs['timestamp']}")
119
+ print(df.head())
120
+ except Exception as e:
121
+ print("Error:", e)
122
+
123
+ print("Fetching airline data from AviationStack…")
124
+ try:
125
+ airline_data = fetch_aviation_API_airlines_endpoint()
126
+ print(f"Fetched {len(airline_data.get('data', []))} airlines")
127
+ print(airline_data)
128
+ except Exception as e:
129
+ print("Error:", e)
src/streamlit_app.py CHANGED
@@ -1,40 +1,293 @@
1
- import altair as alt
2
- import numpy as np
3
  import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
1
+ # streamlit_app.py
2
+
3
  import pandas as pd
4
  import streamlit as st
5
+ import matplotlib.pyplot as plt
6
+ from fetchapi import fetch_opensky_snapshot, fetch_rdu_departures, fetch_aviation_API_airlines_endpoint
7
+ import pandas as pd
8
+
9
+ st.set_page_config(page_title="Flight Volume by Country (OpenSky)", layout="wide")
10
+ st.title("🌍 Global Flight Snapshot (via OpenSky Network)")
11
+
12
+ st.caption("Showing a snapshot of the most recent ~1,800 aircraft globally. Data is live and limited by OpenSky’s API.")
13
+
14
+ run = st.button("Fetch Live Flights")
15
+
16
+ # ---------- Main ----------
17
+ if run:
18
+ st.info("Fetching live data from OpenSky…")
19
+ try:
20
+ df = fetch_opensky_snapshot()
21
+ except Exception as e:
22
+ st.error(f"Failed to fetch data: {type(e).__name__} -> {e}")
23
+ st.stop()
24
+
25
+ st.metric("Flights in snapshot", len(df))
26
+
27
+ if df.empty:
28
+ st.warning("No flights found in snapshot.")
29
+ st.stop()
30
+
31
+ # Aggregate by country
32
+ summary = df.groupby("origin_country").size().reset_index(name="flights")
33
+ summary = summary.sort_values("flights", ascending=False).head(30)
34
+
35
+ # ---------- Plot Top 30 Countries ----------
36
+ st.subheader("✈️ Top 30 Countries by Active Flights")
37
+
38
+ fig, ax = plt.subplots(figsize=(10, 8))
39
+ ax.barh(summary["origin_country"], summary["flights"])
40
+ ax.set_xlabel("Flights (current snapshot)")
41
+ ax.set_ylabel("Country")
42
+ ax.set_title("Top 30 Countries by Active Flights")
43
+ ax.invert_yaxis() # Largest at top
44
+ st.pyplot(fig)
45
+
46
+ # ---------- Plot Flight Scatter Map ----------
47
+ st.subheader("🌐 Flight Positions (Scatter Map)")
48
+ df_map = df.dropna(subset=["latitude", "longitude"])
49
+
50
+ if df_map.empty:
51
+ st.warning("No geolocation data available for mapping.")
52
+ else:
53
+ fig2, ax2 = plt.subplots(figsize=(12, 6))
54
+ ax2.scatter(df_map["longitude"], df_map["latitude"], s=2, alpha=0.5)
55
+ ax2.set_title("Global Flight Positions")
56
+ ax2.set_xlabel("Longitude")
57
+ ax2.set_ylabel("Latitude")
58
+ st.pyplot(fig2)
59
+
60
+ # with st.expander("Raw Country Data"):
61
+ # st.dataframe(summary)
62
+
63
+
64
+ ############# Omkar's Code #############
65
+ st.header("📊 Other Analyses (OpenSky)")
66
+
67
+ col1, col2, col3 = st.columns(3)
68
+
69
+ # 1. Flights by Altitude Band
70
+ with col1:
71
+ if "baro_altitude" in df.columns:
72
+ # Convert meters to feet
73
+ df["alt_ft"] = df["baro_altitude"] * 3.28084
74
+
75
+ bins = [-1000, 10000, 20000, 30000, 60000] # feet
76
+ labels = ["<10k", "10–20k", "20–30k", "30k+"]
77
+ df["alt_band"] = pd.cut(df["alt_ft"], bins=bins, labels=labels)
78
+
79
+ alt_counts = df["alt_band"].value_counts().reindex(labels, fill_value=0)
80
+
81
+ fig_alt, ax_alt = plt.subplots(figsize=(4,3))
82
+ ax_alt.bar(alt_counts.index, alt_counts.values, color="mediumseagreen", alpha=0.8)
83
+ ax_alt.set_title("Flights by Altitude Band (feet)")
84
+ ax_alt.set_xlabel("Altitude band")
85
+ ax_alt.set_ylabel("Aircraft")
86
+ st.pyplot(fig_alt, use_container_width=False)
87
+
88
+
89
+ # 2. Top Airlines by Callsign Prefix
90
+ with col2:
91
+ if "callsign" in df.columns:
92
+ # Clean callsigns
93
+ cs = df["callsign"].astype(str).str.upper().str.strip()
94
+
95
+ # Extract exactly 3 leading letters (ICAO airline code)
96
+ prefix = cs.str.extract(r'^([A-Z]{3})', expand=False)
97
+
98
+ # Tag N-registered private aircraft
99
+ n_reg_mask = prefix.isna() & cs.str.match(r'^N[0-9A-Z]+', na=False)
100
+ prefix = prefix.where(~n_reg_mask, "Private/GA")
101
+
102
+ # Fill remaining blanks
103
+ prefix = prefix.fillna("No Name")
104
+
105
+ # Map common airline codes → names
106
+ airline_map = {
107
+ "AAL": "American Airlines",
108
+ "DAL": "Delta Air Lines",
109
+ "UAL": "United Airlines",
110
+ "SWA": "Southwest Airlines",
111
+ "JBU": "Jet Blue Airways",
112
+ "FFT": "Frontier Airlines",
113
+ "NKS": "Spirit Airlines",
114
+ "ASA": "Alaska Airlines",
115
+ "UPS": "UPS Airlines",
116
+ "FDX": "Fed Ex Express",
117
+ "BAW": "British Airways",
118
+ "DLH": "Lufthansa",
119
+ "AFR": "Air France",
120
+ "KLM": "KLM Royal Dutch Airlines",
121
+ "UAE": "Emirates",
122
+ "Private/GA": "Private/GA",
123
+ "No Name": "No Name",
124
+ }
125
+
126
+ # Replace codes with names where possible
127
+ airline_name = prefix.map(airline_map).fillna(prefix)
128
+
129
+ airline_counts = airline_name.value_counts().head(15)
130
+
131
+ fig_airline, ax_airline = plt.subplots(figsize=(8, 6))
132
+ ax_airline.barh(airline_counts.index, airline_counts.values, color="slateblue", alpha=0.85)
133
+ ax_airline.set_title("Top 15 Airlines by Callsign")
134
+ ax_airline.set_xlabel("Aircraft")
135
+ ax_airline.invert_yaxis()
136
+ st.pyplot(fig_airline, use_container_width=False)
137
+
138
+
139
+ # 3. Flights by Broad Region (Pie)
140
+ with col3:
141
+ if {"latitude","longitude"}.issubset(df.columns):
142
+ df["region"] = pd.cut(
143
+ df["longitude"],
144
+ bins=[-180, -30, 60, 180],
145
+ labels=["Americas", "Europe/Africa", "Asia-Pacific"]
146
+ )
147
+ region_counts = df["region"].value_counts()
148
+
149
+ fig_region, ax_region = plt.subplots(figsize=(3.5,3.5))
150
+ ax_region.pie(region_counts.values, labels=region_counts.index, autopct="%1.0f%%")
151
+ ax_region.set_title("Regions")
152
+ st.pyplot(fig_region, use_container_width=False)
153
+ else:
154
+ st.info("Click 'Fetch Live Flights' to view global snapshot.")
155
+
156
+
157
+
158
+ ## ---------- RDU Specific Analysis (Arnav) ---------- ##
159
+ st.header("🛫 Raleigh-Durham (RDU) Airport Stats")
160
+ run_rdu = st.button("Fetch RDU Stats")
161
+
162
+ if run_rdu:
163
+ with st.spinner("Fetching RDU-specific flight data..."):
164
+ df_departures = fetch_rdu_departures(hours=6)
165
+
166
+ st.metric("Departures (last 6h)", len(df_departures))
167
+
168
+ if not df_departures.empty:
169
+ # ---- Top Airlines ----
170
+ def airline_from_callsign(callsign):
171
+ if not callsign or len(callsign) < 3:
172
+ return "Unknown"
173
+ prefix = callsign[:3].upper()
174
+ mapping = {
175
+ "AAL": "American Airlines",
176
+ "DAL": "Delta",
177
+ "UAL": "United",
178
+ "SWA": "Southwest",
179
+ "JBU": "JetBlue",
180
+ "FDX": "FedEx",
181
+ "UPS": "UPS",
182
+ "NKS": "Spirit",
183
+ "ASA": "Alaska",
184
+ "FFT": "Frontier"
185
+ }
186
+ return mapping.get(prefix, prefix)
187
+
188
+ df_departures["Airline"] = df_departures["callsign"].apply(airline_from_callsign)
189
+ top_airlines = df_departures["Airline"].value_counts().head(10).reset_index()
190
+ top_airlines.columns = ["Airline", "Flights"]
191
+ st.subheader("🏢 Top 10 Airlines from RDU (last 6h)")
192
+ st.bar_chart(top_airlines.set_index("Airline"))
193
+
194
+
195
+ #### ----------- Airline Profile Comparison (AviationAPI - Ethan Dominic's Code) ----------- ####
196
+ airline_data = fetch_aviation_API_airlines_endpoint()
197
+
198
+ def get_airline_feature_dict(feature_type, cast_type):
199
+ """
200
+ Return a dictionary of airline names along with their values for the specified feature type.
201
+
202
+ Parameters:
203
+ - feature_type (str): The specified feature type to extract (e.g., "fleet_size", "fleet_average_age", "date_founded").
204
+ - cast_type (str): The type to cast the feature value to ("int", "float", or "str")
205
+
206
+ Returns:
207
+ - dict: A dictionary whose keys are airline names and values are the corresponding feature values.
208
+ """
209
+ airline_feature_dict = {}
210
+ for i in range(len(airline_data["data"])):
211
+ airline_name = airline_data["data"][i]["airline_name"]
212
+ if airline_data["data"][i][feature_type] is not None and airline_data["data"][i][feature_type] != "":
213
+ if cast_type == "int":
214
+ airline_feature_value = int(airline_data["data"][i][feature_type])
215
+ elif cast_type == "str":
216
+ airline_feature_value = str(airline_data["data"][i][feature_type])
217
+ else:
218
+ airline_feature_value = float(airline_data["data"][i][feature_type])
219
+ airline_feature_dict[airline_name] = airline_feature_value
220
+ return airline_feature_dict
221
+
222
+ def plot_bar_graph(feature_series, title, ylabel, bottom_ylim=0):
223
+ """
224
+ Plot a bar graph for the given feature Series.
225
+
226
+ Parameters:
227
+ - feature_series (pd.Series): A pandas Series where the index is airline names and the values are the feature values.
228
+ - title (str): The desired title of the graph.
229
+ - ylabel (str): The desired label for the y-axis.
230
+ - bottom_ylim (int, optional): The minimum limit for the y-axis. Defaults to 0.
231
+
232
+ Returns:
233
+ - None: Displays the bar graph using Streamlit.
234
+ """
235
+ fig, ax = plt.subplots()
236
+ bars = ax.bar(feature_series.index.astype(str), feature_series.values)
237
+ ax.set_title(title)
238
+ ax.set_xlabel("Airline")
239
+ ax.set_ylabel(ylabel)
240
+ ax.bar(feature_series.index, feature_series.values)
241
+ ax.bar_label(bars, padding=3)
242
+ plt.xticks(rotation=90)
243
+ plt.ylim(bottom=bottom_ylim)
244
+ st.pyplot(fig)
245
+
246
+ # Main Program Execution
247
+ st.title("Airline Profile Comparison")
248
+
249
+ comparison_option = st.radio(
250
+ "Pick the type of comparison you would like to see: ",
251
+ ("Fleet Size", "Fleet Average Age", "Founding Year")
252
+ )
253
+
254
+ countries_of_origin = pd.Series(get_airline_feature_dict("country_name", "str"))
255
+ country_filters = countries_of_origin.unique().tolist()
256
+ country_filters.append("All Countries") # Add option for user to see all countries
257
+ country_filter_option = st.radio(
258
+ "Pick a country of origin to filter by: ",
259
+ (country_filters)
260
+ )
261
 
262
+ if country_filter_option == "All Countries":
263
+ if comparison_option == "Fleet Size":
264
+ fleet_sizes = (pd.Series(get_airline_feature_dict("fleet_size", "int"))).dropna() # Remove airlines with no fleet size data
265
+ sorted_fleet_sizes = fleet_sizes.sort_values(ascending=True)
266
+ top10_sorted_fleet_sizes = sorted_fleet_sizes.tail(10) # Get the top 10 largest airlines by fleet size
267
+ plot_bar_graph(top10_sorted_fleet_sizes, "Airline Fleet Sizes", "Fleet Size")
268
+ elif comparison_option == "Fleet Average Age":
269
+ fleet_avg_ages = (pd.Series(get_airline_feature_dict("fleet_average_age", "float"))).dropna() # Remove airlines with no fleet average age data
270
+ sorted_fleet_avg_ages = fleet_avg_ages.sort_values(ascending=True)
271
+ top10_sorted_fleet_avg_ages = sorted_fleet_avg_ages.head(10) # Get the top 10 youngest airlines by fleet average age
272
+ plot_bar_graph(top10_sorted_fleet_avg_ages, "Airline Fleet Average Ages", "Fleet Average Age")
273
+ elif comparison_option == "Founding Year":
274
+ founding_years = (pd.Series(get_airline_feature_dict("date_founded", "int"))).dropna() # Remove airlines with no founding year data
275
+ sorted_founding_years = founding_years.sort_values(ascending=True)
276
+ top10_sorted_founding_years = sorted_founding_years.head(10) # Get the top 10 oldest airlines by founding year
277
+ plot_bar_graph(top10_sorted_founding_years, "Airline Founding Years", "Founding Year", bottom_ylim=1900) # Set y-axis minimum so years before 1900 since no airlines were founded before then
278
+ else:
279
+ if comparison_option == "Fleet Size":
280
+ fleet_sizes = (pd.Series(get_airline_feature_dict("fleet_size", "int"))).dropna() # Remove airlines with no fleet size data
281
+ filtered_fleet_sizes = fleet_sizes[countries_of_origin == country_filter_option] # Ensure only airlines from the selected country are included
282
+ sorted_fleet_sizes = filtered_fleet_sizes.sort_values(ascending=True)
283
+ plot_bar_graph(sorted_fleet_sizes, "Airline Fleet Sizes", "Fleet Size")
284
+ elif comparison_option == "Fleet Average Age":
285
+ fleet_avg_ages = (pd.Series(get_airline_feature_dict("fleet_average_age", "float"))).dropna() # Remove airlines with no fleet average age data
286
+ filtered_fleet_avg_ages = fleet_avg_ages[countries_of_origin == country_filter_option] # Ensure only airlines from the selected country are included
287
+ sorted_fleet_avg_ages = filtered_fleet_avg_ages.sort_values(ascending=True)
288
+ plot_bar_graph(sorted_fleet_avg_ages, "Airline Fleet Average Ages", "Fleet Average Age")
289
+ elif comparison_option == "Founding Year":
290
+ founding_years = (pd.Series(get_airline_feature_dict("date_founded", "int"))).dropna() # Remove airlines with no founding year data
291
+ filtered_founding_years = founding_years[countries_of_origin == country_filter_option] # Ensure only airlines from the selected country are included
292
+ sorted_founding_years = filtered_founding_years.sort_values(ascending=True)
293
+ plot_bar_graph(sorted_founding_years, "Airline Founding Years", "Founding Year", bottom_ylim=1900) # Set y-axis minimum so years before 1900 since no airlines were founded before then