Get string value from Bokeh Multiselect - python-3.x

My goal here was to create a Bokeh widgetbox which you could use to provide input to a form, however the only widgets that allow me to get my inputs back from Bokeh's javascript side into Python variables are RadioButtonGroups. Otherwise, Multiselect, AutocompleteInput, and others are ONLY able to return my input if it's in the form of an integer. This is being done in a Jupyter NB using Python and Bokeh 0.13.0, if you happen to have any questions or I've left anything out please don't hesitate to let me know.
Please see code below:
import os, time, sys
from bokeh.layouts import widgetbox
from bokeh.models.widgets import RadioButtonGroup, Button, TextInput
from bokeh.models.widgets.inputs import MultiSelect
from bokeh.models.widgets import AutocompleteInput
from bokeh.models.callbacks import CustomJS
from bokeh.io import output_notebook, show
from bokeh.models import ColumnDataSource
from bokeh.models.widgets.markups import Div
from bokeh.resources import INLINE
output_notebook(resources=INLINE)
ipies=[str(i.strip('.ipynb')) for i in os.listdir() if i.endswith('.ipynb')]
minutes=0
hours=0
days=0
months=0
daysmonth=0
days=0
minute_options=[str(i) for i in range(1,60)]
minute_options.append("*")
minute_callback = CustomJS(args=dict(a=minute_options), code="""
var options=a;
console.log(options[parseInt(cb_obj.active)]);
var ind=options[parseInt(cb_obj.active)];
IPython.notebook.kernel.execute('minutes='+ind+'');
""")
minute_rbg = RadioButtonGroup(
labels=minute_options, callback=minute_callback, active=len(minute_options)-1)
min_title=Div(text="Which minute on the hour, * for every minute")
hour_options=[str(i) for i in range(24)]
hour_options.append("*")
hour_callback = CustomJS(args=dict(a=hour_options), code="""
var options=a;
console.log(options[parseInt(cb_obj.active)]);
var ind=options[parseInt(cb_obj.active)];
IPython.notebook.kernel.execute('hours='+ind+'');
""")
hour_rbg = RadioButtonGroup(
labels=hour_options,callback=hour_callback,active=len(hour_options)-1)
hour_title=Div(text="Which hour in a day, * for every hour")
day_month_options=[str(i) for i in range(1,32)]
day_month_options.append("*")
day_month_callback = CustomJS(args=dict(a=day_month_options), code="""
var options=a;
console.log(options[parseInt(cb_obj.active)]);
var ind=options[parseInt(cb_obj.active)];
IPython.notebook.kernel.execute('daysmonth='+ind+'');
""")
day_month_rbg = RadioButtonGroup(
labels=day_month_options,callback=day_month_callback,active=len(day_month_options)-1)
day_month_title=Div(text="Which day in a month, * for every day of the month")
month_options=[str(i) for i in range(1,13)]
month_options.append("*")
month_callback = CustomJS(args=dict(a=month_options), code="""
var options=a;
console.log(options[parseInt(cb_obj.active)]);
var ind=options[parseInt(cb_obj.active)];
IPython.notebook.kernel.execute('months='+ind+'');
""")
month_rbg = RadioButtonGroup(
labels=month_options, callback=month_callback,active=len(month_options)-1)
month_title=Div(text="Which month in a year, * for every month")
day_week_options=[str(i) for i in range(7)]
day_week_options.append("*")
day_week_callback = CustomJS(args=dict(a=day_week_options), code="""
var options=a;
console.log(options[parseInt(cb_obj.active)]);
var ind=options[parseInt(cb_obj.active)];
IPython.notebook.kernel.execute('days='+ind+'');
""")
day_week_rbg = RadioButtonGroup(
labels=day_week_options, callback=day_week_callback, active=len(day_week_options)-1)
days_week_title=Div(text="Which day in a week, * for every day of the week")
import pandas as pd
ipies_pd = pd.DataFrame({"a":ipies})
#Selection source: IPIES CDS
cds = ColumnDataSource(data=ipies_pd)
#Selection source: autocompleteinput & multiselect widgets
selection_callback = CustomJS(args=dict(source=cds), code="""
// THIS CALLBACK ONLY BRINGS BACK SELECTIONS IF THEY ARE INTEGERS
var cbobj = cb_obj.value;
IPython.notebook.kernel.execute("auto_c_value = "\"+ cbobj + "\");
""")
ms = MultiSelect(title="power", callback=selection_callback, options=ipies)
auto_c=AutocompleteInput(completions=ipies, height=100, callback=selection_callback)
button_callback = CustomJS(code="""
var cur_index = IPython.notebook.get_selected_index()+1;
var end_index=IPython.notebook.ncells();
IPython.notebook.execute_cell_range(IPython.notebook.get_selected_index()+1, IPython.notebook.ncells());
""")
button = Button(label="button~!", button_type="primary", callback=button_callback)
w_box = widgetbox(min_title, minute_rbg, hour_title, hour_rbg, day_month_title, day_month_rbg,
month_title, month_rbg,days_week_title, day_week_rbg, button,
ms, auto_c, width=800, sizing_mode='scale_both')
show(w_box)

