Reputation: 3
I created, using bokeh, a selection histogram that contains a central scatter plot and histograms as the axes. I also have a legend that displays the names of the groups of scatter data that, when clicked, will hide the associated data points to the legend name. I am wondering, however, if it is possible to update the histogram data as the scatter plot data is being updated (i.e., displayed or hidden).
Keep in mind I am new to python and bokeh and writing concise script in general so some of the code might be fluff, but any help would be much appreciated. Thanks!
import numpy as np
import pandas as pd
from bokeh.layouts import row, column
from bokeh.models import BoxSelectTool, LassoSelectTool, Spacer
from bokeh.plotting import figure, show, curdoc
from bokeh.io import output_notebook
from bokeh.models import CategoricalColorMapper
from bokeh.plotting import ColumnDataSource
from bokeh.io import export_png
from bokeh.palettes import Spectral4
data1 = pd.DataFrame({'m/z': np.random.random(100), 'RT': np.random.random(100)})
data2 = pd.DataFrame({'m/z': np.random.random(100), 'RT': np.random.random(100)})
#create array data from each data set for scatter plot
array_data1 = np.array(data1)
array_data2 = np.array(data2)
#create histogram data
##combine 'm/z' values from each data set into new object
x1 = data1[['m/z']]
x2 = data2[['m/z']]
x = pd.concat([x1,x2])
##combine 'RT' values from each data set into new object
y1 = data1[['RT']]
y2 = data2[['RT']]
y = pd.concat([y1,y2])
#create scatterplot figure
p = figure(x_axis_label='m/z',y_axis_label='RT',tools="",
plot_width=600, plot_height=600, min_border=10, min_border_left=50,
toolbar_location="above", title="Mass Recovery Comparison")
p.background_fill_color = "#fafafa"
p.select(BoxSelectTool).select_every_mousemove = False
p.select(LassoSelectTool).select_every_mousemove = False
#create loop for scatter plot
for data, name, color in zip([array_data1,array_data2], ['035','044'],
Spectral4):
df = pd.DataFrame(data)
df.columns = ['m/z','RT']
p.scatter(df['m/z'], df['RT'], line_width=2, color=color,
alpha=0.8, legend=name)
#legend formatting
p.legend.location = "top_right"
p.legend.click_policy="hide"
#create horizontal histogram
hhist,hedges = np.histogram(x,bins=20)
hzeros = np.zeros(len(hedges)-1)
hmax = max(hhist)*1.1
ph = figure(toolbar_location=None, plot_width=p.plot_width,
plot_height=200, x_range=p.x_range, y_range=(0, hmax), min_border=10,
min_border_left=50, y_axis_location="right")
ph.xgrid.grid_line_color = None
ph.yaxis.major_label_orientation = np.pi/4
ph.background_fill_color = "#fafafa"
ph.quad(bottom=0, left=hedges[:-1], right=hedges[1:], top=hhist,
color="white", line_color="#3A5785")
#create vertical histogram
vhist, vedges = np.histogram(y, bins=20)
vzeros = np.zeros(len(vedges)-1)
vmax = max(vhist)*1.1
pv = figure(toolbar_location=None, plot_width=200,
plot_height=p.plot_height, x_range=(0, vmax),y_range=p.y_range,
min_border=10, y_axis_location="right")
pv.ygrid.grid_line_color = None
pv.xaxis.major_label_orientation = np.pi/4
pv.background_fill_color = "#fafafa"
pv.quad(left=0, bottom=vedges[:-1], top=vedges[1:], right=vhist,
color="white", line_color="#3A5785")
layout = column(row(p, pv), row(ph, Spacer(width=200, height=200)))
show(layout)
Upvotes: 0
Views: 425
Reputation: 34568
The best I am able to interpret is that you want to be able to do something whenever a specific glyph is hidden or muted (or unhidden or unmuted) from an interactive legend. The following code illustrates how to do that in a general sense, you'd want to replace the print
with real code that does whatever updates you actually intend:
from functools import partial
import pandas as pd
from bokeh.io import curdoc
from bokeh.palettes import Spectral4
from bokeh.plotting import figure
from bokeh.sampledata.stocks import AAPL, IBM, MSFT, GOOG
p = figure(plot_width=800, plot_height=250, x_axis_type='datetime')
p.title.text = 'Click on legend entries to hide lines'
def update(name, attr, old, new):
# click the legend and see the information print in the console
print(name, new)
for data, name, color in zip([AAPL, IBM, MSFT, GOOG], ["AAPL", "IBM", "MSFT", "GOOG"], Spectral4):
df = pd.DataFrame(data)
df['date'] = pd.to_datetime(df['date'])
r = p.line(df['date'], df['close'], line_width=2, color=color, alpha=0.8, legend=name)
r.on_change('visible', partial(update, name))
p.legend.location = 'top_left'
p.legend.click_policy = 'hide'
curdoc().add_root(p)
Upvotes: 1