Bokeh-数据可视化实用指南-全-

Bokeh 数据可视化实用指南(全)

原文:Hands-On Data Visualization with Bokeh

协议:CC BY-NC-SA 4.0

零、前言

Bokeh 是一个开源的、交互式的 Python 数据可视化包,允许用户创建交互式的、漂亮的可视化,既有统计意义又美观。

这本书旨在为您提供开始 Bokeh 所需的工具,并创建可以通过交互讲述故事的绘图。

这本书是给谁的

这本书非常适合数据科学家和数据分析师,他们希望使用 Bokeh 库在网络浏览器上执行交互式数据可视化。

为了理解这本书的内容,需要 Python 的基本知识。

这本书涵盖了什么

第 1 章Bokeh 安装和关键概念,着眼于如何在您的 PC 上安装 Bokeh,以及如何理解本书其余部分前进所需的基本概念。

第 2 章使用字形绘制,将教你如何使用 Bokeh 的构造块——字形创建可视化。

第 3 章绘制不同的数据结构,解释了如何使用无处不在的数据结构创建可视化,例如熊猫数据框和 NumPy 数组。

第 4 章使用布局进行有效展示,探索如何使用布局来增强视觉化的审美吸引力。

第 5 章使用标注、小部件和视觉属性进行视觉增强,将教你如何增强你的绘图的互动性和美感。

第 6 章在 Bokeh 服务器上构建和托管应用,讲述了如何创建和部署可以托管交互式可视化的应用。

第 7 章使用网络、地理数据、网络地理数据和导出绘图进行高级绘图,深入探讨了 Bokeh 的高级主题,并介绍了一些增强交互式绘图体验的方法。

第 8 章博凯工作流–案例研究,包含一个案例研究,该案例研究将让您按照为博凯量身定制的工作流探索数据并构建交互式可视化!

充分利用这本书

Python 的基本知识是必不可少的。导入包的知识以及使用 NumPy、Pandas 和 DataFrames 的经验将帮助读者从本书中获得最大收益。

下载示例代码文件

你可以从你在www.packtpub.com的账户下载这本书的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support并注册将文件直接通过电子邮件发送给您。

您可以按照以下步骤下载代码文件:

  1. 登录或注册www.packtpub.com
  2. 选择“支持”选项卡。
  3. 点击代码下载和勘误表。
  4. 在搜索框中输入图书的名称,并按照屏幕指示进行操作。

下载文件后,请确保使用最新版本的解压缩文件夹:

  • 视窗系统的 WinRAR/7-Zip
  • zipeg/izp/un ARX for MAC
  • 适用于 Linux 的 7-Zip/PeaZip

这本书的代码包也托管在 GitHub 上,网址为https://GitHub . com/PacktPublishing/hand-Data-Visualization-with-Bokeh。如果代码有更新,它将在现有的 GitHub 存储库中更新。

我们还有来自丰富的图书和视频目录的其他代码包,可在【https://github.com/PacktPublishing/】获得。看看他们!

下载彩色图像

我们还提供了一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图像。可以在这里下载:https://www . packtpub . com/sites/default/files/downloads/Hands-ondata visualization with bokeh _ color images . PDf。

行动中的代码

请访问以下链接查看正在运行的代码的视频:

http://bit.ly/2xZJdHt

使用的约定

本书通篇使用了许多文本约定。

CodeInText:表示文本中的码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和推特句柄。这里有一个例子:“为了沿着 x 轴渲染日期,我们必须在figure功能中将 x 轴类型设置为datetime

代码块设置如下:

#Output the plot

output_file('second_plot.html')

show(plot2)

任何命令行输入或输出都编写如下:

bokeh serve --show bokeh.py

粗体:表示一个新的术语,一个重要的单词,或者你在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示在文本中。这里有一个例子:“我们将使用在卡格尔发现的标准普尔 500 指数股票数据。”

Warnings or important notes appear like this. Tips and tricks appear like this.

取得联系

我们随时欢迎读者的反馈。

综合反馈:发邮件feedback@packtpub.com并在邮件主题中提及书名。如果您对本书的任何方面有疑问,请发电子邮件至questions@packtpub.com

勘误表:虽然我们已经尽了最大的努力来保证内容的准确性,但是错误还是会发生。如果你在这本书里发现了一个错误,如果你能向我们报告,我们将不胜感激。请访问www.packtpub.com/submit-errata,选择您的图书,点击勘误表提交链接,并输入详细信息。

盗版:如果您在互联网上遇到任何形式的我们作品的非法拷贝,如果您能提供我们的位置地址或网站名称,我们将不胜感激。请通过copyright@packtpub.com联系我们,并提供材料链接。

如果你有兴趣成为一名作者:如果有一个你有专长的话题,你有兴趣写或者投稿一本书,请访问authors.packtpub.com

复习

请留下评论。一旦你阅读并使用了这本书,为什么不在你购买它的网站上留下评论呢?然后,潜在的读者可以看到并使用您不带偏见的意见来做出购买决定,我们在 Packt 可以了解您对我们产品的看法,我们的作者可以看到您对他们的书的反馈。谢谢大家!

更多关于 Packt 的信息,请访问packtpub.com

一、Bokeh 安装和关键概念

欢迎来到使用 Python 中流行的 Bokeh 库的交互式数据可视化世界。在本章中,您将了解以下主题:

  • Bokeh 到底是什么,它与其他绘图库有何不同
  • 如何在本地计算机上安装 Bokeh
  • 如何验证您的 Bokeh 安装
  • 如果出了问题,你可以去哪里寻求帮助
  • 关于 Bokeh 内部运作的一些关键概念

Bokeh 是 Python 中的一个交互式数据可视化库,帮助所有级别的用户可视化从小到大的数据集的简单和复杂数据。您可以使用 Bokeh 来创建交互式图表和应用,这些图表和应用面向普通公众、统计学家甚至商业领袖!

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2l0d7Cb

静态绘图和交互式绘图的区别

在数据可视化领域,有三个主要的使用 Python 的库主导着市场,它们是:

  • Matplotlib
  • 希伯恩
  • Bokeh

前两个,Matplotlib 和 Seaborn,让你绘制静态图——不变的图和无法交互的图。当执行探索性数据分析时,这些图很有用,并且增加了价值,因为它们快速且易于实现,并且执行速度非常快。

第三个绘图库 Bokeh 允许您绘制交互式绘图-当用户与其交互时会改变的绘图。当你想给你的观众提供广泛的选项和工具,从不同的角度推断和观察数据时,这些绘图非常有用。

安装 Bokeh 库

Bokeh 有一些依赖关系。为了使用 Bokeh,请确保已经安装了以下软件包:

  • NumPy
  • 金耶 2
  • 要求
  • 龙卷风> = 4.0
  • 皮亚米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅米雅
  • 日期使用

如果您正在使用 Python 2.7,请确保您拥有所有上述软件包以及:

  • 期货

使用 Python 发行版安装 Bokeh

如果您已经使用诸如 Anaconda 之类的发行版安装和管理了所有 Python 包,您可以使用 Bash 终端或 Windows 提示符使用以下代码安装 Bokeh:

conda install bokeh

您还可以通过以下代码使用 Python 2 的 PyPi 安装 Bokeh:

pip install bokeh

您可以通过以下代码使用 Python 3 的 PyPi 安装 Bokeh:

pip3 install bokeh

就本书而言,所有绘图都将使用 Bokeh 版本 0.12.15 进行渲染。如果您已经安装了 Bokeh 并需要更新,只需在您的终端或外壳中输入以下代码:

sudo pip3 install bokeh --upgrade

验证您的安装

一旦安装了 Bokeh,您将需要验证它是否安装正确。为了验证安装并创建所有 Bokeh 图,您需要一个 Jupyter 笔记本。如果您之前不熟悉使用 Jupyter Notebook 或安装过,以下链接将为您提供如何安装和使用 Jupyter Notebook 的分步教程:http://jupyter.org/install

您可以使用带有以下代码的 Jupyter 笔记本生成一个简单的线图来验证 Bokeh 的安装:

from bokeh.plotting import figure, output_file, show

#HTML file to output your plot into
output_file("bokeh.html")

#Constructing a basic line plot 

x = [1,2,3]
y = [4,5,6]

p = figure()

p.line(x,y)

show(p)

这将在您的浏览器上打开一个新的选项卡,图如下所示:

Don't worry too much about what the code does for now. If you have got the preceding plot, you should be satisfied that Bokeh has been successfully installed on your local machine.

当事情出错时

如果安装出现问题,您有以下两种选择:

Bokeh 的关键概念和构建模块

在阅读这本书的过程中,您会遇到一些对理解 Bokeh 包至关重要的术语。这一部分将带你浏览它们。

以下是与 Bokeh 相关的一些关键定义:

  • 应用:Bokeh 应用是在浏览器中运行的渲染 Bokeh 文档
  • 字形:字形是 Bokeh 的构造块,它们是你在 Bokeh 图上看到的线、圆、矩形和其他形状
  • 服务器:Bokeh 服务器用于向您选择的受众共享和发布互动绘图和应用
    *** Widgets😗*Bokeh 中的 Widgets 是滑块、下拉菜单和其他小工具,你可以将它们嵌入到你的绘图中来增加一些交互性****

****# 绘制输出

有两种方法可以用来渲染您的绘图:

  • output_file : 此方法用于将您的绘图输出为HTML文件,可按以下代码所示使用:
output_file('plot.html')
  • output_notebook:这是用来输出你目前正在制作的 Jupyter 笔记本中的绘图,可以按照下面的代码使用:
output_notebook()

接口:

理解接口的第一步是理解什么是类和方法。把一个类想象成一个容器,把不同类型的饼干放在一起。在这种情况下,容器是类,而 cookie 是给容器一些功能的方法,在我们的情况下,作为 cookie 的容器。

因为 Python 是一种面向对象的编程语言,所以它使用类来将它一起创建的不同对象分组。

一个类本身是无用的,除非它有一些相关的功能。这些功能由方法提供给类。

Bokeh 提供了一个中级绘图界面,类似于matplotlib的界面,被称为bokeh.plotting bokeh.plotting界面中的主要类是Figure类,它包括了为一个图添加不同种类的字形的方法。

用户可以使用figure功能创建Figure object,如以下代码所示:

from bokeh.plotting import figure

# create a Figure object
p = figure(plot_width=500, plot_height=400, tools="pan,hover")

在 Bokeh 中,figure函数,如前面的代码所示,用于初始化和存储您的绘图内容。前面代码中的变量 p 现在保存了关于绘图的信息,包括其高度、宽度和绘图将使用的工具类型。由于figure是我们的主类,所以可以在我们的图中添加线、圆等方法来创建图。

摘要

本章已经为您提供了在本地机器上安装 Bokeh 所需的一组确切步骤。它还让你一瞥在你阅读这本书的过程中会遇到的关键术语。

现在,Bokeh 已经成功安装在您的本地机器上,您可以打开一个新的 Jupyter 笔记本,与 Bokeh 一起在您的第一个绘图上工作!

在下一章中,你将学习如何使用字形创建你的第一个图;您将看到它如何为使用 Bokeh 进行绘图奠定基础。****

二、使用字形绘图

字形是 Bokeh 的基本构件,用于创建各种各样的绘图。事实上,您在使用 Bokeh 时构建的每个单独的绘图都有一个附加的字形机制,例如线条、矩形、圆形和组成绘图的任何其他对象。

在本章中,您将了解以下主题:

  • 什么是字形
  • 如何用字形绘图
  • 如何使用字形创建散点图
  • 如何自定义字形

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2sMGWdU

什么是字形?

当你看到一个绘图,不管是互动的还是非互动的,它通常是由构成绘图中每一个元素的几何形状组成的。在 Bokeh,这些几何形状被称为字形。如果我们想要创建一个线图,我们必须使用线来表示图上的信息,如果我们想要创建一个以圆为标记的散点图,我们将使用来表示该信息。

这些用于向读者传达关于数据的视觉信息的几何形状被称为字形。

在本书中,我们将帮助您使用字形绘制上述四种类型的图,我们还将为您提供使用字形绘制的各种类型的图的信息。

用字形绘图

在本节中,我们将学习如何使用字形绘制以下类型的图:

  • 线图:线图提供了一种以直线的形式可视化沿着 x-y- 轴的点的运动的方式。这些图对于执行时间序列分析非常有用。
  • 条形图:条形图对于指示数据集中特定列或字段的每个类别的计数非常有用。
  • 面片图:面片图用于指示特定色调的点区域。此类图可用于区分同一数据集中的不同组。
  • 散点图:散点图用于可视化两个变量之间的关系,并指示它们之间的相关强度。

创建线图

我们可以使用以下代码在 Bokeh 中绘制一个简单的线图:

#Importing the required packages

from bokeh.io import output_file, show

from bokeh.plotting import figure

#Creating our data arrays used for plotting the line plot

x = [5,6,7,8,9,10]

y = [1,2,3,4,5,6]

#Calling the figure() function to create the figure of the plot

plot = figure()

#Creating a line plot using the line() function

plot.line(x,y)

#Creating markers on our line plot at the location of the intersection between x and y

plot.cross(x,y, size = 15)

#Output the plot 

output_file('line_plot.html')

show(plot)

这导致如下所示的图:

在前面的代码中,我们首先调用了figure()函数,作为指示 Bokeh 构建图表的一种方式。一旦我们做到了这一点,我们就可以向图表中添加字形或几何形状的图层。

为了构建线图,我们首先在图中添加了line()字形,然后在线的顶部添加了cross()字形来标记 xy 点之间的交点。

创建条形图

现在让我们看一下构建一个简单的酒吧绘图。我们可以使用以下代码来实现这一点:

#Importing the required packages

from bokeh.plotting import figure, show, output_file

#Points on the x axis

x = [8,9,10]

#Points on the y axis

y = [1,2,3]

#Creating the figure of the plot

plot = figure()

#Code to create the barplot

plot.vbar(x,top = y, color = "blue", width= 0.5)

#Output the plot

output_file('barplot.html')

show(plot)

这导致如下所示的图:

在前面的代码中,我们使用了vbar,或者竖条函数来生成条形图。这包括四个参数,沿着 x- 轴的点:顶部参数,沿着 y- 轴的点,给你的图一个你选择的颜色的颜色参数,和宽度参数,你想要设置为 0.5 或 1,这取决于你想要在你的条之间的分离水平。此外,您可以使用hbar功能构建水平条形图。