Related

Exception in Tkinter callback latitude

from tkinter import *
import phonenumbers
from phonenumbers import carrier
from phonenumbers import geocoder
from phonenumbers import timezone
from timezonefinder import TimezoneFinder
from geopy.geocoders import Nominatim
from datetime import datetime
import pytz
root=Tk()
root.title('Phone Number Traker')
root.geometry('365x584+400+100')
root.resizable(False,False)
def track():
inserisci_numero=entry.get()
number=phonenumbers.parse(inserisci_numero)
locate=geocoder.description_for_number(number,"IT")
country.config(text=locate)
operator=carrier.name_for_number (number,"it")
sim.config (text=operator)
time = timezone.time_zones_for_number(number)
zona.config(text=time)
geolocator= Nominatim(user_agent="geopiExercises")
location= geolocator.geocode(locate)
lng = location.longitude
lat = location.latitude
longitude.config(text=lng)
latitude.config(text=lat)
obj= TimezoneFinder()
result=obj.timezone_at(lng=location.longitude,lat=location.latitude)
home=pytz.timezone(result)
local_time= datetime.now(home)
current_time=local_time.strftime ("%I:%M:%p")
clock.config(text=current_time)
logo=PhotoImage(file="logo image.png")
Label(root,image=logo).place(x=240,y=70)
Heading = Label(root,text ="Traccia",font=("arial",15,"bold"))
Heading.place(x=90,y=110)
Entry_back= PhotoImage(file="search png.png")
Label (root,image=Entry_back).place(x=20,y=190)
entry=StringVar()
inserisci_numero = Entry(root,textvariable=entry,width=17,bd=0,font=
("arial",20),justify="center")
inserisci_numero.place(x=50,y=220)
Serach_image =PhotoImage(file="search.png")
search =Button(image=Serach_image,borderwidth=0,cursor="hand2",bd=0,font=("arial",16),command=
track)
search.place(x=35,y=300)
Box=PhotoImage(file="bottom png.png")
Label(root,image=Box).place(x=-2,y=355)
country=Label(root,text = "Country: ",bg="#57adff",fg="black",font=("arial",10,"bold"))
country.place(x=50,y=400)
sim=Label(root,text = "SIM: ",bg="#57adff",fg="black",font=("arial",10,"bold"))
sim.place(x=200,y=400)
zona=Label(root,text = "Zona: ",bg="#57adff",fg="black",font=("arial",10,"bold"))
zona.place(x=50,y=450)
clock=Label(root,text = "Phone Time: ",bg="#57adff",fg="black",font=("arial",10,"bold"))
clock.place(x=200,y=450)
longitude=Label(root,text = "Longitudine: ",bg="#57adff",fg="black",font=("arial",10,"bold"))
longitude.place(x=50,y=500)
latitude=Label(root,text = "Latitudine: ",bg="#57adff",fg="black",font=("arial",10,"bold"))
latitude.place(x=200,y=500)
root.mainloop()
when I start the application I can't see on the screen, neither the
country nor the position. what did i do wrong? using pytnon 3.10. I
am going crazy

Not able to update the plot on selection of a value of Select widget of Bokeh Library

