3

I currently have a bokeh.models.glyphs.Text to add some text to a plot. Now I want to fill the background of the text label, but bokeh.models.glyphs.Text had no background_fill argument.

Is there maybe an alternative way to add text with a background fill to a bokeh plot?

2 Answers 2

3

You cannot do it with the Text glyph itself. But there are alternatives:

  • Draw a rectangle of the required color right under the text. Very easy to implement but hard to measure the text so that all of the rectangles are always of the required width
  • Create a custom Text model that draws the rectangle for you. A bit harder to implement because it requires some JavaScript/TypeScript, but it will be able to measure the text automatically
Sign up to request clarification or add additional context in comments.

3 Comments

it sounds like the first option is best if the text is of known dimensions, like width and number of lines
A simple way to do this is to draw the full_block (█) character behind your text like here: github.com/pylanglois/cnc-pack-and-cut/blob/…
That's a workaround that might work in some cases. But in general, the size will be off because different characters have different width, depending on the font.
1

here's a simple example that is not exactly a text-box, but it's a list of lines using the LabelSet() object. The LabelSet() is a way of placing labels at multiple locations within a figure window. It has better support generally including:

  • background colors
  • source= field for ColumnDataSource
  • either data or screen units

If you put the LabelSet locations close enough, with the right sized font it'll look like a text box.

This is an example with a button to update the text with the current date every time it's pressed:

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.