3

I have a dataframe of multiple columns. First two columns are x and y coordinates and the rest columns are different property values for (x,y) pairs.

import pandas as pd
import numpy as np
df = pd.DataFrame()
df['x'] = np.random.randint(1,1000,100)
df['y'] = np.random.randint(1,1000,100)
df['val1'] = np.random.randint(1,1000,100)
df['val2'] = np.random.randint(1,1000,100)
df['val3'] = np.random.randint(1,1000,100)

print df.head()

     x    y  val1  val2  val3
0  337  794   449   969   933
1   19  563   592   677   886
2  512  467   664   160    16
3   36  112    91   230   910
4  972  572   336   879   860

Using customJS in Bokeh, I would like to change the value of color in 2-D heatmap by providing a drop down menu.

from bokeh.plotting import figure
from bokeh.models import ColumnDataSource
from bokeh.models import LinearColorMapper
from bokeh.palettes import RdYlBu11 as palette

p = figure()
source =   ColumnDataSource(df)
color_mapper = LinearColorMapper(palette=palette)
p.patches('x', 'y', source=source,\
          fill_color={'field': 'val1', 'transform':color_mapper})

show(p)

The above commands plot a color map whose color is determined by the column 'val1'. I would like to plot different columns (either val1, val2, or val3) based on whatever is selected in the drop down menu.

I can create a drop down widget in bokeh by doing

 from bokeh.models.widgets import Select
 select = Select(title="Option:", value="val1", options=["val1","val2","val3"])

But, I'm not quite sure how I can use the selected value to update the plot by using callback.

Could someone give me a guideline here?

Thanks.

1 Answer 1

7

I have included an example with comments inline with the code. The main important steps are to write the javascript code that is executed each time the selected option on the widget changes. The code simply needs to just re-assign which of the columns is set to the values for the 'y' column of the datasource.

The other issue is that your data is just x and y points. The patches glyph will require a different data structure which defines the boundaries of the patches. I believe there are better ways to make a heatmap in bokeh, there should be numerous examples on stack overflow and the bokeh docs.

import pandas as pd
import numpy as np

from bokeh.io import show
from bokeh.layouts import widgetbox,row
from bokeh.models import ColumnDataSource, CustomJS

df = pd.DataFrame()
df['x'] = np.random.randint(1,1000,1000)
df['y'] = np.random.randint(1,1000,1000)
df['val1'] = np.random.randint(1,1000,1000)
df['val2'] = np.random.randint(1,1000,1000)
df['val3'] = np.random.randint(1,1000,1000)

from bokeh.plotting import figure
from bokeh.models import LinearColorMapper
from bokeh.palettes import RdYlBu11 as palette

p = figure(x_range=(0,1000),y_range=(0,1000))
source = ColumnDataSource(df)
source_orig = ColumnDataSource(df)
color_mapper = LinearColorMapper(palette=palette)
p.rect('x', 'y', source=source,width=4,height=4,
          color={'field': 'val1', 'transform':color_mapper})

from bokeh.models.widgets import Select
select = Select(title="Option:", value="val1", options=["val1","val2","val3"])

callback = CustomJS(args={'source':source},code="""
        // print the selectd value of the select widget - 
        // this is printed in the browser console.
        // cb_obj is the callback object, in this case the select 
        // widget. cb_obj.value is the selected value.
        console.log(' changed selected option', cb_obj.value);

        // create a new variable for the data of the column data source
        // this is linked to the plot
        var data = source.data;

        // allocate the selected column to the field for the y values
        data['y'] = data[cb_obj.value];

        // register the change - this is required to process the change in 
        // the y values
        source.change.emit();
""")

# Add the callback to the select widget. 
# This executes each time the selected option changes
select.callback = callback
show(row(p,select))
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks for the quick answer. Could you explain why you update 'y'? Isn't that y-coordinate value in the data frame df?
In your question you stated you wanted to plot different columns, so I just updated y as a demonstration. You can obviously update either x or y. If your intention is to update the column which changes the colorscale, I would create a seperate column, and then change the values of that in the callback if that makes sense
I see. That makes sense. I was trying to update the field parameter value, but just creating a separate column in source and keep the structure as it is can be a way. Thank you. This really helps.
No problem, please mark the answer as correct if that has achieved what you need.
What does source_orig = ColumnDataSource(df) do in your code? I removed the line, but it doesn't seem to change the output?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.