☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Stream data to a hexbin plot using a ColumnDataSource

Community Supportbokeh
JackFrench2001
JackFrench2001

Hi, I am trying to plot a hexbin plot, which would act as a heatmap, and want to update it every few seconds with new data. Right now I have this, serving as an MRE:

import numpy as np
from bokeh.models import HoverTool, ColumnDataSource
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource

n = 500
x = np.random.normal(size = n)
y = np.random.normal(size = n)

source = ColumnDataSource(dict(x = x, y = y))

p = figure(title="Hexbin for 500 points", match_aspect=True,
           tools="wheel_zoom,reset,pan", background_fill_color='#440154')
p.grid.visible = False

r, _ = p.hexbin(x, y, size=0.1, hover_color="pink", hover_alpha=0.8)

p.add_tools(HoverTool(
    tooltips=[("count", "@c"), ("(q,r)", "(@q, @r)")],
    mode="mouse", point_policy="follow_mouse", renderers=[r],
))

def update():
    global x, y, p, r
    p.renderers.remove(r)
    x = np.random.normal(size = n)
    y = np.random.normal(size = n)
    r, _ = p.hexbin(x, y, size=0.1, hover_color="pink", hover_alpha=0.8)

curdoc().add_periodic_callback(update, 1000)
curdoc().add_root(p)

This does the well for this sized data, however, for my data, the “blinking” which happens everytime the update function is called through the periodic callback is undesirable. Furthermore, it also plots the hexbins over any existing glyphs that are already on my plot which is also undesirable. As such, I was wondering if there was any way to stream data to a ColumnDataSource, as one would do with a scatter plot, and have that act as my stream instead. The code below shows what I would like to be able to do:

import numpy as np
from bokeh.models import HoverTool, ColumnDataSource
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource

n = 500
x = np.random.normal(size = n)
y = np.random.normal(size = n)

source = ColumnDataSource(dict(x = [], y = []))

p = figure(title="Hexbin for 500 points", match_aspect=True,
           tools="wheel_zoom,reset,pan", background_fill_color='#440154')
p.grid.visible = False

r, _ = p.hexbin("x", "y", size=0.1, hover_color="pink", hover_alpha=0.8, source = source)

p.add_tools(HoverTool(
    tooltips=[("count", "@c"), ("(q,r)", "(@q, @r)")],
    mode="mouse", point_policy="follow_mouse", renderers=[r],
))

def update():
    global x, y, p, r
    p.renderers.remove(r)
    x = np.random.normal(size = n)
    y = np.random.normal(size = n)
    source.stream(dict(x=x, y=y))

curdoc().add_periodic_callback(update, 1000)
curdoc().add_root(p)

I do realize that this may be a futile question as the docs indicate that the hexbin function does not take a ColumnDataSource as an argument but I was wondering if anyone had any ideas on a workaround for this?

Thanks

⌁   Link to post
Bryan
Bryan

figure.hexbin is one of only a handful of methods that actually do some data processing and transformation for you. If you want to update an existing hex plot you are going to need to use the lower level hex_tile glyph that hexbin uses under the covers directly, and to update it, you’ll need to the the helper function bokeh.util.hexbin that does the binning and returns the q and r coordinates that a hex tiling expects.

The very short implemention of figure.hexbin is the best reference. You’ll basically just want to do this yourself, instead of using figure.hexbin, so that you can later update the q and r columns of the hex_tile CDS in place.

⌁   Link to post
JackFrench2001
JackFrench2001

Hi Bryan, thank you so much this was exactly what I was looking for but could not find it in the docs.

Thanks

Jack

⌁   Link to post

End of archived discussion · Replies are disabled