Image as background

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

Look at the ‘level’ argument for renderer instantiation (p.line / p.image_url ). I think there is underlay/overlay etc. you can assign to put the send the image “to the back”.

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)

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.

1 Like

@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.

1 Like

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)
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.