I am working on COVID19 analysis and am using a JSON data source. I have converted the json to dataframe. I am working on plotting a daily case, daily death and daily recovered bar chart over a datetime x-axis for each state and the state can be selected using a Select widget. I don't know Javascript so, I am trying to avoid using Javascript callbacks but have been using a function to update the select.value. I am not sure why is the plot not getting updated even when i am running the code on Bokeh server and there are no exceptions raised by the interpreter.
Can someone provide me with any direction or help with what might be causing the issue as I am new to Python and any help is appreciated? Or if there's any other alternative. This code is a derivation from a similar plot on [bokeh discourse][1]
#Creating DataFrame
cases_summary = requests.get('https://api.rootnet.in/covid19-in/stats/history')
json_data = cases_summary.json()
cases_summary=pd.json_normalize(json_data['data'], record_path='regional', meta='day')
cases_summary['day']=pd.to_datetime(cases_summary['day'])
cases_summary['daily deaths']=cases_summary['deaths'].groupby(cases_summary['loc']).diff(1)
cases_summary['daily confirmed']=cases_summary['totalConfirmed'].groupby(cases_summary['loc']).diff(1)
cases_summary['daily discharged']=cases_summary['discharged'].groupby(cases_summary['loc']).diff(1)
#Initializing the first default plot
cases=cases_summary[cases_summary['loc']=='Delhi']
source=ColumnDataSource(data=cases)
a = figure(plot_width=1200, plot_height=700, sizing_mode="scale_both", x_axis_type='datetime')
def make_plot(cases_val):
a.vbar('day', top='daily confirmed', width=timedelta(days=0.5),
legend_label='Daily Confirmed', color='#5e4fa2', source=cases_val)
a.vbar('day', bottom='daily discharged', width=timedelta(days=0.5),
legend_label='Daily Recovered', color='#66c2a5', source=cases_val)
a.vbar('day', bottom='daily deaths', width=timedelta(days=0.5),
legend_label='Daily Deaths', color='#3288bd', source=cases_val)
return a
def update_plot(attr,old,new):
location=select.value
data_loc = cases_summary[cases_summary['loc'] == location]
source = ColumnDataSource(data=dict()).from_df(data_loc)
layout.children[0]=make_plot(source)
select = Select(title="Select State:", value="Delhi", options=cases_summary['loc'].unique().tolist())
plot = make_plot(cases)
controls = column(select)
layout = row(a, controls)
select.on_change('value', update_plot)
curdoc().add_root(layout)
[1]: https://discourse.bokeh.org/t/how-to-update-the-bar-chart-that-has-dataframe-as-source-with-bokeh-select-widget/2031/8
This can be done more simply using a view and a filter. Here is an alternative approach:
import requests
import pandas as pd
from bokeh.plotting import figure
from bokeh.layouts import column, row
from bokeh.io import curdoc
from bokeh.models import *
from datetime import timedelta
cases_summary = requests.get("https://api.rootnet.in/covid19-in/stats/history")
json_data = cases_summary.json()
cases_summary = pd.json_normalize(json_data["data"], record_path="regional", meta="day")
cases_summary["day"] = pd.to_datetime(cases_summary["day"])
cases_summary["daily deaths"] = (
cases_summary["deaths"].groupby(cases_summary["loc"]).diff(1)
)
cases_summary["daily confirmed"] = (
cases_summary["totalConfirmed"].groupby(cases_summary["loc"]).diff(1)
)
cases_summary["daily discharged"] = (
cases_summary["discharged"].groupby(cases_summary["loc"]).diff(1)
)
source = ColumnDataSource(cases_summary)
filter = GroupFilter(column_name='loc',group='Delhi')
view = CDSView(source=source, filters = [filter])
a = figure(
plot_width=1200, plot_height=700, sizing_mode="scale_both", x_axis_type="datetime"
)
a.vbar(
"day",
top="daily confirmed",
width=timedelta(days=0.5),
legend_label="Daily Confirmed",
color="#5e4fa2",
source=source,
view = view
)
a.vbar(
"day",
bottom="daily discharged",
width=timedelta(days=0.5),
legend_label="Daily Recovered",
color="#66c2a5",
source=source,
view = view
)
a.vbar(
"day",
bottom="daily deaths",
width=timedelta(days=0.5),
legend_label="Daily Deaths",
color="#3288bd",
source=source,
view = view
)
def update_plot(attr, old, new):
view.filters = [GroupFilter(column_name='loc',group=select.value)]
select = Select(
title="Select State:", value="Delhi", options=cases_summary["loc"].unique().tolist()
)
controls = column(select)
layout = row(a, controls)
select.on_change("value", update_plot)
curdoc().add_root(layout)

How do I implement a start-stop button / play-resume button for an animation in bokeh?

I am trying to implement a star-stop button for a bokeh animation. I am using bokeh server in combination with the curdoc() function, but so far I haven't had much success.
I am wondering how someone with more experience would do that?
thanks
Here you go. Run with bokeh serve --show app.py (tested on Bokeh v1.0.4)
from bokeh.models import ColumnDataSource, Toggle, Column
from bokeh.plotting import figure, curdoc
from datetime import datetime
import random
source = ColumnDataSource(dict(time = [datetime.now()], value = [random.randint(5, 10)]))
plot = figure(plot_width = 1200, x_axis_type = 'datetime', tools = 'pan,box_select,crosshair,reset,save,wheel_zoom')
plot.line(x = 'time', y = 'value', line_color = 'black', source = source)
toggle = Toggle(label = "Toggle", button_type = "success")
def update():
if toggle.active:
source.stream(dict(time = [datetime.now()], value = [random.randint(5, 10)]))
curdoc().add_root(Column(plot, toggle))
curdoc().add_periodic_callback(update, 1000)
Result:

