cognitiveclass.ai logo

Launch Sites Locations Analysis with Folium

Estimated time needed: 40 minutes

The launch success rate may depend on many factors such as payload mass, orbit type, and so on. It may also depend on the location and proximities of a launch site, i.e., the initial position of rocket trajectories. Finding an optimal location for building a launch site certainly involves many factors and hopefully we could discover some of the factors by analyzing the existing launch site locations.

In the previous exploratory data analysis labs, you have visualized the SpaceX launch dataset using matplotlib and seaborn and discovered some preliminary correlations between the launch site and success rates. In this lab, you will be performing more interactive visual analytics using Folium .

Objectives

This lab contains the following tasks:

  • TASK 1: Mark all launch sites on a map
  • TASK 2: Mark the success/failed launches for each site on the map
  • TASK 3: Calculate the distances between a launch site to its proximities

After completed the above tasks, you should be able to find some geographical patterns about launch sites.

Let's first import required Python packages for this lab:

In [1]:
# !pip3 install folium
# !pip3 install wget
In [2]:
import folium
# import wget
import pandas as pd
In [3]:
# Import folium MarkerCluster plugin
from folium.plugins import MarkerCluster
# Import folium MousePosition plugin
from folium.plugins import MousePosition
# Import folium DivIcon plugin
from folium.features import DivIcon

If you need to refresh your memory about folium, you may download and refer to this previous folium lab:

Task 1: Mark all launch sites on a map

First, let's try to add each site's location on a map using site's latitude and longitude coordinates

The following dataset with the name spacex_launch_geo.csv is an augmented dataset with latitude and longitude added for each site.

In [4]:
# Download and read the `spacex_launch_geo.csv`
# spacex_csv_file = wget.download('https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBM-DS0321EN-SkillsNetwork/datasets/spacex_launch_geo.csv')
# spacex_df=pd.read_csv(spacex_csv_file)
spacex_df=pd.read_csv("data/IBM-DS0321EN-SkillsNetwork/datasets/spacex_launch_geo.csv")

Now, you can take a look at what are the coordinates for each site.

In [5]:
# Select relevant sub-columns: `Launch Site`, `Lat(Latitude)`, `Long(Longitude)`, `class`
spacex_df = spacex_df[['Launch Site', 'Lat', 'Long', 'class']]
launch_sites_df = spacex_df.groupby(['Launch Site'], as_index=False).first()
launch_sites_df = launch_sites_df[['Launch Site', 'Lat', 'Long']]
launch_sites_df
Out[5]:
Launch Site Lat Long
0 CCAFS LC-40 28.562302 -80.577356
1 CCAFS SLC-40 28.563197 -80.576820
2 KSC LC-39A 28.573255 -80.646895
3 VAFB SLC-4E 34.632834 -120.610746

Above coordinates are just plain numbers that can not give you any intuitive insights about where are those launch sites. If you are very good at geography, you can interpret those numbers directly in your mind. If not, that's fine too. Let's visualize those locations by pinning them on a map.

We first need to create a folium Map object, with an initial center location to be NASA Johnson Space Center at Houston, Texas.

In [6]:
# Start location is NASA Johnson Space Center
nasa_coordinate = [29.559684888503615, -95.0830971930759]
site_map = folium.Map(location=nasa_coordinate, zoom_start=10)

We could use folium.Circle to add a highlighted circle area with a text label on a specific coordinate. For example,

In [7]:
# Create a blue circle at NASA Johnson Space Center's coordinate with a popup label showing its name
circle = folium.Circle(nasa_coordinate, radius=1000, color='#d35400', fill=True).add_child(folium.Popup('NASA Johnson Space Center'))
# Create a blue circle at NASA Johnson Space Center's coordinate with a icon showing its name
marker = folium.map.Marker(
    nasa_coordinate,
    # Create an icon as a text label
    icon=DivIcon(
        icon_size=(20,20),
        icon_anchor=(0,0),
        html='<div style="font-size: 12; color:#d35400;"><b>%s</b></div>' % 'NASA JSC',
        )
    )
