Adding watermark to chart

Is there a way to add a local file as a watermark to the chart that is created? I tried the following but it did not work:

d1 = Div(
    text='<div style="position: absolute; left:-300px; top:10px"><img src="watermark.png" style="width:280px; height:280px; opacity: 0.3"></div>')
show(column(p, data_table), d1)

Error:

File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/webbrowser.py", line 48, in get
if '%s' in browser:
TypeError: argument of type 'Div' is not iterable

There is no way to overlay a Bokeh Div on top of any other Bokeh objects, it can only in layouts adjacent to them. If you just need it on plots, you could plot a (mostly) transparent image as an overlay layer. Otherwise, you best bet is to embed the Bokeh content in a custom Jinja template using e.g. file_html, so that you could truly overlay other HTML DOM elements on top of Bokeh content.

Thanks, sounds a little too complicated for a newbie like me for the moment. I’ll try and find some time to research these options.

Actually, I tried p.image_url and it kind of worked but:

  • It’s not scaling with the image (probably my code)

  • It’s not being included in the PNG export - i can see it in the browser but not the export?

    p = figure(x_range=report01data.xcords, plot_width=800, plot_height=600, toolbar_location=None,
             title=f'Performance Summary for {report01data.name}', name='chart')
    p.image_url(url=['watermark.png'], x=report01data.xcords, y=0, w=10, h=0.05, anchor="bottom_left", global_alpha=0.2)
    export_png(column(p, data_table), filename='report01.png')
    show(column(p, data_table))
    

Is it not possible to do it this way at all? I spent today looking at html and jinja but simply couldn’t head my head around it.

ImageURL is different from almost all the other glyphs in that it has to load the image asynchronously, and trigger a re-render, instead of drawing directly on the canvas itself directly. I expect the export is happening before the image is actually loaded. That’s a bug, so a GitHub issue with a reproducing script would be appropriate.

There are various ways to embed in templates. I’m not sure how to advise you because I don’t have a picture of where you are having issues. Here is an example that uses the components API to embed in a Jinja template you can refer to:

You’ll want to arrange the HTML so that there is a div with the image you want on top of the plot. I know that is possible, but I don’t actually know the details of how to do it.

Unfortunately watermarks is something that almost no-one has asked for in ~7 years, so we have never put any effort into that idea at all.

One approach I’ve had used to do exactly this is to simply transform the image to a numpy RGB array and plot it as a regular figure. It would not be a watermark per se, but you can include the watermark logo on the same page as your plot figure. You can control the size with the figure size and the location with regular layout tools such as row, columns and layouts. You would need to import the numpy and PIL modules.

from bokeh.plotting import figure
import numpy as np
from PIL import Image

def html_WM_logo():
    WM = figure(x_range = (0,10), y_range = (0,5),height = 120, width = 240)
    WM_logo = Image.open('my_image.png')
    WM_logo = WM_logo.transpose(Image.FLIP_TOP_BOTTOM)
    WM_logo = WM_logo.convert('RGBA')
    WM_logo = np.array(WM_logo)
    WM.image_rgba(image=[WM_logo], x=0,y=0,dw=10, dh=5)
    WM.axis.visible = False
    WM.toolbar.active_drag = None
    WM.toolbar.logo = None
    WM.toolbar_location = None        
    return WM

Ok, i might give this a try. Where/how do you attach the rest of the graph data to that?

You need a layout container, assuming you already created another figure with a plot (fig1)

from bokeh.plotting import figure, output_file, show
from bokeh.layouts import column

output_file("MyReport.html", title = 'My Report')   
output_col = column([html_WM_logo(), fig1])
show(output_col)

Aaah ok, it shows the image but not overlay over the graph image.