Glyphs with nonexistent column names (non-continuous ranges!)

I think the crux of the problem is exactly how Bokeh translated your solution into a ColumnDataSource object behind the scenes - which must be happening, correct?.

Bingo. The high level api, plotting things by going:

p.line(x=somearray,y=somearray)

etc. is actually doing several things all at once for you, including manufacturing a “behind the scenes” CDS for you as you correctly surmised. You actually do have access to that manufactured CDS though, because that higher level api call actually returns the renderer object too (and adds it to the figure obviously). Try:

renderer = p.line(x=[0,1],y=[0,1])
print(dir(renderer))

You’ll that renderer object has a boatload of properties/methods, including datasource. If you drop “renderer.data_source” into the console, you’ll see the CDS that bokeh made for you. “renderer.data_source.data” will return the CDS in dictionary form. Us “creating them beforehand” gives you way more creative control for customization etc though, as you can a) assign more than just the main args (i.e. more than just x+y) and b) in creating a variable pointing to the CDS, it suddenly gets a lot easier to pass into/manipulate via callbacks, especially CustomJS ones.

What I like to do is organize all my stuff into dictionaries. This helps me structure what I’m doing better and makes for real ease of use passing back and forth into callbacks.

Something like this:

bk_dict = {}
for i,k in enumerate(data.keys()):
    bk_dict[k] = {}
    bk_dict[k]['src'] = ColumnDataSource(data= {'x':data[k],'y' : [i+0.5 for x in range(len(data[k]))]})
    bk_dict[k]['rend'] = f.line(x='x',y='y'
                                ,legend_label=k,line_color=colors[i]
                                ,source=bk_dict[k]['src']) #now pointing to that source
show(f)

Idea of this is that bk_dict will look like this:

{'a':{'src':ColumnDataSource(...) #the CDS driving 'a' 
       ,'renderer': LineRenderer(...) #the renderer for 'a'
,'b':{... etc.}

With this, I can pass stuff into CustomJS as args, and even on the python side it helps because it becomes a lot easier to access the things you want to access/manipulate. Now what I outlined above is a bit redundant as

bk_dict['a']['rend'].data_source 

would return the exact same cds object as

bk_dict['a']['src']

but I have found that I’m manipulating CDS’s so much, and often times I have multiple renderers running off the same CDS (see docs about linking data, it’s amazing), that it pays to be redundant :smiley:

2 Likes