site_map.add_child(circle)
site_map.add_child(marker)
Out[7]:
Make this Notebook Trusted to load map: File -> Trust Notebook

and you should find a small yellow circle near the city of Houston and you can zoom-in to see a larger circle.

Now, let's add a circle for each launch site in data frame launch_sites

TODO: Create and add folium.Circle and folium.Marker for each launch site on the site map

An example of folium.Circle:

folium.Circle(coordinate, radius=1000, color='#000000', fill=True).add_child(folium.Popup(...))

An example of folium.Marker:

folium.map.Marker(coordinate, icon=DivIcon(icon_size=(20,20),icon_anchor=(0,0), html='<div style="font-size: 12; color:#d35400;"><b>%s</b></div>' % 'label', ))

In [8]:
# Initial the map
site_map = folium.Map(location=nasa_coordinate, zoom_start=5)
# For each launch site, add a Circle object based on its coordinate (Lat, Long) values. In addition, add Launch site name as a popup label
for idx,row in launch_sites_df.iterrows():
    circle = folium.Circle([row['Lat'],row['Long']], radius=1000, color='#d35400', fill=True).add_child(folium.Popup(row['Launch Site']))
    marker = folium.map.Marker(
        [row['Lat'],row['Long']],
        # Create an icon as a text label
        icon=DivIcon(
            icon_size=(20,20),
            icon_anchor=(0,0),
            html='<div style="font-size: 12; color:#d35400;"><b>%s</b></div>' % row['Launch Site'],
            )
        )
    site_map.add_child(circle)
    site_map.add_child(marker)
site_map
Out[8]:
Make this Notebook Trusted to load map: File -> Trust Notebook

The generated map with marked launch sites should look similar to the following:

Now, you can explore the map by zoom-in/out the marked areas , and try to answer the following questions:

  • Are all launch sites in proximity to the Equator line?
  • Are all launch sites in very close proximity to the coast?

Also please try to explain your findings.

Task 2: Mark the success/failed launches for each site on the map

Next, let's try to enhance the map by adding the launch outcomes for each site, and see which sites have high success rates. Recall that data frame spacex_df has detailed launch records, and the class column indicates if this launch was successful or not

In [9]:
spacex_df.tail(10)
Out[9]:
Launch Site Lat Long class
46 KSC LC-39A 28.573255 -80.646895 1
47 KSC LC-39A 28.573255 -80.646895 1
48 KSC LC-39A 28.573255 -80.646895 1
49 CCAFS SLC-40 28.563197 -80.576820 1
50 CCAFS SLC-40 28.563197 -80.576820 1
51 CCAFS SLC-40 28.563197 -80.576820 0
52 CCAFS SLC-40 28.563197 -80.576820 0
53 CCAFS SLC-40 28.563197 -80.576820 0
54 CCAFS SLC-40 28.563197 -80.576820 1
55 CCAFS SLC-40 28.563197 -80.576820 0

Next, let's create markers for all launch records. If a launch was successful (class=1) , then we use a green marker and if a launch was failed, we use a red marker (class=0)

Note that a launch only happens in one of the four launch sites, which means many launch records will have the exact same coordinate. Marker clusters can be a good way to simplify a map containing many markers having the same coordinate.

Let's first create a MarkerCluster object

In [10]:
marker_cluster = MarkerCluster()

TODO: Create a new column in launch_sites dataframe called marker_color to store the marker colors based on the class value

