Defining axis values for bokeh image glyphs?

I am hoping that someone might help me understand how the axes’ tick values are defined when using an image glyph. All of the examples in the gallery show the x and y axes ranging from 0 -> 10, and I have been hard-pressed to get them to show anything else.

As in my other recent post, I am working on various ways to create audio spectrograms. So if using an image, the idea would be that the color of each pixel represents a value at a particular timestamp and frequency. However for the life of me, I can’t seem to define the figure and/or figure.image() x/y properties to create axes which reflect this.

In my use case, I would eventually like to have x labels in some sort of datetime format, and y labels in Hz. However, to define a simpler problem, taking the image example from the gallery what would need to be modified to get the axes for the same image (as well as the x,y coordinates of the pixels when using tooltips) to read -5 -> 5. Or 2->17, or anything else?

Here’s some things I have tried so far, including changing x,y anchors in figure.image, x/y_range props etc. I hope the solution here ends up being as simple as my last question. Many thanks.

import numpy as np

from bokeh.plotting import figure, output_file, show

N = 500

# original example
# x = np.linspace(0, 10, N)  v
# y = np.linspace(0, 10, N)

# modified example
x = np.linspace(-5, 5, N)
y = np.linspace(-5, 5, N)

xx, yy = np.meshgrid(x, y)
d = np.sin(xx)*np.cos(yy)

# breakout the ranges directly
x_range = (min(x), max(x))
y_range = (min(y), max(y))

# original example
# p = figure(tooltips=[("x", "$x"), ("y", "$y"), ("value", "@image")])
# p.x_range.range_padding = p.y_range.range_padding = 0

# modified example
p = figure(tooltips=[("x", "$x"), ("y", "$y"), ("value", "@image")], x_range=x_range, y_range=y_range) # modified
# p.x_range.range_padding = p.y_range.range_padding = 0

# must give a vector of image data for image parameter
# original example
# p.image(image=[d], x=0, y=0, dw=10, dh=10, palette="Spectral11", level="image")
# modified example
p.image(image=[d], x=int(x_range[0]), y=int(y_range[0]), dw=10, dh=10, palette="Spectral11", level="image")
p.grid.grid_line_width = 0.5


output_file("image.html", title="image_axis.py example")

show(p)

The image function has x, y, dw, and dh arguments. These specify the image position on the plot in data units. So, if you pass x=0, y=0, dw=10, dh=10, then the image will span the (0, 0), (10, 10) square. If you pass x=-5, y=2, dw=10, dh=15, then it will span the (-5, 2), (5, 17) rectangle.

Regarding datetime - internally, Bokeh uses UNIX timestamp, so just specify the arguments accordingly.
Regarding other formats - that’s what axis tick label formatters are for.

@p-himik, thanks, much appreciated. That’s what I had thought I had done, and was the case in my example code. However with your answer, I have now isolated my actual problem.

I had commented out show(), and reloaded the html file in the browser assuming that output_file() updated the html, and show() merely opened a new browser tab. I now realize that show() also contains the saving of the html file, and that the html file was simply not updating. I have now found the save() command, which doesn’t feature much in the user guide. But save() does seem to update the html file, without opening a new browser tab. Thanks for your help.

Some day, I’ll actually ask you guys a hard question :wink:

1 Like