{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Layouts, Interactions, and Annotations\n", "> 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.\n", "\n", "- toc: true \n", "- badges: true\n", "- comments: true\n", "- author: Chanseok Kang\n", "- categories: [Python, Datacamp, Visualization]\n", "- image: images/bokeh_plot.png" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "from bokeh.io import output_file, show\n", "from bokeh.plotting import figure\n", "from IPython.display import HTML" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction to layouts\n", "- Arranging multiple plots\n", " - Arrange plots (and controls) visually on a page.\n", " - rows, columns\n", " - grid arrangements\n", " - tabbed layouts\n", " - Nested layouts\n", " - Rows and columns can be nested for more sophisticated layouts" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating rows of plots\n", "Layouts are collections of Bokeh figure objects.\n", "\n", "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.\n", "\n", "By using the `row()` method, you'll create a single layout of the two figures.\n", "\n", "Remember, as in the previous chapter, once you have created your figures, you can interact with them in various ways.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "df = pd.read_csv('./dataset/literacy_birth_rate.csv').dropna()\n", "df['fertility'] = df['fertility'].astype('float')\n", "df['female literacy'] = df['female literacy'].astype('float')" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from bokeh.plotting import ColumnDataSource\n", "\n", "source = ColumnDataSource(df)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "from bokeh.layouts import row\n", "\n", "# Create the first figure: p1\n", "p1 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female_literacy (% population)')\n", "\n", "# Add a circle glyph to p1\n", "p1.circle(x='fertility', y='female literacy', source=source);\n", "\n", "# Create the second figure: p2\n", "p2 = figure(x_axis_label='population', y_axis_label='female_literacy (% population)')\n", "\n", "# Add a circle glyph to p2\n", "p2.circle(x='population', y='female literacy', source=source)\n", "\n", "# Put p1 and p2 into a horizontal row: layout\n", "layout = row(p1, p2)\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/fert_row.html')\n", "show(layout)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/fert_row.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating columns of plots\n", "In 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.\n", "\n", "In this exercise and the ones to follow, you may have to scroll down to view the lower portion of the figure.\n", "\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "from bokeh.layouts import column\n", "\n", "source = ColumnDataSource(df)\n", "\n", "# Create a blank figure: p1\n", "p1 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female_literacy (% population)')\n", "\n", "# Add circle scatter to the figure p1\n", "p1.circle('fertility', 'female literacy', source=source)\n", "\n", "# Create a new blank figure: p2\n", "p2 = figure(x_axis_label='population', \n", " y_axis_label='female_literacy (% population)')\n", "\n", "# Add circle scatter to the figure p2\n", "p2.circle('population', 'female literacy', source=source)\n", "\n", "# Put plots p1 and p2 in a column: layout\n", "layout = column(p1, p2)\n", "output_file('./html/fert_column.html')\n", "show(layout)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/fert_column.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Nesting rows and columns of plots\n", "You 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`).\n", "\n", "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.\n", "\n", "By using the `sizing_mode` argument, you can scale the widths to fill the whole figure." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
mpgcyldisplhpweightaccelyroriginnamecolorsize
018.06250.088313914.571USford mustangblue15.0
19.08304.0193473218.570UShi 1200dblue20.0
236.1491.060180016.478Asiahonda civic cvccred10.0
318.56250.098352519.077USford granadablue15.0
434.3497.078218815.880Europeaudi 4000green10.0
\n", "
" ], "text/plain": [ " mpg cyl displ hp weight accel yr origin name color \\\n", "0 18.0 6 250.0 88 3139 14.5 71 US ford mustang blue \n", "1 9.0 8 304.0 193 4732 18.5 70 US hi 1200d blue \n", "2 36.1 4 91.0 60 1800 16.4 78 Asia honda civic cvcc red \n", "3 18.5 6 250.0 98 3525 19.0 77 US ford granada blue \n", "4 34.3 4 97.0 78 2188 15.8 80 Europe audi 4000 green \n", "\n", " size \n", "0 15.0 \n", "1 20.0 \n", "2 10.0 \n", "3 15.0 \n", "4 10.0 " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_csv('./dataset/auto-mpg.csv').dropna()\n", "df.head()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "mean_mpg = df.groupby('yr').mean()['mpg']" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "source = ColumnDataSource(df)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "# Create a blank figure: avg_mpg\n", "avg_mpg = figure(x_axis_label='year', \n", " y_axis_label='mean mpg')\n", "\n", "avg_mpg.line(mean_mpg.index, mean_mpg);\n", "\n", "# Create a blank figure: mpg_hp\n", "mpg_hp = figure(x_axis_label='hp', y_axis_label='mpg')\n", "\n", "mpg_hp.circle(x='hp', y='mpg', source=source);\n", "\n", "# Create a blank figure: mpg_weight\n", "mpg_weight = figure(x_axis_label='weight', y_axis_label='mpg')\n", "\n", "mpg_weight.circle(x='weight', y='mpg', source=source);" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# Make a column layout that will be used as the second row: row2\n", "row2 = row([mpg_hp, mpg_weight], sizing_mode='scale_width')\n", "\n", "# Make a row layout that includes the above column layout: layout\n", "layout = column([avg_mpg, row2], sizing_mode='scale_width')\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/layout_custom.html')\n", "show(layout)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/layout_custom.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advanced layouts\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating gridded layouts\n", "Regular grids of Bokeh plots can be generated with `gridplot`.\n", "\n", "In this example, you're going to display four plots of fertility vs female literacy for four regions: Latin America, Africa, Asia and Europe.\n", "\n", "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.\n" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
CountryContinentfemale literacyfertilitypopulation
0ChineASI90.51.7691324.655000
1IndeASI50.82.6821139.964932
2USANAM99.02.077304.060000
3IndonésieASI88.82.132227.345082
4BrésilLAT90.21.827191.971506
\n", "
" ], "text/plain": [ " Country Continent female literacy fertility population\n", "0 Chine ASI 90.5 1.769 1324.655000\n", "1 Inde ASI 50.8 2.682 1139.964932\n", "2 USA NAM 99.0 2.077 304.060000\n", "3 Indonésie ASI 88.8 2.132 227.345082\n", "4 Brésil LAT 90.2 1.827 191.971506" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = pd.read_csv('./dataset/literacy_birth_rate.csv').dropna()\n", "df['fertility'] = df['fertility'].astype('float')\n", "df['female literacy'] = df['female literacy'].astype('float')\n", "df['population'] = df['population'] / 1000000\n", "df.head()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "LAT = df[df['Continent'] == 'LAT']\n", "EUR = df[df['Continent'] == 'EUR']\n", "AF = df[df['Continent'] == 'AF']\n", "ASI = df[df['Continent'] == 'ASI']" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "p1 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Latin America');\n", "\n", "p1.circle(LAT['fertility'], LAT['female literacy']);\n", "\n", "p2 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Africa');\n", "\n", "p2.circle(AF['fertility'], AF['female literacy']);\n", "\n", "p3 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Asia');\n", "\n", "p3.circle(ASI['fertility'], ASI['female literacy']);\n", "\n", "p4 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Europe');\n", "\n", "p4.circle(EUR['fertility'], EUR['female literacy']);" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "# Import gridplot from bokeh.layouts\n", "from bokeh.layouts import gridplot\n", "\n", "# Create a list containing plots p1 and p2: row1\n", "row1 = [p1, p2]\n", "\n", "# Create a list containing plots p3 and p4: row2\n", "row2 = [p3, p4]\n", "\n", "# Create a gridplot using row1 and row2: layout\n", "layout = gridplot([row1, row2], plot_width=400, plot_height=400)\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/grid.html')\n", "show(layout)" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/grid.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Starting tabbed layouts\n", "Tabbed layouts can be created in Bokeh by placing plots or layouts in Panels.\n", "\n", "In this exercise, you'll take the four fertility vs female literacy plots from the last exercise and make a `Panel()` for each.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "p1 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Latin America');\n", "\n", "p1.circle(LAT['fertility'], LAT['female literacy']);\n", "\n", "p2 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Africa');\n", "\n", "p2.circle(AF['fertility'], AF['female literacy']);\n", "\n", "p3 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Asia');\n", "\n", "p3.circle(ASI['fertility'], ASI['female literacy']);\n", "\n", "p4 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Europe');\n", "\n", "p4.circle(EUR['fertility'], EUR['female literacy']);" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "from bokeh.models.widgets import Panel\n", "\n", "# Create tab1 from plot p1: tab1\n", "tab1 = Panel(child=p1, title='Latin America')\n", "\n", "# Create tab2 from plot p2: tab2\n", "tab2 = Panel(child=p2, title='Africa')\n", "\n", "# Create tab3 from plot p3: tab3\n", "tab3 = Panel(child=p3, title='Asia')\n", "\n", "# Create tab4 from plot p4: tab4\n", "tab4 = Panel(child=p4, title='Europe')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Displaying tabbed layouts\n", "Tabbed 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.\n", "\n", "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`.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "from bokeh.models.widgets import Tabs\n", "\n", "# Create a Tabs layout: layout\n", "layout = Tabs(tabs=[tab1, tab2, tab3, tab4])\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/tabs.html')\n", "show(layout)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/tabs.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Linking plots together\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Linked axes\n", "Linking axes between plots is achieved by sharing `range` objects.\n", "\n", "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.\n", "\n", "The four plots `p1`, `p2`, `p3` and `p4` along with the `layout` that you created in the last section have been provided for you.\n", "\n", "Your job is link `p1` with the three other plots by assignment of the `.x_range` and `.y_range` attributes.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "p1 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Latin America');\n", "\n", "p1.circle(LAT['fertility'], LAT['female literacy']);\n", "\n", "p2 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Africa');\n", "\n", "p2.circle(AF['fertility'], AF['female literacy']);\n", "\n", "p3 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Asia');\n", "\n", "p3.circle(ASI['fertility'], ASI['female literacy']);\n", "\n", "p4 = figure(x_axis_label='fertility (children per woman)', \n", " y_axis_label='female literacy (% population)', title='Europe');\n", "\n", "p4.circle(EUR['fertility'], EUR['female literacy']);\n", "\n", "# Create a list containing plots p1 and p2: row1\n", "row1 = [p1, p2]\n", "\n", "# Create a list containing plots p3 and p4: row2\n", "row2 = [p3, p4]\n", "\n", "# Create a gridplot using row1 and row2: layout\n", "layout = gridplot([row1, row2], plot_width=400, plot_height=400)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [], "source": [ "# Link the x_range of p2 to p1: p2.x_range\n", "p2.x_range = p1.x_range\n", "\n", "# Link the y_range of p2 to p1: p2.y_range\n", "p2.y_range = p1.y_range\n", "\n", "# Link the x_range of p3 to p1: p3.x_range\n", "p3.x_range = p1.x_range\n", "\n", "# Link the y_range of p4 to p1: p4.y_range\n", "p4.y_range = p1.y_range\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/linked_range.html')\n", "show(layout)" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/linked_range.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Linked brushing\n", "By 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.\n", "\n", "In this exercise, you'll plot female literacy vs fertility and population vs fertility in two plots using the same ColumnDataSource.\n", "\n", "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.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "# Create ColumnDataSource: source\n", "source = ColumnDataSource(df)\n", "\n", "# Create the first figure: p1\n", "p1 = figure(x_axis_label='fertility (children per woman)', y_axis_label='female literacy (% population)',\n", " tools='box_select,lasso_select')\n", "\n", "# Add a circle glyph to p1\n", "p1.circle('fertility', 'female literacy', source=source)\n", "\n", "# Create the second figure: p2\n", "p2 = figure(x_axis_label='fertility (children per woman)', y_axis_label='population (millions)',\n", " tools='box_select,lasso_select')\n", "\n", "# Add a circle glyph to p2\n", "p2.circle('fertility', 'population', source=source)\n", "\n", "# Create row layout of figures p1 and p2: layout\n", "layout = row(p1, p2)\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/linked_brush.html')\n", "show(layout)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/linked_brush.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Annotations and guides\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### How to create legends\n", "Legends can be added to any glyph by using the `legend` keyword argument.\n", "\n", "In this exercise, you will plot two `circle` glyphs for female literacy vs fertility in Africa and Latin America.\n", "\n", "Two ColumnDataSources called `latin_america` and `africa` have been provided.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [], "source": [ "latin_ameria = ColumnDataSource(LAT)\n", "africa = ColumnDataSource(AF)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "p = figure(x_axis_label='fertility (children per woman)', y_axis_label='female_literacy (% population)')" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "# Add the first circle glyph to the figure p\n", "p.circle('fertility', 'female literacy', source=latin_ameria, size=10, color='red', \n", " legend_label='Latin America');\n", "\n", "# Add the second circle glyph to the figure p\n", "p.circle('fertility', 'female literacy', source=africa, size=10, color='blue', legend_label='Africa');\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/fert_lit_groups.html')\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/fert_lit_groups.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Positioning and styling legends\n", "Properties of the legend can be changed by using the `legend` member attribute of a Bokeh figure after the glyphs have been plotted.\n", "\n", "In this exercise, you'll adjust the background color and legend location of the female literacy vs fertility plot from the previous exercise." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [], "source": [ "latin_ameria = ColumnDataSource(LAT)\n", "africa = ColumnDataSource(AF)\n", "\n", "p = figure(x_axis_label='fertility (children per woman)', y_axis_label='female_literacy (% population)')\n", "\n", "# Add the first circle glyph to the figure p\n", "p.circle('fertility', 'female literacy', source=latin_ameria, size=10, color='red', \n", " legend_label='Latin America');\n", "\n", "# Add the second circle glyph to the figure p\n", "p.circle('fertility', 'female literacy', source=africa, size=10, color='blue', legend_label='Africa');" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "# Assign the legend to the bottom left: p.legend.location\n", "p.legend.location='bottom_left'\n", "\n", "# Fill the legend background with the color 'lightgray': p.legend.background_fill_color\n", "p.legend.background_fill_color = 'lightgray'\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/fert_lit_groups2.html')\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/fert_lit_groups2.html')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Adding a hover tooltip\n", "Working with the `HoverTool` is easy for data stored in a ColumnDataSource.\n", "\n", "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.\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "C:\\Users\\kcsgo\\anaconda3\\lib\\site-packages\\pandas\\core\\indexing.py:844: SettingWithCopyWarning: \n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", " self.obj[key] = _infer_fill_value(value)\n", "C:\\Users\\kcsgo\\anaconda3\\lib\\site-packages\\pandas\\core\\indexing.py:965: SettingWithCopyWarning: \n", "A value is trying to be set on a copy of a slice from a DataFrame.\n", "Try using .loc[row_indexer,col_indexer] = value instead\n", "\n", "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", " self.obj[item] = s\n" ] } ], "source": [ "LAT.loc[:,'Country'] = 'Latin America'\n", "AF.loc[:, 'Country'] = 'Africa'" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "latin_ameria = ColumnDataSource(LAT)\n", "africa = ColumnDataSource(AF)\n", "\n", "p = figure(x_axis_label='fertility (children per woman)', y_axis_label='female_literacy (% population)')\n", "\n", "# Add the first circle glyph to the figure p\n", "p.circle('fertility', 'female literacy', source=latin_ameria, size=10, color='red', \n", " legend_label='Latin America');\n", "\n", "# Add the second circle glyph to the figure p\n", "p.circle('fertility', 'female literacy', source=africa, size=10, color='blue', legend_label='Africa');\n", "\n", "# Assign the legend to the bottom left: p.legend.location\n", "p.legend.location='bottom_left'\n", "\n", "# Fill the legend background with the color 'lightgray': p.legend.background_fill_color\n", "p.legend.background_fill_color = 'lightgray'" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [], "source": [ "from bokeh.models import HoverTool\n", "\n", "# Create a HoverTool object: hover\n", "hover = HoverTool(tooltips=[\n", " ('Country', '@Country')\n", "])\n", "\n", "# Add the HoverTool object to figure p\n", "p.add_tools(hover)\n", "\n", "# Specify the name of the output_file and show the result\n", "output_file('./html/hover.html')\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "\n", " \n", " \n", " \n", " \n", " Bokeh Plot\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "" ], "text/plain": [ "" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HTML('./html/hover.html')" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 4 }