bwinn
bwinn

Reputation: 3

Selection Histogram Axis Data Update

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

Answers (1)

bigreddot
bigreddot

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

Related Questions