Hide items from the legend when visible set to False from callback

Hi all,

I am working with bokeh from a pandas dataframe (code below). I have a working example of adding a CheckBox group that controls the hiding/showing of series in my plot. THis works just fine. The only problem is with the legend. This part of the sample doesn’t work as I get the following error: AttributeError(“unexpected attribute ‘legend’ to GlyphRenderer, possible attributes are data_source, glyph, hover_glyph, level, name, nonselection_glyph, selection_glyph, tags, visible, x_range_name or y_range_name”,)

Clearly the GlyphRenderer doesn’t have the attribute “legend” anymore after instantiating it. But is there another way to remove the series from the legend when it’s visible property is set to False?

Cheers,

Dolf.

import pandas as pd
from bokeh.layouts import row
from bokeh.plotting import figure, curdoc
from bokeh.models import CheckboxGroup

input_table = pd.read_pickle(‘data.pickle’)

p = figure(title=“Event Troubleshooting”, x_axis_type=“datetime”)
labels =
active =
series =
for col in input_table.keys():
if col == ‘timestamp’ or col == ‘timestamp_string’:
continue
result = input_table[pd.notnull(input_table[col])][[‘timestamp’, col]]
labels.append(col)
if col.startswith(‘evt_’):
ser = p.diamond(result[‘timestamp’], result[col], legend=col,
visible=True)
active.append(len(labels)-1)
else:
ser = p.line(result[‘timestamp’], result[col], legend=col,
visible=False)
series.append(ser)

cb = CheckboxGroup(labels=labels, active=active)

def update(attr, old, new):
print(‘updating’)
for i, s in enumerate(series):
print((i, s))
if i in cb.active:
s.visible = True
s.legend = labels[i]
else:
s.visible = False
s.legend = False

cb.on_change(‘active’, update)

layout = row(cb, p)
curdoc().add_root(layout)

``

Hi Dolf,

[First let me note that this answer refers to Bokeh version 0.12.2, see below for comments about some upcoming changes]

Yes, the "legend" keyword arg to glyph methods is just that, a keyword argument. It is a convenience for setting up the plot's Legend model, not an actual property on glyph renderer, as you note. But you can always get ahold of the actual Legend object, and update its .legends fields explicitly:

    In [1]: from bokeh.plotting import figure
       ...: p = figure()
       ...: p.circle([1,2], [3,4], legend="foo")
       ...: p.line([1,2], [3,4], legend="foo")
       ...: p.circle([5,6], [7,8], legend="bar")
       ...: p.legend
       ...:
    Out[1]: [<bokeh.models.annotations.Legend at 0x10d7db4e0>]

    In [2]: p.legend[0].legends
    Out[2]:
    [('foo',
      [<bokeh.models.renderers.GlyphRenderer at 0x104addcf8>,
       <bokeh.models.renderers.GlyphRenderer at 0x10d7db5c0>]),
     ('bar', [<bokeh.models.renderers.GlyphRenderer at 0x10d7db6a0>])]

The .legends property is a mapping of string legend entries, to a list of glyph renderers that should get drawn for that entry. You can add or subtract to that list whatever you like.

UNFORTUNATELY, there is no "plumbing" that causes a legend to re-draw when .legends is changed. This was just an oversight from the past. So you will have to resort to faking some other update to force a re-draw. As an example, add a bogus invisible glyph, and change some property on it, that should force a redraw. This sucks, but it's the best option I can offer immediately.

ALSO NOTE, there is currently some work going on to make some fairly dramatic improvements to legends. Unfortunately they will involve deprecating some of the current way things are done. So anything you do today might require some small adjustments in the near future. I know this also sucks, but the highest goal for a 1.0 release is complete python and JS API stability. But implicit in that is that any breaking changes needed for the long term maintainability of the library have to happen before 1.0, and we are in the process of working through those lingering things that need fixing now.

Thanks,

Bryan

···

On Oct 1, 2016, at 2:51 AM, [email protected] wrote:

Hi all,

I am working with bokeh from a pandas dataframe (code below). I have a working example of adding a CheckBox group that controls the hiding/showing of series in my plot. THis works just fine. The only problem is with the legend. This part of the sample doesn't work as I get the following error: AttributeError("unexpected attribute 'legend' to GlyphRenderer, possible attributes are data_source, glyph, hover_glyph, level, name, nonselection_glyph, selection_glyph, tags, visible, x_range_name or y_range_name",)

Clearly the GlyphRenderer doesn't have the attribute "legend" anymore after instantiating it. But is there another way to remove the series from the legend when it's visible property is set to False?

Cheers,

Dolf.

import pandas as pd
from bokeh.layouts import row
from bokeh.plotting import figure, curdoc
from bokeh.models import CheckboxGroup

input_table = pd.read_pickle('data.pickle')

p = figure(title="Event Troubleshooting", x_axis_type="datetime")
labels =
active =
series =
for col in input_table.keys():
    if col == 'timestamp' or col == 'timestamp_string':
        continue
    result = input_table[pd.notnull(input_table[col])][['timestamp', col]]
    labels.append(col)
    if col.startswith('evt_'):
        ser = p.diamond(result['timestamp'], result[col], legend=col,
                        visible=True)
        active.append(len(labels)-1)
    else:
        ser = p.line(result['timestamp'], result[col], legend=col,
                     visible=False)
    series.append(ser)

cb = CheckboxGroup(labels=labels, active=active)

def update(attr, old, new):
    print('updating')
    for i, s in enumerate(series):
        print((i, s))
        if i in cb.active:
            s.visible = True
            s.legend = labels[i]
        else:
            s.visible = False
            s.legend = False

cb.on_change('active', update)

layout = row(cb, p)
curdoc().add_root(layout)

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/a0b6cc52-d301-4e9a-9075-33c3ce49a410%40continuum.io\.
For more options, visit https://groups.google.com/a/continuum.io/d/optout\.