20

For example you can plot an image in matplotlib using this code:

%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img=mpimg.imread('image.png')
plt.imshow(img)

Is something like this possible with Bokeh(0.10)?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Trevor McCormick
  • 366
  • 1
  • 3
  • 12
  • 1
    Not directly like this. Bokeh has `Image` (scalar data, to color map), `ImageRGBA` (raw RGBA data) and `ImageURL` (images loaded over the network). This would make a good feature request on the GitHub issue tracker. – bigreddot Jan 07 '16 at 03:26

5 Answers5

27

You can use the ImageURL glyph (image_url plot method)to load images locally or from the web.

from bokeh.plotting import figure, show, output_file

output_file('image.html')

p = figure(x_range=(0,1), y_range=(0,1))
p.image_url(url=['tree.png'], x=0, y=1, w=0.8, h=0.6)
## could also leave out keywords
# p.image_url(['tree.png'], 0, 1, 0.8, h=0.6)  
show(p)

Image Example

One gotcha - if you graph only an image (and no other data), you'll have to explicitly set the plot ranges.

Here's the docs:

http://docs.bokeh.org/en/latest/docs/reference/models/glyphs.html#bokeh.models.glyphs.ImageURL

Steven C. Howell
  • 16,902
  • 15
  • 72
  • 97
Luke Canavan
  • 2,107
  • 12
  • 13
  • 5
    This example code no longer works on 0.12.5, I tried to edit the example code but it was rejected twice, you need to use the following call to image_url: `p.image_url(url=['tree.png'], x=0, y=0, w=1, h=1, anchor="bottom_left")` – johnf Apr 24 '17 at 13:35
  • 3
    the example does not work when using the bokeh server. It is not able to find the image (404) – Cutú Chiqueño Nov 02 '17 at 09:01
  • Is there a way to ensure the image is rendered 1:1 (Actual size, pixel for pixel, etc...)? – Royi Aug 23 '22 at 11:23
10

The earlier answer was helpful. However, I wanted an image only option without any additional object. So, adding the answer for Bokeh version 0.12.0 and removed all the grids, axes and toolbar.

from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Range1d

bosch_logo = "static/tree.jpg"
logo_src = ColumnDataSource(dict(url = [bosch_logo]))

page_logo = figure(plot_width = 500, plot_height = 500, title="")
page_logo.toolbar.logo = None
page_logo.toolbar_location = None
page_logo.x_range=Range1d(start=0, end=1)
page_logo.y_range=Range1d(start=0, end=1)
page_logo.xaxis.visible = None
page_logo.yaxis.visible = None
page_logo.xgrid.grid_line_color = None
page_logo.ygrid.grid_line_color = None
page_logo.image_url(url='url', x=0.05, y = 0.85, h=0.7, w=0.9, source=logo_src)
page_logo.outline_line_alpha = 0 
curdoc().add_root(page_logo)
Jayant
  • 346
  • 3
  • 14
  • 2
    ``figure`` is a convenience function that returns a ``bokeh.models.Plot`` instance with all of the axis/grids/tools set on it. Alternatively, you could instantiate a bare ``Plot`` object and add the image to that (avoided all of the subtraction stuff) – Luke Canavan Sep 16 '16 at 22:24
  • 1
    @Luke thanks for the comment, would it be possible for you to share a working code. – Jayant Sep 16 '16 at 23:23
6

Another option is to display the image in a div.:

from bokeh.io import output_notebook, show
from bokeh.models.widgets import Div

output_notebook()
div_image = Div(text="""<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png" alt="div_image">""", width=150, height=150)
show(div_image)

Squirtle sprite

ImageURL can't get updated dynamically with a callback. However, using a div, you can do so by treating the div_image.text as a regular Python string, for example:

from ipywidgets import interact

from bokeh.io import output_notebook, show, push_notebook
from bokeh.models.widgets import Div

output_notebook()
div_image = Div(text="""<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png" alt="div_image">""", width=100, height=100)

def update(pokemon_number=1):
    div_image.text = """<img src="https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png" alt="div_image">""".format(pokemon_number)
    push_notebook()

show(div_image, notebook_handle=True)

interact(update, pokemon_number=[1, 4, 7])

Pokemon selector

Of course, the image source can also point to a local file.

(Tested in Python 3.7.3 and bokeh 1.2.0)

Arturo Moncada-Torres
  • 1,236
  • 14
  • 23
  • I am trying to follow this answer with a local image, but Bokeh always displays the alt text. Where am I going wrong? ```"""i_broken"""``` – Finncent Price Oct 29 '21 at 21:44
5

Running this example using bokeh serve is a bit more tricky. I suggest to setup working directory properly:

server_folder/
     +main.py
     +static/
         +logo.png

.. and run bokeh serve command from directory ABOVE server_folder

bokeh serve server_folder --show

Then this code works for me

#main.py file
from bokeh.plotting import figure, curdoc
x_range = (-20,-10) # could be anything - e.g.(0,1)
y_range = (20,30)
p = figure(x_range=x_range, y_range=y_range)
#img_path = 'https://docs.bokeh.org/en/latest/_static/images/logo.png'
img_path = 'server_folder/static/logo.png'
p.image_url(url=[img_path],x=x_range[0],y=y_range[1],w=x_range[1]-x_range[0],h=y_range[1]-y_range[0])
doc = curdoc()
doc.add_root(p)

enter image description here

bigreddot
  • 33,642
  • 5
  • 69
  • 122
Karel Marik
  • 811
  • 8
  • 13
0

Here is a simple example that works, almost the same simple format as you requested:

from PIL import Image
import numpy as np 
from bokeh.plotting import figure, output_notebook, show
output_notebook()

#load image
im = Image.open('Segment_image.png') # just replace any image that you want here


p = figure()
imarray = np.array(im.convert("RGBA"))

plotted_image = p.image_rgba(image=[imarray.view("uint32").reshape(imarray.shape[:2])], x=0, y=0, dw=imarray.shape[0], dh=imarray.shape[1])
show(p)
Oren
  • 4,711
  • 4
  • 37
  • 63