Manual multi-column legends

I’m plotting a bokeh figure with ~250 different time-series, and I’d like the legend to have multiple columns to avoid the legend extending off the figure, cutting off the majority of entries. There isn’t an automatic feature for multi-column legends in bokeh, but I’ve been told it can be done manually by specifying multiple Legend objects.

I’ve found this SO post which does what I need, but in my case all the lines are already plotted on the figure using hvPlot . Is there a bokeh Figure attribute that returns a list of lines and their handles, so that I can manually loop through them to create multiple legends from the existing lines?

Hi @tom-andersson

See if the renderers property suits your requirements.

Depending on your code organization it might make sense to capture the lines at creation time. This can be especially useful if you have other renderers that you want to selectively exclude from the processing.

There’s also a name property which can help uniquely identify individual glyphs…

In [256]: p = figure(width=500, height=300)

In [257]: R = []

In [258]: for i in range(10):
     ...:     r = p.line(x=[0.0,1.0], y=[0.0,0.1*i], name='line_{:d}'.format(i))
     ...:     R += [r]
     ...:     

In [259]: p.renderers
Out[259]: 
[GlyphRenderer(id='2941', ...),
 GlyphRenderer(id='2946', ...),
 GlyphRenderer(id='2951', ...),
 GlyphRenderer(id='2956', ...),
 GlyphRenderer(id='2961', ...),
 GlyphRenderer(id='2966', ...),
 GlyphRenderer(id='2971', ...),
 GlyphRenderer(id='2976', ...),
 GlyphRenderer(id='2981', ...),
 GlyphRenderer(id='2986', ...)]

In [260]: p.renderers is R
Out[260]: False

In [261]: p.renderers == R
Out[261]: True

In [262]: 

Another possibility is to configure the glyphs with arbitrary name values (you can specify whatever names you want) and then you can query for thing that match that name:

In [8]: p = figure()

In [9]: p.circle()
Out[9]: GlyphRenderer(id='1036', ...)

In [10]: p.circle(name="foo")
Out[10]: GlyphRenderer(id='1041', ...)

In [11]: p.select(name="foo")
Out[11]: [GlyphRenderer(id='1041', ...)]

FYI you can also query by type or other criteria.

There is also a similar select on the BokehJS side (it’s not clear if you mean to get the the renderers in Python or JS code).

If for some reason setting name is not convenient (e.g. if you are already relying @name in hover tooltips) then on the Python side there is an even more general querying facility in bokeh.core.query (it gets very little attention, but has been around and maintained forever)