Why won't bokeh figure update with new data?

I'm creating a bokeh application that pulls data from Quandl stock prices and changes the plot based the stock symbol the user inputs. I used an example from this bokeh tuorial as a model.
Everything is working except the plot won't update when I input a new symbol.
I've tried passing the new data as a dictionary (before I was just passing a DataFrame to ColumnDataSource(), but no luck.
import pandas as pd
import numpy as np
from bokeh.models.widgets import TextInput, Select
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.layouts import column, row
from bokeh.io import show, output_notebook
import quandl
This is the function to get the data:
def get_data(symbol):
dictionary = {}
data = quandl.get('WIKI/' + symbol, collapse = 'annual', returns='numpy')
df = pd.DataFrame(data)
dictionary['date'] = list(df.Date.values)
dictionary['high'] = list(df.High.values)
return dictionary
And this is a function for the plot:
def modify_doc(doc):
symbol = 'AAWW'
source = ColumnDataSource(data = get_data(symbol))
p = figure(x_axis_type='datetime', title='Stock Price', plot_height=350, plot_width=800)
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.5
p.xaxis.axis_label = 'year'
p.yaxis.axis_label = 'close'
r = p.line(source.data['date'],
source.data['high'],
line_color = 'navy')
select = Select(title="Color", value="navy", options=COLORS)
input = TextInput(title="Ticker Symbol", value=symbol)
def update_symbol(attrname, old, new):
source.data = get_data(input.value)
input.on_change('value', update_symbol)
layout = column(row(input, width=400), row(p))
doc.add_root(layout)
show(modify_doc)
I would think that the plot would update when the new symbol is entered, but it just stays the same.
Any thoughts?
Your code looks like Bokeh server application but you use show() what doesn't look good to me. You are also trying to update the figure by assigning new data to the source but you did not pass your source to the figure object so it won't have any effect. Could you try if this code works for you? (should work for Bokeh v1.0.4)
import random
import pandas as pd
from tornado.ioloop import IOLoop
from bokeh.server.server import Server
from bokeh.application import Application
from bokeh.application.handlers.function import FunctionHandler
from bokeh.plotting import figure, ColumnDataSource
from bokeh.models.widgets import TextInput
from bokeh.layouts import column, row
def make_document(doc):
symbol = 'AAWW'
def get_data(symbol):
dictionary = {}
data = quandl.get('WIKI/' + symbol, collapse = 'annual', returns = 'numpy')
df = pd.DataFrame(data)
dictionary['date'] = list(df.Date.values)
dictionary['high'] = list(df.High.values)
return dictionary
source = ColumnDataSource(data = get_data(symbol))
p = figure(x_axis_type = 'datetime', title = 'Stock Price', plot_height = 350, plot_width = 800)
p.xgrid.grid_line_color = None
p.ygrid.grid_line_alpha = 0.5
p.xaxis.axis_label = 'year'
p.yaxis.axis_label = 'close'
r = p.line(x = 'date',
y = 'high',
source = source,
line_color = 'navy')
input = TextInput(title = "Ticker Symbol", value = symbol)
def update_symbol(attrname, old, new):
source.data = get_data(input.value)
input.on_change('value', update_symbol)
layout = column(row(input, width = 400), row(p))
doc.add_root(layout)
io_loop = IOLoop.current()
server = Server({'/myapp': Application(FunctionHandler(make_document))}, port = 5001, io_loop = io_loop)
server.start()
server.show('/myapp')
io_loop.start()
Basically the main change is here:
r = p.line(x = 'date',
y = 'high',
source = source,
line_color = 'navy')
Based on the answer I got from Tony, I just had to change one line of code:
r = p.line(x = 'date',
y = 'high',
source = source,
line_color = 'navy')

Interaction with multiple widgets Bokeh

