How to place images using image_url in Bokeh

Viewed 658

I have a chart that uses datetime for the x-axis and dollars for the y-axis in Bokeh. I want to place a logo in the upper left corner of the plot area. Bokeh documentations seems especially cryptic on placing images. This code works:

from bokeh.plotting import figure, show

#p = figure(x_range=(0,1200), y_range=(0,600))
p = figure(plot_width=1200, plot_height=600,
                sizing_mode = 'scale_width',
                toolbar_location='above',
                x_axis_label='date',
                x_axis_type='datetime',
                y_axis_label='value',
                )
p.image_url(x=0, y=1, url=["Shrewd_Lines_200.png"], anchor='bottom_left')

show(p)

But when I place this into my main chart, where the data is in datetime, I can not get an image to appear. Here are the key excerpts from the code within the primary chart:

plot = figure(plot_width=1200, plot_height=600,
                sizing_mode = 'scale_width',
                toolbar_location='above',
                tools=tools,
                title=plot_dict['chart_title'],
                x_axis_label='date',
                x_axis_type='datetime',
                y_axis_label='value',
                )

plot.x_range.end=plot_dict['end_data'] + extend_time

if plot_dict['start_chart'] == 'auto':
        plot.x_range.start=plot_dict['start_user_data']     
    else:
        plot.x_range.start = plot_dict['start_chart']

    plot.y_range.start=0
    plot.y_range.end=  extend_y * plot_dict['max_value']
    plot.left[0].formatter.use_scientific = False
    plot.title.text_font_size = "16pt"

I have tried various approaches to plot the image such as:

plot.image_url(x=0, y=0, url=["Shrewd_Lines_200.png"], anchor='bottom_left')

plot.image_url(x=plot_dict['start_user_data'], y=10000000, url=["Shrewd_Lines_200.png"], anchor='bottom_left')

I have several labels in the chart that work quite nicely. Is there a way to specify image location and size using screen units, in the same manner as you specify locations for labels?

1 Answers

Thought I would post how I got this working in order to move forward. I used the following for my Bokeh plot that places my logo with some generic math to convert data space to screen space. It does this without using numpy arrays or ColumnDataSource (neither of which are bad, but trying to keep simple):

from bokeh.plotting import figure, show

# chart size and ranges need defined for dataspace location
# chart size
chart_width = 900
chart_height = 600
aspect_ratio = chart_width/chart_height

# limits of data ranges
x1 = 300
x2 = 1200
y1 = 0
y2 = 600

plot = figure(
    plot_width=chart_width,
    plot_height=chart_height,
    x_range=(x1, x2),
    y_range=(y1, y2),
    sizing_mode = 'stretch_both',
    x_axis_label='date',
    x_axis_type='datetime',
    y_axis_label='value')

plot.image_url(url=['my_image.png'], x=(.01*(x2-x1))+x1, y=(.98*(y2-y1))+y1,
    w=.35*(x2-x1)/aspect_ratio, h=.1*(y2-y1), anchor="top_left")

show(plot)

Note the x_axis_type can be any type with this schema, datetime was just the issue I was dealing with.

Related