<jupyter_start><jupyter_text>Layouts, Interactions, and Annotations> Learn how to combine multiple Bokeh plots into different kinds of layouts on a page, how to easily link different plots together, and how to add annotations such as legends and hover tooltips. This is the Summary of lecture "Interactive Data Visualization with Bokeh", via datacamp.- toc: true - badges: true- comments: true- author: <NAME>- categories: [Python, Datacamp, Visualization]- image: images/bokeh_plot.png<jupyter_code>import pandas as pd
import numpy as np
from bokeh.io import output_file, show
from bokeh.plotting import figure
from IPython.display import HTML<jupyter_output><empty_output><jupyter_text>Introduction to layouts- Arranging multiple plots    - Arrange plots (and controls) visually on a page.        - rows, columns        - grid arrangements        - tabbed layouts    - Nested layouts        - Rows and columns can be nested for more sophisticated layouts  Creating rows of plotsLayouts are collections of Bokeh figure objects.In this exercise, you're going to create two plots from the Literacy and Birth Rate data set to plot fertility vs female literacy and population vs female literacy.By using the `row()` method, you'll create a single layout of the two figures.Remember, as in the previous chapter, once you have created your figures, you can interact with them in various ways.In this exercise, you may have to scroll sideways to view both figures in the row layout. Alternatively, you can view the figures in a new window by clicking on the expand icon to the right of the "Bokeh plot" tab.<jupyter_code>df = pd.read_csv('./dataset/literacy_birth_rate.csv').dropna()
df['fertility'] = df['fertility'].astype('float')
df['female literacy'] = df['female literacy'].astype('float')
from bokeh.plotting import ColumnDataSource

source = ColumnDataSource(df)
from bokeh.layouts import row

# Create the first figure: p1
p1 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female_literacy (% population)')

# Add a circle glyph to p1
p1.circle(x='fertility', y='female literacy', source=source);

# Create the second figure: p2
p2 = figure(x_axis_label='population', y_axis_label='female_literacy (% population)')

# Add a circle glyph to p2
p2.circle(x='population', y='female literacy', source=source)

# Put p1 and p2 into a horizontal row: layout
layout = row(p1, p2)

# Specify the name of the output_file and show the result
output_file('./html/fert_row.html')
show(layout)
HTML('./html/fert_row.html')<jupyter_output><empty_output><jupyter_text>Creating columns of plotsIn this exercise, you're going to use the column() function to create a single column layout of the two plots you created in the previous exercise.In this exercise and the ones to follow, you may have to scroll down to view the lower portion of the figure.<jupyter_code>from bokeh.layouts import column

source = ColumnDataSource(df)

# Create a blank figure: p1
p1 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female_literacy (% population)')

# Add circle scatter to the figure p1
p1.circle('fertility', 'female literacy', source=source)

# Create a new blank figure: p2
p2 = figure(x_axis_label='population', 
            y_axis_label='female_literacy (% population)')

# Add circle scatter to the figure p2
p2.circle('population', 'female literacy', source=source)

# Put plots p1 and p2 in a column: layout
layout = column(p1, p2)
output_file('./html/fert_column.html')
show(layout)
HTML('./html/fert_column.html')<jupyter_output><empty_output><jupyter_text>Nesting rows and columns of plotsYou can create nested layouts of plots by combining row and column layouts. In this exercise, you'll make a 3-plot layout in two rows using the auto-mpg data set. Three plots have been created for you of average mpg vs year (`avg_mpg`), mpg vs hp (`mpg_hp`), and mpg vs weight (`mpg_weight`).Your job is to use the `row()` and `column()` functions to make a two-row layout where the first row will have only the average mpg vs year plot and the second row will have mpg vs hp and mpg vs weight plots as columns.By using the `sizing_mode` argument, you can scale the widths to fill the whole figure.<jupyter_code>df = pd.read_csv('./dataset/auto-mpg.csv').dropna()
df.head()
mean_mpg = df.groupby('yr').mean()['mpg']
source = ColumnDataSource(df)
# Create a blank figure: avg_mpg
avg_mpg = figure(x_axis_label='year', 
            y_axis_label='mean mpg')