创建面片图

面片图以特定颜色为空间区域着色,以指示具有相似属性的区域或组。我们可以使用以下代码构建一个简单的补丁图:

#Importing the required packages

from bokeh.io import output_file, show

from bokeh.plotting import figure

#Creating the regions to map

x_region = [[1,1,2,], [2,2,3], [2,3,5,4]]

y_region = [[2,5,6], [3,6,7], [2,4,7,8]]

#Creating the figure

plot = figure()

#Building the patch plot

plot.patches(x_region, y_region, fill_color = ['yellow', 'black', 'green'], line_color = 'white')

#Output the plot

output_file('patch_plot.html')

show(plot)

这导致如下所示的图:

在前面的代码中,x_regiony_region被分为三个不同的区域。沿着 x 轴的【1,1,2】的第一个区域映射沿着 y 轴的【2,5,6】的对应区域,并被赋予黄色。沿着 x 轴的【2,2,3】的第二个区域映射了沿着 y 轴的【3,6,7】的对应区域,并被赋予黑色。沿着 x- 轴的【2,3,5,4】的第三个区域映射了沿着 y 轴的【2,4,7,8】的对应区域,并被赋予绿色。然后,我们使用patches函数,通过给它区域,以及每个区域的颜色作为参数来构建图。line_color参数用于为每个面片赋予边框颜色。

创建散点图

散点图是确定两个变量之间双变量关系最常用的图之一,因此当我们使用 Bokeh 向它们添加交互性时,这种关系会得到增强。为了使用 Bokeh 构建一个简单的散点图,我们可以使用以下代码:

#Importing the required packages

from bokeh.io import output_file, show

from bokeh.plotting import figure

#Creating the figure

plot = figure()

#Creating the x and y points

x = [1,2,3,4,5]

y = [5,7,2,2,4]

#Plotting the points with a cirle marker

plot.circle(x,y, size = 30)

#Output the plot

output_file('scatter.html')

show(plot)

这导致如下所示的图:

在前面的代码中,我们使用圆形标记为每个圆形创建大小为 30 的散点图。圆圈表示 xy 列表中的点之间的交点。

自定义字形

创建前面的散点图时,我们使用圆形标记来指示图上的点。Bokeh 为我们提供了各种各样的标记,您可以使用它们来代替圆圈,它们如下:

- cross()
- x()
- diamond()
- diamond_cross()
- circle_x()
- circle_cross()
- triangle()
- inverted_triangle()
- square()
- square_x()
- square_cross()
- asterisk()

您也可以使用以下代码为x-和 y 轴添加标签:

plot.figure(x_axis_label = "Label name of x axis", y_axis_label = "Label name of y axis")

您可以使用以下代码来自定义散点图上点的透明度:

plot.circle(x, y, alpha = 0.5)

alpha 参数的取值范围在 0 到 1 之间,0 表示完全透明,1 表示不透明。

摘要

这一章已经给你介绍了什么是字形,以及如何使用它们来创建使用 Bokeh 的基本图。我们还研究了如何进一步定制这些图。

字形是 Bokeh 的基本构造块,为了在未来创建更复杂、更有统计意义的绘图,需要字形。

在本章中,您学习了如何使用字形创建四种不同的绘图。线图通常用于时间序列分析,条形图通常用于比较不同类别之间的计数,面片图通常用于突出显示一个区域的点,散点图通常用于映射两个或多个变量之间的关系。

在下一章中,我们将利用这些概念,并使用 NumPy 数组和 Pandas 数据帧绘制图表。

三、使用不同的数据结构绘图

现在,您已经学习了如何使用 Glyphs 从头开始构建可视化,我们可以扩展这个概念,并使用数据结构(如 NumPy 数组和熊猫数据框)构建绘图。

本章还将教你ColumnDataSource,Bokeh 库的核心本质,它将允许你通过多个图和小部件共享你的数据!

简而言之,您将获得在各种数据结构中使用 Bokeh 的实际经验,因为本章将带您了解:

  • 使用 NumPy 数组创建绘图
  • 用熊猫数据帧创建绘图
  • 使用ColumnDataSource创建绘图

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2MjrvSm

使用 NumPy 数组创建绘图

NumPy 数组是 Python 中最基本的数据结构之一,因此在 Bokeh 中创建交互式可视化时是一种重要的数据结构。在本节中,我们将介绍如何使用 NumPy 阵列构建直线和散点图。

使用 NumPy 数组创建线图

为了使用 NumPy 数组创建简单的线图,我们可以使用以下代码:

#Import required packages

import numpy as np
import random
from bokeh.io import output_file, show
from bokeh.plotting import figure

#Creating an array for the points along the x and y axes

array_x =np.array([1,2,3,4,5,6])

array_y = np.array([5,6,7,8,9,10])

#Creating a line plot

plot = figure()

plot.line(array_x, array_y)

#Output the plot

output_file('numpy_line.html')

show(plot)

这将绘制如下图所示的图:

在前面的代码中,我们创建了两个 NumPy 数组来保存沿着 x 轴和 y 轴的点。然后,我们使用我们在上一章中学习的常规 Bokeh 函数调用来构建线图。

使用 NumPy 数组创建散点图

为了使用 NumPy 数组创建散点图,我们使用如下所示的代码:

#Import required packages

import numpy as np
import random
from bokeh.io import output_file, show
from bokeh.plotting import figure

#Creating arrays for two different categories of points

x_red = np.array([1,2,3,4,5])
y_red = np.array([5,6,7,8,9])

x_blue = np.array([10,11,12,13])
y_blue = np.array([14,15,16,17])

#Creating the categorical scatter plot 

plot = figure()

plot.circle(x_red, y_red, size = 9, color = 'red', alpha = 0.8)
plot.circle(x_blue, y_blue, size = 9, color = 'blue', alpha = 0.8)

#Output the plot 

output_file('numpy_scatter.html')

show(plot)

这将产生如下图所示的图:

在前面的代码中,我们创建了两组不同的点:红色组和蓝色组。每组都有自己的一组 xy 点,它们是 NumPy 数组。然后,我们通过相应地给每个组着色来创建散点图。

现在,您可以在散点图上看到两组不同的彩色点。这些图对于可视化分类数据非常有用。

使用熊猫数据帧创建绘图

您将使用的大部分数据将以 CSV 或 Excel 格式提供,因此您将不可避免地将它们转换为熊猫数据框,以便有效地使用它们。Bokeh 扩展了它的功能,帮助我们使用 Python 中的熊猫数据框架构建交互式但有意义的绘图。在本节中,我们将使用熊猫数据框构建散点图和时间序列图。

