在散景 2.x 中使用 annual_wedge 在 pie/donut 图表中添加标签

Adding labels in pie/donut chart using annual_wedge in bokeh 2.x

我在将正确对齐的标签集应用到使用散景中的 annual_wedge 字形创建的甜甜圈样式图表时遇到问题。

我无法对齐属于甜甜圈图 "rings" 类别的标签 "horizontaly",其中 horizo​​ntaly 是来自 inner_radius 的标签的对齐方式14=] 到 outer_radius。 目前标签集似乎没有对应于 annual_wedgeinner_radius 设置,这使得将标签集应用和对齐到年度楔形非常困难。

我正在按照 中的示例使用字符串填充,但这似乎是水平移动标签的非常肮脏的技巧。

如何以与 annual_wedge 字形的 inner_radius 对应的对齐方式将标签应用于 annual_wedge?

这是我的代码示例:

# > gics_sector_data
gics_sector_data["gics_name"] = gics_sector_data["gics_name"].astype(str)
gics_sector_data["gics_name"] = gics_sector_data["gics_name"].str.pad(47, side = "left")

    # Sector Ring
    p.annular_wedge(x=9, y=9, inner_radius=0.8,outer_radius=2.5,
            start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
            line_color="white", fill_color='color', source=gics_sector_data)

    sourceSector = ColumnDataSource(gics_sector_data)
    labelsSector = LabelSet(x=9, y=9, text='gics_name',
                        angle=cumsum('angle', include_zero=True), source=sourceSector, render_mode='canvas',
                        text_font_size="8pt", text_align='left',background_fill_color='white')
    p.add_layout(labelsSector)

在图片中,我将标签的背景颜色设置为白色,这样可以更好地看到标签的对齐方式和间距。

]

仅供参考:这是要显示的数据Global Industry Classification Standard

您必须自己计算坐标。

扩展链接示例:

from math import pi

import numpy as np
import pandas as pd

from bokeh.io import show
from bokeh.models import LabelSet, ColumnDataSource
from bokeh.palettes import Category20c
from bokeh.plotting import figure

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}

R = 0.4
data = (pd.Series(x)
        .reset_index(name='value')
        .rename(columns={'index': 'country'})
        .assign(end_angle=lambda d: np.cumsum(d['value'] / d['value'].sum() * 2 * pi),
                start_angle=lambda d: np.pad(d['end_angle'], (1, 0))[:-1],
                color=Category20c[len(x)],
                label_x=lambda d: R * 0.95 * np.cos(d['start_angle']),
                label_y=lambda d: R * 0.95 * np.sin(d['start_angle'])))

source = ColumnDataSource(data)

p_range = (-R * 1.2, R * 1.2)
p_size = 500
p = figure(plot_height=p_size, plot_width=p_size, toolbar_location=None,
           x_range=p_range, y_range=p_range,
           tools="hover", tooltips="@country: @value")
for r in [p.xaxis, p.yaxis, p.grid]:
    r.visible = False

p.wedge(x=0, y=0, radius=R,
        start_angle='start_angle', end_angle='end_angle',
        line_color="white", fill_color='color', legend_label='country', source=source)

p.add_layout(LabelSet(x='label_x', y='label_y', text='value', text_align='right',
                      angle='start_angle', source=source, render_mode='canvas'))

show(p)

多亏了 Eugene,我才走上了启蒙之路,并且能够得到我想要的图表。 我不得不通过计算 "donut" 扇区的起始角和结束角之间的中间值来修改标签位置的计算,因为我想让标签位于每个楔形的中间。

我修改了 Eugene 的例子,其中 "num" 只是我用来计算每个 annual_wedge 的相对宽度的值(Eugene 在他的例子中使用 'value',我使用 num对于 'donut' 上总共类似宽度的插槽中每个楔形占用的插槽数,我希望这足够清楚):

R = 3
gics_sector_data= gics_sector_data.assign(
                end_angle=lambda d: np.cumsum(d['num'] / d['num'].sum() * 2 * pi),
                start_angle=lambda d: np.pad(d['end_angle'], (1, 0))[:-1],
                label_x=lambda d: R* 1.00 * np.cos(((d['end_angle']-d['start_angle'])/2)+d['start_angle']),
                label_y=lambda d: R* 1.00 * np.sin(((d['end_angle']-d['start_angle'])/2)+d['start_angle']),
                label_angle=lambda d: (((d['end_angle']-d['start_angle'])/2)+d['start_angle']))

关于 1.00 乘法,您可以将标签从楔形的外边缘移开 f.e。使用 0.95.

除此之外:我通过添加 label_shortname 列来缩短标签名称,因为散景不能换行标签。短名称将用于标签,长名称用于工具提示:

gics_sector_data['gics_name_short'] = gics_sector_data['gics_name'].str.slice(stop=20)

然后像 start_angles 和 end_anglescalculated 一样绘制 annual_wedge:

# Sector Ring
p.annular_wedge(x=0, y=0, inner_radius=gics_sector_radius-ringWidth, outer_radius=gics_sector_radius,
                start_angle='start_angle', end_angle='end_angle',
                line_color="white", fill_color='color', source=gics_sector_data)

最后用计算出的label_x、label_y和label_angle绘制LabelSet,将在楔形中间绘制标签,text_baseline='middle' 是获得良好结果所必需的:

sourceSector = ColumnDataSource(gics_sector_data)
labelsSector = LabelSet(x='label_x', y='label_y', text='gics_name_short',
                   angle='label_angle', source=sourceSector, render_mode='canvas',
                    text_font_size="7pt", text_align='right', text_baseline='middle')
p.add_layout(labelsSector)

这里是 99.999% 的完美结果GICS result bokeh chart,我希望这有助于创建类似的图表