avg_mpg.line(mean_mpg.index, mean_mpg);

# Create a blank figure: mpg_hp
mpg_hp = figure(x_axis_label='hp', y_axis_label='mpg')

mpg_hp.circle(x='hp', y='mpg', source=source);

# Create a blank figure: mpg_weight
mpg_weight = figure(x_axis_label='weight', y_axis_label='mpg')

mpg_weight.circle(x='weight', y='mpg', source=source);
# Make a column layout that will be used as the second row: row2
row2 = row([mpg_hp, mpg_weight], sizing_mode='scale_width')

# Make a row layout that includes the above column layout: layout
layout = column([avg_mpg, row2], sizing_mode='scale_width')

# Specify the name of the output_file and show the result
output_file('./html/layout_custom.html')
show(layout)
HTML('./html/layout_custom.html')<jupyter_output><empty_output><jupyter_text>Advanced layouts  Creating gridded layoutsRegular grids of Bokeh plots can be generated with `gridplot`.In this example, you're going to display four plots of fertility vs female literacy for four regions: Latin America, Africa, Asia and Europe.Your job is to create a list-of-lists for the four Bokeh plots that have been provided to you as `p1`, `p2`, `p3` and `p4`. The list-of-lists defines the row and column placement of each plot.<jupyter_code>df = pd.read_csv('./dataset/literacy_birth_rate.csv').dropna()
df['fertility'] = df['fertility'].astype('float')
df['female literacy'] = df['female literacy'].astype('float')
df['population'] = df['population'] / 1000000
df.head()
LAT = df[df['Continent'] == 'LAT']
EUR = df[df['Continent'] == 'EUR']
AF = df[df['Continent'] == 'AF']
ASI = df[df['Continent'] == 'ASI']
p1 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Latin America');

p1.circle(LAT['fertility'], LAT['female literacy']);

p2 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Africa');

p2.circle(AF['fertility'], AF['female literacy']);

p3 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Asia');

p3.circle(ASI['fertility'], ASI['female literacy']);

p4 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Europe');

p4.circle(EUR['fertility'], EUR['female literacy']);
# Import gridplot from bokeh.layouts
from bokeh.layouts import gridplot

# Create a list containing plots p1 and p2: row1
row1 = [p1, p2]

# Create a list containing plots p3 and p4: row2
row2 = [p3, p4]

# Create a gridplot using row1 and row2: layout
layout = gridplot([row1, row2], plot_width=400, plot_height=400)

# Specify the name of the output_file and show the result
output_file('./html/grid.html')
show(layout)
HTML('./html/grid.html')<jupyter_output><empty_output><jupyter_text>Starting tabbed layoutsTabbed layouts can be created in Bokeh by placing plots or layouts in Panels.In this exercise, you'll take the four fertility vs female literacy plots from the last exercise and make a `Panel()` for each.No figure will be generated in this exercise. Instead, you will use these panels in the next exercise to build and display a tabbed layout.<jupyter_code>p1 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Latin America');

p1.circle(LAT['fertility'], LAT['female literacy']);

p2 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Africa');

p2.circle(AF['fertility'], AF['female literacy']);

p3 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Asia');

p3.circle(ASI['fertility'], ASI['female literacy']);

p4 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Europe');

p4.circle(EUR['fertility'], EUR['female literacy']);
from bokeh.models.widgets import Panel

# Create tab1 from plot p1: tab1
tab1 = Panel(child=p1, title='Latin America')

# Create tab2 from plot p2: tab2
tab2 = Panel(child=p2, title='Africa')

# Create tab3 from plot p3: tab3
tab3 = Panel(child=p3, title='Asia')

# Create tab4 from plot p4: tab4
tab4 = Panel(child=p4, title='Europe')<jupyter_output><empty_output><jupyter_text>Displaying tabbed layoutsTabbed layouts are collections of Panel objects. Using the figures and Panels from the previous two exercises, you'll create a tabbed layout to change the region in the fertility vs female literacy plots.Your job is to create the layout using `Tabs()` and assign the `tabs` keyword argument to your list of Panels. The Panels have been created for you as `tab1`, `tab2`, `tab3` and `tab4`.After you've displayed the figure, explore the tabs you just added! The "Pan", "Box Zoom" and "Wheel Zoom" tools are also all available as before.<jupyter_code>from bokeh.models.widgets import Tabs

