What is Bokeh?
Create a scatterplot using the iris data from the previous lesson.
Plot petal_width vs. petal_length.
Colour each data point by species.
# 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()
sepal_length | sepal_width | petal_length | petal_width | species | color | |
---|---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa | orange |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa | orange |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa | orange |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa | orange |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa | orange |
# 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);
# and finally, show it
show(iris_figure)
We can add tooltips to display information about each data point
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)
show(iris_figure)
# 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)
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.
# 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()
alt | vel | radiance | force | year | month | day | lattitude | longitude | X | Y | energy | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | NaN | 5.800000e+10 | 0.19 | 2017 | 7 | 31 | -118.5 | 24.7 | -1.319136e+07 | 2.838941e+06 | 58000.0 |
1 | 38.0 | 17.2 | 3.500000e+10 | 0.12 | 2017 | 7 | 23 | -69.7 | -6.6 | -7.758969e+06 | -7.363389e+05 | 35000.0 |
2 | 35.0 | 13.7 | 7.300000e+10 | 0.23 | 2017 | 7 | 13 | 60.7 | 23.1 | 6.757093e+06 | 2.644116e+06 | 73000.0 |
3 | 20.0 | 15.2 | 9.400000e+10 | 0.29 | 2017 | 6 | 30 | 134.5 | -34.3 | 1.497247e+07 | -4.069156e+06 | 94000.0 |
4 | 35.1 | 24.3 | 1.840000e+11 | 0.52 | 2017 | 6 | 23 | 143.7 | 57.0 | 1.599661e+07 | 7.760119e+06 | 184000.0 |
# 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);
show(fireball_fig)
# 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)
# 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
)
show(fireball_fig)
# 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()
alt | vel | radiance | force | year | month | day | lattitude | longitude | X | Y | energy | size | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | NaN | 5.800000e+10 | 0.19 | 2017 | 7 | 31 | -118.5 | 24.7 | -1.319136e+07 | 2.838941e+06 | 58000.0 | 7.179449 |
1 | 38.0 | 17.2 | 3.500000e+10 | 0.12 | 2017 | 7 | 23 | -69.7 | -6.6 | -7.758969e+06 | -7.363389e+05 | 35000.0 | 6.732051 |
2 | 35.0 | 13.7 | 7.300000e+10 | 0.23 | 2017 | 7 | 13 | 60.7 | 23.1 | 6.757093e+06 | 2.644116e+06 | 73000.0 | 7.397916 |
3 | 20.0 | 15.2 | 9.400000e+10 | 0.29 | 2017 | 6 | 30 | 134.5 | -34.3 | 1.497247e+07 | -4.069156e+06 | 94000.0 | 7.692582 |
4 | 35.1 | 24.3 | 1.840000e+11 | 0.52 | 2017 | 6 | 23 | 143.7 | 57.0 | 1.599661e+07 | 7.760119e+06 | 184000.0 | 8.605551 |
# 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
);
show(fireball_fig)
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)
show(fireball_fig)
# 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)
# make a list of all the available years
years = list(set(fireball_data.year))
print(years)
[1988, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017]
# 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)
)
interactive(children=(SelectionSlider(description='year', options=(1988, 1990, 1991, 1993, 1994, 1995, 1996, 1…
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.
# 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)
)