In [11]:
# Apply a function to check the value of `class` column
# If class=1, marker_color value will be green
# If class=0, marker_color value will be red
spacex_df = spacex_df.assign(marker_color=lambda x:['green' if c==1 else 'red' for c in x['class']])
spacex_df.tail(10)
Out[11]:
Launch Site Lat Long class marker_color
46 KSC LC-39A 28.573255 -80.646895 1 green
47 KSC LC-39A 28.573255 -80.646895 1 green
48 KSC LC-39A 28.573255 -80.646895 1 green
49 CCAFS SLC-40 28.563197 -80.576820 1 green
50 CCAFS SLC-40 28.563197 -80.576820 1 green
51 CCAFS SLC-40 28.563197 -80.576820 0 red
52 CCAFS SLC-40 28.563197 -80.576820 0 red
53 CCAFS SLC-40 28.563197 -80.576820 0 red
54 CCAFS SLC-40 28.563197 -80.576820 1 green
55 CCAFS SLC-40 28.563197 -80.576820 0 red
In [12]:
# Function to assign color to launch outcome
def assign_marker_color(launch_outcome):
    if launch_outcome == 1:
        return 'green'
    else:
        return 'red'
    
spacex_df['marker_color'] = spacex_df['class'].apply(assign_marker_color)
spacex_df.tail(10)
Out[12]:
Launch Site Lat Long class marker_color
46 KSC LC-39A 28.573255 -80.646895 1 green
47 KSC LC-39A 28.573255 -80.646895 1 green
48 KSC LC-39A 28.573255 -80.646895 1 green
49 CCAFS SLC-40 28.563197 -80.576820 1 green
50 CCAFS SLC-40 28.563197 -80.576820 1 green
51 CCAFS SLC-40 28.563197 -80.576820 0 red
52 CCAFS SLC-40 28.563197 -80.576820 0 red
53 CCAFS SLC-40 28.563197 -80.576820 0 red
54 CCAFS SLC-40 28.563197 -80.576820 1 green
55 CCAFS SLC-40 28.563197 -80.576820 0 red

TODO: For each launch result in spacex_df data frame, add a folium.Marker to marker_cluster

In [13]:
# Add marker_cluster to current site_map
site_map.add_child(marker_cluster)

# for each row in spacex_df data frame
# create a Marker object with its coordinate
# and customize the Marker's icon property to indicate if this launch was successed or failed, 
# e.g., icon=folium.Icon(color='white', icon_color=row['marker_color']
for index, row in spacex_df.iterrows():
    # TODO: Create and add a Marker cluster to the site map
    # marker = folium.Marker(...)
    marker = folium.map.Marker(
        [row['Lat'],row['Long']],
        icon=folium.Icon(color='white', icon_color=row['marker_color'])
        )
    marker_cluster.add_child(marker)

site_map
Out[13]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Your updated map may look like the following screenshots:

From the color-labeled markers in marker clusters, you should be able to easily identify which launch sites have relatively high success rates.

TASK 3: Calculate the distances between a launch site to its proximities

Next, we need to explore and analyze the proximities of launch sites.

Let's first add a MousePosition on the map to get coordinate for a mouse over a point on the map. As such, while you are exploring the map, you can easily find the coordinates of any points of interests (such as railway)

In [14]:
# Add Mouse Position to get the coordinate (Lat, Long) for a mouse over on the map
formatter = "function(num) {return L.Util.formatNum(num, 5);};"
mouse_position = MousePosition(
    position='topright',
    separator=' Long: ',
    empty_string='NaN',
    lng_first=False,
    num_digits=20,
    prefix='Lat:',
    lat_formatter=formatter,
    lng_formatter=formatter,
)

site_map.add_child(mouse_position)
site_map
Out[14]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Now zoom in to a launch site and explore its proximity to see if you can easily find any railway, highway, coastline, etc. Move your mouse to these points and mark down their coordinates (shown on the top-left) in order to the distance to the launch site.

You can calculate the distance between two points on the map based on their Lat and Long values using the following method:

In [15]:
from math import sin, cos, sqrt, atan2, radians

def calculate_distance(lat1, lon1, lat2, lon2):
    # approximate radius of earth in km
    R = 6373.0

    lat1 = radians(lat1)
    lon1 = radians(lon1)
    lat2 = radians(lat2)
    lon2 = radians(lon2)

    dlon = lon2 - lon1
    dlat = lat2 - lat1

    a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))

    distance = R * c
    return distance

