Highlighting Data Using the Legend
In this lesson you will explore the final interactivity example in this tutorial: interactive legends. In this visualization, you’ll see two identical scatter plots comparing the game-by-game points and rebounds of LeBron James and Kevin Durant. The only difference will be that one will use a hide as its click_policy
, while the other uses mute.
In this case you will use the existing player_stats
DataFrame from read_nba_data.py
. You will isolate data using GroupFilter
and CDSView
.
File: InteractiveLegends.py
# Bokeh Libraries
from bokeh.plotting import figure, show
from bokeh.io import output_file
from bokeh.models import ColumnDataSource, CDSView, GroupFilter
from bokeh.layouts import row
# Import the data
from read_nba_data import player_stats
# Output to a static html file
output_file('lebron_vs_durant.html',
title='LeBron James vs. Kevin Durant')
# Store the data in a ColumnDataSource
player_gm_stats = ColumnDataSource(player_stats)
# Create a view for each player
lebron_filters = [GroupFilter(column_name='playFNm', group='LeBron'),
GroupFilter(column_name='playLNm', group='James')]
lebron_view = CDSView(source=player_gm_stats,
filters=lebron_filters)
durant_filters = [GroupFilter(column_name='playFNm', group='Kevin'),
GroupFilter(column_name='playLNm', group='Durant')]
durant_view = CDSView(source=player_gm_stats,
filters=durant_filters)
# Consolidate the common keyword arguments in dicts
common_figure_kwargs = {
'plot_width': 400,
'x_axis_label': 'Points',
'toolbar_location': None,
}
common_circle_kwargs = {
'x': 'playPTS',
'y': 'playTRB',
'source': player_gm_stats,
'size': 12,
'alpha': 0.7,
}
common_lebron_kwargs = {
'view': lebron_view,
'color': '#002859',
'legend': 'LeBron James'
}
common_durant_kwargs = {
'view': durant_view,
'color': '#FFC324',
'legend': 'Kevin Durant',
}
# Create the two figures and draw the data
hide_fig = figure(**common_figure_kwargs,
title='Click Legend to HIDE Data',
y_axis_label='Rebounds')
hide_fig.circle(**common_circle_kwargs, **common_lebron_kwargs)
hide_fig.circle(**common_circle_kwargs, **common_durant_kwargs)
mute_fig = figure(**common_figure_kwargs, title='Click Legend to MUTE Data')
mute_fig.circle(**common_circle_kwargs, **common_lebron_kwargs,
muted_alpha=0.1)
mute_fig.circle(**common_circle_kwargs, **common_durant_kwargs,
muted_alpha=0.1)
# Add interactivity to the legend
hide_fig.legend.click_policy = 'hide'
mute_fig.legend.click_policy = 'mute'
# Visualize
show(row(hide_fig, mute_fig))
00:00 For the last example, you’re going to create interactive legends. For that, you may remember from a earlier exercise drawing data with glyphs. You saw how easy it was to implement a legend when creating a plot.
00:11
When you have a legend in place, adding interactivity is merely a matter of assigning what’s called a .click_policy
. Using just a single line of code, you can quickly add the ability to either hide or mute data using your legend.
00:23
For this example, you’re going to create two identical scatter plots comparing the game by game points and rebounds for LeBron James and Kevin Durant. The only difference will be that one will use a "hide"
as its .click_policy
while the other uses "mute"
.
00:36
The first step is to create a new file and isolate the data for the two players from the player_stats
DataFrame. So create a new file that’ll be called InteractiveLegends.py
.
00:52
And at the top of your file, you’re going to bring in some libraries. from plotting import figure, show
,
01:05
from bokeh.io import output_file
. From models
import ColumnDataSource
, and for this one you’re going to use CDSView
again and GroupFilter
.
01:18
Do some of that data management inside of Bokeh instead of creating it externally. From layouts
, you’re going to put this all in a row
.
01:31
from read_nba_data import player_stats
. Okay. Create your output file.
01:43
It’s going to be called 'lebron_vs_durant.html'
with a title
equal to
01:54
'LeBron James vs. Kevin Durant'
. Okay. This the data you’re going to use. Store it in a ColumnDataSource
. Call it player_gm_stats
, and it’s going to use player_stats
. All right.
02:10
It’s time to create a view for each player. lebron_filters
will be using a GroupFilter
with a column_name
equal to—and this you might remember—pulling the player first name.
02:28
It should be part of the 'LeBron'
group. And you’re going to do the same basic info, except for it’s going to be the player last name and the grouping will be 'James'
.
02:47
And lebron_view
is a CDSView
. source
will be the ColumnDataSource
you created, player_gm_stats
. And the filters
are equal to the lebron_filters
you just built. Great. So a lot of this information is going to be the same, so why not repeat this data and say durant_filters
and the group will be 'Kevin'
and 'Durant'
.
03:09
And then here, it’s the durant_view
, which will be loading in the durant_filters
. Nice. So you create these filters, these grouping filters, that are pulling 'LeBron'
and 'James'
from first name and last name, and 'Kevin'
and 'Durant'
from first name and last name from player_gm_stats
CDS—column data source—and making this new view. Cool! All right.
03:28 There are some common parameters that you’re going to use across all the figures, markers, and data. And what’s nice is you can consolidate all that information into dictionaries and reuse them.
03:37 This will help eliminate redundant code and provide an easy way to tweak parameters using the legends you’re about to set up.
03:49
You’re going to consolidate the common keyword arguments into dictionaries. The first is the common_figure_kwargs
, which will be with the plot_width
of 400
, an x_axis_label
named 'Points'
, and a toolbar_location
you’re going to set to be None
so it won’t show up.
04:12
For glyphs, you’ll set up common circle keyword arguments. 'x'
is the player points, 'y'
is the player’s rebounds. Don’t forget the commas.
04:24
The 'source'
will be set to player_gm_stats
. That’ll be your ColumnDataSource
. With a 'size'
of 12
and an 'alpha'
amount of 0.7
.
04:34
Okay. So here the common_lebron_kwargs
(common LeBron keyword arguments)
04:43
will be the lebron_view
. The 'color'
will be in hexadecimal, '#002859'
. And then the 'legend'
will be LeBron’s name.
05:06
And for Durant, it’ll be the durant_view
you created. The 'color'
will be in hexadecimal, '#FFC324'
, and then the 'legend'
will be 'Kevin Durant'
.
05:21 Great. So, you’ve created these dictionaries, and what’s nice about creating them is they’re reusable. So in the next couple of things here, you’re going to set up two scatter plots. For the first one, you’re going to use a technique called hiding.
05:40
You’re going to use common_figure_kwargs
for it. And again, this is the hiding figure, so it’s going to use clicking on the legend to hide the data. That’ll be the title.
05:53
And the y-axis is 'Rebounds'
. Okay. For hide_fig
, you’re going to create circles using the common_circle_kwargs
and using the common_lebron_kwargs
.
06:09
Then you’re going to create a second set of glyphs for this image that will again use the common_circle_kwargs
. This time, the common_durant_kwargs
.
06:18
That’ll put these two sets of circle glyphs inside the hide_fig
. For your other figure where you’re muting, it’ll be called mute_fig
.
06:28
And you’re using common_figure_kwargs
and setting up a title. In this case, click on the legend to mute the data.
06:42
So, the first set of glyphs will be mute_fig.circle()
, and then you’re using common_circle_kwargs
with then common_lebron_kwargs
(LeBron’s arguments).
06:51
You’re going to set a muted_alpha
, muted down to 0.1
. You can copy this
07:02
and change it to common_durant_kwargs
(Durant), and the rest can remain the same. Great! What’s left? Only a couple of lines. To add interactivity with the hide_fig
, the legend, you’re going to set what’s called a .click_policy
.
07:21
So with this single line, we’re saying the .click_policy
is 'hide'
. And for the mute_fig
,
07:29
set that one to 'mute'
. Great. And you’re ready to turn on the visualization. Create it in a row
, and inside that row()
will be hide_fig
and then mute_fig
. All right, this all looks good.
07:41
Now that you’ve saved, you can run your script, InteractiveLegends.py
. Okay! So in this case, you have the legend, and LeBron James and Kevin Durant are in there.
07:53 You click on Kevin Durant and it will hide all the points for Kevin, versus hiding the ones for LeBron. Pretty neat interactivity. And then over here, clicking on LeBron will mute and you can see it really changing that alpha down very low versus Kevin’s data. Cool! All right!
08:11 You’re doing great! You’re ready to do a wrap-up and review next.
Become a Member to join the conversation.
toigopaul on Aug. 27, 2024
I had a hard time getting my code to track. A lot of it was that I have yet to get CDSView to work for me and that figure.circle has been depricated. Rather than discuss every change I made to get it to work, I’ll just dump my code where the code that’s been commented out is from “Contents” that doesn’t work for me and what immediately follows is what does work for me.