DropDown not working with Bokeh

拟墨画扇 提交于 2021-02-07 08:19:50

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!