Как заменить легенду в интерактивном графике Боке, а не дополнить легенду? - PullRequest
0 голосов
/ 20 января 2019

Я использую выпадающий список в Bokeh, чтобы изменить то, что показывает график. Я также хотел бы, чтобы легенда диаграммы изменилась соответственно. Однако вместо этого условные обозначения дополняются каждый раз, когда пользователь выбирает новое раскрывающееся значение. В конце концов, легенда отображает все значения из всех возможных вариантов раскрывающегося списка одновременно. Как «очистить» старую легенду при каждом новом раскрывающемся списке?

import numpy as np
import pandas as pd
import os

from bokeh.plotting import figure
from bokeh.io import output_file, show, save, curdoc
from bokeh.models import HoverTool, CategoricalColorMapper, BoxSelectTool
from bokeh.models import ColumnDataSource, Select, Range1d
from bokeh.layouts import row, column, gridplot
from bokeh.models.widgets import Panel, Tabs
from bokeh.transform import factor_cmap

team = ['Bears', 'Bears', 'Bears', 'Bears', 'Bears']
player = ['Charles Leno', 'James Daniels', 'Cody Whitehair', 'Kyle Long', 'Bobby Massie']
position = ['LT', 'LG', 'C', 'RG', 'RT']
year_acquired = [2014, 2018, 2016, 2013, 2016]
round_drafted = [7, 2, 2, 1, np.NaN]
star=[False, False, False, True, False]

position_loc_x = [-4, -2, 0, 2, 4]
position_loc_y = [0, 0, 0, 0, 0]

year_acquired_color = ['green', 'yellow', 'blue', 'purple', 'blue']
round_drafted_color = ['grey', 'green', 'green', 'purple', np.NaN]
star_color = ['black', 'black', 'black', 'red', 'black']

df = pd.DataFrame({'team':team, 'player':player, 'position':position, 'year_acquired':year_acquired, 
                   'round_drafted':round_drafted, 'star':star, 'position_loc_x':position_loc_x, 
                   'position_loc_y':position_loc_y, 'year_acquired_color':year_acquired_color, 
                   'round_drafted_color':round_drafted_color, 'star_color':star_color})

p = figure(x_range=[-5,5], y_range=[-5, 5])

source = ColumnDataSource(data=df)

p.rect(source=source, x='position_loc_x', y=0, width=1, height=1, line_width=5, line_color=None,
       fill_color='round_drafted_color', legend='round_drafted')

hover = HoverTool(tooltips=[('Name', '@player'), ('Round', '@round_drafted'), ('Year', '@year_acquired')])
p.add_tools(hover)

def update():
    p.rect(source=source, x='position_loc_x', y=0, width=1, height=1, line_width=5, line_color=None, 
           fill_color=select.value, legend=select.value.rpartition('_')[0])

select = Select(title='choose an attribute', options=['round_drafted_color', 'year_acquired_color', 'star_color'], 
               value = 'round_drafted_color')

select.on_change('value', lambda attr, old, new: update())

p.legend.click_policy="hide"

layout = column(select, p)
curdoc().add_root(layout)

1 Ответ

0 голосов
/ 21 января 2019

Вместо того, чтобы снова рисовать прямоугольник с новым именем цвета / легенды, вы должны обновить ColumnDataSource, используемый для построения прямоугольников. Вы можете сделать это, отредактировав словарь source.data.

#!/usr/bin/python3
import numpy as np
import pandas as pd
import os

from bokeh.plotting import figure
from bokeh.io import output_file, show, save, curdoc
from bokeh.models import HoverTool, CategoricalColorMapper, BoxSelectTool
from bokeh.models import ColumnDataSource, Select, Range1d
from bokeh.layouts import row, column, gridplot
from bokeh.models.widgets import Panel, Tabs
from bokeh.transform import factor_cmap

team = ['Bears', 'Bears', 'Bears', 'Bears', 'Bears']
player = ['Charles Leno', 'James Daniels', 'Cody Whitehair', 'Kyle Long', 'Bobby Massie']
position = ['LT', 'LG', 'C', 'RG', 'RT']
year_acquired = [2014, 2018, 2016, 2013, 2016]
round_drafted = [7, 2, 2, 1, np.NaN]
star=[False, False, False, True, False]

position_loc_x = [-4, -2, 0, 2, 4]
position_loc_y = [0, 0, 0, 0, 0]

year_acquired_color = ['green', 'yellow', 'blue', 'purple', 'blue']
round_drafted_color = ['grey', 'green', 'green', 'purple', np.NaN]
star_color = ['black', 'black', 'black', 'red', 'black']

df = pd.DataFrame({'team':team, 'player':player, 'position':position, 'year_acquired':year_acquired, 
                   'round_drafted':round_drafted, 'star':star, 'position_loc_x':position_loc_x, 
                   'position_loc_y':position_loc_y, 'year_acquired_color':year_acquired_color, 
                   'round_drafted_color':round_drafted_color, 'star_color':star_color, 'legend':round_drafted, 'color':round_drafted_color})

p = figure(x_range=[-5,5], y_range=[-5, 5])

source = ColumnDataSource(data=df)

glyph = p.rect(source=source, x='position_loc_x', y=0, width=1, height=1, line_width=5, line_color=None,
       fill_color='color', legend='legend')

hover = HoverTool(tooltips=[('Name', '@player'), ('Round', '@round_drafted'), ('Year', '@year_acquired')])
p.add_tools(hover)

def update():
    #Use select.value to get the right key from the dictionary and set its list as color/legend item
    source.data['color'] = source.data[select.value]
    source.data['legend'] = source.data[select.value.replace('_color', '')]


select = Select(title='choose an attribute', options=['round_drafted_color', 'year_acquired_color', 'star_color'], 
               value = 'round_drafted_color')

select.on_change('value', lambda attr, old, new: update())

p.legend.click_policy="hide"

layout = column(select, p)
curdoc().add_root(layout)
...