☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Image as background

Community Supportbokeh
paul_c
paul_c

Hi, this should be simple, but I can’t work it out.

I am trying to load an image as a background for a line plot.

This works, but I don’t how to control the size of the image so it matches the plot.

import pandas as pd
import numpy as np

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, ImageURL, Div, Row
from bokeh.io import show, output_notebook
output_notebook()

dates = pd.date_range("20210101", periods=6)
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list("ABCD"))
df.rename_axis('Date', axis=0, inplace=True)
source = ColumnDataSource(df)

url = 'https://images.unsplash.com/photo-1586061968253-7bf5724aab7b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE0fHxiYW1ib298ZW58MHx8fHwxNjQ5NjgxMzA0&ixlib=rb-1.2.1&q=80&w=2000'

p = figure(aspect_ratio = 16/9)

p.line(x='Date',
        y='A',
        source = source,
        color='green')

d1 = Div(text = '<div style="position: absolute; left:-570px; top:10px"><img src=' + url + ' style="aspect_ratio : 16/9; opacity: 0.2;"></div>')

show(Row(p, d1))

I thought this seemed like the better method to control the size, but I can’t get both the line and the background to appear:

p = figure(aspect_ratio = 16/9)

p.image_url(url=[url],
           x=0, y=0, w=1, h=1, anchor="bottom_left", alpha=0.2)

p.line(x='Date',
        y='A',
        source = source,
        color='green')

show(p)

Thanks

⌁   Link to post
paul_c
paul_c

Thanks. Found that now, so I thought it should be something like this, but it still doesn’t work. Whatever levels I seem to use, the line doesn’t appear.

p = figure(aspect_ratio = 16/9)
p.image_url(url=[url],x=0, y=0, w=1, h=1, anchor=“bottom_left”, alpha=0.2, level=‘underlay’)
p.line(x=‘Date’,y=‘A’,source = source,color=‘green’, level=‘overlay’)
show(p)

⌁   Link to post
gmerritt123
gmerritt123

Ahh that threw me for a sec.

The problem (in your example at least) is that your line is using a Date (6 dates around 2021) for its X values, and your image is being placed at 0,0 with a width/height of 1,1… which I believe means it is getting anchored at Jan 1, 1970 and is 1 millisecond wide. So in your example… the image and the line ARE there… you just gotta zoom in “a bit” (lol) to see the image.

⌁   Link to post
Bryan
Bryan

@gmerritt123 is exactly correct, the underlying units of a datetime axis are “milliseconds since epoch” so you’d need to supply an appropriate width/height in those units. Alternatively, you could add secondary axis scales with (0, 1) ranges, and point the glyph at those, instead of the default ones.

⌁   Link to post
paul_c
paul_c

Thanks v much @Bryan and @gmerritt123. This works I think.

dates = pd.date_range("20210101", periods=6)
df = pd.DataFrame(np.random.randn(6, 4), index=dates, columns=list("ABCD"))
df.rename_axis('Date', axis=0, inplace=True)
source = ColumnDataSource(df)

url = 'https://images.unsplash.com/photo-1586061968253-7bf5724aab7b?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDE0fHxiYW1ib298ZW58MHx8fHwxNjQ5NjgxMzA0&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000'

p = figure(aspect_ratio=16/9,
           x_range=Range1d(start=dates[0], end=dates[-1]), x_axis_type='datetime')

p.extra_y_ranges = {"secondary": Range1d(start=0, end=1)}

p.image_url(url=[url], x=dates[0], y=0, w=dates[-1] - dates[0], h=1, anchor="bottom_left", alpha=0.2, level='underlay', y_range_name="secondary")

p.line(x='Date', y='A', source=source, color='green', level='overlay')

show(p)
⌁   Link to post

End of archived discussion · Replies are disabled