# Create a Tabs layout: layout
layout = Tabs(tabs=[tab1, tab2, tab3, tab4])

# Specify the name of the output_file and show the result
output_file('./html/tabs.html')
show(layout)
HTML('./html/tabs.html')<jupyter_output><empty_output><jupyter_text>Linking plots together  Linked axesLinking axes between plots is achieved by sharing `range` objects.In this exercise, you'll link four plots of female literacy vs fertility so that when one plot is zoomed or dragged, one or more of the other plots will respond.The four plots `p1`, `p2`, `p3` and `p4` along with the `layout` that you created in the last section have been provided for you.Your job is link `p1` with the three other plots by assignment of the `.x_range` and `.y_range` attributes.After you have linked the axes, explore the plots by clicking and dragging along the x or y axes of any of the plots, and notice how the linked plots change together.<jupyter_code>p1 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Latin America');

p1.circle(LAT['fertility'], LAT['female literacy']);

p2 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Africa');

p2.circle(AF['fertility'], AF['female literacy']);

p3 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Asia');

p3.circle(ASI['fertility'], ASI['female literacy']);

p4 = figure(x_axis_label='fertility (children per woman)', 
            y_axis_label='female literacy (% population)', title='Europe');

p4.circle(EUR['fertility'], EUR['female literacy']);

# Create a list containing plots p1 and p2: row1
row1 = [p1, p2]

# Create a list containing plots p3 and p4: row2
row2 = [p3, p4]

# Create a gridplot using row1 and row2: layout
layout = gridplot([row1, row2], plot_width=400, plot_height=400)
# Link the x_range of p2 to p1: p2.x_range
p2.x_range = p1.x_range

# Link the y_range of p2 to p1: p2.y_range
p2.y_range = p1.y_range

# Link the x_range of p3 to p1: p3.x_range
p3.x_range = p1.x_range

# Link the y_range of p4 to p1: p4.y_range
p4.y_range = p1.y_range

# Specify the name of the output_file and show the result
output_file('./html/linked_range.html')
show(layout)
HTML('./html/linked_range.html')<jupyter_output><empty_output><jupyter_text>Linked brushingBy sharing the same `ColumnDataSource` object between multiple plots, selection tools like BoxSelect and LassoSelect will highlight points in both plots that share a row in the ColumnDataSource.In this exercise, you'll plot female literacy vs fertility and population vs fertility in two plots using the same ColumnDataSource.After you have built the figure, experiment with the Lasso Select and Box Select tools. Use your mouse to drag a box or lasso around points in one figure, and notice how points in the other figure that share a row in the ColumnDataSource also get highlighted.Before experimenting with the Lasso Select, however, click the Bokeh plot pop-out icon to pop out the figure so that you can definitely see everything that you're doing.<jupyter_code># Create ColumnDataSource: source
source = ColumnDataSource(df)

# Create the first figure: p1
p1 = figure(x_axis_label='fertility (children per woman)', y_axis_label='female literacy (% population)',
            tools='box_select,lasso_select')

# Add a circle glyph to p1
p1.circle('fertility', 'female literacy', source=source)

# Create the second figure: p2
p2 = figure(x_axis_label='fertility (children per woman)', y_axis_label='population (millions)',
            tools='box_select,lasso_select')

# Add a circle glyph to p2
p2.circle('fertility', 'population', source=source)

# Create row layout of figures p1 and p2: layout
layout = row(p1, p2)

# Specify the name of the output_file and show the result
output_file('./html/linked_brush.html')
show(layout)
HTML('./html/linked_brush.html')<jupyter_output><empty_output><jupyter_text>Annotations and guides  How to create legendsLegends can be added to any glyph by using the `legend` keyword argument.In this exercise, you will plot two `circle` glyphs for female literacy vs fertility in Africa and Latin America.Two ColumnDataSources called `latin_america` and `africa` have been provided.Your job is to plot two circle glyphs for these two objects with `fertility` on the x axis and `female_literacy` on the y axis and add the legend values.<jupyter_code>latin_ameria = ColumnDataSource(LAT)
africa = ColumnDataSource(AF)
p = figure(x_axis_label='fertility (children per woman)', y_axis_label='female_literacy (% population)')
# Add the first circle glyph to the figure p
p.circle('fertility', 'female literacy', source=latin_ameria, size=10, color='red', 
        legend_label='Latin America');