TODO: Mark down a point on the closest coastline using MousePosition and calculate the distance between the coastline point and the launch site.

In [16]:
# find coordinate of the closet coastline
# e.g.,: Lat: 28.56367  Lon: -80.57163
launch_site_lat=28.56326
launch_site_lon=-80.57684
coastline_lat=28.56401
coastline_lon=-80.56811
distance_coastline = calculate_distance(launch_site_lat, launch_site_lon, coastline_lat, coastline_lon)
distance_coastline
Out[16]:
0.8569186317390074

TODO: After obtained its coordinate, create a folium.Marker to show the distance

In [17]:
# Create and add a folium.Marker on your selected closest coastline point on the map
# Display the distance between coastline point and launch site using the icon property 
# for example
# distance_marker = folium.Marker(
#    coordinate,
#    icon=DivIcon(
#        icon_size=(20,20),
#        icon_anchor=(0,0),
#        html='<div style="font-size: 12; color:#d35400;"><b>%s</b></div>' % "{:10.2f} KM".format(distance),
#        )
#    )

distance_marker = folium.Marker(
   [coastline_lat,coastline_lon],
   icon=DivIcon(
       icon_size=(20,20),
       icon_anchor=(0,0),
       html='<div style="font-size: 12; color:#d35400;"><b>%s</b></div>' % "{:10.2f} KM".format(distance_coastline),
       )
   )
site_map.add_child(distance_marker)
site_map
Out[17]:
Make this Notebook Trusted to load map: File -> Trust Notebook

TODO: Draw a PolyLine between a launch site to the selected coastline point

In [18]:
# Create a `folium.PolyLine` object using the coastline coordinates and launch site coordinate
# lines=folium.PolyLine(locations=coordinates, weight=1)
lines=folium.PolyLine(locations=[[launch_site_lat,launch_site_lon],[coastline_lat,coastline_lon]], weight=1)
site_map.add_child(lines)
site_map
Out[18]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Your updated map with distance line should look like the following screenshot:

TODO: Similarly, you can draw a line betwee a launch site to its closest city, railway, highway, etc. You need to use MousePosition to find the their coordinates on the map first

A railway map symbol may look like this:

A highway map symbol may look like this:

A city map symbol may look like this:

In [19]:
# Create a marker with distance to a closest city, railway, highway, etc.
# Draw a line between the marker to the launch site
In [20]:
proximities_df = spacex_df.groupby('Launch Site').first()[['Lat','Long']].assign(Proximity=lambda x:['self' for i in range(len(x))]).set_index('Proximity', append=True)

proximities_df.loc[('CCAFS LC-40','coastline'),['Lat','Long']] = 28.5634,-80.56796
proximities_df.loc[('CCAFS LC-40','railway'),['Lat','Long']] = 28.57217,-80.58528
proximities_df.loc[('CCAFS LC-40','highway'),['Lat','Long']] = 28.56301,-80.57076
proximities_df.loc[('CCAFS LC-40','city'),['Lat','Long']] = 28.10469,-80.64784

proximities_df.loc[('CCAFS SLC-40','coastline'),['Lat','Long']] = 28.56409,-80.56806
proximities_df.loc[('CCAFS SLC-40','railway'),['Lat','Long']] = 28.57217,-80.58528
proximities_df.loc[('CCAFS SLC-40','highway'),['Lat','Long']] = 28.56385,-80.57088
proximities_df.loc[('CCAFS SLC-40','city'),['Lat','Long']] = 28.10469,-80.64784

proximities_df.loc[('KSC LC-39A','coastline'),['Lat','Long']] = 28.60283,-80.58815
proximities_df.loc[('KSC LC-39A','railway'),['Lat','Long']] = 28.57314,-80.65398
proximities_df.loc[('KSC LC-39A','highway'),['Lat','Long']] = 28.57307,-80.65553
proximities_df.loc[('KSC LC-39A','city'),['Lat','Long']] = 28.10469,-80.64784

