''' Present a scatter plot with linked histograms on both axes.
Use the ``bokeh serve`` command to run the example by executing:
    bokeh serve basic_selection_profile.py
at your command prompt. Then navigate to the URL
    http://localhost:5006/basic_selection_profile
in your browser.

Once the system is up and running all lines in the right panel are red
(this is what the code should do)
Then experience indicate that first the plot needs to be reset
and then the selection tool works nicely
however, warnings are generated indicated that the ColumnDataSource colunms are not of same size
in fact the warning message indicates that "xs" column has the correct size, but the "ys" column has not been updated.

'''
from numpy import random, linspace, sin, pi, array, ndarray
from bokeh.layouts import row, column
from bokeh.models import BoxSelectTool, LassoSelectTool, Spacer, ColumnDataSource, CDSView, IndexFilter
from bokeh.plotting import figure, curdoc
from bokeh.models import Range1d

def make_some_data(**kwargs):
    """A naive way to create some data"""

    data_set={}
    # one dimensional
    data_set["x"] = linspace(0,int(kwargs["array_size"])-1,kwargs["array_size"])+1
    data_set["y"] = random.normal(loc=5.0, size=kwargs["array_size"]) 
    # two dimensional
    z = linspace(0,359,360)
    data_set["xs"]=[]
    data_set["ys"] = []
    for index in linspace(0,data_set["x"].shape[0]-1, data_set["x"].shape[0],dtype="int"):
        data_set["ys"].append(z)
        data_set["xs"].append( data_set["y"][index]*sin(z*data_set["x"][index]*2*pi/360.))
    # make them numpy arrays
    data_set["xs"] = array(data_set["xs"])
    data_set["ys"] = array(data_set["ys"])

    return data_set

# create some waves
# larger values create busy plots.
#
kiwi={"array_size":10}
data_to_explore= make_some_data(**kiwi)

# use some intrinsic function to create the scatter plot data
# in line with recommendation
scatter_data={"x":data_to_explore["x"],"y":data_to_explore["y"]}
scatter_data_source = ColumnDataSource(data=scatter_data)

# for the multi line plot only 1D lists can be used

xs = ndarray.tolist(data_to_explore["xs"])
ys = ndarray.tolist(data_to_explore["ys"])

TOOLS="pan,wheel_zoom,box_select,lasso_select,reset"

# create the scatter plot
p = figure(tools=TOOLS, plot_width=600, plot_height=600, min_border=10, min_border_left=50,
        toolbar_location="above", x_axis_location=None, y_axis_location=None,
        title="Linked Profile")
# some decorations
p.background_fill_color = "#fafafa"
p.select(BoxSelectTool).select_every_mousemove = False
p.select(LassoSelectTool).select_every_mousemove = False

# nice sized symbols

r = p.scatter(x="x", y="y", size=20, color="#3A5785", alpha=0.6, source=scatter_data_source)

# now the line plot

pv = figure(toolbar_location=None, plot_width=200, plot_height=p.plot_height, 
             min_border=10, min_border_left=50, y_axis_location="right")

# some decorations

pv.xaxis.major_label_orientation = pi/4
pv.background_fill_color = "#fafafa"

pv.multi_line(xs=xs[:], ys=ys[:], line_color="grey", alpha=0.5)
pv2 = pv.multi_line(xs=xs[:], ys=ys[:], line_color="tomato", line_width=2)

# put them on a graph

layout = column(row(p, pv))

curdoc().add_root(layout)
curdoc().title = "Selection Profile"

def update(attr, old, new):
    #
    # not clear what really happens here
    # but from the example, the selection
    # action creates a list of indices
    # which can be used to update the line plot
    #
    inds = array(new['1d']['indices'])        
    update_xst = []
    update_yst = []
    for i in inds:
        update_xst.append(xs[i])
        update_yst.append(ys[i])
    
    pv2.data_source.data["xs"] = update_xst
    pv2.data_source.data["ys"] = update_yst

r.data_source.on_change('selected', update)