在本节中,我们将使用一个关于卡格勒上的股票市场的流行数据集,该数据集可通过以下链接访问:卡格勒标准普尔 500 股票数据(https://www.kaggle.com/camnugent/sandp500/data)。

作为第一步,让我们将数据集加载到 Jupyter 笔记本中。我们可以使用这里显示的代码来实现这一点:

#Importing the required packages

import pandas as pd

#Read in the data

df = pd.read_csv('all_stocks_5yr.csv')

#Filtering for apple stocks

df_apple = df[df['Name'] == 'AAL']

#Converting the date column to a time series

df_apple['date'] = pd.to_datetime(df_apple['date'])

在前面的代码中,我将从 Kaggle 下载的文件保存为all_stocks_5yr.csv,并使用 pandas 将其加载到 Jupyter Notebook 中。然后我过滤了股票,创建了一个新的数据框架,其中只有苹果的股票信息。

使用熊猫数据框创建时间序列图

时间序列图显示了数据集中的点在一定时间内是如何变化的。时间通常沿着 x- 轴绘制,而感兴趣的点在 y 轴上。

我们现在将创建一个时间序列图,以便通过使用这里显示的代码来可视化苹果股票的High Prices在 5 年期间是如何变化的:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.plotting import figure
import pandas as pd

#Read in the data

df = pd.read_csv('all_stocks_5yr.csv')

#Filtering for apple stocks

df_apple = df[df['Name'] == 'AAL']

#Converting the date column to a time series

df_apple['date'] = pd.to_datetime(df_apple['date'])

#Create the time series plot

plot = figure(x_axis_type = 'datetime', x_axis_label = 'date', y_axis_label = 'High Prices')

plot.line(x = df_apple['date'], y = df_apple['high'])

#Output the plot

output_file('pandas_time.html')

show(plot)

这将产生如下图所示的图:

在前面的代码中,我们必须在figure功能中将 x 轴类型设置为datetime,以便沿 x 轴渲染日期。然后,我们使用线函数来生成过去 5 年中苹果的日期和高价之间的时间序列图。

使用熊猫数据框创建散点图

为了在低价和高价之间创建散点图,以及在同一图中呈现的开盘价和收盘价,我们使用这里显示的代码:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.plotting import figure

#Create the scatter plot

plot = figure()

plot.circle(x = df_apple['high'], y = df_apple['low'], color = 'red', size = 10, alpha = 0.8)

plot.diamond(x = df_apple['open'], y = df_apple['close'], color = 'green', size = 10, alpha = 0.8)

#Output the plot

output_file('pandas_scatter.html')

show(plot)

这将产生如下图所示的图:

在之前的绘图中,红色的圆圈代表苹果价格高低的关系,绿色的钻石代表开盘价和收盘价的关系。我们使用circle函数在高、低价格之间创建红色圆圈,而使用diamond函数在开盘价和收盘价之间创建绿色钻石。

使用列数据源创建绘图

ColumnDataSource为我们提供了一种跨多个图和小部件使用相同数据的方法。通过将数据输入ColumnDataSource,你就建立了一个可以随时调用的数据基础,而不是将数据多次加载到你的 Jupyter 笔记本中。

基本上,ColumnDataSource创建一个字典,其中值是包含在列中的数据,键是您为该特定列指定的字符串名称。

使用列数据源创建时间序列图

为了使用ColumnDataSource构建时间序列图,我们使用以下代码:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.plotting import ColumnDataSource

#Create the ColumnDataSource object

data = ColumnDataSource(df_apple)

#Create the time series plot

plot = figure(x_axis_type = 'datetime', x_axis_label = 'date', y_axis_label = 'High Prices')

plot.line(x = 'date', y = 'high', source = data, color = 'red')

plot.circle(x = 'date', y = 'high', source = data, fill_color = 'white', size = 3)

#Output the plot

output_file('CDS_time.html')

show(plot)

这将产生如下图所示的图:

该图向我们展示了苹果股票的高价格在 5 年期间是如何变化的,蓝色圆圈表示股票的每个价格点。

创建此图时,我们将整个苹果股票数据框传递到ColumnDataSource函数,并将其保存到名为data的变量中。

然后,我们在创建图时使用了源参数,并在此传递了data 我们现在可以在创建绘图时直接使用列名,而不是调用数据框。

最后,我们使用圆函数生成带有白色填充的蓝色圆来表示各个数据点。

使用列数据源创建散点图

使用ColumnDataSource的另一种方法是传入数据,如代码所示:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource

#Create the ColumnDataSource object

data = ColumnDataSource(data = {
    'x' : df_apple['high'],
    'y' : df_apple['low'],
    'x1': df_apple['open'],
    'x2': df_apple['close'],

})

#Create the scatter plot

plot = figure()

plot.cross(x = 'x', y = 'y', source = data, color = 'red', size = 10, alpha = 0.8)

plot.circle(x = 'x1', y = 'x2', source = data, color = 'green', size = 10, alpha = 0.3)

#Output the plot

output_file('CDS_scatter.html')

show(plot)

这将产生如下图所示的图:

在前面的代码中,我们将数据框的列映射为字典中的值,该字典由键值对组成,键是您选择的字符串名称,值是数据框的列。

然后,我们将该字典作为ColumnDataSource函数的data 参数的值传递。最后,在创建圆形和交叉散点图时,字典的关键字被传递到 xy 参数中。

摘要

本章向您介绍了使用 Python 时会遇到的最常见的数据格式,以及如何使用这些格式在 Bokeh 中创建可视化。

您还学习了如何使用ColumnDataSource将列名映射到数据值列表,该列表可用于多个图和小部件。

在接下来的一章中,你将学习如何使用布局,通过熊猫数据帧构建的图来有效地展示数据。

四、将布局用于有效演示

在绘制多个图时,最好总是使用布局,以便并排显示图,或者在彼此的顶部垂直显示图,以便在两个图之间进行统计比较,同时使它们具有视觉吸引力。

使用 Bokeh 创建绘图时,有效地使用布局、选项卡和网格也将允许您通过使用相同的轴将多个绘图链接在一起。这使得多个图的比较比您在 Jupyter 笔记本的单独单元格中创建图要精确得多。

在本章中,您将学习如何:

  • 沿同一行创建多个绘图
  • 沿同一列创建多个图
  • 在行和列中创建多个图
  • 使用选项卡式布局创建多个绘图
  • 创建健壮的网格布局
  • 将多个绘图链接在一起

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2sOMTab

沿同一行创建多个绘图

为了沿着同一行创建多个图,让我们首先创建三个唯一的图。我们将使用在卡格尔(https://www.kaggle.com/camnugent/sandp500/data)上找到的标准普尔 500 股票数据。

第一步是读取数据并对其进行过滤,以便我们只使用与 Apple 相关的数据,如下所示:

#Import the required packages

import pandas as pd

#Read in the data

df = pd.read_csv('all_stocks_5yr.csv')

#Convert the date column into datetime data type

df['date'] = pd.to_datetime(df['date'])

#Filter the data for Apple stocks only

df_apple = df[df['Name'] == 'AAL']

接下来,让我们使用如下所示的代码构建三个独特的图:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.plotting import ColumnDataSource

#Create the ColumnDataSource object

data = ColumnDataSource(data = {
    'x' : df_apple['high'],
    'y' : df_apple['low'],
    'x1': df_apple['open'],
    'y1': df_apple['close'],
    'x2': df_apple['date'],
    'y2': df_apple['volume'],

})

#Create the first scatter plot

plot1 = figure()

plot1.cross(x = 'x', y = 'y', source = data, color = 'red', size = 10, alpha = 0.8)

#Create the second scatter plot

plot2 = figure()

plot2.circle(x = 'x1', y = 'y1', source = data, color = 'green', size = 10, alpha = 0.3)

#Create the third scatter plot

plot3 = figure(x_axis_type = 'datetime', x_axis_label = 'date', y_axis_label = 'Volume Traded')

plot3.line(x = 'x2', y = 'y2', source = data, color = 'red')

plot3.circle(x = 'x2', y = 'y2', source = data, fill_color = 'white', size = 3)

在前面的代码中,为了映射所有感兴趣的变量,我们创建了一个ColumnDataSource对象。

第一个散点图位于苹果的高价格和低价格之间,可以使用这里显示的代码显示:

#Output the plot

output_file('first_plot.html')

show(plot1)

这将产生如下图所示的图:

第二个图位于苹果的开盘价和收盘价之间,可以使用以下代码显示:

#Output the plot

output_file('second_plot.html')

show(plot2)

这将产生如下图所示的图:

第三个图是 5 年期间苹果股票交易量之间的时间序列图。我们可以使用下面显示的代码显示该图:

#Output the plot

output_file('third_plot.html')

show(plot3)

这将产生如下图所示的图:

请注意,为了查看三个图,我们必须创建三个单独的输出。当我们想要并排查看三个图以便快速简单地比较所有三个图时,这对我们不利。

为了绘制水平行中的三个图,我们使用如下所示的代码:

#Import the required packages

from bokeh.layouts import row
from bokeh.io import output_file, show

#Group the 3 plots into a 'row' layout

row_layout = row(plot1,plot2,plot3)

#Output the plot

output_file('horizontal.html')

show(row_layout)

这将产生如下图所示的图:

Plots 1, 2, and 3 in a horizontal layout

我们现在可以观察到,三个绘图以水平方式并排堆叠在一起。在前面的代码中,我们使用了函数,该函数将我们之前创建的图作为参数,以便水平绘制三个图形。

在同一列中创建多个图

在本节中,您将学习如何将多个图垂直堆叠在一起,以创建图的列式比较。我们将使用本章前面创建的两个散点图来实现这一点。

为了创建绘图的垂直布局,我们使用如下所示的代码:

#Import the required packages

from bokeh.layouts import column
from bokeh.io import output_file, show

#Group the 2 plots into a 'column' layout

col_layout = column(plot1,plot2)

#Output the plot

output_file('vertical.html')

show(col_layout)

这导致了图的布局,如下图所示:

Plots 1 and 2 in a vertical layout

在前面的代码中,我们使用了column函数,该函数将我们想要垂直堆叠的图作为输入参数,以创建图的垂直布局。这创建了散点图的垂直布局,我们现在可以使用它进行比较。

在行和列中创建多个图

我们可能会看到这样一种情况,即我们希望水平比较两个散点图,但希望时间序列图与散点图堆叠在一起,但都在同一布局的范围内。

这种水平和垂直布局的组合称为嵌套布局。

我们可以使用下面显示的代码构建嵌套布局:

#Import the required packages

from bokeh.layouts import column, row
from bokeh.io import output_file, show

#Construct the nested layout

nested_layout = column(row(plot1,plot2), plot3)

#Output the plot

output_file('nested.html')

show(nested_layout)

这将产生如下图所示的图:

Plots 1, 2, and 3 in a nested layout

在前面的代码中,我们使用行函数将图 1 和图 2 组合成一个水平行,然后在散点图和图 3 的水平组合上使用列函数。

这生成了一个嵌套布局,散点图并排,而时间序列图在这里是一个独立的实体。嵌套布局提供了一种有效的方法,可以将特定的图组分成行和列,从而通过有效的比较帮助我们理解数据。

使用选项卡式布局创建多个绘图

有时,一次查看一个绘图,但在同一空间中有多个绘图可能更有效。这可以通过使用 Bokeh 提供的选项卡式布局来实现。使用选项卡式布局,每个图都存储在一个选项卡中,只需单击该选项卡即可访问。

我们将使用与前面部分相同的三个图来构建选项卡式布局。

为了在选项卡式布局中创建图,我们可以使用这里显示的代码:

#Import the required packages

from bokeh.models.widgets import Tabs, Panel
from bokeh.io import output_file, show
from bokeh.layouts import column, row

#Create the two panels 

tab1 = Panel(child = plot1, title = 'Tab One')

tab2 = Panel(child = column(plot2,plot3), title = 'Tab Two')

#Feed the tabs into a Tabs object

tabs_object = Tabs(tabs = [tab1, tab2])

#Output the plot

output_file('tab_layout.html')

show(tabs_object)

这将产生一个选项卡式布局,如下所示:

Plot 1 in a tabbed layout

在前面的代码中,我们首先使用Panel函数创建了两个面板。每个面板都由自己的一组图组成,这些图是使用Panel函数中的child参数指定的。

然后,我们使用Tabs函数创建了一个标签对象,方法是将面板传递给tabs参数。

在前面的图中,我们现在在标签一上,它由一个散点图组成。如果我们单击选项卡二,我们将在垂直布局中看到图 2 和图 3,如下图所示:

Plot 2 and Plot 3 in a vertical layout

如果我们希望轻松地将所有图集中在一个位置,但同时又希望查看单个图或一组图,而又不想让所有图在屏幕上杂乱无章,那么使用选项卡式布局会非常有效。

创建健壮的网格布局

网格布局结合了行、列和嵌套布局,允许您水平、垂直或水平和垂直创建绘图。使用网格布局更加健壮,因为该布局提供了在单个屏幕中将多个图堆叠在一起的组合的多功能性。

为了构建一个网格布局,我们将使用与前面几节中相同的三个图。

我们可以使用下面显示的代码创建嵌套网格布局:

#Import required packages

from bokeh.io import output_file, show
from bokeh.layouts import gridplot

#Create the grid layout

grid_layout = gridplot([plot1, plot2], [plot3, None])

#Output the plot

output_file('grid.html')

show(grid_layout)

这将产生如下所示的网格布局:

Creating a nested layout using the grid layout

在前面的代码中,我们使用了gridplot函数来创建图的网格,如前所述。我们将plot1plot2作为列表传入gridplot功能,表示我们希望 p lot 1plot2水平显示在第一行。然后我们将plot3None作为第二个列表传递给gridplot函数,以表明我们想要plot3,并且第二行中没有水平显示的图。

将多个绘图链接在一起

有时,我们可能希望我们的图沿着 x- 和/或 y- 轴具有相同的值范围,以便于对不同图中相同范围的点进行有意义的比较。

我们将与plot1plot2,plot3合作,如之前章节所述。

为了沿着 y- 轴创建具有相同范围的多个图,我们使用如下所示的代码:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.layouts import row

#Creating equal y axis ranges

plot3.y_range = plot1.y_range

#Create the row layout

row_layout = row(plot3, plot1)

#Output the plot

output_file('grid.html')

show(row_layout)

这将产生如下图所示的绘图布局:

Plots 1 and 3 linked together by the same *y *axis range as plot 3

在前面的代码中,我们给了plot1plot3相同的 y 范围。在生成的图表中,您可以观察到plot3plot1如何具有完全相同的 y- 轴范围。您还可以看到,使用plot1,由于其 y 轴范围的变化,最初非常线性的散点图变成了水平线。这是因为plot1最初的 y- 轴范围在 0 到 60 之间,但是现在它采用了plot3y- 轴范围,这是一个在 10^7 范围内的值,该图的形状也发生了巨大的变化。

我们可以使用此处显示的代码沿 x- 轴创建多个范围相同的图:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.layouts import row

#Creating equal x-axis ranges

plot2.x_range = plot1.x_range

#Create the row layout

row_layout = row(plot2, plot1)

#Output the plot

output_file('row.html')

show(row_layout)

这将产生如下图所示的行布局:

Plots 1 and 2 linked together using the same x-axis range as Plot 2

将多个绘图链接在一起时,需要注意的最重要的一点是 x -/ y- 轴中的数据类型必须相同。例如,沿 x- 轴链接两个绘图,其中一个绘图沿 x- 轴具有日期(时间戳)类型,而另一个绘图具有数字,这种方法不可行。

摘要

本章让您深入了解了如何在 Bokeh 中使用布局来最大限度地发挥您的绘图带来的影响,包括统计和视觉效果。

您学习了如何在水平布局、垂直布局和嵌套布局中创建绘图。您还学习了如何使用网格布局作为将水平和垂直布局组合在一起的更有效的方法。

独立布局需要更多的代码行才能在同一个图像中水平和垂直堆叠图,而网格布局只需一行代码就可以做到这一点,是在不同布局配置中将多个图堆叠在一起的更有效方法。

创建选项卡以减少混乱,并将多个图链接在一起以改进数据点的比较研究,现在这些都在您位于 Bokeh 的工具带上。

在下一章中,您将学习如何使用注释、小部件和属性来增强您到目前为止创建的绘图的视觉效果,这些将为您的绘图增加一个交互性的世界!

五、使用标注、小部件和视觉属性进行视觉增强

现在您已经学习了如何在 Bokeh 中创建图和布局,是时候在视觉上增强它们,并使用标注、小部件和视觉属性添加一层交互性了。

标注用于向您的绘图添加补充信息,例如标题、图例和彩色地图,它们提供了有关绘图试图向查看您的绘图的人传达的信息。

小部件通过按钮、下拉菜单、滑块和文本框提供交互性。这些小部件允许观看绘图的人与绘图互动,并改变他或她想要观看的方式。

视觉属性为绘图提供了大量的视觉增强,例如线条和文本的颜色和填充,以及交互性增强,例如悬停工具,用于悬停和选择感兴趣的点。

在本章中,您将学习如何创建:

  • 传达绘图补充信息的标注
  • 为绘图增加互动性的小部件
  • 增强绘图风格和互动性的视觉属性

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2sYn4DN

创建标注以传达补充信息

在创作绘图时,最基本的是要理解绘图中的信息试图传达的故事。这可以通过在你的绘图中添加标题、图例和彩色地图来完成。

向绘图添加标题

标题是用来告诉读者整个故事绘图的。

为了本章的目的,我们将使用卡格尔网站上的标准普尔 500 股票数据。(https://www.kaggle.com/camnugent/sandp500/data)。

我们还将过滤数据,只显示有关苹果股票的信息,如以下代码所示:

#Import the required packages

import pandas as pd

#Read in the data

df = pd.read_csv('all_stocks_5yr.csv')

#Convert the date column into datetime data type

df['date'] = pd.to_datetime(df['date'])

#Filter the data for Apple stocks only

df_apple = df[df['Name'] == 'AAL']

我们现在将使用这里显示的代码将所需的数据存储在一个ColumnDataSource对象中:

#Import the required packages

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.plotting import ColumnDataSource

#Create the ColumnDataSource object

data = ColumnDataSource(data = {
    'x' : df_apple['high'],
    'y' : df_apple['low'],
    'x1': df_apple['open'],
    'y1': df_apple['close'],
    'x2': df_apple['date'],
    'y2': df_apple['volume'],

})

为了给我们的绘图增加一个标题,我们使用了如下所示的代码:

#Import the required packages

from bokeh.plotting import figure, show, output_file, output_notebook

#Create the plot with the title

plot = figure(title = "5 year time series distribution of volume of Apple stocks traded",title_location = "above",x_axis_type = 'datetime', x_axis_label = 'date', y_axis_label = 'Volume Traded')

#Create the time series plot

plot.line(x = 'x2', y = 'y2', source = data, color = 'red')

plot.circle(x = 'x2', y = 'y2', source = data, fill_color = 'white', size = 3)

#Output the plot

output_file('title.html')

show(plot)

这将产生一个标题图,如下图所示:

在这段代码中,我们使用了figure 函数,以便使用title参数生成标题。此外,我们还可以使用title_location参数指定标题的位置。标题的不同位置是aboveleftrightbelow

向图中添加图例

当我们有一个绘图,其中有不同的可视化不同的颜色,这是很重要的读者能够区分不同的颜色。这可以通过在我们的绘图中加入一个传说来实现。

在下面的代码中,我们在同一个图中绘制了两个不同的散点图,但颜色不同。我们使用下面显示的代码为每个散点图添加一个图例:

#Import the required packages

from bokeh.plotting import figure, show, output_file

#Create the two scatter plots

plot = figure()

#Create the legends

plot.cross(x = 'x', y = 'y', source = data, color = 'red', size = 10, alpha = 0.8, legend = "High Vs. Low")

plot.circle(x = 'x1', y = 'y1', source = data, color = 'green', size = 10, alpha = 0.3, legend = "Open Vs. Close")

#Output the plot

output_file('legend.html')

show(plot)

这将产生一个带有图例的图,如下图所示:

在这段代码中,我们在创建单个散点图时使用了legend参数来指定该特定图的图例。多亏了这个传说,我们现在可以清楚地区分绿色散点图和红色散点图的含义。

向绘图添加彩色地图

当我们有分类数据时,用不同的颜色给不同的类别着色是一个很好的做法,这样读者就可以清楚地看到不同的颜色表示不同的类别。

为了做到这一点,我们首先使用这里显示的代码过滤两个股票的S&P 500股票数据:谷歌和 USB:

#Reading in the S&P 500 data

df = pd.read_csv('all_stocks_5yr.csv')

#Filtering for Google or USB

df_multiple = df[(df['Name'] == 'GOOGL') | (df['Name'] == 'USB')]

接下来,我们将在highlow之间创建一个散点图,并使用这里显示的代码用不同的颜色对谷歌股票和通用串行总线股票进行分类着色:

#Import the required packages

from bokeh.models import CategoricalColorMapper

#Store the data in the ColumnDataSource object

data = ColumnDataSource(df_multiple)

#Create the mapper 

category_map = CategoricalColorMapper(
    factors = ['GOOGL', 'USB'], palette = ['blue', 'red'])

#Plot the figure

plot = figure()

plot.circle('high', 'low', size = 8, source = data, color = {'field': 'Name', 'transform': category_map})

#Output the plot

output_file('category.html')

show(plot)

这将产生如图所示的图:

从绘图来看,很明显蓝色和红色这两种颜色分别代表了谷歌和 USB 股票。

在这段代码中,我们使用CategoricalColorMapper函数为每只股票指定一种特定的颜色。然后,我们在创建图时使用color参数来构建包含类别的field或列的字典,以及我们用CategoricalColorMapper 创建的类别地图。

创建小部件来增加绘图的互动性

Bokeh 最独特的功能之一是能够添加小部件,为绘图增加交互性。小部件允许用户通过选择、点击按钮和在文本框中输入来改变他们想要看到的内容。在本节中,您将了解 Bokeh 可以添加到工具带的所有小部件。

这里给出了创建和输出任何类型的小部件所需的两个导入:

from bokeh.io import output_file, show
from bokeh.layouts import widgetbox

创建按钮小部件

按钮允许用户点击并进行选择。我们可以使用下面显示的代码在 Bokeh 中创建一个按钮小部件:

#Import the required packages

from bokeh.models.widgets import Button

#Create the button widget

button_widget = Button(label="Click this")

#Output the button

output_file("button_widget.html")

show(widgetbox(button_widget))

这将创建一个按钮,如下图所示:

在这段代码中,我们使用Button 功能创建了一个按钮,其文本为点击此处。

创建复选框小部件

复选框允许用户进行一个或多个选择。当一个图有多个类别和/或可视化时,它们通常用于选择单个或多个类别/图。

为了在 Bokeh 中创建一个简单的复选框,请使用下面显示的代码:

#Import the required packages

from bokeh.models.widgets import CheckboxGroup

#Create the checkbox

checkbox_widget = CheckboxGroup(
        labels=["box: 1", "box: 2", "box:3"], active=[1,2])

#Output the checkbox

output_file("checkbox_widget.html")

show(widgetbox(checkbox_widget))

这将导致复选框的创建,如下所示:

在这段代码中,我们使用了CheckboxGroup 功能来创建三个类别。active参数用于指定创建复选框时三个类别中的哪一个应保持选中状态。在这种情况下,我们在创建时将active配置为复选框 2 和 3。

创建下拉菜单小部件

下拉菜单可用于从用户可用的众多选项中进行选择。要构建下拉菜单,请使用下面显示的代码:

#Import the required packages

from bokeh.models.widgets import Dropdown

#Create the menu

menu_widget = [("menu option 1", "1"), ("menu option 2", "2")]

#Create the Dropdown

menu_dropdown = Dropdown(label="Dropdown Menu", menu=menu_widget)

#Output the dropdown menu

output_file("dropdown.html")

show(widgetbox(menu_dropdown))

这将创建一个下拉菜单,如下图所示:

在这段代码中,我们首先创建了一个将出现在下拉菜单中的名称列表。然后,我们通过使用Dropdown 功能并通过将菜单列表传递给menu参数来创建下拉菜单。

创建单选按钮小部件

单选按钮限制用户只能选择一个选项,而不是复选框等多个选项。当多次选择导致错误时,此类按钮非常有用。要构建单选按钮,请使用此处显示的代码:

#Import the required packages

from bokeh.models.widgets import RadioGroup

#Create the radio button 

radio_button_widget = RadioGroup(
        labels=["First Radio Button", "Second Radio Button"], active=0)

#Output the radio button widget

output_file("radiobutton_widget.html")

show(widgetbox(radio_button_widget))

这将创建一个单选按钮,如下图所示:

在这段代码中,我们使用RadioGroup功能来创建单选按钮。labels参数用于指定按钮的名称,而active参数用于指定默认选择哪个按钮。

创建滑块小部件

滑块用于增加或减少您可能想要在绘图中查看的设定点数或区域。为了在 Bokeh 中构建一个简单的滑块小部件,请使用下面显示的代码:

#Import the required packages

from bokeh.models.widgets import Slider

#Create the slider widget

slider_widget = Slider(start=0, end=50, value=0, title="Simple Slider", step = 5)

#Output the slider

output_file("slider_widget.html")

show(widgetbox(slider_widget))

这将产生一个滑块小部件,如下图所示:

在这段代码中,我们使用了Slider函数来创建滑块部件。start参数用于指定滑块的起始值,end参数用于指定滑块的最后一个值,在本例中为 50value参数用于指定滑块生成时的起始值。step参数用于指定滑块向右或向左移动时其值增加或减少的次数。最后,title参数被用来给滑块一个标题。

创建文本输入小部件

文本输入框为用户提供了一种键入文本的方式,该方式可以链接到更改绘图的输出,具体取决于您之前如何配置绘图。要创建文本输入小部件,请使用下面显示的代码:

#Import the required packages

from bokeh.models.widgets import TextInput

#Create the text input widget

text_input_widget = TextInput(title="Type your text here", value = "")

#Output the text input widget

output_file("text_input_widget.html")

show(widgetbox(text_input_widget))

这将产生一个文本输入小部件,如下图所示:

在这段代码中,我们使用了TextInput 功能来创建文本输入小部件。value参数用于设置创建文本输入小部件时出现在文本输入框中的默认文本。title参数用于指定文本输入小部件的标题,它很重要,因为标题通常会向用户提供他/她必须在文本输入框中键入的内容。

创建视觉属性以增强风格和交互性

视觉属性可以大致分为两类:

  • 增加绘图互动性的属性
  • 增强绘图视觉风格的属性

本节将为这两个类别奠定基础,并展示如何充分利用和开发 Bokeh 来充分利用您的绘图。

增加绘图互动性的属性

进一步增强绘图互动性的视觉属性如下:

  • 悬停工具提示:让您将鼠标指向图中的特定点并显示相关信息
  • 选择:允许您选择绘图的一个区域,并为该区域选择不同的颜色

创建悬停工具提示

为了创建悬停工具提示,我们将使用这里显示的代码:

#Import the required packages

from bokeh.models import CategoricalColorMapper
from bokeh.models import HoverTool
from bokeh.io import output_file, show
from bokeh.plotting import ColumnDataSource
from bokeh.plotting import figure
import pandas as pd

#Read in the data and filter for Google and USB stocks

df = pd.read_csv('all_stocks_5yr.csv')

df_multiple = df[(df['Name'] == 'GOOGL') | (df['Name'] == 'USB')]

#Create the hover tooltip

hover_tool = HoverTool(tooltips = [
    ('Stock Ticker', '@Name'),
    ('High Price', '@high'),
    ('Low Price', '@low')
]) 

#Save the data in a ColumnDataSource object

data = ColumnDataSource(df_multiple)

#Create the categorical color mapper

category_map = CategoricalColorMapper(
    factors = ['GOOGL', 'USB'], palette = ['blue', 'red'])

#Create the plot with the hover tooltip

plot = figure(tools = [hover_tool])

plot.circle('high', 'low', size = 8, source = data, color = {'field': 'Name', 'transform': category_map})

#Output the plot

output_file('hover.html')

show(plot)

这将产生一个带有悬停工具提示的绘图,显示有关绘图中特定点的信息,如下所示:

在这段代码中,我们重用了我们使用分类颜色映射器为不同类别着色而创建的图。我们使用HoverTool 函数来创建元组列表。每个元组包含要传递的信息的名称,如Stock Ticker,以及在其中找到该信息的关联列,如@Name。然后,我们在创建绘图时将这个HoverTool 对象传递到figure函数的tools参数中。

将鼠标指向图中的特定点,我们会看到诸如股票代码、高价和低价等信息。

创建选择

为了选择我们刚刚创建的绘图区域,我们将使用这里显示的代码:

#Import the required packages

from bokeh.models import CategoricalColorMapper
from bokeh.models import HoverTool
from bokeh.io import output_file, show
from bokeh.plotting import ColumnDataSource
from bokeh.plotting import figure

#Read in the dataset and filter for Google and USB stocks

df = pd.read_csv('all_stocks_5yr.csv')

df_multiple = df[(df['Name'] == 'GOOGL') | (df['Name'] == 'USB')]

#Save the data into a ColumnDataSource object

data = ColumnDataSource(df_multiple)

#Create the categorical color mapper

category_map = CategoricalColorMapper(
    factors = ['GOOGL', 'USB'], palette = ['blue', 'red'])

#Create the plot with the selection tool 

plot = figure(tools = 'box_select')

plot.circle('high', 'low', size = 8, source = data, 
            color = {'field': 'Name', 'transform': category_map}, selection_color = 'green',
           nonselection_fill_alpha = 0.3, nonselection_fill_color = 'grey')

#Output the plot

output_file('selection.html')

show(plot)

这导致了如下图所示的结果:

在这个图中,Box Select工具可以在右上角找到。单击框选择工具后,我们可以在绘图上拖动并创建一个框来选择绘图的一个区域。在前面的图中,选定的区域显示为绿色,而未选定的区域显示为灰色。

在这段代码中,我们在创建绘图时使用selection_color参数来指定绘图在选择后将变为的颜色。我们使用nonselection_fill_color来指定图中未选择的区域将采用的颜色,在本例中为灰色。

最后,我们使用figure功能来指定tools,在这种情况下是box_select工具,它以正方形选择绘图的区域。

增强绘图视觉风格的属性

增强绘图视觉风格的属性可分为以下几类:

  • 设计标题
  • 设计背景
  • 设计绘图的轮廓
  • 设计标签的样式

设计标题

设计绘图的标题是一个非常棒的方法,可以创造出一个对手头的任务来说真正独特的绘图。为了创建自定义的绘图样式,我们使用如下所示的代码:

#Import the required packages

from bokeh.models import CategoricalColorMapper
from bokeh.models import HoverTool
from bokeh.io import output_file, show
from bokeh.plotting import ColumnDataSource
from bokeh.plotting import figure

#Read in and filter the data for Google and USB stocks

df = pd.read_csv("all_stocks_5yr.csv")

df_multiple = df[(df['Name'] == 'GOOGL') | (df['Name'] == 'USB')]

#Store the data in a ColumnDataSource

data = ColumnDataSource(df_multiple)

#Create the categorical color mapper

category_map = CategoricalColorMapper(
    factors = ['GOOGL', 'USB'], palette = ['blue', 'red'])

#Create the plot and configure the title 

plot = figure(title = "High Vs. Low Prices (Google & USB)")

plot.title.text_color = "red"

plot.title.text_font = "times"

plot.title.text_font_style = "bold"

plot.circle('high', 'low', size = 8, source = data, 
            color = {'field': 'Name', 'transform': category_map})

#Output the plot

output_file('title.html')

show(plot)

这将产生一个标题独特的图,如下图所示:

在这个绘图中,标题是红色的,用的是泰晤士新罗马字体,而且是粗体。在这段代码中,我们使用title.text_color给标题一个红色。然后我们使用title.text_font给标题命名为泰晤士新罗马字体。最后我们用title.text_font_style给绘图加粗字体。

设计背景

你的绘图背景可以设计成不同的颜色。当我们希望绘图中的要点在对比鲜明的背景下显得突出时,这一点尤其有用。我们可以使用下面显示的代码定制和设计我们的绘图背景:

#Import the required packages

from bokeh.models import CategoricalColorMapper
from bokeh.models import HoverTool
from bokeh.io import output_file, show
from bokeh.plotting import ColumnDataSource
from bokeh.plotting import figure

#Read in the data and filter for Google and USB stocks

df = pd.read_csv("all_stocks_5yr.csv")

df_multiple = df[(df['Name'] == 'GOOGL') | (df['Name'] == 'USB')]

#Save the data in a ColumnDataSource object

data = ColumnDataSource(df_multiple)

#Create the categorical color mapper

category_map = CategoricalColorMapper(
    factors = ['GOOGL', 'USB'], palette = ['blue', 'red'])

#Create the plot and configure the background

plot = figure(title = "High Vs. Low Prices (Google & USB)")

plot.background_fill_color = "yellow"
plot.background_fill_alpha = 0.3

plot.circle('high', 'low', size = 8, source = data, 
            color = {'field': 'Name', 'transform': category_map})

#Output the plot

output_file('title.html')

show(plot)

这将产生一个黄色背景的图,如下图所示:

我们现在可以看到,绘图得到了增强,红色和蓝色的点由于黄色背景而更加突出。

在这段代码中,我们使用了background_fill_color给绘图黄色背景。然后我们使用background_fill_alpha给我们的背景一点透明度。

设计绘图的轮廓

对我们的绘图轮廓进行造型是一个很好的方法,可以给绘图一个强烈且定义明确的边界,增强绘图的整体美感,给它一个人像效果。这可以使用下面显示的代码来完成:

#Import the required packages

from bokeh.models import CategoricalColorMapper
from bokeh.models import HoverTool
from bokeh.io import output_file, show
from bokeh.plotting import ColumnDataSource
from bokeh.plotting import figure

#Read in the data and filter for Google and USB stocks

df = pd.read_csv("all_stocks_5yr.csv")

df_multiple = df[(df['Name'] == 'GOOGL') | (df['Name'] == 'USB')]

#Save data into a ColumnDataSource object

data = ColumnDataSource(df_multiple)

#Create the color mapper

category_map = CategoricalColorMapper(
    factors = ['GOOGL', 'USB'], palette = ['blue', 'red'])

plot = figure(title = "High Vs. Low Prices (Google & USB)")

#Configure the outline of the plot

plot.outline_line_width = 8
plot.outline_line_alpha = 0.8
plot.outline_line_color = "black"

#Create and output the plot

plot.circle('high', 'low', size = 8, source = data, 
            color = {'field': 'Name', 'transform': category_map})

output_file('outline.html')

show(plot)

这将产生一个黑色轮廓的图,如下图所示:

在这段代码中,我们使用outline_line_width来配置轮廓的宽度。值越高,轮廓越宽。然后我们使用outline_line_alpha来配置轮廓的透明度。值越高,轮廓越不透明。最后,我们使用outline_line_color给轮廓一个黑色。

设计标签的样式

为您的绘图标签提供独特的字体和颜色,为您的绘图提供更高级别的可定制性。为了自定义我们的图的标签,我们将使用这里显示的代码:

#Import the required packages

from bokeh.models import CategoricalColorMapper
from bokeh.models import HoverTool
from bokeh.io import output_file, show
from bokeh.plotting import ColumnDataSource
from bokeh.plotting import figure

#Read in the data

df = pd.read_csv("all_stocks_5yr.csv")

df_multiple = df[(df['Name'] == 'GOOGL') | (df['Name'] == 'USB')]

#Save the data as a ColumnDataSource object

data = ColumnDataSource(df_multiple)

#Create a categorical color mapper

category_map = CategoricalColorMapper(
    factors = ['GOOGL', 'USB'], palette = ['blue', 'red'])

#Create the plot and configure the labels

plot = figure(title = "High Vs. Low Prices (Google & USB)")

plot.xaxis.axis_label = "High Prices"
plot.xaxis.axis_label_text_color = "green"

plot.yaxis.axis_label = "Low Prices"
plot.yaxis.axis_label_text_font_style = "bold"

plot.circle('high', 'low', size = 8, source = data, 
            color = {'field': 'Name', 'transform': category_map})

#Output the plot

output_file('title.html')

show(plot)

这将生成带有自定义标签的图,如下图所示:

在该图中,我们可以观察到 x 轴标签为绿色,而 y 轴标签为粗体。在这段代码中,我们使用axis_label_text_color给标签一个我们选择的独特颜色,使用axis_label_text_font_style给标签一个加粗的字体样式。

摘要

这一章已经阐明了所有不同的工具,你可以利用这些工具来为你的绘图增加互动性和视觉吸引力。

您已经学习了如何使用标注将标题、图例和分类颜色映射添加到绘图中,以便传达有关绘图的补充信息。您还学习了如何构建 Bokeh 提供的所有不同类型的小部件,以使您的绘图更具互动性。最后,您还了解了为可视化添加交互性和风格的视觉属性。

在下一章中,你将学习如何将你在这一章和前几章中学到的东西结合成一个互动的应用,让你自己和你的绘图的用户都着迷!

六、使用 Bokeh 服务器构建和托管应用

Bokeh 为用户提供了在自己的服务器上托管实时应用的灵活性和便利性。Bokeh 服务器是连接 Python 和浏览器的桥梁,您可以在浏览器中托管应用。事实上,当你在 Jupyter 笔记本中创建你的绘图时,你一直在使用 Bokeh 服务器,方法是遵循在此之前章节中的代码!

您可以使用 Bokeh Server 的方法之一是在您的机器上本地部署具有交互性的应用,然后您可以与同事共享这些应用。

在本章中,您将获得:

  • Bokeh 服务器简介
  • 创建 Bokeh 应用简介
  • 部署 Bokeh 应用简介

本章旨在构建您关于 Bokeh 服务器的基础知识,以便我们可以在本书的最后一章构建一个漂亮的交互式实时 Bokeh 应用!

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2LGCqEC

Bokeh 服务器简介

在使用 Bokeh 服务器创建我们自己的应用之前,明确 Bokeh 服务器到底是什么是很重要的。

简单来说,您创建的 Bokeh 对象,例如图、轴、小部件,以及几乎所有与您的交互式可视化相关的东西,都是由您用 Python 编码的。这些 Bokeh 对象然后被 Bokeh 转换成 JSON 格式。

为了可视化这个过程,请看一下这个图表:

在 BOKEH SERVER 的上下文中,您编写的 Python 代码将被转换为 JSON 文档。然后,名为 BOKEHJS 的客户端库用 JavaScript 呈现 JSON 文档,这样我们就可以在浏览器中查看应用。

Bokeh 为您做了所有这些,所以制作一个应用不需要 JavaScript 的先验知识!

构建 Bokeh 应用

每个 Bokeh 应用都有一个结构。这种结构有助于将大型应用分解成较小的组件,这些组件可以单独构建,然后组合在一起,作为一个整体呈现应用。这种结构如下图所示:

如图所示,在 Bokeh 中构建端到端应用的第一步是创建您希望在应用中看到的图和小部件。在这个阶段,创建绘图和小部件是一个您应该很熟悉的概念。

下一步是定义回调函数。回调函数只是一个告诉应用当用户与您的应用交互时如何响应的函数。例如,如果您创建了一个名为Update Plot的按钮,该函数将使用它从网络上检索的新数据来更新绘图。换句话说,回调函数充当连接您创建的小部件以及这些小部件如何交互和更改您的绘图的桥梁。

最后一步是创建布局,以尽可能最有效和美观的方式展示您的绘图。同样,创建和定制布局是一个您现在已经熟悉的概念。

结合这三个步骤将呈现你自己的 Bokeh 应用!

创建单个滑块应用

在前一章中,您学习了如何在 Jupyter 笔记本中创建一个简单的滑块小部件。然而,这个小部件不是一个可以被你或者你的内部团队/更广泛的受众使用的应用。

为了创建应用,我们将使用文本编辑器而不是 Jupyter 笔记本。您可以使用自己选择的任何文本编辑器。一旦您将下面显示的代码复制并粘贴到文本编辑器中,您必须确保将文件保存为bokeh.py或任何{name}.py,只要它有一个.py扩展名。

在您的终端(对于 MacOS/Linux)或 PowerShell (Windows)中,您需要转到保存文件的目录,以便启动应用。

为了在 Bokeh 中创建一个简单的单滑块应用,我们使用这里显示的代码:

#Import the required packages

from bokeh.layouts import widgetbox
from bokeh.models import Slider
from bokeh.io import curdoc

#Create a slider widget

slider_widget = Slider(start = 0, end = 100, step = 10, title = 'Single Slider')

#Create a layout for the widget

slider_layout = widgetbox(slider_widget)

#Add the slider widget to the application

curdoc().add_root(slider_layout)

在这段代码中,我们创建了一个简单的单滑块小部件,从 0 开始,到 100 结束。然后,我们使用widgetbox功能将此滑块添加到布局中。最后,我们使用curdoc函数,通过调用add_root方法将滑块部件嵌入到我们的应用中。

每当我们创建一个应用时,Bokeh 都会为该应用创建一个空白文档或画布。这份空白文件被称为curdoc。我们可以使用add_root方法向这个空白文档添加小部件、图和感兴趣的元素。

这次的不同之处在于,我们没有将前面的代码键入 Jupyter Notebook 单元格并执行它。相反,我们使用文本编辑器保存前面的代码。您必须确保前面的代码有一个.py扩展名。例如,前面的代码是使用文本编辑器保存为bokeh.py的。

为了运行该应用,如果您在 Mac/Linux 上,您将打开终端,如果您在 Windows 机器上,您将打开 Windows Shell,并键入此处显示的命令:

bokeh serve --show bokeh.py

这将在浏览器中启动您的 Bokeh 应用,如下图所示:

虽然我们将滑块小部件配置为从 0 开始,到 100 结束,但它不会显示这一点,因为滑块小部件没有链接到它可以处理的任何数据源。这就是为什么我们定义了一个回调函数来通过数据源将您的图和小部件连接在一起,正如在 Bokeh Server 部分的介绍中所解释的那样。

创建多滑块应用

在本节中,我们将创建一个具有三个滑块的应用。为此,我们使用这里显示的代码:

#Import the required packages

from bokeh.layouts import widgetbox
from bokeh.models import Slider
from bokeh.io import curdoc

#Create multiple slider widgets

slider_widget1 = Slider(start = 0, end = 100, step = 10, title = 'Slider 1')

slider_widget2 = Slider(start = 0, end = 50, step = 5, title = 'Slider 2')

slider_widget3 = Slider(start = 50, end = 100, step = 5, title = 'Slider 3')

#Create a layout for the widget

slider_layout = widgetbox(slider_widget1, slider_widget2, slider_widget3)

#Add the slider widget to the application

curdoc().add_root(slider_layout)

在前面的代码中,我们创建了三个滑块小部件,然后将它们添加到widgetbox函数中。然后,我们使用终端/外壳执行应用,如下所示:

bokeh serve --show bokeh.py

这将产生如下所示的应用:

我们现在有一个使用三个滑块而不是一个滑块的应用。

将滑块应用与散点图相结合

滑块应用的基本目的只有在我们可以使用它为我们的绘图添加一层交互性时才能实现。我们可以将一个简单的散点图与一个滑块结合起来,并使用下面显示的代码作为一个应用:

#Import the required packages

from bokeh.models import Slider, ColumnDataSource
from bokeh.io import curdoc
from bokeh.layouts import row
from bokeh.plotting import figure
from numpy.random import random

#Create data for the plot

initial_points = 500

data_points = ColumnDataSource(data = {'x': random(initial_points), 'y': random(initial_points)})

#Create the plot

plot = figure(title = "Random scatter plot generator")

plot.diamond(x = 'x', y = 'y', source = data_points, color = 'red')

#Create the slider widget

slider_widget = Slider(start = 0, end = 10000, step = 10, value = initial_points, title = 'Slide right to increase number of points')

#Define the callback function

def callback(attr, old, new):

    points = slider_widget.value
    data_points.data = {'x': random(points), 'y': random(points)}

slider_widget.on_change('value', callback)

#Create a layout for the application

layout = row(slider_widget, plot)

#Add the layout to the application

curdoc().add_root(layout)

现在,我们可以使用这里显示的命令来执行这个脚本:

bokeh serve --show bokeh.py

这将产生如下所示的应用:

在前面的代码中,我们首先定义了希望在散点图中显示的初始点数。这个数字是 500。

然后我们使用ColumnDataSource通过使用来自NumPy的随机函数来定义 xy 变量的数据。基本上, xy 各生成一组随机的 500 个数字,这用于生成之前显示的散点图。

接下来,我们创建了一个滑块函数,它从 0 个数据点开始,到 10,000 个数据点结束,滑块的初始值是我们前面定义的数据点的初始数量,即 500。

让滑块为我们工作的最重要的部分是callback功能。在这个函数中,我们定义了一个名为points的变量,它基本上取滑块可以取的可能值,在本例中是 0 到 10,000 之间的任何值。

然后,我们使用data_points.data变量定义了当我们从左向右移动滑块时滑块将改变的数据,反之亦然。

最后,我们在滑块部件上使用on_change方法,主要是告诉滑块,当我们在任一方向上移动滑块时,它必须改变数据的values

因此,该图向我们展示了当滑块位于70点时以及当滑块位于9030点时会发生什么:

我们可以清楚地观察到散点图上看到的点数是如何随着使用滑块添加更多的点而急剧增加的。

当我们想要完全控制想要查看的数据量时,可以使用这样的应用,因为有时更少或更多的数据点可能会揭示有趣的见解。

将滑块应用与折线图相结合

在本节中,我们将看到如何在线图的用例中扩展滑块应用的功能。为了构建一个带有线图的滑块应用,我们使用如下所示的代码:

#Import the required packages

from bokeh.models import Slider, ColumnDataSource
from bokeh.io import curdoc
from bokeh.layouts import row
from bokeh.plotting import figure
from numpy.random import random

#Define the points that create the line plot

x = [1,2,3,4,5,6,7,8,9]
y = [2,3,4,5,6,7,8,9,10]

#Create the data source

data_points = ColumnDataSource(data = {'x': x, 'y': y})

#Create the line plot

plot = figure(title = 'Random Line plot generator')

plot.line('x', 'y', source = data_points, color = 'red')

#Create the slider widget 

slider_widget = Slider(start = 0, end = 100, step = 1, value = 10)

#Define the callback function

def callback(attr, old, new):

    points = slider_widget.value
    data_points.data = {'x': random(points), 'y': random(points)}

slider_widget.on_change('value', callback)

#Create the layout

layout = row(slider_widget, plot)

#Add the layout to the application

curdoc().add_root(layout)

我们现在可以使用终端/外壳中显示的代码来执行这个脚本:

bokeh serve --show bokeh.py

这将产生如下所示的应用:

在前面的代码中,我们创建了一个简单的线图,并添加了一个滑块小部件,其值可以从 0 增加到 100。

然后我们定义了一个回调函数,它将滑块的值作为points变量。因此,points变量可以存储 0 到 100 之间的任何值。

接下来,我们定义了每次移动滑块时滑块必须更新的数据。在前面的代码中,我们从变量points中给出了变量 xy 的随机值,因为我们的目的是创建一个随机线图生成器。

最后,我们用滑块小部件和绘图创建了一个布局,并将这个布局添加到应用中。

在应用的初始启动时,我们可以看到应用显示一条直线,因为这是我们创建的初始图。如果我们移动滑块到 48 点,我们会得到一个随机生成的线图,其中 xy 变量都有 48 点,如下图所示:

因此,我们看到如何将滑块应用与线图结合使用,以生成具有不同点数的新图。

使用选择小部件创建应用

在本节中,我们将创建一个用于更改数据分布的应用。我们将给用户两个选择:均匀分布和正态分布。我们可以通过使用这里显示的代码来做到这一点:

#Import the required packages

from bokeh.models import Select, ColumnDataSource
from bokeh.io import curdoc
from bokeh.layouts import row
from bokeh.plotting import figure
from numpy.random import random, normal

#Create data for the plot

initial_points = 500

data_points = ColumnDataSource(data = {'x': random(initial_points), 'y': random(initial_points)})

#Create the plot

plot = figure(title = "Scatter plot distribution selector")

plot.diamond(x = 'x', y = 'y', source = data_points, color = 'red')

#Create the select widget

select_widget = Select(options = ['uniform distribution', 'normal distribution'], value = 'uniform distribution', title = 'Select the distribution of your choice')

#Define the callback function

def callback(attr, old, new):

    if select_widget.value == 'uniform distribution':
        function = random
    else:
        function = normal
    data_points.data = {'x': function(size = initial_points), 'y': function(size = initial_points)}

select_widget.on_change('value', callback)

#Create a layout for the application

layout = row(select_widget, plot)

#Add the layout to the application

curdoc().add_root(layout)

现在,我们可以使用这里显示的代码来运行应用:

bokeh serve --show bokeh.py

这将产生如下所示的应用:

在前面我们用来创建这个应用的代码中,我们创建了一个 500 点的随机散点图。然后我们创建了一个 select 小部件,它有两个选项:均匀分布和正态分布。

在我们定义的回调函数中,如果用户选择均匀分布,则函数设置为random,如果用户选择正态分布,则函数设置为normal。然后,根据用户在应用中所做的选择,将这些函数应用于数据点。

在前面的截图中,我们将随机函数应用于数据点,以便创建一个均匀的分布,这被设置为应用启动时显示的默认分布。

但是,如果我们将分布更改为正态分布,我们将获得如下所示的散点图:

我们现在可以观察当我们改变点的分布时散点图是如何变化的。这样的应用有助于从不同的角度、使用不同的分布来观察我们的数据,以便获取我们以前通常无法获取的见解。

使用按钮小部件创建应用

在本节中,我们将创建一个带有按钮小部件的应用,当您单击它时,它将改变数据的显示方式。为了创建这样一个应用,我们使用如下所示的代码:

#Import the required packages

from bokeh.models import Button, ColumnDataSource
from bokeh.io import curdoc
from bokeh.layouts import row
from bokeh.plotting import figure
from numpy.random import random, normal
import numpy as np

#Create data for the plot

initial_points = 500

data_points = ColumnDataSource(data = {'x': random(initial_points), 'y': random(initial_points)})

#Create the plot

plot = figure(title = "Data change application")

plot.diamond(x = 'x', y = 'y', source = data_points, color = 'red')

#Create the button widget

button_widget = Button(label = 'Change Data')

#Define the callback function

def callback():

    #New y values 

    y = np.cos(initial_points) + random(initial_points)

    data_points.data = {'x': random(initial_points), 'y': y}

button_widget.on_click(callback)

#Create a layout for the application

layout = row(button_widget, plot)

#Add the layout to the application

curdoc().add_root(layout)

使用这个脚本,我们可以使用如下所示的命令来执行应用:

bokeh serve --show bokeh.py

这将启动此处显示的应用:

在前面的代码中,我们首先创建了一个 500 点的随机散点图。然后我们创建了一个按钮小部件,并定义了callback函数。

在回调函数的构造中,我们通过使用NumPycosrandom函数给沿 y- 轴的点新值。

然后,我们将 y 的值输入到ColumnDataSource中。每次我们单击按钮,散点图都会用我们指定的新值 y 进行更新。如下所示:

虽然没有明显的不同,但这些点已经从第一个绘图改变了位置。因此,您可以看到如何使用按钮功能来更新您的图,并允许用户通过修改数据的操作方式来查看单个图的不同版本。

创建应用以选择不同的列

使用 Bokeh 创建一个应用的一个小例子是,作为用户,您可以选择不同的列显示在 x-y- 轴上,如下所示的代码所示:

#Importing the required packages

import pandas as pd
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, Select
from bokeh.io import curdoc
from bokeh.layouts import row

#Read in the data

df = pd.read_csv('all_stocks_5yr.csv')

#Filtering for apple stocks

df_apple = df[df['Name'] == 'AAL']

#Create the ColumnDataSource object

data = ColumnDataSource(data = {
    'x' : df_apple['high'],
    'y' : df_apple['low'],
    'x1': df_apple['volume']

})

#Creating the scatter plot 

plot = figure(title = 'Attribute selector application')

plot.diamond('x', 'y', source = data, color = 'red')

#Creating the select widget

select_widget = Select(options = ['low', 'volume'], value = 'low', title = 'Select a new y axis attribute')

#Define the callback function

def callback(attr, old, new):

    if new == 'low':

        data.data = {'x' : df_apple['high'], 'y': df_apple['low']}

    else:

        data.data = {'x' : df_apple['high'], 'y': df_apple['volume']}

select_widget.on_change('value', callback)

#Add the layout to the application

layout = row(select_widget, plot)

curdoc().add_root(layout)

然后,我们可以使用这里显示的命令启动这个应用:

bokeh serve --show bokeh.py

这将产生如下所示的应用:

在前面的代码中,我们首先加载了 5 年期的股票数据,可以在 Kaggle 这里找到:https://www.kaggle.com/camnugent/sandp500/data

然后,我们过滤数据,只包括苹果股票,并在ColumnDataSource的构造中添加感兴趣的属性/列。

接下来,我们用两个选项lowvolume创建了一个选择小部件,并将默认选项设置为low

我们构建回调函数的方式是,如果用户选择low选项,应用将显示苹果股票的highlow值之间的散点图,如果用户选择volume选项,应用将显示highvolume之间的散点图。

选择volume选项会产生如下散点图:

因此,我们看到了这样一个应用是如何在一个浏览器选项卡中显示多个图的,并因此可以向用户呈现各种各样的信息。

部署 Bokeh 应用简介

在前面的部分中,我们使用本地机器部署了我们的 Bokeh 应用,然后可以与我们内部团队的同事共享。

为了部署一个 Bokeh 应用,我们首先用 Python 编写了一个脚本,其中包含了绘图、回调函数和布局。然后我们给剧本取了一个合适的名字。在前面的例子中,我们给我们的脚本命名为bokeh.py

使用 Mac/Linux 的终端或 Windows 的外壳,我们从 Python 脚本所在的目录部署了应用,命令如下所示:

bokeh serve --show bokeh.py

这将在您选择的默认浏览器中启动应用,如下所示:

http://localhost:5006/bokeh

在这种情况下,我们使用 Bokeh 服务器来运行和部署我们的应用。

摘要

本章已经向您介绍了在本地机器上构建和部署自己的 Bokeh 应用的基本原理。

您已经学习了如何使用 select 小部件、slider 小部件和 button 小部件构建基本应用,以及如何将这些应用用于各种应用。

在下一章中,您将学习如何使用实时数据构建您自己的应用,以便创建一个具有统计意义且美观的应用。

七、将网络、地理数据、网络地理数据库和导出绘图用于高级绘图

向用于可视化网络(如社交网络和运输网络)的图中添加交互性允许用户突出显示他们感兴趣的特定部分并与之交互,而忽略网络的其余部分。当您有一个庞大而复杂的网络时,这尤其有用。

当涉及提取感兴趣的特定位置的信息时,地理数据中的交互性尤其有用,而不是查看整个绘图。这种基于地理的可视化帮助我们放大位置并将这些地图嵌入到我们的应用中。

在处理大型复杂数据集时,充分利用 Bokeh 在速度方面的性能符合我们的最佳利益。我们可以用 WebGL 做到这一点。

最后,在某些情况下,我们可能希望以高水平的图像质量在书籍和期刊中发布我们用 Bokeh 创建的绘图。我们可以使用 Bokeh 的导出功能以巴布亚新几内亚格式导出我们的绘图。

在本章中,您将了解:

  • 使用 Bokeh 可视化网络
  • 使用 Bokeh 可视化地理数据
  • 使用 WebGL 提高性能
  • 使用 Bokeh 将绘图导出为 PNG 图像

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2HCCUJJ

使用 Bokeh 可视化网络

网络帮助您可视化人与物品之间的关系。例如,一个简单的网络可以向你展示人们是如何相互关联的。下图说明了这一点:

在这个网络中,很容易看到玛丽和乔恩是朋友,而玛丽和蒂姆是同事。我们也可以看到蒂姆和乔恩根本没有关系。这样的网络有强大的应用,尤其是在社交网络领域!

在本节中,我们将学习如何使用 Bokeh 构建交互式网络。从根本上说,有两种方法可以做到这一点。第一种是使用默认直线将两个节点连接在一起来构建和可视化这些网络,下一种是通过为我们选择的路径定义形状来构建和可视化这些网络。

用直线路径可视化网络

第一步是导入所需的包:

import math
from bokeh.io import show, output_file
from bokeh.plotting import figure
from bokeh.models import GraphRenderer, StaticLayoutProvider, Oval
from bokeh.palettes import Spectral10

这里新增的套餐有mathGraphRendererStaticLayoutProviderOvalSpectral10。随着我们逐步建立自己的网络,您将看到为什么以及何时使用以下软件包。

在本例中,我们将构建一个包含 10 个节点的网络。让我们构建一个从09的列表,我们可以将其用作网络中节点的点。这里显示的代码说明了这一点:

total_nodes = 10
node_points = list(range(total_nodes))
print(node_points)

作为前面代码的结果,我们有 10 个节点,将从09合并到我们的网络中:

#Output of print(node_points)

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

下一步是构建将进入我们网络的图,并将其渲染为网络图。我们可以通过使用这里显示的代码来做到这一点:

plot = figure(x_range=(-1.1,1.1), y_range=(-1.1,1.1))

network = GraphRenderer()

在前面的代码中,我们通过指定 xy 范围创建了一个图形。在前面的例子中,我们的范围是-1.1+1.1。这给了我们一个相当明显的网络。例如,将 xy 范围的大小增加到-10 到+ 10 会使网络变小。

最后,GraphRenderer功能用于创建和渲染感兴趣的网络。

下一步是定制您的网络。我们可以通过使用这里显示的代码来做到这一点:

network.node_renderer.data_source.add(Spectral10, 'color')

在前面的代码中,我们从Spectral10包中为网络的每个节点提供了 10 种独特颜色中的一种。这里说明了这一点:

如果我们希望所有的节点都有相同的颜色,我们可以完全跳过编写前面的代码。

为了将节点添加到网络中,我们使用如下所示的代码:

network.node_renderer.data_source.add(node_points, 'index')

为了自定义网络的形状、大小和颜色,我们使用这里显示的代码:

network.node_renderer.glyph = Oval(height=0.2, width=0.3, fill_color='color')

如果我们想创建一个具有更大节点的网络,其中每个节点都是红色的,那么我们可以将前面显示的代码修改为:

network.node_renderer.glyph = Oval(height=0.4, width=0.5, fill_color='red')

这将呈现此处显示的网络:

下一步是配置网络中的边缘连接。边只是将两个节点连接在一起的链接。为此,我们使用这里显示的代码:

network.edge_renderer.data_source.data = dict(start=[1]*total_nodes, end=node_points)

为了创建一条边,我们只需创建一个将点集相互映射的字典。在前面的代码中,start参数等于包含数字1的列表乘以节点总数,即10。这将导致此处显示的列表:

#Output of [1] * total_nodes:

[10,10,10,10,10,10,10,10,10,10]

参数结束包含node_points,这是我们之前定义的从09的列表:

#Output of total_nodes:

[0,1,2,3,4,5,6,7,8,9]

换句话说,我们将这两个列表映射在一起:

{10:0, 10:1, 10:2, 10:3, 10:4, 10:5, 10:6, 10:7, 10:8, 10:9}

这导致节点 10 被映射到网络中的每一个其他节点。这里显示的输出说明了这一点:

从根本上说,我们到目前为止创建的代码足以设计您的网络,但不足以在您的浏览器/ Jupyter Notebook 中呈现网络的输出。

我们需要使用布局提供者模型,以便在二维空间中呈现这个网络。为了在二维空间中渲染一个对象,我们需要指定二维空间中每个节点的 xy 坐标。我们通过提取每个节点的周长,然后使用余弦函数和周长来为每个节点建立 xy 坐标。

第一步是为每个节点创建一个周长列表。我们可以通过使用这里显示的代码来做到这一点:

#Extracting the circumference of each node

node_circumference = [node*2*math.pi/10 for node in node_points]

如果你记得,node_points是从09的每个节点的点列表。这将产生如下所示的输出:

#Output of the circumference of each node

[0.0, 0.6283185307179586, 1.2566370614359172, 1.8849555921538759, 2.5132741228718345, 3.141592653589793, 3.7699111843077517, 4.39822971502571, 5.026548245743669, 5.654866776461628]

下一步是提取 xy 坐标。我们可以通过使用这里显示的代码来做到这一点:

#Extracting the x and y co-ordinates

x = [math.cos(circum) for circum in node_circumference]

y = [math.sin(circum) for circum in node_circumference]

这将产生一个由 xy 坐标组成的列表,如代码块所示:

#Output of the x co-ordinates

[1.0, 0.8090169943749475, 0.30901699437494745, -0.30901699437494734, -0.8090169943749473, -1.0, -0.8090169943749475, -0.30901699437494756, 0.30901699437494723, 0.8090169943749473]

#Output of the y co-ordinates

[0.0, 0.5877852522924731, 0.9510565162951535, 0.9510565162951536, 0.5877852522924732, 1.2246467991473532e-16, -0.587785252292473, -0.9510565162951535, -0.9510565162951536, -0.5877852522924732]

最后,我们需要用字典把这些坐标联系在一起。我们可以通过使用这里显示的代码来做到这一点:

network_layout = dict(zip(node_points, zip(x, y)))

这将生成一个字典,其中包含一个关键字(即节点(0)到9)和一个值(即元组( xy ):

#Output of the dictionary

{0: (1.0, 0.0), 1: (0.8090169943749475, 0.5877852522924731), 2: (0.30901699437494745, 0.9510565162951535), 3: (-0.30901699437494734, 0.9510565162951536), 4: (-0.8090169943749473, 0.5877852522924732), 5: (-1.0, 1.2246467991473532e-16), 6: (-0.8090169943749475, -0.587785252292473), 7: (-0.30901699437494756, -0.9510565162951535), 8: (0.30901699437494723, -0.9510565162951536), 9: (0.8090169943749473, -0.5877852522924732)}

最后,我们使用 Bokeh 包的布局提供程序来实时和在二维空间中渲染网络:

#Output the network in two dimensional space

network.layout_provider = StaticLayoutProvider(graph_layout=network_layout)

plot.renderers.append(network)

output_file('network.html')
show(plot)

在前面的代码中,StaticLayoutProvider函数用于渲染我们在二维空间中构建的网络,也就是最终渲染绘图的网页的笔记本或者 HTML 文件。

现在我们已经完全理解了构建网络的所有组件,让我们将所有代码联系在一起,并查看生成的网络:

#Import the required packages

import math
from bokeh.io import show, output_file
from bokeh.plotting import figure
from bokeh.models import GraphRenderer, StaticLayoutProvider, Oval

#Configure the number of nodes

total_nodes = 10
node_points = list(range(total_nodes))

#Create the network

plot = figure(x_range=(-1.1,1.1), y_range=(-1.1,1.1))

network = GraphRenderer()

#Customize your network

network.node_renderer.data_source.add(node_points, 'index')

network.node_renderer.glyph = Oval(height=0.2, width=0.3, fill_color='blue')

network.edge_renderer.data_source.data = dict(start=[1]*total_nodes, end=node_points)

#Render your network in 2-D space

node_circumference = [node*2*math.pi/10 for node in node_points]

x = [math.cos(circum) for circum in node_circumference]

y = [math.sin(circum) for circum in node_circumference]

network_layout = dict(zip(node_points, zip(x, y)))

#Output the network

network.layout_provider = StaticLayoutProvider(graph_layout=network_layout)

plot.renderers.append(network)

output_file('network.html')

show(plot)

这导致此处显示的网络:

用显式路径可视化网络

在本节中,您将学习如何为连接网络两个节点的路径定义形状。

第一步是定义一个函数,它将为我们返回一个二次路径。为此,我们使用如下所示的代码:

#Function that outputs the quadratic path

values = [value/100\. for value in range(100)]

def quad_path(start, end, control, values):
    return [(1-value)**2*start + 2*(1-value)*value*control + value**2*end for value in values]

Values是一个包含从 0 到 0.99 的数字范围的列表,我们将使用它来构造一个函数,该函数根据贝塞尔曲线方程从数学上返回二次路径。

上面的函数接受四个参数:startendcontrolvalues。起点和终点定义了如何在二维空间中显示和构建函数。quad_path函数然后返回在二维空间中构建二次网络路径所需的 xy 坐标。为此,我们将使用上一小节中用于构建网络的相同网络布局。这个网络布局是一个把节点点映射到 xy 坐标的字典,看起来是这样的:

{0: (1.0, 0.0), 1: (0.8090169943749475, 0.5877852522924731), 2: (0.30901699437494745, 0.9510565162951535), 3: (-0.30901699437494734, 0.9510565162951536), 4: (-0.8090169943749473, 0.5877852522924732), 5: (-1.0, 1.2246467991473532e-16), 6: (-0.8090169943749475, -0.587785252292473), 7: (-0.30901699437494756, -0.9510565162951535), 8: (0.30901699437494723, -0.9510565162951536), 9: (0.8090169943749473, -0.5877852522924732)}

为了构建startend点,我们使用这里显示的代码:

#Initialize empty lists to store the x and y co-ordinates
x_point, y_point = [], []

#Store the starting and ending points

x_start, y_start = network_layout[0]

#Create the set of co-ordinates for the quadratic path

values = [value/100\. for value in range(100)]
for node in node_points:
    x_end, y_end = network_layout[node]
    x_point.append(quad_path(x_start, x_end, 0, values))
    y_point.append(quad_path(y_start, y_end, 0, values))

在前面的代码中,我们首先初始化空列表来存储 xy 坐标。 xy 坐标的起点是从网络布局字典中提取的,x_starty_start的起点分别为 1.0 和 0.0。

然后,我们循环遍历从09的节点列表,然后通过将节点子集化为网络布局来提取end点。例如,第二个节点的end点将是:

network_layout[1] = (0.8090169943749475, 0.5877852522924731)

然后我们使用quad_path函数将xy点添加到我们在开始初始化的列表中。

最后一步就是将新的 xy 坐标添加到您创建的网络中,并渲染该图。我们可以通过使用这里显示的代码来做到这一点:

#Add the x and y co-ordinates of the quadratic path to the network

network.edge_renderer.data_source.data['xs'] = x_point

network.edge_renderer.data_source.data['ys'] = y_point

#Output the plot

plot.renderers.append(network)

output_file("quad_path.html")

show(plot)

最后一步是将所有这些代码与我们在上一节中使用的代码绑定在一起,以便构建网络。这里显示的代码块说明了这一点:

#Import the required packages

import math
from bokeh.io import show, output_file
from bokeh.plotting import figure
from bokeh.models import GraphRenderer, StaticLayoutProvider, Oval

#Configure the number of nodes

total_nodes = 10
node_points = list(range(total_nodes))

#Create the network

plot = figure(x_range=(-1.1,1.1), y_range=(-1.1,1.1))

network = GraphRenderer()

#Customize your network

network.node_renderer.data_source.add(node_points, 'index')

network.node_renderer.glyph = Oval(height=0.2, width=0.3, fill_color='green')

network.edge_renderer.data_source.data = dict(start=[1]*total_nodes, end=node_points)

#Render your network in 2-D space

node_circumference = [node*2*math.pi/10 for node in node_points]

x = [math.cos(circum) for circum in node_circumference]

y = [math.sin(circum) for circum in node_circumference]

network_layout = dict(zip(node_points, zip(x, y)))

network.layout_provider = StaticLayoutProvider(graph_layout=network_layout)

#Function that outputs the quadratic path

values = [value/100\. for value in range(100)]

def quad_path(start, end, control, values):
    return [(1-value)**2*start + 2*(1-value)*value*control + value**2*end for value in values]

#Initialize empty lists to store the x and y co-ordinates
x_point, y_point = [], []

#Store the starting and ending points

x_start, y_start = network_layout[0]

#Create the set of co-ordinates for the quadratic path

values = [value/100\. for value in range(100)]
for node in node_points:
    x_end, y_end = network_layout[node]
    x_point.append(quad_path(x_start, x_end, 0, values))
    y_point.append(quad_path(y_start, y_end, 0, values))

#Add the x and y co-ordinates of the quadratic path to the network

network.edge_renderer.data_source.data['xs'] = x_point

network.edge_renderer.data_source.data['ys'] = y_point

#Output the plot

plot.renderers.append(network)

output_file("quad_path.html")

show(plot)

这导致网络具有连接节点的二次路径,如下图所示:

用 Bokeh 可视化地理数据

在本节中,我们将为美国犯罪率最低的州创建一个 Bokeh 可视化。为了做到这一点,我们将绘制一张美国地图,并指出犯罪率最低的州。

第一步是导入所需的包:

from bokeh.sampledata import us_states
from bokeh.plotting import figure, show, output_file
from bokeh.models import HoverTool

us_states是一本字典,包含了我们在 Bokeh 构建美国地图所需的所有信息。此外,如果你想在 Bokeh 岛创建一张其他国家的地图,你可以在网上找到必要的地理数据,然后将文件导入你的 Jupyter 笔记本。

下一步是将数据复制到 Bokeh 中,这样我们就可以修改数据并删除不重要的状态(如果需要的话)。这里,我们将删除夏威夷和阿拉斯加,因为我们只对美国大陆的州感兴趣。我们可以使用下面显示的代码从地图中删除各个州:

#Create a copy of the USA data in our notebook

usa_data = us_states.data.copy()

#Delete the states that are not of interest 

del usa_data["HI"]
del usa_data["AK"]

下一步是从我们的数据中提取latitudelongitude信息。我们可以通过使用这里显示的代码来做到这一点:

#Extract the latitude and longitude information

longitude = [usa_data[long]["lons"] for long in usa_data]

latitude = [usa_data[lat]["lats"] for lat in usa_data]

下一步是设计和配置我们的绘图应该是什么样子。这可以通过使用下面显示的代码来完成:

#Create the figure

plot = figure(title="The 3 safest states in the USA")

#Configure the borders of the states

plot.patches(longitude, latitude, line_color="red", line_width=2)

在前面的代码中,我们使用patches函数根据前面构建的longitudelatitude坐标来构建块或面片。我们给州的边界一个red的颜色和一个2的宽度。

下一步是创建两个列表,保存美国三个最安全州的longitudelatitude信息。根据热门网站美国新闻,这些州是缅因州、佛蒙特州和新罕布什尔州。

这三种状态的longitudelatitude如下:

#Longitude and latitude information for Maine 

longitude = -69.44 West
latitude = 45.25 North

#Longitude and latitude information for Vermont

longitude = -72.57 West
latitude = 44.55 North

#Longitude and latitude information for New Hampshire

longitude = -71.57 West
latitude = 43.19 North

下一步是将这些位置参数放入一个列表:

#Mapping the longitude and latitude information into lists

long_list = [-69.44, -72.57, -71.57]

lat_list = [45.25, 44.55, 43,19]

最后,我们使用下面显示的代码来定义如何在图上标记这些点:

# Create the markers for the states

plot.diamond(long_list, lat_list, size=15, color='yellow')

# output the plot

output_file("safe.html")

show(plot)

为了增强绘图的互动性,我们可以添加一个不错的附加功能,那就是创建一个悬停工具,它可以为我们提供感兴趣点的信息,比如latitudelongitude。我们可以使用下面显示的代码来创建这个工具:

#Create the hover tooltip

hover_tool = HoverTool(tooltips = [
    ('Longitude', '@x'),
    ('Latitude', '@y')
]) 

#Embed the hover tool into the plot
plot = figure(title="The 3 safest states in the USA", tools = [hover_tool])

最后,我们可以将所有代码块绑定在一起,以创建美国三个最安全州的地理可视化:

#Import the required packages

from bokeh.sampledata import us_states
from bokeh.plotting import figure, show, output_file
from bokeh.models import HoverTool

#Create a copy of the USA data in our notebook

usa_data = us_states.data.copy()

#Delete the states that are not of interest 

del usa_data["HI"]
del usa_data["AK"]

#Extract the latitude and longitude information

longitude = [usa_data[long]["lons"] for long in usa_data]

latitude = [usa_data[lat]["lats"] for lat in usa_data]

#Create the Hover Tool

hover_tool = HoverTool(tooltips = [
    ('Longitude', '@x'),
    ('Latitude', '@y')
]) 

#Create the figure

plot = figure(title="The 3 safest states in the USA", tools = [hover_tool])

#Configure the borders of the states

plot.patches(longitude, latitude, line_color="red", line_width=2)

#Mapping the longitude and latitude information into lists

long_list = [-69.44, -72.57, -71.57]

lat_list = [45.25, 44.55, 43,19]

# Create the markers for the states

plot.diamond(long_list, lat_list, size=15, color='yellow')

# output the plot

output_file("safe.html")

show(plot)

这导致如下图所示的结果:

从这个绘图中,我们可以识别出一个独特的趋势。我们可以立即注意到美国最安全的州在地图上是多么的接近。悬停工具增加的交互性也帮助我们非常快速地提取这些位置的坐标。

使用 WebGL 提高性能

WebGL 是一个 JavaScript API,几乎可以在市场上每一个流行的浏览器中使用。基本上,显示在浏览器上的 Bokeh 图是在插件的帮助下完成的。这可能会降低绘图的渲染速度,尤其是在用于渲染这些绘图的数据集很大的情况下!WebGL 使用图形处理器渲染图形,不需要插件。

为了在渲染图时启用 WebGL,您只需在构建图时使用此处显示的代码:

plot = figure(output_backend = 'webgl')

在 WebGL 中渲染图的唯一缺点是它不支持 Bokeh 必须提供的每个组件。目前,WebGL 渲染只支持两种类型的字形。它们是:

  • 圆形符号
  • 线路健身房

WebGL 支持的标记如下:

  • 星号
  • 平方
  • 钻石
  • 三角形
  • 倒三角
  • 跨过
  • 圆形交叉
  • 方形十字
  • 钻石十字架
  • x
  • 平方

您可以使用 Bokeh 的所有组件创建一个绘图,但是只有 WebGL 支持的组件才会在 WebGL 中呈现,而其余组件将使用插件呈现。

这里显示了一个使用 WebGL 渲染图的示例:

#Import required packages

import numpy as np
import random
from bokeh.io import output_file, show
from bokeh.plotting import figure

#Creating an array for the points along the x and y axes

array_x =np.array([1,2,3,4,5,6])

array_y = np.array([5,6,7,8,9,10])

#Creating a line plot

plot = figure(output_backend = 'webgl')

plot.line(array_x, array_y)

#Output the plot

output_file('numpy_line.html')

show(plot)

这导致如下图所示的结果:

可以清楚地看到,在 BokehJS 渲染的图和使用 WebGL 渲染的图之间没有明显的区别。您唯一注意到差异的时候是当您有一个大数据集时,在这种情况下,使用 WebGL 渲染的速度会快得多。

本节的主要目的是确保您具备提高使用 Bokeh 构建的应用的性能所需的知识。在大多数情况下,您将呈现大量数据的交互式可视化,这些数据通常在浏览器上呈现得非常慢。WebGL 通过一行简单的代码帮助缓解了这个问题。

将绘图导出为巴布亚新几内亚图像

上面产生的绘图看起来令人印象深刻,同时也提供了信息。我们可能希望在网站或杂志/期刊上以更高质量的.PNG图像发布该图。幸运的是,Bokeh 提供了这种灵活性。

Bokeh 可以使用导出功能生成这样的图像。这个函数使用一个名为 Webkit 的浏览器将该图保存在其内存中,并捕获一个截图。生成图像的尺寸将与您创建的图的尺寸相同。

第一步是安装这个 Bokeh 功能所依赖的依赖项。这叫做 Phantomjs。您可以使用 Anaconda 安装此软件包,命令如下所示:

conda install selenium phantomjs pillow

下一步是使用pip安装 Selenium。我们可以使用这里显示的命令来实现这一点:

pip3 install selenium

最后一步是导出使用地理数据创建的绘图。我们可以通过使用这里显示的代码来做到这一点:

#Import the required packages

from bokeh.io import export_png

#Export the png image

export_png(plot, filename="safe_states.png")

保存的最终图像如下所示:

摘要

本章已经向您正式介绍了使用 Bokeh 包构建交互式网络的世界。通过系统的方式,您学习了如何使用默认的直线路径和显式定义的路径来创建和构造构建网络的过程。

您还了解了向地理数据添加交互性如何对可视化的查看者产生重大影响,因为他或她现在可以从中提取信息。

然后,您学习了如何使用 WebGL 更快地渲染您的绘图,从而提高应用的性能。

最后,您学习了如何以 PNG 格式导出这些绘图,并以非常高的质量渲染它们以供发布。

在下一章中,您将学习如何构建您自己的 Bokeh 应用,您可以使用它来分析股票市场。

八、Bokeh 工作流——案例研究

当谈到从头开始构建自己的 Bokeh 可视化时,一个很好的开发实践是永远不要从 Bokeh 开始。相反,理想的方法是首先对您的数据进行一些探索性的分析,以便可视化您可以使用 Bokeh 创建的能够为您的用户提供最大价值的应用。

这样的方法,首先探索你的数据集,帮助你制定你可能想要呈现给你的观众的理想的可视化。

在本章中,您将学习需要遵循的确切工作流程,从获取数据到想要呈现的最终可视化。

Bokeh 和大多数数据可视化工具一样,最适合在遵循逻辑步骤序列的工作流中使用,这将允许您向您的受众提供有影响力的见解。该工作流程可以总结为四个步骤:

在本章中,您将学习如何:

  • 在可视化数据之前,问正确的问题
  • 对真实数据集执行探索性数据分析
  • 构建交互式可视化,提供具体的见解
  • 展示你的结果

技术要求

您需要在系统上安装 Python。最后,为了使用本书的 Git 存储库,用户需要安装 Git。

本章的代码文件可以在 GitHub:
https://GitHub . com/PacktPublishing/动手-数据-可视化-with-Bokeh 上找到。

查看以下视频,了解代码的运行情况:

http://bit.ly/2sLSoX1

问正确的问题

就数据可视化而言,问正确的问题是最重要的一步。你寻求的答案是什么?

在决定可视化数据之前,您需要问自己一些最常见的问题:

  • 我想观察两个特征的关联程度吗?
  • 我是否怀疑我的数据中存在潜在的异常值,除非我将数据可视化,否则我无法看到这些异常值?
  • 我想看看我的数据是否显示了一段时间内的特定趋势?
  • 我是否希望观察数据中各个要素/列的分布?
  • 我是否希望查看我的数据中是否有可以从中提取价值的集群/组?
  • 我相信可视化可以告诉我的观众一个关于数据的故事吗?

如果其中任何一个问题的答案是肯定的,那么你知道你需要可视化你的数据。你想问自己的第二个问题是,“我用什么工具来可视化我的数据?”

在决定工具时,您最想问的一些常见问题是:

  • 我想让我的观众和我的绘图互动吗?如果是的话,Bokeh 和 Tableau 是一个不错的选择。
  • 我想做探索性的数据分析而不想做别的吗?如果是,Python 中的 Matplotlib 和 Seaborn 是不错的选择。
  • 我想在一个能被广大读者阅读的出版物上发表我的绘图吗?如果是的话,Bokeh 和 Tableau 是一个不错的选择。

一旦你决定了数据可视化是必须的,并且你决定了你将要使用的工具,下一步就是问正确的关于你当前拥有的数据的问题。让我们看看在本书的整个过程中,我们可以问的关于股票的问题:

  • 特定股票或多只股票的高低价格之间是否存在相关性?
  • 苹果股票的开盘价如何随时间变化?
  • 微软、苹果、谷歌等科技股的行为是否有相似之处?

你的可视化效果只和你随身携带的数据一样好。如果你的数据质量不好,那么你的可视化效果也会随之受损。您可以采取以下步骤来提高数据质量:

  • 基于现有功能创建新功能,以更好地增强可视化效果
  • 将多个数据集合并在一起,这有助于揭示更好的见解
  • 以有意义的方式处理空值
  • 调查数据的收集方式

这些步骤将通过揭示原始数据集本身所不具备的洞察力,极大地提高您的演示质量。

一旦我们清楚地了解了我们想要回答的问题,我们就可以继续下一步了。

探索性数据分析

由于我们已经广泛使用了来自 Kaggle 的标准普尔 500 股票数据,我们将使用该数据集来创建我们的应用。数据集可以在这里找到:https://www.kaggle.com/camnugent/sandp500/data

第一步是将数据读入 Jupyter Notebook,了解数据的样子。这可以使用下面显示的代码来完成:

#Import packages

import pandas as pd

#Read the data into the notebook

df = pd.read_csv('all_stocks_5yr.csv')

#Extract information about the data

df.info()

这将呈现此屏幕截图中显示的输出:

这可以显示数据集的行数、每列的数据类型、变量的数量以及任何缺少的值。

下一步是了解数据集所有列中包含的信息类型。我们可以通过使用这里显示的代码来做到这一点:

df.head()

这将产生如下所示的输出:

我们可以很快看到我们有日期,这是一个时间序列属性。开放、高、低和关闭是连续的数字数据,可用于生成散点图。成交量也是连续的,但是数值要比其他四个数字栏大很多,Name 是一个分类栏,有每只股票的名称。

由于名称是一个分类列,包含每只股票的名称,因此了解变量的总类别数可能会很有用。我们可以通过使用这里显示的代码来做到这一点:

df['Name'].value_counts()

这将产生如下所示的输出:

我们现在了解到股票数据中列出了 505 家公司。

创建有洞察力的可视化

既然我们已经对数据包含的内容有了一个基本的概念,我们就可以进行可视化了。第一步是确保我们已经准备好可视化的基础。

创建基准图

基础由您想要可视化的基础图组成。在我们的例子中,我们希望看到一段时间内股票交易量与高价格之间的关系。为了构建这个应用,我们使用这里显示的代码:

#Import the required packages

from bokeh.io import curdoc
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
import pandas as pd

#Read the data into the notebook

df = pd.read_csv('all_stocks_5yr.csv')

#Convert the date column to a datetime object and extract the year only.

df['date'] = pd.to_datetime(df['date']).apply(lambda x:x.strftime('%Y'))

#Create the ColumnDataSource Object

data = ColumnDataSource(data = {
    'high' : df[df['date'] == '2013'].high,
    'low' : df[df['date'] == '2013'].low,
    'open' : df[df['date'] == '2013'].open,
    'close': df[df['date'] == '2013'].close,
    'volume': df[df['date'] == '2013'].volume,
    'Name' : df[df['date'] == '2013'].Name
})

#Specify the range of the x and y axis

xmin, xmax = min(df.high), max(df.high)
ymin, ymax = min(df.volume), max(df.volume)

#Create the plot

plot = figure(title = 'Volume traded Vs. High Prices', plot_height = 400, plot_width = 700, x_range = (xmin, xmax),
             y_range = (ymin, ymax))

plot.diamond(x = 'high', y = 'volume', source = data)

plot.xaxis.axis_label = 'High Prices for 2013'

plot.yaxis.axis_label = 'Volume traded in 2013'

#Add the plot to the application

curdoc().add_root(plot)

curdoc().title = 'Volume and High prices of stocks'

在前面的代码中,我们首先读入数据,并将其存储在名为df的数据帧中。在下一行中,我们将date列转换为datetime对象。我们使用apply函数将日期列中的每个元素转换为年格式,即20112012等等。lambda功能用于将这种格式变化应用到日期列的每个元素中的日期。

然后,我们创建了一个列数据源元素,其中我们仅基于 2013 年的数据过滤了数据框的每一列。例如,代表股票高价格的high栏将只有 2013 年的数据。

最后,我们指定了 x-y- 轴的范围,并在交易量和高价格之间创建了一个简单的散点图。

将前面的脚本保存为bokeh.py后,我们可以使用如下所示的命令启动它:

bokeh serve --show bokeh.py

这导致了此屏幕截图中显示的应用:

我们已经可以看到,股票交易量和高价格之间是有关系的。看起来价格非常高的股票比价格较低的股票交易频率要低得多。

绘制科技股地图

现在,如果我们有兴趣投资和购买科技巨头——谷歌、脸书、亚马逊、微软或苹果——的一些股票,我们可能想知道这些公司与标准普尔 500 指数中的其他公司相比表现如何。

这可以通过使用下面显示的代码来实现:

#Import the required packages

from bokeh.io import curdoc
from bokeh.models import ColumnDataSource, CategoricalColorMapper
from bokeh.plotting import figure
from bokeh.palettes import Spectral5
import pandas as pd

#Read the data into the notebook

df = pd.read_csv('all_stocks_5yr.csv')

df['date'] = pd.to_datetime(df['date']).apply(lambda x:x.strftime('%Y'))

#List the tech giants

tech_giants = ['GOOGL', 'FB', 'MSFT', 'AMZN', 'AAPL']

#Create the color map

color_map = CategoricalColorMapper(factors = tech_giants, palette = Spectral5)

#Create the ColumnDataSource Object

data = ColumnDataSource(data = {
    'high' : df[df['date'] == '2013'].high,
    'low' : df[df['date'] == '2013'].low,
    'open' : df[df['date'] == '2013'].open,
    'close': df[df['date'] == '2013'].close,
    'volume': df[df['date'] == '2013'].volume,
    'Name' : df[df['date'] == '2013'].Name
})

#Create ranges for the x and y axis

xmin, xmax = min(df.high), max(df.high)
ymin, ymax = min(df.volume), max(df.volume)

#Create the plot

plot = figure(title = 'Volume traded Vs. High Prices', plot_height = 400, plot_width = 700, x_range = (xmin, xmax),
             y_range = (ymin, ymax))

plot.diamond(x = 'high', y = 'volume', source = data, color = dict(field = 'Name', transform = color_map))

plot.xaxis.axis_label = 'High Prices for 2013'

plot.yaxis.axis_label = 'Volume traded in 2013'

#Add the plot to the application

curdoc().add_root(plot)

curdoc().title = 'Volume and High prices of stocks'

然后,我们使用终端/外壳中显示的命令启动应用:

bokeh.serve --show bokeh.py

这将产生如下所示的应用:

现在,我们可以清楚地看到科技巨头在数量和高价格方面的位置。

添加悬停工具

下一步是添加一个悬停工具,以便在我们与可视化交互时帮助我们准确地识别公司的名称。我们可以通过使用这里显示的代码来做到这一点:

#Import the required packages

from bokeh.io import curdoc
from bokeh.models import ColumnDataSource, CategoricalColorMapper
from bokeh.plotting import figure
from bokeh.palettes import Spectral5
import pandas as pd
from bokeh.models import HoverTool

#Read the data into the notebook

df = pd.read_csv('all_stocks_5yr.csv')

df['date'] = pd.to_datetime(df['date']).apply(lambda x:x.strftime('%Y'))

#List the tech giants

tech_giants = ['GOOGL', 'FB', 'MSFT', 'AMZN', 'AAPL']

#Create the color map

color_map = CategoricalColorMapper(factors = tech_giants, palette = Spectral5)

#Create the ColumnDataSource Object

data = ColumnDataSource(data = {
    'high' : df[df['date'] == '2013'].high,
    'low' : df[df['date'] == '2013'].low,
    'open' : df[df['date'] == '2013'].open,
    'close': df[df['date'] == '2013'].close,
    'volume': df[df['date'] == '2013'].volume,
    'Name' : df[df['date'] == '2013'].Name
})

#Create ranges for the x and y axis

xmin, xmax = min(df.high), max(df.high)
ymin, ymax = min(df.volume), max(df.volume)

#Create the hover tool

hover_tool = HoverTool(tooltips = [('Company:', '@Name')])

#Create the plot

plot = figure(title = 'Volume traded Vs. High Prices', plot_height = 400, plot_width = 700, x_range = (xmin, xmax),
             y_range = (ymin, ymax))

plot.diamond(x = 'high', y = 'volume', source = data, color = dict(field = 'Name', transform = color_map))

#Adding the hover tool to the plot

plot.add_tools(hover_tool)

plot.xaxis.axis_label = 'High Prices for 2013'

plot.yaxis.axis_label = 'Volume traded in 2013'

#Add the plot to the application

curdoc().add_root(plot)

curdoc().title = 'Volume and High prices of stocks'

我们现在可以使用终端/外壳中显示的命令来启动这个应用:

bokeh serve --show bokeh.py

放大应用并使用悬停工具,我们可以在可视化中获得股票名称的相关信息,如下所示:

缩放工具是右上角 Bokeh 徽标下的第二个工具。这是 Bokeh 在您创建的每个可视化中发布的默认工具之一。

使用 WebGL 提高性能

创建快速渲染的 Bokeh 可视化的最后一步是使用 WebGL 来提高其性能。我们可以使用这里显示的代码来实现这一点:

#Import the required packages

from bokeh.io import curdoc
from bokeh.models import ColumnDataSource, CategoricalColorMapper
from bokeh.plotting import figure
from bokeh.palettes import Spectral5
import pandas as pd
from bokeh.models import HoverTool

#Read the data into the notebook

df = pd.read_csv('all_stocks_5yr.csv')

df['date'] = pd.to_datetime(df['date']).apply(lambda x:x.strftime('%Y'))

#List the tech giants

tech_giants = ['GOOGL', 'FB', 'MSFT', 'AMZN', 'AAPL']

#Create the color map

color_map = CategoricalColorMapper(factors = tech_giants, palette = Spectral5)

#Create the ColumnDataSource Object

data = ColumnDataSource(data = {
    'high' : df[df['date'] == '2013'].high,
    'low' : df[df['date'] == '2013'].low,
    'open' : df[df['date'] == '2013'].open,
    'close': df[df['date'] == '2013'].close,
    'volume': df[df['date'] == '2013'].volume,
    'Name' : df[df['date'] == '2013'].Name
})

#Create ranges for the x and y axis

xmin, xmax = min(df.high), max(df.high)
ymin, ymax = min(df.volume), max(df.volume)

#Create the hover tool

hover_tool = HoverTool(tooltips = [('Company:', '@Name')])

#Create the plot

plot = figure(title = 'Volume traded Vs. High Prices', plot_height = 400, plot_width = 700, x_range = (xmin, xmax),
             y_range = (ymin, ymax), output_backend = 'webgl')

plot.diamond(x = 'high', y = 'volume', source = data, color = dict(field = 'Name', transform = color_map))

#Adding the hover tool to the plot

plot.add_tools(hover_tool)

plot.xaxis.axis_label = 'High Prices for 2013'

plot.yaxis.axis_label = 'Volume traded in 2013'

#Add the plot to the application

curdoc().add_root(plot)

curdoc().title = 'Volume and High prices of stocks'

使用此处显示的命令执行脚本:

bokeh serve --show bokeh.py

你会注意到执行速度的不同。由于您使用 WebGL 来增强 Bokeh 的性能,您的可视化现在将呈现得更快!

展示您的结果

正确的可视化不仅仅局限于选择正确的绘图类型,例如散点图或条形图。它扩展到选择正确的颜色、形状、标记和特征。

选择正确的可视化时,您需要问自己以下一些问题:

  • 我想向我的读者传递积极的信息吗?如果是的话,绿色和蓝色是很好的选择
  • 我是否想向我的读者传达一个警告/负面信息,表明某种形式的危险/拒绝?如果是,红色效果最好
  • 我是否想展示两个不同的细分市场/类别之间的差异?如果是,使用红色和蓝色等对比色效果很好

在创建理想的可视化时,您想要传达的洞察力和信息的基调至关重要。

摘要

在本章中,您学习了如何构建实时 Bokeh 可视化,可以用来从头开始分析股票的表现。您学习了如何执行初始探索性数据分析,以确定您想要创建的可视化类型。然后,您创建了可视化,并使用 WebGL 提高了它的性能。

最后,您学习了构成 Bokeh 工作流程不可或缺的一部分的四个步骤。您学习了如何在任何数据可视化项目中提出正确的问题,然后是探索性数据分析。你还学会了如何展示你的结果不仅限于你使用的绘图类型,还包括你想传达给观众的信息的语气。

这本书到此结束!我希望这本书给了你一个丰富的,对 Bokeh 世界的实际介绍!我希望你能继续利用你在这里学到的技能,制作出能吸引广大观众的互动绘图!

posted @ 2025-10-01 11:27  绝不原创的飞龙  阅读(11)  评论(0)    收藏  举报