使用背景填充向散景图添加文本

Adding text to a bokeh plot with a background fill

我目前有一个 bokeh.models.glyphs.Text 可以向绘图中添加一些文本。现在我想填充文本标签的背景,但是 bokeh.models.glyphs.Text 没有 background_fill 参数。

是否有其他方法可以将带有背景填充的文本添加到散景图?

您无法使用 Text 字形本身来完成此操作。但还有其他选择:

  • 在文本正下方绘制一个所需颜色的矩形。非常容易实现但很难测量文本,以便所有矩形始终具有所需的宽度
  • 创建一个自定义 Text 模型来为您绘制矩形。实施起来有点困难,因为它需要一些 JavaScript/TypeScript,但它将能够自动测量文本

这是一个简单的示例,它不完全是一个文本框,而是一个使用 LabelSet() 对象的行列表。 LabelSet() 是一种在图形 window 中的多个位置放置标签的方法。它有更好的支持,通常包括:

  • 背景颜色
  • source= 字段 ColumnDataSource
  • datascreen 个单位

如果您将 LabelSet 个位置放置得足够近,字体大小合适,它看起来就像一个文本框。

这是一个示例,其中包含一个按钮,每次按下该按钮时都会使用当前日期更新文本:

import numpy as np
from datetime import datetime

from bokeh.layouts import layout
from bokeh.io import curdoc
from bokeh.models import ColumnDataSource, Button, LabelSet
from bokeh.plotting import figure


nLines=4 # max number of lines
text_str = ['{0}'.format(line) for line in range(nLines)] # init with empty strings


# create some other data coordinates for a figure
xData=np.arange(-3,+12,0.5)
yData=xData
plot = figure(title="Text placement example, in screen units", 
              height=300, sizing_mode='scale_width',
              x_range=(min(xData), max(xData)), y_range=(min(yData), max(yData)),
              x_axis_label="my X-axis", y_axis_label="my Y-axis")





# ------------ text box with a LabelSet() object ----------------
x_scr_lo=20; x_scr_hi=67
label_data = ColumnDataSource(data=dict(
       x=[x_scr_lo]*nLines,
       y=np.linspace(x_scr_lo,x_scr_hi,nLines),
       text=text_str))
plot_label = LabelSet(x='x', y='y', text='text',
              text_font_size='11pt',
              background_fill_color='lightskyblue',
              x_units='screen', y_units='screen',
              background_fill_alpha=0.2,
              text_color='blue', source=label_data)
plot.add_layout(plot_label)


def bt_add_lines_callback():
    new_text=label_data.data['text'] # grab current string list
    new_text.pop() # drop the oldest (last)
    new_text.insert(0,    'update {0}'.format( datetime.now().strftime('%c') )    )
    label_data.data=dict(x=[20]*nLines,
    y=np.linspace(x_scr_lo,x_scr_hi,nLines), text=new_text)

bt_add_lines = Button(label="Update next line" ,
               button_type="success", width=200)
bt_add_lines.on_click(bt_add_lines_callback)

## arrange all map views in a grid layout then add to the document
layout = layout([
    [bt_add_lines],
    [plot] ], sizing_mode='stretch_width')

doc = curdoc()
doc.add_root(layout)