Bokeh包括几种不同类型的注释,允许用户在可视化中添加补充信息。
Title 注释允许在打印边缘周围呈现描述性文本。
Title
使用时 bokeh.plotting 或 bokeh.Charts ,添加基本标题的最快方法是将文本作为 title 参数到 Figure 或任何图表函数:
bokeh.plotting
bokeh.Charts
title
Figure
from bokeh.plotting import figure, output_file, show p = figure(title="Basic Title", plot_width=300, plot_height=300) p.circle([1,2], [3,4]) output_file("title.html") show(p)
默认标题通常位于绘图的顶部,与左侧对齐。但是默认标题出现在绘图的哪一侧可以由 title_location 参数:
title_location
from bokeh.plotting import figure, output_file, show p = figure(title="Left Title", title_location="left", plot_width=300, plot_height=300) p.circle([1,2], [3,4]) output_file("title.html") show(p)
默认值 Title 可通过 Plot.title 财产。字体、边框、背景和其他视觉属性可以直接在 .title . 下面是一个使用设置字体和背景属性以及标题文本和标题对齐方式的示例 .title :
Plot.title
.title
from bokeh.plotting import figure, output_file, show p = figure(plot_width=300, plot_height=300) p.circle([1,2], [3,4]) # configure visual properties on a plot's title attribute p.title.text = "Title With Options" p.title.align = "right" p.title.text_color = "orange" p.title.text_font_size = "25px" p.title.background_fill_color = "#aaaaee" output_file("title.html") show(p)
请注意,对齐是沿着文本方向测量的。例如,对于地块左侧的标题,“left”将位于下角。
除了默认标题之外,还可以创建和添加其他 Title 对象以使用 add_layout 绘图方法:
add_layout
from bokeh.models import Title from bokeh.plotting import figure, output_file, show p = figure(title="Left Title", title_location="left", plot_width=300, plot_height=300) p.circle([1,2], [3,4]) # add extra titles with add_layout(...) p.add_layout(Title(text="Bottom Centered Title", align="center"), "below") output_file("title.html") show(p)
如果标题和粘滞工具栏设置在同一侧,它们将占用相同的空间:
from bokeh.plotting import figure, output_file, show p = figure(title="Top Title with Toolbar", toolbar_location="above", plot_width=600, plot_height=300) p.circle([1,2], [3,4]) output_file("title.html") show(p)
如果打印大小足够大,则可以生成更紧凑的打印。但是,如果打印大小不够大,标题和工具栏可能会以不理想的方式在视觉上重叠。
有可能创造 Legend 通过在创建绘图时为glyph方法指定图例参数,可以轻松地进行注释。
Legend
要为glyph提供一个简单的显式标签,请传递 legend_label 关键字参数:
legend_label
p.circle('x', 'y', legend_label="some label")
如果多个glyph被赋予同一个标签,它们将被合并到一个带有该标签的图例项中。
import numpy as np from bokeh.plotting import figure, output_file, show x = np.linspace(0, 4*np.pi, 100) y = np.sin(x) output_file("legend.html") p = figure() p.circle(x, y, legend_label="sin(x)") p.line(x, y, legend_label="sin(x)") p.line(x, 2*y, legend_label="2*sin(x)", line_dash=[4, 4], line_color="orange", line_width=2) p.square(x, 3*y, legend_label="3*sin(x)", fill_color=None, line_color="green") p.line(x, 3*y, legend_label="3*sin(x)", line_color="green") show(p)
通常需要通过对数据源列中的值进行分组来生成多个图例项。Bokeh可以通过传递 legend_group glyph方法的关键字参数:
legend_group
p.circle('x', 'y', legend_group="colname", source=source)
使用此方法时,将立即在Python中执行分组,随后的Python代码将能够在中查看各个图例项 Legend.items 财产。如果需要,可以重新排列或修改这些项目。
Legend.items
from bokeh.io import show from bokeh.models import ColumnDataSource from bokeh.palettes import RdBu3 from bokeh.plotting import figure c1 = RdBu3[2] # red c2 = RdBu3[0] # blue source = ColumnDataSource(dict( x=[1, 2, 3, 4, 5, 6], y=[2, 1, 2, 1, 2, 1], color=[c1, c2, c1, c2, c1, c2], label=['hi', 'lo', 'hi', 'lo', 'hi', 'lo'] )) p = figure(x_range=(0, 7), y_range=(0, 3), plot_height=300, tools='save') # legend field matches the column in the source p.circle( x='x', y='y', radius=0.5, color='color', legend_group='label', source=source) show(p)
注解
要使用此功能,一个 source 参数 还必须提供 到glyph方法。此外,要分组的列必须已经存在于数据源中。
source
也可以在浏览器中指定分组发生在JavaScript端。这可能是可取的,例如,如果分组发生在只在JavaScript端计算的列上。
p.circle('x', 'y', legend_field="colname", source=source)
在本例中,Python代码 not 查看中的多个项目 Legend.items . 相反,只有一个项目表示要在浏览器中执行的分组。
from bokeh.io import show from bokeh.models import ColumnDataSource from bokeh.palettes import RdBu3 from bokeh.plotting import figure c1 = RdBu3[2] # red c2 = RdBu3[0] # blue source = ColumnDataSource(dict( x=[1, 2, 3, 4, 5, 6], y=[2, 1, 2, 1, 2, 1], color=[c1, c2, c1, c2, c1, c2], label=['hi', 'lo', 'hi', 'lo', 'hi', 'lo'] )) p = figure(x_range=(0, 7), y_range=(0, 3), plot_height=300, tools='save') # legend field matches the column in the source p.circle( x='x', y='y', radius=0.5, color='color', legend_field='label', source=source) show(p)
也可以不指定任何图例参数,而手动生成 Legend 用手。这方面的一个例子可以在 examples/models/file/legends.py :
其他时候,显式地告诉Bokeh ColumnDataSource 应在绘制图例项时使用。尤其是,如果要为“多”字形绘制多个图例项,例如 MultiLine 或 Patches . 这是通过指定 index 对于图例项,如下所示。
ColumnDataSource
MultiLine
Patches
index
from bokeh.models import Legend, LegendItem from bokeh.plotting import figure, show p = figure() r = p.multi_line([[1,2,3], [1,2,3]], [[1,3,2], [3,4,3]], color=["orange", "red"], line_width=4) legend = Legend(items=[ LegendItem(label="orange", renderers=[r], index=0), LegendItem(label="red", renderers=[r], index=1), ]) p.add_layout(legend) show(p)
也可以将图例配置为交互式的,这样单击或点击图例条目会影响相应的字形可见性。见 交互式图例 有关更多信息和示例,请参阅用户指南的一节。
交互式图例 功能目前适用于第一个“每字形”样式图例。通过指定要自动分组的列创建的图例尚不支持交互式功能。
A ColorBar 可以使用 ColorMapper 实例,其中包含调色板。同时支持on和off打印颜色条;在添加 ColorBar 对情节的影响。
ColorBar
ColorMapper
这个示例依赖于开源NumPy库来生成演示数据。
import numpy as np from bokeh.models import ColorBar, LogColorMapper, LogTicker from bokeh.plotting import figure, output_file, show output_file('color_bar.html') def normal2d(X, Y, sigx=1.0, sigy=1.0, mux=0.0, muy=0.0): z = (X-mux)**2 / sigx**2 + (Y-muy)**2 / sigy**2 return np.exp(-z/2) / (2 * np.pi * sigx * sigy) X, Y = np.mgrid[-3:3:100j, -2:2:100j] Z = normal2d(X, Y, 0.1, 0.2, 1.0, 1.0) + 0.1*normal2d(X, Y, 1.0, 1.0) image = Z * 1e6 color_mapper = LogColorMapper(palette="Viridis256", low=1, high=1e7) plot = figure(x_range=(0,1), y_range=(0,1), toolbar_location=None) plot.image(image=[image], color_mapper=color_mapper, dh=[1.0], dw=[1.0], x=[0], y=[0]) color_bar = ColorBar(color_mapper=color_mapper, ticker=LogTicker(), label_standoff=12, border_line_color=None, location=(0,0)) plot.add_layout(color_bar, 'right') show(plot)
Arrow 注释可用于连接图示符和标签注释,或仅高亮显示打印区域。箭头是复合注释,这意味着 start 和 end 属性本身就是另一个 ArrowHead 注解。默认情况下 Arrow 注释与 end 设置为 OpenHead -键入arrowhead(一种开放式背面楔形样式)和 start 属性设置为 None . 可以通过设置 start 和 end 适当的属性 ArrowHead 子类实例。
Arrow
start
end
ArrowHead
OpenHead
None
箭头具有用于设置箭头轴的颜色和外观的标准线属性:
my_arrow.line_color = "blue" my_arrow.line_alpha = 0.6
箭头也可以配置为引用其他非默认的x或y范围 x_range 和 y_range 属性,与 双斧 .
x_range
y_range
此外,任何箭头对象 start 或 end 有一个 size 属性控制箭头的大小,以及直线和填充属性。线属性控制箭头的轮廓,填充属性控制箭头的内部(如果适用)。
size
from bokeh.models import Arrow, NormalHead, OpenHead, VeeHead from bokeh.plotting import figure, output_file, show output_file("arrow.html", title="arrow.py example") p = figure(plot_width=600, plot_height=600) p.circle(x=[0, 1, 0.5], y=[0, 0, 0.7], radius=0.1, color=["navy", "yellow", "red"], fill_alpha=0.1) p.add_layout(Arrow(end=OpenHead(line_color="firebrick", line_width=4), x_start=0, y_start=0, x_end=1, y_end=0)) p.add_layout(Arrow(end=NormalHead(fill_color="orange"), x_start=1, y_start=0, x_end=0.5, y_end=0.7)) p.add_layout(Arrow(end=VeeHead(size=35), line_color="red", x_start=0.5, y_start=0.7, x_end=0, y_end=0)) show(p)
A Band 将创建一个维度链接的“条纹”,位于数据或屏幕坐标中。波段注释的一个常见用途是指示与一系列测量相关的不确定度。
Band
import numpy as np import pandas as pd from bokeh.models import Band, ColumnDataSource from bokeh.plotting import figure, output_file, show output_file("band.html", title="band.py example") # Create some random data x = np.random.random(2500) * 140 - 20 y = np.random.normal(size=2500) * 2 + 5 df = pd.DataFrame(data=dict(x=x, y=y)).sort_values(by="x") sem = lambda x: x.std() / np.sqrt(x.size) df2 = df.y.rolling(window=100).agg({"y_mean": np.mean, "y_std": np.std, "y_sem": sem}) df2 = df2.fillna(method='bfill') df = pd.concat([df, df2], axis=1) df['lower'] = df.y_mean - df.y_std df['upper'] = df.y_mean + df.y_std source = ColumnDataSource(df.reset_index()) TOOLS = "pan,wheel_zoom,box_zoom,reset,save" p = figure(tools=TOOLS) p.scatter(x='x', y='y', line_color=None, fill_alpha=0.3, size=5, source=source) band = Band(base='x', lower='lower', upper='upper', source=source, level='underlay', fill_alpha=1.0, line_width=1, line_color='black') p.add_layout(band) p.title.text = "Rolling Standard Deviation" p.xgrid[0].grid_line_color=None p.ygrid[0].grid_line_alpha=0.5 p.xaxis.axis_label = 'X' p.yaxis.axis_label = 'Y' show(p)
A BoxAnnotation 可以链接到数据或屏幕坐标,以强调特定的绘图区域。默认情况下,框注释尺寸(例如。 left 或 top )将注释扩展到绘图区域的边缘。
BoxAnnotation
left
top
from bokeh.models import BoxAnnotation from bokeh.plotting import figure, output_file, show from bokeh.sampledata.glucose import data output_file("box_annotation.html", title="box_annotation.py example") TOOLS = "pan,wheel_zoom,box_zoom,reset,save" #reduce data size data = data.loc['2010-10-06':'2010-10-13'] p = figure(x_axis_type="datetime", tools=TOOLS) p.line(data.index.to_series(), data['glucose'], line_color="gray", line_width=1, legend_label="glucose") low_box = BoxAnnotation(top=80, fill_alpha=0.1, fill_color='red') mid_box = BoxAnnotation(bottom=80, top=180, fill_alpha=0.1, fill_color='green') high_box = BoxAnnotation(bottom=180, fill_alpha=0.1, fill_color='red') p.add_layout(low_box) p.add_layout(mid_box) p.add_layout(high_box) p.title.text = "Glucose Range" p.xgrid[0].grid_line_color=None p.ygrid[0].grid_line_alpha=0.5 p.xaxis.axis_label = 'Time' p.yaxis.axis_label = 'Value' show(p)
标签是文本元素,可用于注释字形或打印区域。
要创建单个文本标签,请使用 Label 注释。此批注配置为 text 属性包含要显示的文本,以及 x 和 y 属性设置位置(以屏幕或数据空间单位为单位)。另外,渲染模式 "canvas" 或 "css" 可以指定。最后,标签 text , border_line 和 background_fill 属性。这些控件控制文本的视觉外观以及文本边框和背景:
Label
text
x
y
"canvas"
"css"
border_line
background_fill
Label(x=70, y=70, x_units='screen', text='Some Stuff', render_mode='css', border_line_color='black', border_line_alpha=1.0, background_fill_color='white', background_fill_alpha=1.0)
要同时创建多个标签,可能要轻松地注释另一个现有的glyph,请使用 LabelSet 注释,它配置了一个数据源,其中 text 和 x 和 y 位置以列名的形式给出。 LabelSet 对象也可以 x_offset 和 y_offset ,以屏幕空间单位指定标签位置的偏移距离 x 和 y . 最后,渲染级别可以用 level 属性,若要将标签放置在其他渲染器的上方或下方,请执行以下操作:
LabelSet
x_offset
y_offset
level
LabelSet(x='x', y='y', text='names', level='glyph', x_offset=5, y_offset=5, source=source)
以下示例说明了两者的用法:
from bokeh.models import ColumnDataSource, Label, LabelSet, Range1d from bokeh.plotting import figure, output_file, show output_file("label.html", title="label.py example") source = ColumnDataSource(data=dict(height=[66, 71, 72, 68, 58, 62], weight=[165, 189, 220, 141, 260, 174], names=['Mark', 'Amir', 'Matt', 'Greg', 'Owen', 'Juan'])) p = figure(title='Dist. of 10th Grade Students at Lee High', x_range=Range1d(140, 275)) p.scatter(x='weight', y='height', size=8, source=source) p.xaxis[0].axis_label = 'Weight (lbs)' p.yaxis[0].axis_label = 'Height (in)' labels = LabelSet(x='weight', y='height', text='names', level='glyph', x_offset=5, y_offset=5, source=source, render_mode='canvas') citation = Label(x=70, y=70, x_units='screen', y_units='screen', text='Collected by Luke C. 2016-04-01', render_mode='css', border_line_color='black', border_line_alpha=1.0, background_fill_color='white', background_fill_alpha=1.0) p.add_layout(labels) p.add_layout(citation) show(p)
Slope 注释是可以倾斜并延伸到打印区域边缘的线。
Slope
import numpy as np from bokeh.models import Slope from bokeh.plotting import figure, output_file, show output_file("slope.html", title="slope.py example") # linear equation parameters gradient = 2 y_intercept = 10 # create random data xpts = np.arange(0, 20) ypts = gradient * xpts + y_intercept + np.random.normal(0, 4, 20) p = figure(plot_width=450, plot_height=450, y_range=(0, 1.1 * max(ypts))) p.circle(xpts, ypts, size=5, color="skyblue") slope = Slope(gradient=gradient, y_intercept=y_intercept, line_color='orange', line_dash='dashed', line_width=3.5) p.add_layout(slope) p.yaxis.axis_label = 'y' p.xaxis.axis_label = 'x' show(p)
Span 注释是具有单一尺寸(宽度或高度)并延伸到打印区域边缘的线。
Span
import time from datetime import datetime as dt from bokeh.models import Span from bokeh.plotting import figure, output_file, show from bokeh.sampledata.daylight import daylight_warsaw_2013 output_file("span.html", title="span.py example") p = figure(x_axis_type="datetime", y_axis_type="datetime") p.line(daylight_warsaw_2013.Date, daylight_warsaw_2013.Sunset, line_dash='solid', line_width=2, legend_label="Sunset") p.line(daylight_warsaw_2013.Date, daylight_warsaw_2013.Sunrise, line_dash='dotted', line_width=2, legend_label="Sunrise") start_date = time.mktime(dt(2013, 3, 31, 2, 0, 0).timetuple())*1000 daylight_savings_start = Span(location=start_date, dimension='height', line_color='green', line_dash='dashed', line_width=3) p.add_layout(daylight_savings_start) end_date = time.mktime(dt(2013, 10, 27, 3, 0, 0).timetuple())*1000 daylight_savings_end = Span(location=end_date, dimension='height', line_color='red', line_dash='dashed', line_width=3) p.add_layout(daylight_savings_end) p.title.text = "2013 Sunrise and Sunset times in Warsaw" p.yaxis.axis_label = 'Time of Day' show(p)
A Whisker 将创建一个维度链接的“茎”,位于数据或屏幕坐标中。在一个点上指示测量的误差或不确定度是触须注释的一个常见用途。
Whisker
from bokeh.models import ColumnDataSource, Whisker from bokeh.plotting import figure, show from bokeh.sampledata.autompg import autompg as df colors = ["red", "olive", "darkred", "goldenrod", "skyblue", "orange", "salmon"] p = figure(plot_width=600, plot_height=300, title="Years vs mpg with Quartile Ranges") base, lower, upper = [], [], [] for i, year in enumerate(list(df.yr.unique())): year_mpgs = df[df['yr'] == year]['mpg'] mpgs_mean = year_mpgs.mean() mpgs_std = year_mpgs.std() lower.append(mpgs_mean - mpgs_std) upper.append(mpgs_mean + mpgs_std) base.append(year) source_error = ColumnDataSource(data=dict(base=base, lower=lower, upper=upper)) p.add_layout( Whisker(source=source_error, base="base", upper="upper", lower="lower") ) for i, year in enumerate(list(df.yr.unique())): y = df[df['yr'] == year]['mpg'] color = colors[i % len(colors)] p.circle(x=year, y=y, color=color) show(p)