#!/usr/bin/env python
# coding: utf-8
# # Data Visualization with Python
# ## Part 2: Interactive Visualizations With Bokeh
# # Bokeh
#
# What is Bokeh?
# - A python library for browser based visualizations
#
# - Cross-platform
# - interactive plots
# - dashboards
# - data applications
#
# - High-performance interactivity over very large or streaming datasets
#
# - Tight integration with Jupyter and pandas
# - shareable, explorable data analysis notebooks
#
# - Large community
#
# - Active development
# # More information
#
# - Bokeh Homepage: https://bokeh.pydata.org
#
# - Bokeh Discussion Group: https://groups.google.com/a/continuum.io/forum/#!forum/bokeh
#
# - Userguide: https://bokeh.pydata.org/en/latest/docs/user_guide.html
#
# - API Reference: https://bokeh.pydata.org/en/latest/docs/reference.html
#
# - Gallery: https://bokeh.pydata.org/en/latest/docs/gallery.html
#
# - Tutorial: http://nbviewer.jupyter.org/github/bokeh/bokeh-notebooks/blob/master/index.ipynb#Tutorial
# # A Simple Example
#
# Create a scatterplot using the iris data from the previous lesson.
#
# Plot petal_width vs. petal_length.
#
# Colour each data point by species.
# In[1]:
# Import pandas for handling the data
import pandas as pd
# import some functions from the bokeh library
from bokeh.plotting import figure, output_notebook, show
# configure bokeh for notebook mode
output_notebook()
# In[2]:
# load the iris data set
iris_data = pd.read_csv('https://git.lumc.nl/courses/programming-course/raw/visualization-2018/visualization/data/iris.csv')
# Create a dictionary which maps a color to each species name
colormap = {
'setosa': 'orange',
'versicolor': 'green',
'virginica': 'blue'
}
# add a column to the dataframe which contains the color
iris_data['color'] = iris_data['species'].map(colormap)
# check that we now have a color column
iris_data.head()
# In[3]:
# Create a figure
iris_figure = figure(title = 'Iris Morphology')
# Label the x_axis
iris_figure.xaxis.axis_label = 'Petal Length'
# label the y_axis
iris_figure.yaxis.axis_label = 'Petal Width'
# Add some circles, using the iris_data dataframe as the data source
# plot the 'petal_length' column on the x axis,
# the 'petal_width' column on the y axis,
# and use the 'color' column for the circle color
iris_figure.circle(x='petal_length', y='petal_width', color='color',
source=iris_data, fill_alpha=0.5, size=10);
# In[4]:
# and finally, show it
show(iris_figure)
# # Add some more interactivity
# We can add tooltips to display information about each data point
# In[5]:
from bokeh.models import HoverTool
# Create a HoverTool which displays tooltips
# The tooltips are a list of tuples, where each tuple
# contains a text label to display, followed by a string
# indicating the column to display a value from
tooltips = HoverTool(
tooltips=[
("Petal Width", "@petal_width"),
("Petal Length", "@petal_length"),
("Species", "@species")
]
)
# add the tooltips to the figure
iris_figure.add_tools(tooltips)
# In[6]:
show(iris_figure)
# ```python
# # Here is all of the code for the final figure in one cell
#
# # Import pandas for handling the data
# import pandas as pd
#
# # import some functions from the bokeh library
# from bokeh.plotting import figure, output_notebook, show
# from bokeh.models import HoverTool
#
# # configure bokeh for notebook mode
# output_notebook()
#
# # load the iris data set
# iris_data = pd.DataFrame.from_csv('https://git.lumc.nl/courses/programming-course/raw/master/visualization/data/iris.csv')
#
# # Create a dictionary which maps a color to each species name
# colormap = {
# 'setosa': 'orange',
# 'versicolor': 'green',
# 'virginica': 'blue'
# }
#
# # add a column to the dataframe which contains the color
# iris_data['color'] = iris_data['species'].map(colormap)
#
# # Create a figure
# iris_figure = figure(title = 'Iris Morphology')
#
# # Label the x_axis
# iris_figure.xaxis.axis_label = 'Petal Length'
#
# # label the y_axis
# iris_figure.yaxis.axis_label = 'Petal Width'
#
# # Add the circles
# iris_figure.circle(x='petal_length', y='petal_width', color='color',
# source=iris_data, fill_alpha=0.5, size=10)
#
# # Create a HoverTool which displays tooltips
# tooltips = HoverTool(
# tooltips=[
# ("Petal Width", "@petal_width"),
# ("Petal Length", "@petal_length"),
# ("Species", "@species")
# ]
# )
#
# # add the tooltips to the figure
# iris_figure.add_tools(tooltips)
#
# # display the image
# show(iris_figure)
# ```
# # Let's make a data exploration tool!
#
# NASA have a data available which provides information about all large meteors which have exploded in the atmosphere since 1988.
#
# We will use that data set as the basis for an interactive data exploration tool.
# In[7]:
# load the data
fireball_data = pd.read_csv(
'https://git.lumc.nl/courses/programming-course/raw/visualization-2018/visualization/data/fireballs.csv'
)
# how does it look?
fireball_data.head()
# ## Tool Design
#
# - Basic Requirements
# - Display a map of the Earth
# - Overlay circles for each meteor event
# - Make the size of the circle proportional to the force of the explosion
# - Add tool-tips which give more information for each event
#
# - Advanced Requirements
# - Add a widget which allows us to filter the data for a single year
# In[8]:
# STEP 1
# Display a map of the earth
# the tile provider will display a map of the earth for us
import bokeh.tile_providers
# the earth is approx 40,000km in circumference
# or, -20,000km to +20,000km ==> -20,000,000m to +20,000,000m
# lets store this value:
map_limit = 20000000
# create a figure
fireball_fig = figure(x_range=(-map_limit, map_limit), y_range=(-map_limit, map_limit))
# hide the axes
fireball_fig.axis.visible = False
# Add a map tile
fireball_fig.add_tile(bokeh.tile_providers.STAMEN_TERRAIN);
# In[9]:
show(fireball_fig)
# ## Tool Design
#
# - Basic Requirements
# - Display a map of the Earth
# - **Overlay circles for each meteor event**
# In[10]:
# Now, we can plot a circle for each meteor,
# using the X and Y columns for the position
fireballs = fireball_fig.circle(x="X", y="Y", source=fireball_data)
show(fireball_fig)
# In[11]:
fireball_fig.renderers.remove(fireballs)
# ## Tool Design
#
# - Basic Requirements
# - Display a map of the Earth
# - Overlay circles for each meteor event
# - **Make the size of the circle proportional to the force of the explosion**
# In[12]:
# The force column represents the strength of the explosion, let's use it
# for the size of the circles. And let's change the color of the circles
# to something more 'fiery'
fireballs = fireball_fig.circle(
x="X", y="Y", size="force", source=fireball_data,
fill_color="orange", fill_alpha=0.6,
line_color="red", line_alpha=0.6
)
# In[13]:
show(fireball_fig)
# In[14]:
fireball_fig.renderers.remove(fireballs)
# In[15]:
# Maybe we need to scale the size of the circles a bit!
# We can add a column to the dataframe with the scaled force
# then use that for the circle size
from numpy import sqrt
fireball_data["size"] = 5 + sqrt(fireball_data.force) * 5
fireball_data.head()
# In[16]:
# update the circles to use the 'size' column
fireballs = fireball_fig.circle(
x="X", y="Y", size="size", source=fireball_data,
fill_color="orange", fill_alpha=0.6,
line_color="red", line_alpha=0.6
);
# In[17]:
show(fireball_fig)
# ## Tool Design
#
# - Basic Requirements
# - Display a map of the Earth
# - Overlay circles for each meteor event
# - Make the size of the circle proportional to the force of the explosion
# - **Add tool-tips which give more information for each event**
# In[18]:
from bokeh.models import HoverTool
# use the same syntax as with the iris data
tooltips = HoverTool(tooltips=[
("Date", "@day/@month/@year"),
("Lattitude", "@lattitude"),
("Longitude", "@longitude"),
("Energy (MJ)", "@energy"),
("Force (kT)", "@force")
])
fireball_fig.add_tools(tooltips)
# In[19]:
show(fireball_fig)
# ```python
# # The entire code so far
# # Import pandas for handling the data
# import pandas as pd
#
# # import some functions from the bokeh library
# from bokeh.plotting import figure, output_notebook, show
# from bokeh.models import HoverTool
# import bokeh.tile_providers
#
# # numpy sqrt function
# from numpy import sqrt
#
# # configure bokeh for notebook mode
# output_notebook()
#
# # load the data
# fireball_data = pd.DataFrame.from_csv(
# 'https://git.lumc.nl/courses/programming-course/raw/master/visualization/data/fireballs.csv'
# )
#
# # map boundary in km
# map_limit = 20000000
#
# # create a figure
# fireball_fig = figure(x_range=(-map_limit, map_limit), y_range=(-map_limit, map_limit))
#
# # hide the axes
# fireball_fig.axis.visible = False
#
# # Add a map tile
# fireball_fig.add_tile(bokeh.tile_providers.STAMEN_TERRAIN)
#
# # add a size column which is proportional to the force
# fireball_data["size"] = 5 + sqrt(fireball_data.force) * 5
#
# # add the circles
# fireballs = fireball_fig.circle(
# x="X", y="Y", size="size", source=fireball_data,
# fill_color="orange", fill_alpha=0.6,
# line_color="red", line_alpha=0.6
# );
#
# # add the tooltips
# tooltips = HoverTool(tooltips=[
# ("Date", "@day/@month/@year"),
# ("Lattitude", "@lattitude"),
# ("Longitude", "@longitude"),
# ("Energy (MJ)", "@energy"),
# ("Force (kT)", "@force")
# ])
#
# fireball_fig.add_tools(tooltips)
#
# # display it
# show(fireball_fig)
# ```
# # Final touches
#
# ## Tool Design
#
# - Basic Requirements
# - Display a map of the Earth
# - Overlay circles for each meteor event
# - Make the size of the circle proportional to the force of the explosion
# - Add tool-tips which give more information for each event
#
# - Advanced Requirements
# - **Add a widget which allows us to filter the data for a single year**
# ## Now it gets complicated.
#
# ## Don't panic if you don't get it.
#
# ## I just want to show you how powerful this stuff is.
# In[20]:
# make a list of all the available years
years = list(set(fireball_data.year))
print(years)
# In[21]:
# we can use the list of years to power a 'slider' widget
from ipywidgets import interact, SelectionSlider
# The slider will call this function with its value
# to begin with we will simply repeat the value given to us
def update_year(year):
print("Chosen year is {}".format(year))
# make the slider
fireball_slider = interact(
update_year,
year=SelectionSlider(description='year', options=years)
)
# Now we have a slider that feeds 'years' to the update_year function.
#
# We can now change the update_year function so that it modifies the data behind the figure to only display data for the chosen year.
#
# There are a few other things that need to be changed, I will show the final code and explain.
# In[22]:
# The final application
import pandas as pd
# import some functions from the bokeh library
from bokeh.plotting import figure, output_notebook, show
from bokeh.models import HoverTool, ColumnDataSource
import bokeh.tile_providers
from bokeh.io import push_notebook
# numpy sqrt function
from numpy import sqrt
# configure bokeh for notebook mode
output_notebook()
# load the data
fireball_data = pd.read_csv(
'https://git.lumc.nl/courses/programming-course/raw/master/visualization/data/fireballs.csv'
)
# make a list of the years for use later
years = list(set(fireball_data.year))
# map boundary in km
map_limit = 20000000
# create a figure
fireball_fig = figure(x_range=(-map_limit, map_limit), y_range=(-map_limit, map_limit))
# hide the axes
fireball_fig.axis.visible = False
# Add a map tile
fireball_fig.add_tile(bokeh.tile_providers.STAMEN_TERRAIN)
# add a size column which is proportional to the force
fireball_data["size"] = 5 + sqrt(fireball_data.force) * 5
# add the circles
fireballs = fireball_fig.circle(
x="X", y="Y", size="size", source=fireball_data,
fill_color="orange", fill_alpha=0.6,
line_color="red", line_alpha=0.6
);
# add the tooltips
tooltips = HoverTool(tooltips=[
("Date", "@day/@month/@year"),
("Lattitude", "@lattitude"),
("Longitude", "@longitude"),
("Energy (MJ)", "@energy"),
("Force (kT)", "@force")
])
fireball_fig.add_tools(tooltips)
# display it, and keep a handle to the figure
fireball_handle = show(fireball_fig, notebook_handle=True)
def update_fireballs(year=1988):
fireballs.data_source.data = ColumnDataSource(fireball_data[fireball_data["year"] == year]).data
fireball_fig.title.text = "Global Bolide Strikes {}".format(year)
push_notebook(handle=fireball_handle)
# make the slider
fireball_slider = interact(
update_fireballs,
year=SelectionSlider(description='year', options=years)
)
# # The End
#
# Author: Guy Allard
#
# License: Creative Commons Attribution 3.0 License (CC-by)
# In[ ]: