Using CustomJS to make a dynamic scatter plot with Bokeh- Issue with “nonexistent column name”












1















I thought I found a concrete example that I could leverage here, but the same logic is not working for me, unfortunately.



I have two questions:




  • Is what I'm attempting to do even possible: send a dynamic scatter plot in a html document that allows you to control what is plotted on the x & y axes. I've succeeded with static plots, but haven't cracked dynamic plots yet.


  • Where is my code going wrong (see below?)



Here are the relevant pieces of code (in order. I have a dataframe that I've converted into "source" using ColumnDataSource.



I create an initial plot (note, at this point, there are no columns called 'x' and 'y'. I create those in the callback function later) :



plot.circle('x', 'y',
source=source,
color={'field': 'Picker',
'transform': mapper},
legend='Picker')


I create two dropdown menus (note that the options in each correspond to the columns from "source" I'd want people to be able to choose from)



x_menu=Select(options=['Box Office', 'Difference', 'Price Paid'],
value='Box Office',
title='What do you want to put on the x axis')

y_menu=Select(options=['Metacritic', 'Rotten Tomatoes'],
value='Metacritic',
title='What do you want to put on the y axis')


I create the callback:



callback = CustomJS (args=dict(source=source), code="""
console.log('changed selected option', cb_obj.value)
var data=source.data
data['x']=data[cb_obj.value]
data['y']=data[cb_obj.value]
source.change.emit();
""")


I assign the callbacks to the dropdown menus:



x_menu.callback = callback
y_menu.callback = callback


And then I try to show the plot:



show(row(widgetbox(x_menu, y_menu), plot))


But it returns the below error:



ERROR:bokeh.core.validation.check:E-1001 (BAD_COLUMN_NAME): Glyph refers to nonexistent column name: x, y [renderer: GlyphRenderer(id='df96b108-e2e4-4b8c-b0c6-12df40b4205d', ...)]


Any help is very much appreciated. Thank you!










share|improve this question



























    1















    I thought I found a concrete example that I could leverage here, but the same logic is not working for me, unfortunately.



    I have two questions:




    • Is what I'm attempting to do even possible: send a dynamic scatter plot in a html document that allows you to control what is plotted on the x & y axes. I've succeeded with static plots, but haven't cracked dynamic plots yet.


    • Where is my code going wrong (see below?)



    Here are the relevant pieces of code (in order. I have a dataframe that I've converted into "source" using ColumnDataSource.



    I create an initial plot (note, at this point, there are no columns called 'x' and 'y'. I create those in the callback function later) :



    plot.circle('x', 'y',
    source=source,
    color={'field': 'Picker',
    'transform': mapper},
    legend='Picker')


    I create two dropdown menus (note that the options in each correspond to the columns from "source" I'd want people to be able to choose from)



    x_menu=Select(options=['Box Office', 'Difference', 'Price Paid'],
    value='Box Office',
    title='What do you want to put on the x axis')

    y_menu=Select(options=['Metacritic', 'Rotten Tomatoes'],
    value='Metacritic',
    title='What do you want to put on the y axis')


    I create the callback:



    callback = CustomJS (args=dict(source=source), code="""
    console.log('changed selected option', cb_obj.value)
    var data=source.data
    data['x']=data[cb_obj.value]
    data['y']=data[cb_obj.value]
    source.change.emit();
    """)


    I assign the callbacks to the dropdown menus:



    x_menu.callback = callback
    y_menu.callback = callback


    And then I try to show the plot:



    show(row(widgetbox(x_menu, y_menu), plot))


    But it returns the below error:



    ERROR:bokeh.core.validation.check:E-1001 (BAD_COLUMN_NAME): Glyph refers to nonexistent column name: x, y [renderer: GlyphRenderer(id='df96b108-e2e4-4b8c-b0c6-12df40b4205d', ...)]


    Any help is very much appreciated. Thank you!










    share|improve this question

























      1












      1








      1








      I thought I found a concrete example that I could leverage here, but the same logic is not working for me, unfortunately.



      I have two questions:




      • Is what I'm attempting to do even possible: send a dynamic scatter plot in a html document that allows you to control what is plotted on the x & y axes. I've succeeded with static plots, but haven't cracked dynamic plots yet.


      • Where is my code going wrong (see below?)



      Here are the relevant pieces of code (in order. I have a dataframe that I've converted into "source" using ColumnDataSource.



      I create an initial plot (note, at this point, there are no columns called 'x' and 'y'. I create those in the callback function later) :



      plot.circle('x', 'y',
      source=source,
      color={'field': 'Picker',
      'transform': mapper},
      legend='Picker')


      I create two dropdown menus (note that the options in each correspond to the columns from "source" I'd want people to be able to choose from)



      x_menu=Select(options=['Box Office', 'Difference', 'Price Paid'],
      value='Box Office',
      title='What do you want to put on the x axis')

      y_menu=Select(options=['Metacritic', 'Rotten Tomatoes'],
      value='Metacritic',
      title='What do you want to put on the y axis')


      I create the callback:



      callback = CustomJS (args=dict(source=source), code="""
      console.log('changed selected option', cb_obj.value)
      var data=source.data
      data['x']=data[cb_obj.value]
      data['y']=data[cb_obj.value]
      source.change.emit();
      """)


      I assign the callbacks to the dropdown menus:



      x_menu.callback = callback
      y_menu.callback = callback


      And then I try to show the plot:



      show(row(widgetbox(x_menu, y_menu), plot))


      But it returns the below error:



      ERROR:bokeh.core.validation.check:E-1001 (BAD_COLUMN_NAME): Glyph refers to nonexistent column name: x, y [renderer: GlyphRenderer(id='df96b108-e2e4-4b8c-b0c6-12df40b4205d', ...)]


      Any help is very much appreciated. Thank you!










      share|improve this question














      I thought I found a concrete example that I could leverage here, but the same logic is not working for me, unfortunately.



      I have two questions:




      • Is what I'm attempting to do even possible: send a dynamic scatter plot in a html document that allows you to control what is plotted on the x & y axes. I've succeeded with static plots, but haven't cracked dynamic plots yet.


      • Where is my code going wrong (see below?)



      Here are the relevant pieces of code (in order. I have a dataframe that I've converted into "source" using ColumnDataSource.



      I create an initial plot (note, at this point, there are no columns called 'x' and 'y'. I create those in the callback function later) :



      plot.circle('x', 'y',
      source=source,
      color={'field': 'Picker',
      'transform': mapper},
      legend='Picker')


      I create two dropdown menus (note that the options in each correspond to the columns from "source" I'd want people to be able to choose from)



      x_menu=Select(options=['Box Office', 'Difference', 'Price Paid'],
      value='Box Office',
      title='What do you want to put on the x axis')

      y_menu=Select(options=['Metacritic', 'Rotten Tomatoes'],
      value='Metacritic',
      title='What do you want to put on the y axis')


      I create the callback:



      callback = CustomJS (args=dict(source=source), code="""
      console.log('changed selected option', cb_obj.value)
      var data=source.data
      data['x']=data[cb_obj.value]
      data['y']=data[cb_obj.value]
      source.change.emit();
      """)


      I assign the callbacks to the dropdown menus:



      x_menu.callback = callback
      y_menu.callback = callback


      And then I try to show the plot:



      show(row(widgetbox(x_menu, y_menu), plot))


      But it returns the below error:



      ERROR:bokeh.core.validation.check:E-1001 (BAD_COLUMN_NAME): Glyph refers to nonexistent column name: x, y [renderer: GlyphRenderer(id='df96b108-e2e4-4b8c-b0c6-12df40b4205d', ...)]


      Any help is very much appreciated. Thank you!







      python bokeh






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 13 '18 at 18:51









      E LarsonE Larson

      84




      84
























          1 Answer
          1






          active

          oldest

          votes


















          0














          It would be easier to help if you gave a self-contained minimal example (code that we can just copy, paste and run). With that said, here is something that might help you to get started. You were already very close to this solution, but I guess the important part is to have one callback for each menu.



          I hope this helps :-)



          # -*- coding: utf-8 -*-
          import numpy as np
          import pandas as pd

          from bokeh.layouts import row, widgetbox
          from bokeh.models import CustomJS, Select
          from bokeh.plotting import figure, show, ColumnDataSource

          # Define some random data
          dataframe = pd.DataFrame({
          'Difference': np.sin(np.linspace(0, 100, 500)),
          'Price': np.cos(np.linspace(0, 100, 500)),
          'Metacritic': np.sin(np.linspace(0, 100, 500)),
          'Rotten Tomatoes': np.cos(np.linspace(0, 200, 500)),
          })

          # Set x and y-axis defaults
          dataframe['x'] = dataframe['Difference']
          dataframe['y'] = dataframe['Metacritic']

          # Create Bokeh's ColumnDataSource
          source = ColumnDataSource(data=dataframe)

          # Create the plot figure
          plot = figure(plot_width=400, plot_height=400)
          plot.circle('x', 'y', source=source)

          # Create the dropdown menus
          x_menu = Select(options=['Difference', 'Price'],
          value='Difference',
          title='What do you want to put on the x axis')

          y_menu = Select(options=['Metacritic', 'Rotten Tomatoes'],
          value='Metacritic',
          title='What do you want to put on the y axis')

          # Create two callbacks, one for each menu
          callback_x = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['x']=data[cb_obj.value]
          source.change.emit();
          """)

          callback_y = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['y']=data[cb_obj.value]
          source.change.emit();
          """)

          # Assign callbacks to menu widgets
          x_menu.callback = callback_x
          y_menu.callback = callback_y

          # Show the html document with a layout
          show(row(widgetbox(x_menu, y_menu), plot))





          share|improve this answer
























          • Thanks so much. Good call on adding the random data so that people can just run it. Unfortunately, I'm still having similar issues. I'll send a new snippet of code below to clarify the issue

            – E Larson
            Nov 13 '18 at 22:12













          • Never mind... I glazed right over your "set x and y defaults." That was the issue with the nonexistent columns (on top of adding the two callbacks).

            – E Larson
            Nov 13 '18 at 22:23











          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%2f53287715%2fusing-customjs-to-make-a-dynamic-scatter-plot-with-bokeh-issue-with-nonexisten%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









          0














          It would be easier to help if you gave a self-contained minimal example (code that we can just copy, paste and run). With that said, here is something that might help you to get started. You were already very close to this solution, but I guess the important part is to have one callback for each menu.



          I hope this helps :-)



          # -*- coding: utf-8 -*-
          import numpy as np
          import pandas as pd

          from bokeh.layouts import row, widgetbox
          from bokeh.models import CustomJS, Select
          from bokeh.plotting import figure, show, ColumnDataSource

          # Define some random data
          dataframe = pd.DataFrame({
          'Difference': np.sin(np.linspace(0, 100, 500)),
          'Price': np.cos(np.linspace(0, 100, 500)),
          'Metacritic': np.sin(np.linspace(0, 100, 500)),
          'Rotten Tomatoes': np.cos(np.linspace(0, 200, 500)),
          })

          # Set x and y-axis defaults
          dataframe['x'] = dataframe['Difference']
          dataframe['y'] = dataframe['Metacritic']

          # Create Bokeh's ColumnDataSource
          source = ColumnDataSource(data=dataframe)

          # Create the plot figure
          plot = figure(plot_width=400, plot_height=400)
          plot.circle('x', 'y', source=source)

          # Create the dropdown menus
          x_menu = Select(options=['Difference', 'Price'],
          value='Difference',
          title='What do you want to put on the x axis')

          y_menu = Select(options=['Metacritic', 'Rotten Tomatoes'],
          value='Metacritic',
          title='What do you want to put on the y axis')

          # Create two callbacks, one for each menu
          callback_x = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['x']=data[cb_obj.value]
          source.change.emit();
          """)

          callback_y = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['y']=data[cb_obj.value]
          source.change.emit();
          """)

          # Assign callbacks to menu widgets
          x_menu.callback = callback_x
          y_menu.callback = callback_y

          # Show the html document with a layout
          show(row(widgetbox(x_menu, y_menu), plot))





          share|improve this answer
























          • Thanks so much. Good call on adding the random data so that people can just run it. Unfortunately, I'm still having similar issues. I'll send a new snippet of code below to clarify the issue

            – E Larson
            Nov 13 '18 at 22:12













          • Never mind... I glazed right over your "set x and y defaults." That was the issue with the nonexistent columns (on top of adding the two callbacks).

            – E Larson
            Nov 13 '18 at 22:23
















          0














          It would be easier to help if you gave a self-contained minimal example (code that we can just copy, paste and run). With that said, here is something that might help you to get started. You were already very close to this solution, but I guess the important part is to have one callback for each menu.



          I hope this helps :-)



          # -*- coding: utf-8 -*-
          import numpy as np
          import pandas as pd

          from bokeh.layouts import row, widgetbox
          from bokeh.models import CustomJS, Select
          from bokeh.plotting import figure, show, ColumnDataSource

          # Define some random data
          dataframe = pd.DataFrame({
          'Difference': np.sin(np.linspace(0, 100, 500)),
          'Price': np.cos(np.linspace(0, 100, 500)),
          'Metacritic': np.sin(np.linspace(0, 100, 500)),
          'Rotten Tomatoes': np.cos(np.linspace(0, 200, 500)),
          })

          # Set x and y-axis defaults
          dataframe['x'] = dataframe['Difference']
          dataframe['y'] = dataframe['Metacritic']

          # Create Bokeh's ColumnDataSource
          source = ColumnDataSource(data=dataframe)

          # Create the plot figure
          plot = figure(plot_width=400, plot_height=400)
          plot.circle('x', 'y', source=source)

          # Create the dropdown menus
          x_menu = Select(options=['Difference', 'Price'],
          value='Difference',
          title='What do you want to put on the x axis')

          y_menu = Select(options=['Metacritic', 'Rotten Tomatoes'],
          value='Metacritic',
          title='What do you want to put on the y axis')

          # Create two callbacks, one for each menu
          callback_x = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['x']=data[cb_obj.value]
          source.change.emit();
          """)

          callback_y = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['y']=data[cb_obj.value]
          source.change.emit();
          """)

          # Assign callbacks to menu widgets
          x_menu.callback = callback_x
          y_menu.callback = callback_y

          # Show the html document with a layout
          show(row(widgetbox(x_menu, y_menu), plot))





          share|improve this answer
























          • Thanks so much. Good call on adding the random data so that people can just run it. Unfortunately, I'm still having similar issues. I'll send a new snippet of code below to clarify the issue

            – E Larson
            Nov 13 '18 at 22:12













          • Never mind... I glazed right over your "set x and y defaults." That was the issue with the nonexistent columns (on top of adding the two callbacks).

            – E Larson
            Nov 13 '18 at 22:23














          0












          0








          0







          It would be easier to help if you gave a self-contained minimal example (code that we can just copy, paste and run). With that said, here is something that might help you to get started. You were already very close to this solution, but I guess the important part is to have one callback for each menu.



          I hope this helps :-)



          # -*- coding: utf-8 -*-
          import numpy as np
          import pandas as pd

          from bokeh.layouts import row, widgetbox
          from bokeh.models import CustomJS, Select
          from bokeh.plotting import figure, show, ColumnDataSource

          # Define some random data
          dataframe = pd.DataFrame({
          'Difference': np.sin(np.linspace(0, 100, 500)),
          'Price': np.cos(np.linspace(0, 100, 500)),
          'Metacritic': np.sin(np.linspace(0, 100, 500)),
          'Rotten Tomatoes': np.cos(np.linspace(0, 200, 500)),
          })

          # Set x and y-axis defaults
          dataframe['x'] = dataframe['Difference']
          dataframe['y'] = dataframe['Metacritic']

          # Create Bokeh's ColumnDataSource
          source = ColumnDataSource(data=dataframe)

          # Create the plot figure
          plot = figure(plot_width=400, plot_height=400)
          plot.circle('x', 'y', source=source)

          # Create the dropdown menus
          x_menu = Select(options=['Difference', 'Price'],
          value='Difference',
          title='What do you want to put on the x axis')

          y_menu = Select(options=['Metacritic', 'Rotten Tomatoes'],
          value='Metacritic',
          title='What do you want to put on the y axis')

          # Create two callbacks, one for each menu
          callback_x = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['x']=data[cb_obj.value]
          source.change.emit();
          """)

          callback_y = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['y']=data[cb_obj.value]
          source.change.emit();
          """)

          # Assign callbacks to menu widgets
          x_menu.callback = callback_x
          y_menu.callback = callback_y

          # Show the html document with a layout
          show(row(widgetbox(x_menu, y_menu), plot))





          share|improve this answer













          It would be easier to help if you gave a self-contained minimal example (code that we can just copy, paste and run). With that said, here is something that might help you to get started. You were already very close to this solution, but I guess the important part is to have one callback for each menu.



          I hope this helps :-)



          # -*- coding: utf-8 -*-
          import numpy as np
          import pandas as pd

          from bokeh.layouts import row, widgetbox
          from bokeh.models import CustomJS, Select
          from bokeh.plotting import figure, show, ColumnDataSource

          # Define some random data
          dataframe = pd.DataFrame({
          'Difference': np.sin(np.linspace(0, 100, 500)),
          'Price': np.cos(np.linspace(0, 100, 500)),
          'Metacritic': np.sin(np.linspace(0, 100, 500)),
          'Rotten Tomatoes': np.cos(np.linspace(0, 200, 500)),
          })

          # Set x and y-axis defaults
          dataframe['x'] = dataframe['Difference']
          dataframe['y'] = dataframe['Metacritic']

          # Create Bokeh's ColumnDataSource
          source = ColumnDataSource(data=dataframe)

          # Create the plot figure
          plot = figure(plot_width=400, plot_height=400)
          plot.circle('x', 'y', source=source)

          # Create the dropdown menus
          x_menu = Select(options=['Difference', 'Price'],
          value='Difference',
          title='What do you want to put on the x axis')

          y_menu = Select(options=['Metacritic', 'Rotten Tomatoes'],
          value='Metacritic',
          title='What do you want to put on the y axis')

          # Create two callbacks, one for each menu
          callback_x = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['x']=data[cb_obj.value]
          source.change.emit();
          """)

          callback_y = CustomJS(args=dict(source=source), code="""
          console.log('changed selected option', cb_obj.value)
          var data=source.data
          data['y']=data[cb_obj.value]
          source.change.emit();
          """)

          # Assign callbacks to menu widgets
          x_menu.callback = callback_x
          y_menu.callback = callback_y

          # Show the html document with a layout
          show(row(widgetbox(x_menu, y_menu), plot))






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 13 '18 at 21:02









          Azrael_DDAzrael_DD

          465




          465













          • Thanks so much. Good call on adding the random data so that people can just run it. Unfortunately, I'm still having similar issues. I'll send a new snippet of code below to clarify the issue

            – E Larson
            Nov 13 '18 at 22:12













          • Never mind... I glazed right over your "set x and y defaults." That was the issue with the nonexistent columns (on top of adding the two callbacks).

            – E Larson
            Nov 13 '18 at 22:23



















          • Thanks so much. Good call on adding the random data so that people can just run it. Unfortunately, I'm still having similar issues. I'll send a new snippet of code below to clarify the issue

            – E Larson
            Nov 13 '18 at 22:12













          • Never mind... I glazed right over your "set x and y defaults." That was the issue with the nonexistent columns (on top of adding the two callbacks).

            – E Larson
            Nov 13 '18 at 22:23

















          Thanks so much. Good call on adding the random data so that people can just run it. Unfortunately, I'm still having similar issues. I'll send a new snippet of code below to clarify the issue

          – E Larson
          Nov 13 '18 at 22:12







          Thanks so much. Good call on adding the random data so that people can just run it. Unfortunately, I'm still having similar issues. I'll send a new snippet of code below to clarify the issue

          – E Larson
          Nov 13 '18 at 22:12















          Never mind... I glazed right over your "set x and y defaults." That was the issue with the nonexistent columns (on top of adding the two callbacks).

          – E Larson
          Nov 13 '18 at 22:23





          Never mind... I glazed right over your "set x and y defaults." That was the issue with the nonexistent columns (on top of adding the two callbacks).

          – E Larson
          Nov 13 '18 at 22:23


















          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%2f53287715%2fusing-customjs-to-make-a-dynamic-scatter-plot-with-bokeh-issue-with-nonexisten%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

          Full-time equivalent

          Bicuculline

          さくらももこ