Creating plot from Columndatasource

Hi,
I am trying to create a line plot from columndatasource and deploy it on bokeh server. I am stuck on as to how do i should create a line plot after the datatable is created using the columndatasource (src_data). is there a way whereby change in value of source in datatable be passed to plot using datatable_model.on_change(‘source’,call_func) and define plot creation in call_func()? This method dinot work as bokeh couldnt identify the plot in the layout(not there in present code). Thanks.

from re import X
from string import Formatter
from numpy import source
import pandas as pd
import io
import requests

from bokeh.models import PasswordInput,TextInput,ColumnDataSource,DataTable,TableColumn,DateFormatter,Line,NumberFormatter
from bokeh.io import curdoc
from bokeh.layouts import layout
from bokeh.plotting import figure

df=pd.DataFrame([])
src_data=ColumnDataSource()

def callback_obtain_data(attr,old,new):
    global df
    api_key=api_input_wisget.value
    ticker_list=ticker_input_widget.value
    url_download='https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol={}&datatype=csv&outputsize=full&apikey={}'.format(ticker_list,api_key)
    r=requests.get(url=url_download)
    data=io.StringIO(r.text)
    df=pd.read_csv(data)
    df['timestamp']=pd.to_datetime(df['timestamp'])
    df['Ticker']=ticker_list

def activate_widget(attr,old,bew):
    ticker_input_widget.disabled=False

def datatble_builder(attr,new,old):
    global src_data
    src_data=ColumnDataSource(df)
    columns_datatable=[
        TableColumn(field='timestamp',title="Date",formatter=DateFormatter()),
        TableColumn(field='Ticker',title='Ticker'),
        TableColumn(field='open',title='open'),
        TableColumn(field='close',title='close'),
    ]
    datatable_model.source=src_data
    datatable_model.columns=columns_datatable
    datatable_model.visible=True


# create widgets
api_input_wisget=PasswordInput(placeholder='Please input API_KEY',prefix='API_KEY',value='')
ticker_input_widget=TextInput(placeholder='Please input coma sparated ticker',prefix='ticker_list',disabled=True)
datatable_model=DataTable(visible=False)

# create event callback

api_input_wisget.on_change('value',activate_widget)
ticker_input_widget.on_change('value',callback_obtain_data,datatble_builder)


# create layout
layout_output=layout([
    [api_input_wisget,ticker_input_widget],
    [datatable_model],
])

# visualize
curdoc().add_root(layout_output)

Sorry I might be a bit unclear about what you’re looking for, but if I understand correctly from your code you are populating a dataframe from an api call, then using that dataframe to populate a ColumnDataSource, and you want a line plot of that data to update accordingly?

I don’t see a figure or a line plot in your code… and I guess you are asking how to incorporate it?

My advice would be roughly as follows:

#instantiate a CDS with the columns you know it will have, empty arrays for values
src = ColumnDataSource(data={c:[] for c in ['timestamp','Ticker','open','close']})

#instantiate a figure
fig = figure(x_axis_type='datetime') #give it sizing/other props etc

#add a line glyph as a renderer to the figure, driving off the CDS you made
r = fig.line(x='timestamp',y='open', source= src)

#then in your callback you want to...

#make the request (as you're doing),
#populate the dataframe df (as you're doing)
#use the dataframe to update src's '.data' attribute:
#along the lines of:
src.data = {c:df[c].to_list() for c in df.columns}

The way it kinda works is the renderer listens for a change in the CDS that’s driving it and will update when that happens.

Hopefully that’s roughly the guidance you’re looking for :slight_smile:

2 Likes

That works and your explanation was lucid. Thanks :slight_smile:

1 Like