How to replace the legend in interactive Bokeh graph, rather than augment the legend?












0















I am using a selection dropdown in Bokeh to change what the chart shows. I'd also like the chart's legend to change accordingly. However, what happens instead is the legend becomes augmented every time the user selects a new dropdown value. Eventually, the legend displays every value from every possible dropdown option simultaneously. How do I "clear" the old legend on every new dropdown select?



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)









share|improve this question



























    0















    I am using a selection dropdown in Bokeh to change what the chart shows. I'd also like the chart's legend to change accordingly. However, what happens instead is the legend becomes augmented every time the user selects a new dropdown value. Eventually, the legend displays every value from every possible dropdown option simultaneously. How do I "clear" the old legend on every new dropdown select?



    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)









    share|improve this question

























      0












      0








      0








      I am using a selection dropdown in Bokeh to change what the chart shows. I'd also like the chart's legend to change accordingly. However, what happens instead is the legend becomes augmented every time the user selects a new dropdown value. Eventually, the legend displays every value from every possible dropdown option simultaneously. How do I "clear" the old legend on every new dropdown select?



      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)









      share|improve this question














      I am using a selection dropdown in Bokeh to change what the chart shows. I'd also like the chart's legend to change accordingly. However, what happens instead is the legend becomes augmented every time the user selects a new dropdown value. Eventually, the legend displays every value from every possible dropdown option simultaneously. How do I "clear" the old legend on every new dropdown select?



      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)






      python bokeh






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 20 at 3:45









      gnotnekgnotnek

      637




      637
























          1 Answer
          1






          active

          oldest

          votes


















          1














          Instead of plotting the rectangle again with a new color/legendname, you should update the ColumnDataSource used to plot the rectangles. You can do this by editing the source.data dictionary.



          #!/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)





          share|improve this answer
























          • Thank you, that works! But there is another remaining problem that I thought would be fixed: clicking on a legend element to hide it instead hides the entire legend. Any suggestions? I think my brain just doesn't get the basics of how Bokeh works in general, and there doesn't appear to be much good documentation out there. The official docs provide only the most simplistic examples, and once I need to use a combo of 2+ Bokeh features at once, I'm lost.

            – gnotnek
            Jan 21 at 19:15













          • bokeh.pydata.org/en/latest/docs/user_guide/interaction/… ~ "Interactive legend features currently work on “per-glyph” legends. Legends that are created by specifying a column to automatically group do no yet work with the features described below". It is possible to work around this problem by using some CustomJS and checkboxes as explained in this question: stackoverflow.com/questions/45380781/…

            – Jasper
            Jan 22 at 7:49











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54273406%2fhow-to-replace-the-legend-in-interactive-bokeh-graph-rather-than-augment-the-le%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          Instead of plotting the rectangle again with a new color/legendname, you should update the ColumnDataSource used to plot the rectangles. You can do this by editing the source.data dictionary.



          #!/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)





          share|improve this answer
























          • Thank you, that works! But there is another remaining problem that I thought would be fixed: clicking on a legend element to hide it instead hides the entire legend. Any suggestions? I think my brain just doesn't get the basics of how Bokeh works in general, and there doesn't appear to be much good documentation out there. The official docs provide only the most simplistic examples, and once I need to use a combo of 2+ Bokeh features at once, I'm lost.

            – gnotnek
            Jan 21 at 19:15













          • bokeh.pydata.org/en/latest/docs/user_guide/interaction/… ~ "Interactive legend features currently work on “per-glyph” legends. Legends that are created by specifying a column to automatically group do no yet work with the features described below". It is possible to work around this problem by using some CustomJS and checkboxes as explained in this question: stackoverflow.com/questions/45380781/…

            – Jasper
            Jan 22 at 7:49
















          1














          Instead of plotting the rectangle again with a new color/legendname, you should update the ColumnDataSource used to plot the rectangles. You can do this by editing the source.data dictionary.



          #!/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)





          share|improve this answer
























          • Thank you, that works! But there is another remaining problem that I thought would be fixed: clicking on a legend element to hide it instead hides the entire legend. Any suggestions? I think my brain just doesn't get the basics of how Bokeh works in general, and there doesn't appear to be much good documentation out there. The official docs provide only the most simplistic examples, and once I need to use a combo of 2+ Bokeh features at once, I'm lost.

            – gnotnek
            Jan 21 at 19:15













          • bokeh.pydata.org/en/latest/docs/user_guide/interaction/… ~ "Interactive legend features currently work on “per-glyph” legends. Legends that are created by specifying a column to automatically group do no yet work with the features described below". It is possible to work around this problem by using some CustomJS and checkboxes as explained in this question: stackoverflow.com/questions/45380781/…

            – Jasper
            Jan 22 at 7:49














          1












          1








          1







          Instead of plotting the rectangle again with a new color/legendname, you should update the ColumnDataSource used to plot the rectangles. You can do this by editing the source.data dictionary.



          #!/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)





          share|improve this answer













          Instead of plotting the rectangle again with a new color/legendname, you should update the ColumnDataSource used to plot the rectangles. You can do this by editing the source.data dictionary.



          #!/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)






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 21 at 10:21









          JasperJasper

          43417




          43417













          • Thank you, that works! But there is another remaining problem that I thought would be fixed: clicking on a legend element to hide it instead hides the entire legend. Any suggestions? I think my brain just doesn't get the basics of how Bokeh works in general, and there doesn't appear to be much good documentation out there. The official docs provide only the most simplistic examples, and once I need to use a combo of 2+ Bokeh features at once, I'm lost.

            – gnotnek
            Jan 21 at 19:15













          • bokeh.pydata.org/en/latest/docs/user_guide/interaction/… ~ "Interactive legend features currently work on “per-glyph” legends. Legends that are created by specifying a column to automatically group do no yet work with the features described below". It is possible to work around this problem by using some CustomJS and checkboxes as explained in this question: stackoverflow.com/questions/45380781/…

            – Jasper
            Jan 22 at 7:49



















          • Thank you, that works! But there is another remaining problem that I thought would be fixed: clicking on a legend element to hide it instead hides the entire legend. Any suggestions? I think my brain just doesn't get the basics of how Bokeh works in general, and there doesn't appear to be much good documentation out there. The official docs provide only the most simplistic examples, and once I need to use a combo of 2+ Bokeh features at once, I'm lost.

            – gnotnek
            Jan 21 at 19:15













          • bokeh.pydata.org/en/latest/docs/user_guide/interaction/… ~ "Interactive legend features currently work on “per-glyph” legends. Legends that are created by specifying a column to automatically group do no yet work with the features described below". It is possible to work around this problem by using some CustomJS and checkboxes as explained in this question: stackoverflow.com/questions/45380781/…

            – Jasper
            Jan 22 at 7:49

















          Thank you, that works! But there is another remaining problem that I thought would be fixed: clicking on a legend element to hide it instead hides the entire legend. Any suggestions? I think my brain just doesn't get the basics of how Bokeh works in general, and there doesn't appear to be much good documentation out there. The official docs provide only the most simplistic examples, and once I need to use a combo of 2+ Bokeh features at once, I'm lost.

          – gnotnek
          Jan 21 at 19:15







          Thank you, that works! But there is another remaining problem that I thought would be fixed: clicking on a legend element to hide it instead hides the entire legend. Any suggestions? I think my brain just doesn't get the basics of how Bokeh works in general, and there doesn't appear to be much good documentation out there. The official docs provide only the most simplistic examples, and once I need to use a combo of 2+ Bokeh features at once, I'm lost.

          – gnotnek
          Jan 21 at 19:15















          bokeh.pydata.org/en/latest/docs/user_guide/interaction/… ~ "Interactive legend features currently work on “per-glyph” legends. Legends that are created by specifying a column to automatically group do no yet work with the features described below". It is possible to work around this problem by using some CustomJS and checkboxes as explained in this question: stackoverflow.com/questions/45380781/…

          – Jasper
          Jan 22 at 7:49





          bokeh.pydata.org/en/latest/docs/user_guide/interaction/… ~ "Interactive legend features currently work on “per-glyph” legends. Legends that are created by specifying a column to automatically group do no yet work with the features described below". It is possible to work around this problem by using some CustomJS and checkboxes as explained in this question: stackoverflow.com/questions/45380781/…

          – Jasper
          Jan 22 at 7:49


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54273406%2fhow-to-replace-the-legend-in-interactive-bokeh-graph-rather-than-augment-the-le%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Liquibase includeAll doesn't find base path

          How to use setInterval in EJS file?

          Petrus Granier-Deferre