from bokeh.io import vform
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import Figure, output_file, show

output_file("callback.html")

x = [x*0.005 for x in range(0, 200)]
y = x

source = ColumnDataSource(data=dict(x=x, y=y))

plot = Figure(plot_width=400, plot_height=400)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

callback = CustomJS(args=dict(source=source), code="""
        var data = source.get('data');
        var f = cb_obj.get('value')
        x = data['x']
        y = data['y']
        for (i = 0; i < x.length; i++) {
            y[i] = Math.pow(x[i], f)
        }
        source.trigger('change');
    """)

slider = Slider(start=0.1, end=4, value=1, step=.1, title="power", callback=callback)

layout = vform(slider, plot)

show(layout)

"""
Explanation: Data apps
Much of the motivation for this section came from the experience of making data apps in R on the Shiny platform.
A simple app for querying the WISE catalog and displaying sources is this one I wrote on a Sunday afternoon for a data science class.
A sophisticated Shiny app is this one for photometric redshift estimation using generalized linear models.
How to make apps in Python?
Unfortunately, for publishing data apps, there is not a Python equivalent to Shiny, that makes it easy to host apps and is free of charge. This blog post shows an example from a commercial enterprise.
For now, we will skip the publishing aspect and focus on making a personal app that you run yourself in the notebook (or can give to colleagues to run). 
Bokeh widgets
Adding Widgets
Bokeh provides a simple default set of widgets, largely based off the Bootstrap JavaScript library. In the future, it will be possible for users to wrap and use other widget libraries, or their own custom widgets. By themselves, most widgets are not useful. There are two ways to use widgets to drive interactions:

Use the CustomJS callback. This will work in static HTML documents.
Use the bokeh-server and set up event handlers with .on_change.

The current value of interactive widgets is available from the .value attribute.
End of explanation
"""


from bokeh.models.widgets import Slider, RadioGroup, Button
from bokeh.io import output_file, show, vform
from bokeh.plotting import figure

output_file("queryWise.html")



band = RadioGroup(labels=["3.5 microns", "4.5 microns",
                          "12 microns", "22 microns"], active=0)

fov = Slider(start=5, end=15, value=5, step=.25, title="Field of View (arcmin)")
ra = Slider(start=0, end=359, value=120, step=1, title="Right Ascension (degrees)")
dec = Slider(start=-90, end=90, value=0, step=1, title="Declination (degrees)")
button = Button(label="Submit")

p = figure(plot_width=400, plot_height=400,
           tools="tap", title="WISE sources")

p.circle(ra.value, dec.value)
show(vform(fov,band,ra,dec,button, p))


"""
Explanation: The next cell shows the start of how to set up something like the WISE app.
End of explanation
"""


from ipywidgets import *

from IPython.display import display
fov = FloatSlider(value = 5.0,
                 min = 5.0,
                 max = 15.0,
                 step = 0.25)
display(fov)

"""
Explanation: The rest of the notebook is not currently working
An attempt at a simple app
Since the slider does not display...there is some problem with my installation for using widgets in the notebook.
End of explanation
"""


%matplotlib notebook
import pandas as pd 
import matplotlib.pyplot as plt 
from ipywidgets import * 
from IPython.display import display 
##from jnotebook import display
from IPython.html import widgets 
plt.style.use('ggplot')

NUMBER_OF_PINGS = 4

#displaying the text widget
text = widgets.Text(description="Domain to ping", width=200) 
display(text)

#preparing the plot
data = pd.DataFrame() 
x = range(1,NUMBER_OF_PINGS+1) 
plots = dict() 
fig, ax = plt.subplots() 
plt.xlabel('iterations') 
plt.ylabel('ms') 
plt.xticks(x) 
plt.show()

#preparing a container to put in created checkbox per domain
checkboxes = [] 
cb_container = widgets.HBox() 
display(cb_container)

#add button that updates the graph based on the checkboxes
button = widgets.Button(description="Update the graph")

#function to deal with the added domain name
def handle_submit(sender): 
    #a part of the magic inside python : pinging
    res = !ping -c {NUMBER_OF_PINGS} {text.value}
    hits = res.grep('64 bytes').fields(-2).s.replace("time=","").split()
    if len(hits) == 0:
        print("Domain gave error on pinging")
    else:
        #rebuild plot based on ping result
        data[text.value] = hits
        data[text.value] = data[text.value].astype(float)
        plots[text.value], = ax.plot(x, data[text.value], label=text.value)
        plt.legend()
        plt.draw()
        #add a new checkbox for the new domain
        checkboxes.append(widgets.Checkbox(description = text.value, value=True, width=90))
        cb_container.children=[i for i in checkboxes]
        if len(checkboxes) == 1:
            display(button)

#function to deal with the checkbox update button     
def on_button_clicked(b): 
    for c in cb_container.children:
        if not c.value:
            plots[c.description].set_visible(False)
        else:
            plots[c.description].set_visible(True)
    plt.legend()
    plt.draw()

button.on_click(on_button_clicked) 
text.on_submit(handle_submit) 
plt.show()


"""
Explanation: Example from the blog post
End of explanation
"""


