This file implements a bokeh applet for returns distribution.
It requires a bokeh-server.
See the README.md file in this directory for instructions on running.

import logging


import numpy as np

from bokeh.plotting import figure
from bokeh.models import Plot, ColumnDataSource, DataRange1d, TapTool, Circle
from bokeh.properties import Instance
from bokeh.server.app import bokeh_app
from bokeh.server.utils.plugins import object_page
from bokeh.models.widgets import HBox, VBox, Slider, TextInput, VBoxForm

class StockApp(VBox):
    """ Applet for exploring the returns of a stock """
    extra_generated_classes = [['StockApp', 'StockApp', 'VBox']]
    stock_plot = Instance(Plot)
    source = Instance(ColumnDataSource)

    def create_stock(cls, source):

        # xdr1 = DataRange1d(sources=[source.columns("x")])
        # ydr1 = DataRange1d(sources=[source.columns("y")])

        # plot1 = figure(title="Outliers", x_range=xdr1, y_range=ydr1, plot_width=650, plot_height=400)
        stock_plot = figure(title="", plot_width=650, plot_height=400)
        # stock_plot.tools.append(TapTool(plot=stock_plot))
        # stock_plot.line(x="x", y="values", size=12, color="blue", line_dash=[2, 4], source=source)
        return stock_plot
        # plot1.scatter(x="x", y="y", size="size", fill_color="red", source=source)

    def create(clz):
        """One-time creation of app's objects.

        This function is called once, and is responsible for
        creating all objects (plots, datasources, etc)
        self = clz()
        n_vals = 1000
        self.source = ColumnDataSource(
                x= np.arange(n_vals),
                values= np.random.randn(n_vals)

        # Generate a figure container
        self.stock_plot = clz.create_stock(self.source)

    def setup_events(self):
        """Attaches the on_change event to the value property of the widget.

        The callback is set to the input_change method of this app.
        super(StockApp, self).setup_events()

        logging.debug("%s" % str(self.source))
        # Slider event registration
        # self.source.on_change('selected', self, 'on_selection_change')
        self.stock_plot.on_change('value', self, 'input_change')
        # self.outliers_source.on_change('selected', self, 'on_selection_change')
        # for w in ["bins"]:
        #     getattr(self, w).on_change('value', self, 'input_change')

    def input_change(self, obj, attrname, old, new):
        """Executes whenever the input form changes.

        It is responsible for updating the plot, or anything else you want.

            obj : the object that changed
            attrname : the attr that changed
            old : old value of attr
            new : new value of attr

    def update_data(self):
        """Called each time that any watched property changes.

        This updates the sin wave data with the most recent values of the
        sliders. This is stored as two numpy arrays in a dict into the app's
        data histogram_source property.
        n_vals = 1000
        self.source.data = dict(top=hist, bottom=0, left=0, right = 0, x=np.arange(n_vals), values=np.random.randn(n_vals))

    def on_selection_change(self, attr, _, inds, x):

# The following code adds a "/bokeh/sliders/" url to the bokeh-server. This
# URL will render this sine wave sliders app. If you don't want to serve this
# applet from a Bokeh server (for instance if you are embedding in a separate
# Flask application), then just remove this block of code.
def make_stock():
    app = StockApp.create()
    return app