How to plot interactive points in a map using Python’s Plotly
By: Arnaldo Souza
Tags: Python, Kaggle, Data Science, UFO, Data Visualization

Introduction

The main goal of this tutorial is to plot points in a map in a webapp using Python. Thus, we’ll not explore in depth the process of cleaning the dataset we’ll use.

If everything goes as planned, at the end you’ll have a ngrok link to a dashboard pretty similar to the one below.

The dataset used is the UFO Sightings | Kaggle, which contains over 80,000 reports of UFO sightings over the last century, including, but no limited to, latitude, longitude, shape of the UFO, a comment about the sight and the date in which the sight happened.

We’ll use some of this and turn the whole world a map showing UFO sightnings. How cool is that?

Import libraries

We’ll use Plotly version 4.12 and dash components. Let’s install them:

!pip install Plotly==4.12 !pip install dash

!pip install dash-html-components

!pip install dash-core-components

!pip install dash-table



Let’s also import the usual(pandas, numpy, matplotlib, etc), the Plotly.express plus the server to serve our application:

import os.path

import sys, json

import requests

import subprocess import numpy as np

import pandas as pd

import plotly.express as px

import matplotlib.pyplot as plt from requests.exceptions import RequestException

from requests.adapters import HTTPAdapter

from requests.packages.urllib3.util.retry import Retry from collections import namedtuple

We’ll need a function to download ngrok and other to get the tunnel in which the app is served:



if not os.path.isfile('ngrok'):

!wget

!unzip -o ngrok-stable-linux-amd64.zip

pass def download_ngrok():if not os.path.isfile('ngrok'):!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip !unzip -o ngrok-stable-linux-amd64.zippass Response = namedtuple('Response', ['url','error']) def get_tunnel():

try:

Tunnel = subprocess.Popen(['./ngrok', 'http', '8050'])

retry = Retry(connect=3, backoff_factor=0.5)

adapter = HTTPAdapter(max_retries = retry)

session.mount(' session = requests.Session()retry = Retry(connect=3, backoff_factor=0.5)adapter = HTTPAdapter(max_retries = retry)session.mount(' http://' , adapter)

res.raise_for_status() res = session.get(' http://localhost:4040/api/tunnels' res.raise_for_status() tunnel_str = res.text

tunnel_cfg = json.loads(tunnel_str)

tunnel_url = tunnel_cfg['tunnels'][0]['public_url'] return Response(url=tunnel_url, error=None)

except RequestException as e:

return Response(url=None, error=str(e))

We’ll also need Kaggle’s api to fetch the data from Kaggle:

!pip install --upgrade kaggle

Though, you can also download the dataset in your computer by hand and uploading into your notebook.

Import dataset from Kaggle

Get your api keys in your Kaggle’s profile and upload it to colab with the default name (kaggle.json).

from google.colab import files !mkdir -p ~/.kaggle/ && mv kaggle.json ~/.kaggle/ && chmod 600 ~/.kaggle/kaggle.json !kaggle datasets download -d NUFORC/ufo-sightings data = pd.read_csv('scrubbed.csv') data.head()

Data Cleaning

We’ll need to clean the dataset a little bit so we can use it. The process below will make both latitude and longitude columns of floats and correct 24h format in datetime column. We also handled null data of the main columns and created a new one called year, which is the year from the datetime column.

Ps: it is very important that you save the dataframe using .to_csv() function. This will come handy when creating the code to serve our aplication later.

Plotting

We have a lot of data to use in this dataset. Shape being one of the most interesting, let’s first see it in a histogram, just so we see how it is distributed.

As we can see, UFOs come in all shapes and sizes, lol.

We can use this information as the color when scattering the points over the map.

fig_map_box = px.scatter_mapbox(df,

lat='latitude',

lon='longitude',

hover_data =['comments', 'shape', 'year'],

color='shape',

size_max=100,

mapbox_style='carto-darkmatter')

fig_map_box.update_layout(margin={'r':0, 't':0, 'l':0, 'b':0})

fig_map_box.show()

As you can see, plotly makes it really straight forward to make an interactive map as long as you have latitude and longitude as columns. The hover_data is the data you see when hovering over the points and the color the dataframe column to use as color.

Let’s also plot another scatter graph with a histogram and rug as marginals.

After the 40s we saw a lot more UFOs. Most in the US.

Finally, let’s serve an web aplication to show our creation.

%%writefile my_dash_app.py

import dash

import dash_core_components as dcc

import dash_html_components as html

import plotly.express as px

import pandas as pd external_stylesheets = [' https://codepen.io/chriddyp/pen/bWLwgP.css' app = dash.Dash(__name__, external_stylesheets=external_stylesheets) df = pd.read_csv("out.zip") fig_map_box = px.scatter_mapbox(df,

lat='latitude',

lon='longitude',

hover_data =['comments', 'shape', 'year'],

# size=50,

color='shape',

size_max=100,

# zoom=500,

mapbox_style='carto-darkmatter')

fig_map_box.update_layout(margin={'r':0, 't':0, 'l':0, 'b':0}) fig_scatter = px.scatter(df,

y="country",

x="year",

color='shape',

marginal_y='histogram',

marginal_x="rug")

fig_scatter.layout.template = "plotly_dark" app.layout = html.Div([

dcc.Graph(

id="mapbox-ufo-appearences",

figure = fig_map_box

),

dcc.Graph(

id="scatter-ufo-appearences",

figure = fig_scatter

)

]) if __name__ == '__main__':

app.run_server(debug=True, use_reloader=False)

Server file. This will be executed while serving.

One important thing to note is that we loaded our (out.zip) that we’ve exported earlier. This happens because this file has a completely different scope than the rest of the notebook. Thus, we do need to import all the dash stuff and pandas again and also read the dataframe.

Other important thing is the app.layout (line 26). The html.Div() function has an array of elements we want to show in our page. This is where we copy the figs we saw earlier.

Finally, let’s download ngrok and execute our server:

download_ngrok() return_ = get_tunnel()

print(return_) !python my_dash_app.py

To check your new creation, just enter in the first link:

You’ll have to wait a little to load all the data. Ngrok is also a factor.

Conclusion

As we could see. It’s pretty simple to make an interactive map showing points using Plotly.

Acknowledgements

This was a Data Science’s class exercise in which we had to plot, visualize and interact with data using maps in a web app. Many thanks to Andressa Oliveira and Ivanovitch Silva, from Federal University of Rio Grande do Norte, who made it much simpler to understand colab’s environment to serve web aplications and to scatter points over maps in colab’s environment using Kaggles dataset and API.