Let's Build a Flight Tracker Part 4: Explosion in San Francisco
Today in our python tutorial we are going use two new libraries: plotly and pandas. Plotly is a data visualization library and pandas is a statistical data analysis library. Both are very powerful tools. With these two libraries we can display our flight and airports on a beautiful map! I want to create something like an example I found implemented on the plotly website.
Meanwhile in Oakland California, a news helicopter just took off. The chopper belongs to KTVU2 News. KTVU is a Fox-affiliated television station. The website for the helicopter is below.
They haven't written anything about today yet. I have no idea why the chopper is in the air. Maybe we are ahead of the story! Lets create our map using their flight data. Fire up the tracker!
[bot@botnet plane]$ python tracker.py A815A1
Create a new python program titled plot.py.
import plotly.express as px import pandas as pd
Then we build two new Pandas DataFrames.
# Read the data from the "data.csv" file into a Pandas DataFrame data = pd.read_csv("data.csv") # Read the airport data from the "GlobalAirportDatabase.csv" file into a Pandas DataFrame airports = pd.read_csv("GlobalAirportDatabase.csv", header=None)
Add some code to create a boundary for the map. We're going to automatically center the map on the flight path with lon_min, lon_max, lat_min, and lat_max. lat_center and lon_center are the averages of these values where we will center the map. Since the GlobalAirportDatabase.csv file we created has no header, we'll have to assign some names for the columns as well.
# Calculate the minimum and maximum values of longitude and latitud lon_min = data["Longitude"].min() lon_max = data["Longitude"].max() lat_min = data["Latitude"].min() lat_max = data["Latitude"].max() # Calculate the center latitude and longitude lat_center = (lat_min + lat_max) / 2 long_center = (lon_min + lon_max) / 2 # Give the columns of the airport data meaningful names airports.columns = ["Name1", "Name2", "Name3", "Name4", "Name5", "Latitude", "Longitude"]e
We need to make a scatter plot of the airports and then add another trace on top to map the flight route.
# Create a scatter plot of the airports using Plotly Express fig = px.scatter_mapbox(airports, text="Name1", lat="Latitude", lon="Longitude", hover_name="Name3", color_discrete_sequence=["fuchsia"], zoom=5, height=600, center={"lat": lat_center, "lon": lon_center}) # Add a line trace to the plot to represent the flight route fig.add_scattermapbox( mode="text+lines", # Add both text labels and lines to the trace lat=data['Latitude'], # Latitude values lon=data['Longitude'], # Longitude values text=data['Time'], # Text labels connectgaps=False, # Connect the points in the line trace with lines showlegend=False # Do not show a legend for this trace )
And after that, I want to see each location where the airplane returns "On Ground" equal to "True" so another DataFrame needs to be created on top of the other two.
# Select only the rows in the DataFrame where the "On Ground" column is equal to True df_on_ground = data[data["On Ground"] == True] # Add a scatter mapbox trace for the locations where the flight was on the ground fig.add_scattermapbox( lat=df_on_ground["Latitude"], # Latitude values lon=df_on_ground["Longitude"], # Longitude values mode="markers", # Show markers instead of lines marker=dict( color="green", # Set marker color to green size=10, # Set marker size to 10 opacity=0.7 # Set marker opacity to 0.7 ), showlegend=False # Do not show a legend for this trace )
Finally, we set our map style, remove the margins around the plot, and show the plot.
# Set the mapbox style to "open-street-map" fig.update_layout(mapbox_style="open-street-map") # Remove the margins around the plot fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0}) # Show the plot fig.show()
Now lets execute the program.
python plot.py
Your browser will open up and instantiate the map.
This is really cool, all of our Airports from GlobalAirportDatabase.csv are displayed here. We no longer have to stare at the console all day!
I zoomed in on the KTVU 2 FOX News helicopter.
Here is the completed code for plot.py
import plotly.express as px import pandas as pd # Read the data from the "data.csv" file into a Pandas DataFrame data = pd.read_csv("data.csv") # Read the airport data from the "GlobalAirportDatabase.csv" file into a Pandas DataFrame airports = pd.read_csv("GlobalAirportDatabase.csv", header=None) # Calculate the minimum and maximum values of longitude and latitude lon_min = data["Longitude"].min() lon_max = data["Longitude"].max() lat_min = data["Latitude"].min() lat_max = data["Latitude"].max() # Calculate the center latitude and longitude lat_center = (lat_min + lat_max) / 2 lon_center = (lon_min + lon_max) / 2 # Give the columns of the airport data meaningful names airports.columns = ["Name1", "Name2", "Name3", "Name4", "Name5", "Latitude", "Longitude"] # Create a scatter plot of the airports using Plotly Express fig = px.scatter_mapbox(airports, text="Name1", lat="Latitude", lon="Longitude", hover_name="Name3", color_discrete_sequence=["fuchsia"], zoom=10, height=600, center={"lat": lat_center, "lon": lon_center}) # Add a line trace to the plot to represent the flight route fig.add_scattermapbox( mode="text+lines", # Add both text labels and lines to the trace lat=data['Latitude'], # Latitude values lon=data['Longitude'], # Longitude values text=data['Time'], # Text labels connectgaps=False, # Connect the points in the line trace with lines showlegend=False # Do not show a legend for this trace ) # Select only the rows in the DataFrame where the "On Ground" column is equal to True df_on_ground = data[data["On Ground"] == True] # Add a scatter mapbox trace for the locations where the flight was on the ground fig.add_scattermapbox( lat=df_on_ground["Latitude"], # Latitude values lon=df_on_ground["Longitude"], # Longitude values mode="markers", # Show markers instead of lines marker=dict( color="green", # Set marker color to green size=10, # Set marker size to 10 opacity=0.7 # Set marker opacity to 0.7 ), showlegend=False # Do not show a legend for this trace ) # Set the mapbox style to "open-street-map" fig.update_layout(mapbox_style="open-street-map") # Remove the margins around the plot fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0}) fig.show()
Update on the story, there is a House Fire in San Francisco, CA. The helicopter is on scene! A heavy fire from an explosion was threatening multiple homes. Ninety firefighters on scene, one person was transported to the hospital with multiple burns. Two firefighters with multiple injuries. The firefighters searched the nearby homes and found "no victims". Thank you Firefighters for your bravery and service.
The complete story is below. At the time I am writing this article, the cause of the fire is still unknown. Shout out to KTVU FOX 2 for covering this story.
This project is really coming together. Let's take a step back and reorganize things. I moved the haversine() method from tracker.py into it's own file. I did the same for get_nearest_airport(), get_current_time(), and create_datadatabase(). I already discussed these in previous tutorials and don't plan on changing them. My project folder now looks like this.
This is the current layout. I'm also going to make the project available on my Github. Feel free to play around with the code and suggest improvements like error handling.
More tutorials to come soon - Henry.