proximities_df.loc[('VAFB SLC-4E','coastline'),['Lat','Long']] = 34.6347,-120.62531
proximities_df.loc[('VAFB SLC-4E','railway'),['Lat','Long']] = 34.63585,-120.62401
proximities_df.loc[('VAFB SLC-4E','highway'),['Lat','Long']] = 34.7048,-120.5694
proximities_df.loc[('VAFB SLC-4E','city'),['Lat','Long']] = 34.64253,-120.47331

proximities_df = proximities_df.query("Proximity == 'self'").reset_index("Proximity",drop=True).join(
    proximities_df.query("Proximity != 'self'").reset_index("Proximity", drop=False),
    lsuffix="LaunchSite"
).assign(
    distance=lambda x:[calculate_distance(row['LatLaunchSite'], row['LongLaunchSite'], row['Lat'], row['Long']) for idx,row in x.iterrows()]
).set_index("Proximity", append=True)
proximities_df
Out[20]:
LatLaunchSite LongLaunchSite Lat Long distance
Launch Site Proximity
CCAFS LC-40 coastline 28.562302 -80.577356 28.56340 -80.56796 0.926053
railway 28.562302 -80.577356 28.57217 -80.58528 1.343094
highway 28.562302 -80.577356 28.56301 -80.57076 0.649221
city 28.562302 -80.577356 28.10469 -80.64784 51.365738
CCAFS SLC-40 coastline 28.563197 -80.576820 28.56409 -80.56806 0.861525
railway 28.563197 -80.576820 28.57217 -80.58528 1.295798
highway 28.563197 -80.576820 28.56385 -80.57088 0.584818
city 28.563197 -80.576820 28.10469 -80.64784 51.471475
KSC LC-39A coastline 28.573255 -80.646895 28.60283 -80.58815 6.613767
railway 28.573255 -80.646895 28.57314 -80.65398 0.692172
highway 28.573255 -80.646895 28.57307 -80.65553 0.843713
city 28.573255 -80.646895 28.10469 -80.64784 52.118441
VAFB SLC-4E coastline 34.632834 -120.610746 34.63470 -120.62531 1.349001
railway 34.632834 -120.610746 34.63585 -120.62401 1.259452
highway 34.632834 -120.610746 34.70480 -120.56940 8.853369
city 34.632834 -120.610746 34.64253 -120.47331 12.623668
In [21]:
proximities_df.groupby(level='Proximity')['distance'].mean()
Out[21]:
Proximity
city         41.894831
coastline     2.437587
highway       2.732780
railway       1.147629
Name: distance, dtype: float64
In [22]:
for idx,row in proximities_df.iterrows():
        
    distance_marker = folium.Marker(
        [row['Lat'], row['Long']],
        icon=DivIcon(
            icon_size=(20,20),
            icon_anchor=(0,0),
            html='<div style="font-size: 12; color:#d35400;"><b>%s</b></div>' % "{:10.2f} KM".format(row['distance']),
        )
    )
    site_map.add_child(distance_marker)
    
    lines=folium.PolyLine(locations=[[row['LatLaunchSite'], row['LongLaunchSite']], [row['Lat'], row['Long']]], weight=1)
    site_map.add_child(lines)
site_map
Out[22]:
Make this Notebook Trusted to load map: File -> Trust Notebook

After you plot distance lines to the proximities, you can answer the following questions easily:

  • Are launch sites in close proximity to railways?
  • Are launch sites in close proximity to highways?
  • Are launch sites in close proximity to coastline?
  • Do launch sites keep certain distance away from cities?

Also please try to explain your findings.

Next Steps:

Now you have discovered many interesting insights related to the launch sites' location using folium, in a very interactive way. Next, you will need to build a dashboard using Ploty Dash on detailed launch records.

Authors

Other Contributors

Joseph Santarcangelo

Change Log

Date (YYYY-MM-DD) Version Changed By Change Description
2021-05-26 1.0 Yan Created the initial version

Copyright © 2021 IBM Corporation. All rights reserved.