问题
I have a script to plot the prices of some share that the user wants to look at : he can choose the shares via a Dropdown button and Bokeh will draw the curve accordingly. (I am working in jupyter notebook) :
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
output_notebook()
my code is the following :
from bokeh.models import Callback, ColumnDataSource, Select,CustomJS
from bokeh.plotting import figure, show, gridplot
from bokeh.models.widgets.layouts import VBox
import pandas as pd
shares = ['AAPL', 'MSFT', 'IBM', 'All']
AAPL = pd.read_csv("http://ichart.yahoo.com/table.csv?s=AAPL&a=0&b=1&c=2000&d=0&e=1&f=2015",parse_dates=['Date'])
MSFT = pd.read_csv("http://ichart.yahoo.com/table.csv?s=MSFT&a=0&b=1&c=2000&d=0&e=1&f=2015",parse_dates=['Date'])
IBM = pd.read_csv("http://ichart.yahoo.com/table.csv?s=IBM&a=0&b=1&c=2000&d=0&e=1&f=2015",parse_dates=['Date'])
max_price = max(AAPL['Adj Close'].max(), MSFT['Adj Close'].max(), IBM['Adj Close'].max()) + 10
min_date = min(AAPL['Date'].min(), MSFT['Date'].min(), IBM['Date'].min())
max_date = max(AAPL['Date'].max(), MSFT['Date'].max(), IBM['Date'].max())
myplot = figure(title="Share price", x_axis_type="datetime", x_range=[min_date,max_date],y_range=[0,max_price],
background_fill='#FFF5EE', plot_width=900, plot_height = 400, outline_line_color= None)
source_AAPL = ColumnDataSource(data=dict(x=AAPL['Date'], y = AAPL['Adj Close'], ytemp = AAPL['Adj Close']))
source_MSFT = ColumnDataSource(data=dict(x=MSFT['Date'], y = MSFT['Adj Close'], ytemp = MSFT['Adj Close']))
source_IBM = ColumnDataSource(data=dict(x=IBM['Date'], y = IBM['Adj Close'], ytemp = IBM['Adj Close']))
myplot.line(x ='x', y ='y', color='#A6CEE3', source = source_AAPL, name='AAPL')
myplot.line(x ='x', y ='y', color='#33A02C', source = source_MSFT, name='IBM')
myplot.line(x ='x', y ='y', color='#FB9A99', source = source_IBM, name='MSFT')
Callback_Shares = CustomJS(args={'source_AAPL': source_AAPL,'source_MSFT': source_MSFT,'source_IBM': source_IBM}, code="""
var f = cb_obj.get('value');
var data_AAPL = source_AAPL.get('data');
var data_MSFT = source_MSFT.get('data');
var data_IBM = source_IBM.get('data');
if (f == 'AAPL') {
data_MSFT['y'] = [0 for i in range(len(data_MSFT['x']))];
data_IBM['y'] = [0 for i in range(len(data_IBM['x']))];
data_AAPL['y'] = data_AAPL['ytemp'] ;
source_AAPL.trigger('change');
source_MSFT.trigger('change');
source_IBM.trigger('change');
}
if (f == 'MSFT') {
data_AAPL['y'] = [0 for i in range(len(data_AAPL['x']))];
data_IBM['y'] = [0 for i in range(len(data_IBM['x']))];
data_MSFT['y'] = data_MSFT['ytemp'] ;
source_AAPL.trigger('change');
source_MSFT.trigger('change');
source_IBM.trigger('change');
}
if (f == 'IBM') {
data_AAPL['y'] = [0 for i in range(len(data_AAPL['x']))];
data_MSFT['y'] = [0 for i in range(len(data_MSFT['x']))];
data_IBM['y'] = data_IBM['ytemp'] ;
source_AAPL.trigger('change');
source_MSFT.trigger('change');
source_IBM.trigger('change');
}
if (f == 'All') {
data_AAPL['y'] = data_AAPL['ytemp'];
data_MSFT['y'] = data_MSFT['ytemp'];
data_IBM['y'] = data_IBM['ytemp'];
source_AAPL.trigger('change');
source_MSFT.trigger('change');
source_IBM.trigger('change');
}"""
)
dropdown = Select(title="Shares:", value=shares[3], options=shares, callback = Callback_Shares)
myfigure = VBox(dropdown, gridplot([[myplot]]))
show(myfigure)
My problem is the figure always shows the 3 curves and does not take into account the choice of the DropDown...
回答1:
The other answer is unfortunately not an optimal one. As a project maintainer I feel obligated to show the project in the best light. Here is a much simpler complete example that functions the same and works with Bokeh 0.12.4
:
from bokeh.models import CustomJS, ColumnDataSource, Select
from bokeh.plotting import figure, output_file, show
from bokeh.layouts import column
import pandas as pd
url = "http://ichart.yahoo.com/table.csv?s=%s&a=0&b=1&c=2000&d=0&e=1&f=2015"
AAPL = pd.read_csv(url % "AAPL", parse_dates=['Date'])
MSFT = pd.read_csv(url % "MSFT", parse_dates=['Date'])
IBM = pd.read_csv(url % "IBM", parse_dates=['Date'])
max_price = max(AAPL['Close'].max(), MSFT['Close'].max(), IBM['Close'].max())
source = ColumnDataSource({
'xAAPL' : AAPL['Date'], 'yAAPL' : AAPL['Close'], 'yAAPLp' : AAPL['Close'],
'xMSFT' : MSFT['Date'], 'yMSFT' : MSFT['Close'], 'yMSFTp' : MSFT['Close'],
'xIBM' : IBM['Date'], 'yIBM' : IBM['Close'], 'yIBMp' : IBM['Close']
})
p = figure(width=500, height=250, x_axis_type="datetime", y_range=[0, max_price+10])
r_aapl = p.line('xAAPL', 'yAAPL', source=source, color='navy', alpha=0.5)
r_msft = p.line('xMSFT', 'yMSFT', source=source, color='red', alpha=0.5)
r_ibm = p.line('xIBM', 'yIBM', source=source, color='green', alpha=0.5)
callback = CustomJS(args=dict(r_aapl=r_aapl, r_msft=r_msft, r_ibm=r_ibm), code="""
f = cb_obj.value;
r_aapl.visible = false;
r_msft.visible = false;
r_ibm.visible = false;
if (f == "AAPL") { r_aapl.visible = true; }
else if (f == "MSFT") { r_msft.visible = true; }
else if (f == "IBM") { r_ibm.visible = true; }
else {
r_aapl.visible = true;
r_msft.visible = true;
r_ibm.visible = true;
}
""")
shares = ['AAPL', 'MSFT', 'IBM', 'All']
multi_select = Select(title="Select Shares:", value=shares[3], options=shares, callback=callback)
output_file("datetime.html")
show(column(multi_select, p))
I should also add, "interactive legends" that allow glyphs to be hidden or muted by clicking on the legend, will be added as as standard feature in 0.12.5
.
回答2:
Rather than updating actual data sources, there are much easier ways to control visibility. You can set a glyph's alpha to zero, or color to None
, or probably most directly, set its renderer's visible
property to False
as seen in this example. The relevant part of that example, simplified some, is this code:
r0 = p.line(x, y0, color="red")
r1 = p.line(x, y1, color="green")
r2 = p.line(x, y2, color="blue")
checkbox = CheckboxGroup(labels=["Line 0", "Line 1", "Line 2"],
active=[0, 1, 2], width=100)
checkbox.callback = CustomJS.from_coffeescript(
args=dict(r0=r0, r1=r1, r2=r2, checkbox=checkbox),
code="""
r0.visible = 0 in checkbox.active;
r1.visible = 1 in checkbox.active;
r2.visible = 2 in checkbox.active;
""")
回答3:
I found the following solution after quite some work :
from bokeh.models import CustomJS, ColumnDataSource, Select
from bokeh.plotting import figure, output_file, show
from bokeh.models.layouts import VBox
import pandas as pd
AAPL = pd.read_csv("http://ichart.yahoo.com/table.csv?s=AAPL&a=0&b=1&c=2000&d=0&e=1&f=2015",parse_dates=['Date'])
MSFT = pd.read_csv("http://ichart.yahoo.com/table.csv?s=MSFT&a=0&b=1&c=2000&d=0&e=1&f=2015",parse_dates=['Date'])
IBM = pd.read_csv("http://ichart.yahoo.com/table.csv?s=IBM&a=0&b=1&c=2000&d=0&e=1&f=2015",parse_dates=['Date'])
max_price = max(AAPL['Close'].max(), MSFT['Close'].max(), IBM['Close'].max()) + 10
min_date = min(AAPL['Date'].min(), MSFT['Date'].min(), IBM['Date'].min())
max_date = max(AAPL['Date'].max(), MSFT['Date'].max(), IBM['Date'].max())
output_file("datetime.html")
source = ColumnDataSource({'xAAPL': AAPL['Date'], 'xMSFT': MSFT['Date'], 'xIBM': IBM['Date'],
'yAAPL': AAPL['Close'], 'yAAPLp': AAPL['Close'], \
'yMSFT': MSFT['Close'], 'yMSFTp': MSFT['Close'], \
'yIBM': IBM['Close'], 'yIBMp': IBM['Close'] })
p = figure(width=500, height=250, x_axis_type="datetime", x_range=[min_date,max_date],y_range=[0,max_price])
p.line('xAAPL', 'yAAPL', source=source, color='navy', alpha=0.5)
p.line('xMSFT', 'yMSFT', source=source, color='red', alpha=0.5)
p.line('xIBM', 'yIBM', source=source, color='green', alpha=0.5)
callback = CustomJS(args=dict(source=source), code="""
var data = source.get('data');
var f = cb_obj.get('value')
yAAPL = data['yAAPL']
yMSFT = data['yMSFT']
yIBM = data['yIBM']
yAAPLp = data['yAAPLp']
yMSFTp = data['yMSFTp']
yIBMp = data['yIBMp']
if (f == "AAPL") {
for (i = 0; i < yAAPL.length; i++) {yAAPL[i] = yAAPLp[i]}
for (i = 0; i < yMSFT.length; i++) {yMSFT[i] = 'nan'}
for (i = 0; i < yIBM.length; i++) {yIBM[i] = 'nan'}
}
else if (f == "MSFT") {
for (i = 0; i < yAAPL.length; i++) {yAAPL[i] = 'nan'}
for (i = 0; i < yMSFT.length; i++) {yMSFT[i] = yMSFTp[i]}
for (i = 0; i < yIBM.length; i++) {yIBM[i] = 'nan'}
}
else if (f == "IBM") {
for (i = 0; i < yAAPL.length; i++) {yAAPL[i] = 'nan'}
for (i = 0; i < yMSFT.length; i++) {yMSFT[i] = 'nan'}
for (i = 0; i < yIBM.length; i++) {yIBM[i] = yIBMp[i]}
}
else {
for (i = 0; i < yAAPL.length; i++) {yAAPL[i] = yAAPLp[i]}
for (i = 0; i < yMSFT.length; i++) {yMSFT[i] = yMSFTp[i]}
for (i = 0; i < yIBM.length; i++) {yIBM[i] = yIBMp[i]}
}
source.trigger('change');
""")
shares = ['AAPL', 'MSFT', 'IBM', 'All']
multi_select = Select(title="Select Shares:", value=shares[3], options=shares, callback=callback)
layout = VBox(multi_select, p)
show(layout)
来源:https://stackoverflow.com/questions/41307136/dropdown-not-working-with-bokeh