EDIT: Some users have mentioned that the question is unclear. My objective is to keep track of previous states.
I am trying to create a plot that can be modified using 3 widgets. However, every new widget change does not take into consideration previous widget selections (for example, if a selection is made using widget 1 and then widget 2 is modified, the modification of widget 2 considers the original graph and not the changes made with widget 1).
I am trying to avoid using Custom_JS as I have no experience with Javascript. Is there any way to combine the functions so that any change in the widgets takes into consideration previous widget interactions?
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib
from datetime import date
from ipywidgets import interact
from bokeh.io import push_notebook, show, output_notebook, curdoc
from bokeh.plotting import figure
from bokeh.layouts import column, layout, widgetbox, row
from bokeh.models import ColumnDataSource, HoverTool, CustomJS, Panel
from bokeh.layouts import widgetbox
from bokeh.models.widgets import RangeSlider, Slider, Select,
DateRangeSlider, Tabs
df = pd.read_csv("/Users/danielmontillanavas/Desktop/Tiller/00_Data/SF_may_correct_decimal.csv", sep =',',decimal=',')
df = df.drop(['Unnamed: 0'], axis=1)
df.rename(columns = {'Stamped phone from HS':'phone','Contact Email':'Email','Account Name':'Account_name',
'Opportunity ID':'ID', 'Close Date':'Close_date','Stamped-date of closed (DO NOT USE)':'Stamped_date',
'Quote Amount':'Quote_Amount', 'Lead Source':'Source','Desired activation date':'Activ_date'},
inplace=True)
df.Close_date = pd.to_datetime(df.Close_date, format='%Y-%m-%d')
cols_num = ['Quote_Amount','DISCOUNT']
df[cols_num] = df[cols_num].apply(pd.to_numeric)
df_closed = df[df['Stage']=='Closed']
df_closed.fillna("Unknown", inplace=True)
start_point = min(df['Quote_Amount'])
end_point = max(df['Quote_Amount'])
TOOLS = 'pan,wheel_zoom,box_zoom,reset,tap,save,box_select,lasso_select'
source = ColumnDataSource(df_closed)
hover = HoverTool(
tooltips=[
("Quote", "$x"),
("Discount", "$y")
]
)
p = figure(title='Quotes per Source - Closed deals',tools=[hover,TOOLS],
plot_height=800, plot_width=800)
p.circle('Quote_Amount','DISCOUNT',source=source, size = 8, color = 'CornflowerBlue', alpha = 0.6)
N = 20000
slider = Slider(start=start_point, end=end_point, step=10, value=N,
title='Select Quote Amount Cutoff')
dfList = df_closed.Source.unique().tolist()
All_view = ['All']
source_options = All_view + dfList
menu = Select(title = "Select Lead Source",options=source_options, value = 'All')
first_date = min(df['Close_date'])
last_date = max(df['Close_date'])
date_range_slider = DateRangeSlider(title="Select Date Range ", start=first_date, end=date.today(), value=(date(2017, 9, 7), date(2017, 10, 15)), step=1)
def slider_callback(attr, old, new):
N = new # this works also with slider.value but new is more explicit
new1 = ColumnDataSource(df_closed.loc[(df_closed.Quote_Amount < N)])
source.data = new1.data
slider.on_change('value',slider_callback)
def menu_callback(attr, old, new):
if menu.value == 'All': new2 = ColumnDataSource(df_closed)
else: new2 = ColumnDataSource(df_closed.loc[(df_closed.Source == menu.value)])
source.data = new2.data
menu.on_change('value',menu_callback)
def date_callback(attr, old, new):
start = date_range_slider.value_as_datetime[0].strftime("%Y-%m-%d")
end = date_range_slider.value_as_datetime[1].strftime("%Y-%m-%d")
df_closed_new = df_closed[df_closed['Close_date'] >= start]
df_closed_new = df_closed[df_closed['Close_date'] <= end]
new3 = ColumnDataSource(df_closed_new)
source.data = new3.data
date_range_slider.on_change('value',date_callback)
# Put controls in a single element
controls = widgetbox(menu, slider, date_range_slider)
# Create a row layout
layout = row(controls, p)
curdoc().add_root(layout)
You question is not very clear to me. Are you talking about the previous state of widgets? The callbacks have access to the current state of all the other widgets so if you want to maintain a history of their previous states you'll have to explicitly keep track of that.
However I immediately notice on thing that should not be done, so I am going to post an answer just to draw attention to it. Don't create new CDS objects just to use their .data attribute and throw them away:
new1 = ColumnDataSource(df_closed.loc[(df_closed.Quote_Amount < N)])
source.data = new1.data
There is alot of machinery under the covers that affords all the automatic synchronization other features of Bokeh. CDS in particular are extremely heavyweight, complicated objects, and doing this above is a known anti-pattern that can break things. Instead, if you just need a new suitable .data dict, then use from_df:
new_data = ColumnDataSource.from_df(df_closed.loc[(df_closed.Quote_Amount < N)])
source.data = new_data

Resources