# Add the second circle glyph to the figure p
p.circle('fertility', 'female literacy', source=africa, size=10, color='blue', legend_label='Africa');

# Specify the name of the output_file and show the result
output_file('./html/fert_lit_groups.html')
show(p)
HTML('./html/fert_lit_groups.html')<jupyter_output><empty_output><jupyter_text>Positioning and styling legendsProperties of the legend can be changed by using the `legend` member attribute of a Bokeh figure after the glyphs have been plotted.In this exercise, you'll adjust the background color and legend location of the female literacy vs fertility plot from the previous exercise.<jupyter_code>latin_ameria = ColumnDataSource(LAT)
africa = ColumnDataSource(AF)

p = figure(x_axis_label='fertility (children per woman)', y_axis_label='female_literacy (% population)')

# Add the first circle glyph to the figure p
p.circle('fertility', 'female literacy', source=latin_ameria, size=10, color='red', 
        legend_label='Latin America');

# Add the second circle glyph to the figure p
p.circle('fertility', 'female literacy', source=africa, size=10, color='blue', legend_label='Africa');
# Assign the legend to the bottom left: p.legend.location
p.legend.location='bottom_left'

# Fill the legend background with the color 'lightgray': p.legend.background_fill_color
p.legend.background_fill_color = 'lightgray'

# Specify the name of the output_file and show the result
output_file('./html/fert_lit_groups2.html')
show(p)
HTML('./html/fert_lit_groups2.html')<jupyter_output><empty_output><jupyter_text>Adding a hover tooltipWorking with the `HoverTool` is easy for data stored in a ColumnDataSource.In this exercise, you will create a `HoverTool` object and display the country for each circle glyph in the figure that you created in the last exercise. This is done by assigning the `tooltips` keyword argument to a list-of-tuples specifying the label and the column of values from the ColumnDataSource using the `@` operator.After you have added the hover tooltip to the figure, be sure to interact with it by hovering your mouse over each point to see which country it represents.<jupyter_code>LAT.loc[:,'Country'] = 'Latin America'
AF.loc[:, 'Country'] = 'Africa'
latin_ameria = ColumnDataSource(LAT)
africa = ColumnDataSource(AF)

p = figure(x_axis_label='fertility (children per woman)', y_axis_label='female_literacy (% population)')

# Add the first circle glyph to the figure p
p.circle('fertility', 'female literacy', source=latin_ameria, size=10, color='red', 
        legend_label='Latin America');

# Add the second circle glyph to the figure p
p.circle('fertility', 'female literacy', source=africa, size=10, color='blue', legend_label='Africa');

# Assign the legend to the bottom left: p.legend.location
p.legend.location='bottom_left'

# Fill the legend background with the color 'lightgray': p.legend.background_fill_color
p.legend.background_fill_color = 'lightgray'
from bokeh.models import HoverTool

# Create a HoverTool object: hover
hover = HoverTool(tooltips=[
    ('Country', '@Country')
])

# Add the HoverTool object to figure p
p.add_tools(hover)

# Specify the name of the output_file and show the result
output_file('./html/hover.html')
show(p)
HTML('./html/hover.html')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10370454416520111, 'fraction_numerical': 0.010551994099960289, 'mean_word_length': 5.357014064190407, 'pattern_counts': {'":': 0, '<': 50, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '12', 'dir': 'jupyter-structured-clean-dedup', 'id': '361720', 'license': 'Apache-2.0', 'n_tokens_mistral': 5547, 'n_tokens_neox': 5182, 'n_words': 1974, 'path': '_notebooks/2020-06-30-03-Layouts-Interactions-and-Annotations.ipynb', 'repo_name': 'AntonovMikhail/chans_jupyter', 'size': '17634'}