Auto-scaling colormap?

With streaming data, I notice that the x and y axes of various visualizations automatically scale and offset themselves to keep all new data visible in the window. Could there be a similar thing with a linear_cmap and the like?

Currently, the linear_cmap requires specifying a low and high parameter in the constructor. This forces the user to choose the range at construction time, but it is often very useful to have a ‘data value agnostic’ construction (where only the shapes of the data is known, but not the values).

Instead, the behavior I would like is for these ranges to be computed sensibly from the range of values in in the ColumnDataSource column of field_name.

Does something like this exist?

Thanks,

Henry

Something like this? Basically when data gets streamed, re calculate what you want the colormap low and high to be, and update it.

from bokeh.models import CustomJS, ColumnDataSource,Button, ColorBar
from bokeh.plotting import figure,show
from bokeh.transform import linear_cmap
from bokeh.palettes import Turbo256
from bokeh.layouts import column
import numpy as np

src = ColumnDataSource(data={'x':np.random.random(10)*10,'y':np.random.random(10)*10,'z':np.random.random(10)*10})

cmap = linear_cmap(field_name='z',low=0,high=10,palette=Turbo256)

f = figure()

r = f.scatter(x='x',y='y',size=12,fill_color=cmap,source=src)

cbar = ColorBar(color_mapper=cmap.transform)
f.add_layout(cbar,'right')

btn = Button(label='Stream Bigger Stuff')

cb = CustomJS(args=dict(src=src,cmap=cmap.transform)
              ,code='''
              //some new data that'll always be bigger than current max z
              var newdata = {'x':[Math.random()*10],'y':[Math.random()*10]
                             ,'z':[Math.max(...src.data['z'])+Math.random()*10]}
              
              src.stream(newdata)
              //get the new max/min, and floor/ceil them
              var minz = Math.floor(Math.min(...src.data['z']))
              var maxz = Math.ceil(Math.max(...src.data['z']))
              //update the low and high property of the mapper to those values
              cmap.low=minz
              cmap.high=maxz
              src.change.emit()
              
              ''')
btn.js_on_click(cb)
show(column([f,btn]))

cmaprange

2 Likes

That looks great! Yeah, you got it, that’s what I was asking for. I’m going to scavenge your code and try to make this example work in a server side context.

1 Like

There’s not a feature for this built-in currently. I think it’s a reasonable ask, but it will probably bump up against some long-standing assumptions of Bokeh’s data model. So it will require some discussion and care to avoid breaking things. I’d suggest opening a GitHub development discussion about it.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.