饼图和环图#

Bokeh 没有内置的饼图和环图 API。但是,您可以使用 Bokeh 的各种扇形图形来创建这些类型的图表。

图形#

扇形#

wedge() 图形方法渲染一个填充的扇形。它接受 radiusstart_angleend_angle 来确定位置。此外,direction 属性决定是在起始和结束角度之间顺时针 ("clock") 还是逆时针 ("anticlock") 渲染。

from bokeh.plotting import figure, show

p = figure(width=400, height=400)
p.wedge(x=[1, 2, 3], y=[1, 2, 3], radius=0.2, start_angle=0.4, end_angle=4.8,
        color="firebrick", alpha=0.6, direction="clock")

show(p)

环形扇形#

annular_wedge() 图形方法类似于 wedge(),但会留下扇形内部的一部分空心。它接受 inner_radiusouter_radius 而不是仅 radius

from bokeh.plotting import figure, show

p = figure(width=400, height=400)
p.annular_wedge(x=[1, 2, 3], y=[1, 2, 3], inner_radius=0.1, outer_radius=0.25,
                start_angle=0.4, end_angle=4.8, color="green", alpha=0.6)

show(p)

环形#

最后,该 annulus() 图形方法也接受 inner_radiusouter_radius 来生成空心圆。

饼图#

对每个饼图切片使用扇形图形来创建饼图

from math import pi

import pandas as pd

from bokeh.palettes import Category20c
from bokeh.plotting import figure, show
from bokeh.transform import cumsum

x = {
    'United States': 157,
    'United Kingdom': 93,
    'Japan': 89,
    'China': 63,
    'Germany': 44,
    'India': 42,
    'Italy': 40,
    'Australia': 35,
    'Brazil': 32,
    'France': 31,
    'Taiwan': 31,
    'Spain': 29,
}

data = pd.Series(x).reset_index(name='value').rename(columns={'index': 'country'})
data['angle'] = data['value']/data['value'].sum() * 2*pi
data['color'] = Category20c[len(x)]

p = figure(height=350, title="Pie Chart", toolbar_location=None,
           tools="hover", tooltips="@country: @value", x_range=(-0.5, 1.0))

p.wedge(x=0, y=1, radius=0.4,
        start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
        line_color="white", fill_color='color', legend_field='country', source=data)

p.axis.axis_label = None
p.axis.visible = False
p.grid.grid_line_color = None

show(p)

环图#

环图类似于饼图,但使用环形扇形来划分环形区域

from math import pi

from bokeh.io import show
from bokeh.models import (AnnularWedge, ColumnDataSource,
                          Legend, LegendItem, Plot, Range1d)
from bokeh.sampledata.browsers import browsers_nov_2013 as df

xdr = Range1d(start=-2, end=2)
ydr = Range1d(start=-2, end=2)

plot = Plot(x_range=xdr, y_range=ydr)
plot.title.text = "Web browser market share (November 2013)"
plot.toolbar_location = None

colors = {
    "Chrome": "seagreen",
    "Firefox": "tomato",
    "Safari": "orchid",
    "Opera": "firebrick",
    "IE": "skyblue",
    "Other": "lightgray",
}

aggregated = df.groupby("Browser").sum(numeric_only=True)
selected = aggregated[aggregated.Share >= 1].copy()
selected.loc["Other"] = aggregated[aggregated.Share < 1].sum()
browsers = selected.index.tolist()

angles = selected.Share.map(lambda x: 2*pi*(x/100)).cumsum().tolist()

browsers_source = ColumnDataSource(dict(
    start  = [0] + angles[:-1],
    end    = angles,
    colors = [colors[browser] for browser in browsers],
))

glyph = AnnularWedge(x=0, y=0, inner_radius=0.9, outer_radius=1.8,
                     start_angle="start", end_angle="end",
                     line_color="white", line_width=3, fill_color="colors")
r= plot.add_glyph(browsers_source, glyph)

legend = Legend(location="center")
for i, name in enumerate(colors):
    legend.items.append(LegendItem(label=name, renderers=[r], index=i))
plot.add_layout(legend, "center")

show(plot)