Airline Analysis is fascinating. It’s where incredible engineering, complex logistics, and human stories meet 30,000 feet above the ground. But have you ever thought about how airlines create their routes and the stories those routes tell? In this blog, we’ll explore how to analyze airline routes, gather related news, show relevant images, and map these routes using Aviationstack, Python, Flask, and a bit of AI.
By the end of this blog, we’ll provide you with the code to:
- Analyze airline routes using reliable data sources.
- Collect and understand news about airlines.
- Show relevant images to improve user understanding.
- Map and explore these routes on a map.
- Use AI, like OpenAI’s GPT-4, to create informative narratives about selected routes.
- Use tools like requests, Plotly Express, Pandas, and Geopy for smooth functioning.
- Create a user-friendly interface with Flask, accessible to everyone.
This blog aims to equip readers with the knowledge and code to build a platform that explains airline route networks and their stories. Whether you’re a data enthusiast, developer, or just curious about aviation, this blog will give you insights into data, visualization, and AI in airline analysis.
Giving users control from a web page to perform airline analysis of their choice from the dropdown menu.
Retrieving flight route data from Aviationstack API and passing it to Mapbox. Providing a commentary about the flight routes and destinations using GPT-4.
Retrieving news and image data from Google using Zenserp API.
Our solution integrates a suite of specialized tools and APIs:
- requests: Facilitates data retrieval from various APIs.
- Plotly Express: Employs advanced graphics capabilities to visually represent airline routes on interactive maps.
- Pandas: Provides robust capabilities for data manipulation and analysis.
- Geopy: Converts city or airport names into precise geographical coordinates.
- OpenAI: Uses the GPT-4 model to generate descriptive content related to airline routes and their narratives.
Table of Contents
Flask as the Web Framework
Flask is our chosen lightweight web framework for Python. It supports the rapid development of this application, with a primary interface where users can view an airline’s routes, read about its history, and access the latest news and images.
Data Processing and Visualization
- Data Retrieval: We utilize the aviationstack API, a rich source of information on airline routes, associated airports, and the types of aircraft in use.
- AI-Powered Narratives: After processing the data, we employ OpenAI’s GPT-4 model. This offers users a detailed description of the airline’s history, its primary routes, and unique experiences.
- Visualization: Plotly Express enables us to represent these routes on a map, with the Nominatim service from Geopy converting airport names to geographical coordinates for precision.
Updates on News and Images
We integrate the Zenserp API to continually update the application with:
- News: The latest developments related to an airline, including new route launches or mergers.
- Images: Visuals that showcase the branding and aesthetics of the airline’s fleet.
Interactivity and UI
The Flask-powered user interface boasts:
- Dropdown Menu: Allows users to select from an extensive list of airlines.
- Integrated Results: Displays visualized routes, narratives generated by GPT-4, current news, and related images upon selection.
Optimization Strategies
We have implemented certain best practices for efficiency:
- Caching: We’ve incorporated a caching mechanism to reduce redundancy in geolocation queries.
- Environment Variables for API Keys: API keys are sourced from environment variables for enhanced security and adaptability.
Deployment Overview with PythonAnywhere
Deploying our application is crucial to reach a global audience. To achieve this, we’ve chosen PythonAnywhere, an ideal platform for Python web applications.
Our application’s core lies in the union of flask_app.py and templates/airlines.html. The former manages data processes, API interactions, and routing, while the latter visualizes this data for users. This combination ensures the application is not only functional but also globally accessible. With this structure, we seamlessly bridge backend operations and frontend visuals, immersing users in the airline domain.
Key Aspects of the Deployment:
Deployment Platform
We’ve adopted PythonAnywhere, tailoring our application for global accessibility.
- WSGI Configuration:
- Adjusts system path to pinpoint project files.
- Configures environment variables, enhancing security by preventing hardcoded sensitive data.
- Prepares the Flask app to be the main touchpoint for web requests.
- Flask Application Components:
- flask_app.py: The Flask application’s nucleus. It oversees component management, routing, and user interfacing.
- Sets up initial configurations, including necessary imports.
- Carves out navigation paths, pinpointing the primary route.
- templates/airlines.html: Steers the user interface and data portrayal.
- Leverages Jinja2 for fluid data representation.
- Incorporates interactive elements like maps and charts.
- Facilitates user interactions through various UI elements
In essence, by harnessing Python, Flask, and PythonAnywhere, we’ve crafted a comprehensive tool for airline insights, enabling users to delve deeply into the world of aviation.
How to Find and Edit Files on PythonAnywhere for Airline Analysis:
- Login to PythonAnywhere:
Begin by logging in to your PythonAnywhere account.
- Access the Dashboard:
Once logged in, you’ll be directed to your dashboard. This dashboard displays an array of options, such as ‘Files’, ‘Consoles’, ‘Web’, and more.
For templates/airlines.html
:
- Navigate to ‘Files’:
On the dashboard, click on the ‘Files’ tab.
- Locate the ‘templates’ Directory:
Browse through the list of directories and files to find the ‘templates’ directory.
- Open / create
airlines.html
:
Inside the ‘templates’ directory, find and click on the airlines.html
file to open it.
- Input Your Code:
Here, you can paste or write the code intended for airlines.html
. Once done, save the changes.
airlines.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Airline Analysis</title> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 2rem; background-color: #e6e6e6; color: #333; } h2 { text-align: center; color: #007bff; margin-bottom: 2rem; } form { display: flex; flex-direction: column; align-items: center; gap: 1.5rem; background-color: #fff; padding: 2rem; border-radius: 7px; box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.1); } label, select, input { width: 80%; padding: 0.7rem; border-radius: 5px; border: 1px solid #ccc; } select:focus, input:focus { outline: none; border-color: #007bff; box-shadow: 0px 0px 5px rgba(0, 123, 255, 0.5); } input[type="submit"] { width: 40%; cursor: pointer; background-color: #007bff; color: #fff; border: none; transition: background-color 0.3s ease; } input[type="submit"]:hover { background-color: #0056b3; } #map, #analysis, section { margin-top: 2rem; background-color: #fff; padding: 2rem; border-radius: 7px; box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.1); } #analysis { margin-top: 1rem; } ul { list-style-type: none; padding: 0; } li { margin-bottom: 1rem; } a { color: #007bff; text-decoration: none; } a:hover { text-decoration: underline; } p { margin-top: 0.5rem; font-size: 0.9em; color: #555; } </style> </head> <body> <h2>Airline Analysis for {{ request.form['airline'] if request.method == 'POST' else 'Choose an airline' }}</h2> <form action="/airlines" method="post"> <label for="airline">Select an Airline:</label> <select name="airline" id="airline"> {% for airline in airlines %} <option value="{{ airline }}" {% if request.form['airline'] == airline %}selected{% endif %}>{{ airline }}</option> {% endfor %} </select> <input type="submit" value="Analyze"> </form> <div id="map">{{ map_html|safe if map_html }}</div> <div id="analysis">{{ analysis|safe if analysis }}</div> <section> <h2>Recent News</h2> <ul> {% for news_item in news_data %} <li> <a href="{{ news_item.link }}" target="_blank">{{ news_item.title }}</a> <p>{{ news_item.description }}</p> </li> {% endfor %} </ul> </section> <section> <h2>Airline Images</h2> <div> {% for image_link in image_links %} <img src="{{ image_link }}" alt="Airline related image" style="width: 150px; height: 150px; margin: 10px;"> {% endfor %} </div> </section> </body> </html> |
For flask_app.py
:
- **Back to ‘Files’ Directory**:
If not already there, click on the ‘Files’ tab on the dashboard.
- **Find
flask_app.py
**:
Browse the directory to locate the flask_app.py
file.
- **Edit the File**:
Click on flask_app.py
to open it. Paste or write your desired code and remember to save the changes afterward.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
from flask import Flask, render_template, request import requests import plotly.express as px import pandas as pd from geopy.geocoders import Nominatim import openai import os # for accessing environment variables #app = Flask(__name__) # Access API keys from environment variables (you'd set these on PythonAnywhere) MAPBOX_ACCESS_TOKEN = os.environ.get('MAPBOX_ACCESS_TOKEN') access_key = os.environ.get('AVIATIONSTACK_ACCESS_KEY') openai.api_key = os.environ.get('OPENAI_API_KEY') ZENSERP_API_KEY = os.environ.get('ZENSERP_API_KEY') # Setting up for geocoding caching geo_cache = {} def analyze_competitor_routes(info, airline_name): # Setting the stage for a travel-inspired journey prompt = f"Welcome to {airline_name}! With every takeoff, we embark on a new tale of discovery and wonder. 💼✈️\n\n" prompt += f"Sailing through the skies is our majestic fleet of {', '.join(info['aircraft'])}, each ready to lead you to a world of marvels.\n\n" prompt += "Come, let us paint a canvas of destinations, where every stroke tells a tale:\n" for i, route in enumerate(info['routes']): route_descriptions = [ f"• From the bustling bylanes of {route[0]} to the serene vistas of {route[1]}", f"• Setting sail from the melodies of {route[0]} to the harmonies of {route[1]}", f"• Bridging the tales of old in {route[0]} with the future's echo in {route[1]}", f"• Glide from {route[0]}'s timeless allure to {route[1]}'s modern charm", f"• Traverse the cultural tapestry of {route[0]} and land amidst the festivities of {route[1]}" ] prompt += route_descriptions[i % len(route_descriptions)] + "\n" prompt += "\nDear explorer, as the horizon beckons, what mysteries do these places conceal? Share their stories, and let our passengers dream of the adventures that await." # Craft a chat-based message, sharing notes with a fellow travel enthusiast messages = [{"role": "user", "content": prompt}] # Fetch traveler tales from GPT-4 response = openai.ChatCompletion.create( model="gpt-4", messages=messages, temperature=0.7, max_tokens=1200, top_p=1, frequency_penalty=0, presence_penalty=0 ) # Glean the travel insights sightseeing_ideas = response['choices'][0]['message']['content'].strip() return sightseeing_ideas def get_airports_and_aircraft(access_key, airline_name): url = "http://api.aviationstack.com/v1/flights" params = { "access_key": access_key, "airline_name": airline_name } response = requests.get(url, params=params) if response.status_code != 200: print(f"Error: Received status code {response.status_code}") return {"airports": [], "aircraft": [], "routes": []} data = response.json() if 'data' not in data: print(f"Unexpected response structure: {data}") return {"airports": [], "aircraft": [], "routes": []} # Extract unique airports and aircraft airports = set() aircraft = set() routes = set() # added for unique departure-arrival combinations for flight in data['data']: # Add departure and arrival airports departure_airport = flight.get('departure', {}).get('airport') arrival_airport = flight.get('arrival', {}).get('airport') if departure_airport: airports.add(departure_airport) if arrival_airport: airports.add(arrival_airport) # Add aircraft details aircraft_data = flight.get('aircraft') if aircraft_data: aircraft_registration = aircraft_data.get('registration') if aircraft_registration: aircraft.add(aircraft_registration) # Add unique departure-arrival combinations if departure_airport and arrival_airport: routes.add((departure_airport, arrival_airport)) return { "airports": list(airports), "aircraft": list(aircraft), "routes": list(routes) } def get_coordinates(city_name): if city_name in geo_cache: return geo_cache[city_name] geolocator = Nominatim(user_agent="myUniqueAirlineAnalysisApp") location = geolocator.geocode(city_name) if location: coords = (location.latitude, location.longitude) geo_cache[city_name] = coords return coords return None def generate_mapbox_plot(info): data_list = [{'Airport': airport, 'Latitude': coords[0], 'Longitude': coords[1]} for airport in info["airports"] if (coords := get_coordinates(airport))] df = pd.DataFrame(data_list) fig = px.scatter_mapbox(df, lat='Latitude', lon='Longitude', hover_name='Airport', hover_data={'Latitude': True, 'Longitude': True}, mapbox_style="carto-positron", zoom=5, height=800) for route in info["routes"]: start_coords = get_coordinates(route[0]) end_coords = get_coordinates(route[1]) if start_coords and end_coords: fig.add_trace(px.line_mapbox(pd.DataFrame([start_coords, end_coords], columns=['Latitude', 'Longitude']), lat='Latitude', lon='Longitude').data[0]) return fig.to_html() @app.route('/airlines', methods=['GET', 'POST']) def airlines(): news_data = [] image_links = [] if request.method == 'POST': selected_airline = request.form.get('airline') info = get_airports_and_aircraft(access_key, selected_airline) analysis_result = analyze_competitor_routes(info, selected_airline) map_html = generate_mapbox_plot(info) news_data = get_airline_news(selected_airline) image_links = get_airline_images(selected_airline) return render_template('airlines.html', airlines=AIRLINES, map_html=map_html, analysis=analysis_result, news_data=news_data, image_links=image_links) return render_template('airlines.html', airlines=AIRLINES, map_html=None, analysis=None, news_data=news_data, image_links=image_links) # Sample list of airline names (replace with actual list from the API or another source if necessary) AIRLINES = [ "Loganair", "Ravn Alaska", "Air Chathams", "Air Choice One", "Boutique Air", "Cape Air", "Island Air Service", "Kenmore Air", "PenAir", "Silver Airways", "Skytrans", "Air Bishkek", "Aurigny Air Services", "Blue Islands", "Isle of Man Air Services", "Air Panama", "Air Rarotonga" ] def get_airline_news(airline_name, num_results=5): """ Fetch the latest news related to the airline using Zenserp. """ BASE_URL = "https://app.zenserp.com/api/v2/search" params = { 'q': f"{airline_name} news", 'tbm': 'nws', 'location': 'United States', 'search_engine': 'google.com', 'apikey': ZENSERP_API_KEY } response = requests.get(BASE_URL, params=params) if response.status_code != 200: print(f"Error: Received status code {response.status_code}") return [] data = response.json() news_results = [] for result in data['news_results'][:num_results]: title = result.get('title') description = result.get('description') link = result.get('link') news_results.append({ 'title': title, 'description': description, 'link': link }) return news_results def get_airline_images(airline_name, num_results=10): BASE_URL = "https://app.zenserp.com/api/v2/search" params = { 'q': f"{airline_name} aircraft", 'tbm': 'isch', 'location': 'United States', 'search_engine': 'google.com', 'apikey': ZENSERP_API_KEY } response = requests.get(BASE_URL, params=params) if response.status_code != 200: return [] data = response.json() image_results = data.get('image_results', [])[:num_results] return [item['sourceUrl'] for item in image_results] |
For WSGI Configuration of Airline Analysis:
- Head to the ‘Web’ Tab:
Go back to your dashboard and select the ‘Web’ tab.
- WSGI Configuration File:
In the web application settings, locate the section labeled ‘WSGI Configuration File’. You’ll see a link to the file path, which typically looks like /var/www/your-user-name_pythonanywhere_com_wsgi.py
.
- Open and Edit:
Click on the link to open the file. Here, input the necessary WSGI configuration code. Ensure you save the file after making your edits.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# This file contains the WSGI configuration required to serve up your # web application at http://<your-username>.pythonanywhere.com/ # It works by setting the variable 'application' to a WSGI handler of some # description. import sys # add your project directory to the sys.path project_home = '/home/your-username/mysite' if project_home not in sys.path: sys.path = [project_home] + sys.path # Set environment variables before importing your Flask app import os os.environ['MAPBOX_ACCESS_TOKEN'] = 'YOUR API KEY' os.environ['AVIATIONSTACK_ACCESS_KEY'] = 'YOUR API KEY' os.environ['OPENAI_API_KEY'] = 'YOUR API KEY' os.environ['ZENSERP_API_KEY'] = 'YOUR API KEY' # Now import flask app but need to call it "application" for WSGI to work from flask_app import app as application |
Remember: Always ensure that your code is correctly formatted and free of errors before saving to avoid potential issues when running your application.
Airline Analysis: Conclusion
This project underscores the potential of integrating data analysis, visualization, and AI in a streamlined web interface. It offers value not just to travelers and aviation enthusiasts, but also to industry professionals and data analysts. As the skies become busier, understanding the networks and narratives that shape air travel becomes increasingly vital. We believe this tool serves as a significant step in that direction.
Airline Analysis: FAQs
1. How Does the App Perform Airline Analysis?
It uses a special tool to get information about where airlines fly and the types of planes they use.
2. How Does the App Find News About Airlines?
It looks for the latest stories about airlines to keep users up to date.
3. How Can Users See Airline Routes on a Map?
Users can pick an airline from a list, and the app shows where that airline flies on a map that users can interact with.
4. Which API Is Used in This App for Airline Analysis?
Aviationstack is used in this app.
Sign Up for free at Aviationstack to get 100 free API requests.