from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import colorsys
from rowers.models import (
    Workout, User, Rower, WorkoutForm,RowerForm,
    GraphImage,GeoPolygon,GeoCourse,GeoPoint
    )
from rowingdata import rower as rrower
from rowingdata import main as rmain
from rowingdata import cumcpdata,histodata

from rowingdata import rowingdata as rrdata
from math import pi
from django.utils import timezone
from rowingdata import make_cumvalues

from bokeh.palettes import Dark2_8 as palette
from bokeh.models.glyphs import MultiLine
import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation

from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
from bokeh.palettes import Category20c,Category10
from bokeh.layouts import row as layoutrow
from bokeh.layouts import column as layoutcolumn
from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool
#from bokeh.io import output_file, show, vplot
from bokeh.models import (
    GMapPlot, GMapOptions, ColumnDataSource, Circle,
    DataRange1d, PanTool, WheelZoomTool, BoxSelectTool,
    SaveTool,   # ResizeTool,
    ResetTool, TapTool,CrosshairTool,BoxZoomTool,
    Span, Label
)
from  bokeh.transform import cumsum
from bokeh.models.glyphs import ImageURL
from bokeh.models import OpenURL, TapTool
from rowers.opaque import encoder
#from bokeh.models.widgets import Slider, Select, TextInput
from bokeh.core.properties import value

from collections import OrderedDict
from django.conf import settings

from rowers.courses import (
    course_coord_center,course_coord_maxmin,
    polygon_coord_center
    )

from rowers import mytypes
from rowers.models import course_spline

import datetime
import math
import numpy as np
import pandas as pd
import holoviews as hv
from holoviews import opts
from pytz import timezone as tz,utc
from django.utils.timezone import get_current_timezone
from django.utils.timezone import activate
from django.utils import timezone
activate(settings.TIME_ZONE)
thetimezone = get_current_timezone()

from scipy.stats import linregress,percentileofscore
from scipy.spatial import ConvexHull,Delaunay
from scipy import optimize
from scipy.signal import savgol_filter
from scipy.interpolate import griddata


import rowers.stravastuff as stravastuff

from rowers.dataprep import rdata
import rowers.dataprep as dataprep
import rowers.metrics as metrics
import rowers.c2stuff as c2stuff

from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima

from rowers.utils import lbstoN
from rowers.datautils import p0
import rowers.datautils as datautils


def errorbar(fig, x, y, source=ColumnDataSource(),
             xerr=False, yerr=False, color='black',
             point_kwargs={}, error_kwargs={}):


    xvalues = source.data[x]
    yvalues = source.data[y]


    xerrvalues = source.data['xerror']
    yerrvalues = source.data['yerror']
    try:
        colorvalues = source.data['color']
    except KeyError:
        colorvalues = ["#%02x%02x%02x" % (255,0,0) for x in xvalues]


    try:
        a = xvalues[0]+1
        if xerr:
            x_err_x = []
            x_err_y = []
            err_color = []
            for px, py, err, color in zip(xvalues, yvalues, xerrvalues, colorvalues):
                x_err_x.append((px - err, px + err))
                x_err_y.append((py, py))
                (r, g, b) = tuple(int(color[i:i+2],16) for i in (1, 3, 5))
                h,s,v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
                v = v*0.8
                r, g, b = colorsys.hsv_to_rgb(h, s, v)
                color2 = "#%02x%02x%02x" % (int(255.*r), int(255.*g), int(255*b))
                err_color.append(color2)

            fig.multi_line(x_err_x, x_err_y, color=err_color,
                           name='xerr',
                           **error_kwargs)
    except TypeError:
        pass

    try:
        a = yvalues[0]+1
        if yerr:
            y_err_x = []
            y_err_y = []
            err_color = []
            for px, py, err, color in zip(xvalues, yvalues, yerrvalues, colorvalues):
                y_err_x.append((px, px))
                y_err_y.append((py - err, py + err))
                (r, g, b) = tuple(int(color[i:i+2],16) for i in (1, 3, 5))
                h,s,v = colorsys.rgb_to_hsv(r/255., g/255., b/255.)
                v = v*0.8
                r, g, b = colorsys.hsv_to_rgb(h, s, v)
                color2 = "#%02x%02x%02x" % (int(255.*r), int(255.*g), int(255*b))
                err_color.append(color2)

            fig.multi_line(y_err_x, y_err_y, color=err_color,
                           name='yerr',**error_kwargs)
    except TypeError:
        pass

    fig.circle(x, y, source=source, name='data',color=color,
               **point_kwargs)


def tailwind(bearing,vwind,winddir):
    """ Calculates head-on head/tailwind in direction of rowing

    positive numbers are tail wind

    """

    b = np.radians(bearing)
    w = np.radians(winddir)

    vtail = -vwind*np.cos(w-b)

    return vtail


from rowers.dataprep import nicepaceformat,niceformat
from rowers.dataprep import timedeltaconv

from math import pi

def interactive_hr_piechart(df,rower,title,totalseconds=0):
    if df.empty:
        return "","Not enough data to make a chart"



    df.sort_values(by='hr',inplace=True)
    df['timehr'] = df['deltat']*df['hr']

    sumtimehr = df['deltat'].sum()

    if totalseconds == 0:
        totalseconds = sumtimehr



    qry = 'hr < {ut2}'.format(ut2=rower.ut2)
    frac_lut2 = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr

    qry = '{ut2} <= hr < {ut1}'.format(ut1=rower.ut1,ut2=rower.ut2)
    frac_ut2 = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr

    qry = '{ut1} <= hr < {at}'.format(ut1=rower.ut1,at=rower.at)
    frac_ut1 = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr

    qry = '{at} <= hr < {tr}'.format(at=rower.at,tr=rower.tr)
    frac_at = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr

    qry = '{tr} <= hr < {an}'.format(tr=rower.tr,an=rower.an)
    frac_tr = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr

    qry = 'hr >= {an}'.format(an=rower.an)
    frac_an = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr

    datadict = {
        '<ut2':frac_lut2,
        'ut2': frac_ut2,
        'ut1': frac_ut1,
        'at': frac_at,
        'tr': frac_tr,
        'an': frac_an,
    }



    colors = ['gray','yellow','lime','blue','purple','red']



    data = pd.Series(datadict).reset_index(name='value').rename(columns={'index':'zone'})
    data['angle'] = data['value']/data['value'].sum() * 2*pi
    data['color'] = colors
    data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']])



    size=350
    TOOLS = 'save,hover'


    z = figure(title="HR "+title, x_range=(-0.5,1), plot_height=375,
               tools=TOOLS,toolbar_location=None,tooltips="@zone: @totaltime",
          )



    z.wedge(x=0,y=1, radius=0.4,
            start_angle=cumsum('angle',include_zero=True), end_angle=cumsum('angle'),
            line_color='white',fill_color='color',source=data,legend='zone')



    z.axis.axis_label = None
    z.axis.visible = False
    z.grid.grid_line_color = None
    z.outline_line_color = None
    z.toolbar_location = 'right'


    return components(z)

def pretty_timedelta(secs):
    hours, remainder = divmod(secs,3600)
    minutes, seconds = divmod(remainder,60)

    return '{}:{:02}:{:02}'.format(int(hours),int(minutes),int(seconds))

def interactive_workouttype_piechart(workouts):
    if len(workouts) == 0:
        return "","Not enough workouts to make a chart"

    datadict = {}


    for w in workouts:
        try:
            # label = mytypes.workouttypes_ordered[w.workouttype]
            label = w.workouttype
        except KeyError:
            label = w.workouttype
        try:
            datadict[label] += 60*(60*w.duration.hour+w.duration.minute)+w.duration.second
        except KeyError:
            datadict[label] = 60*(60*w.duration.hour+w.duration.minute)+w.duration.second

    data = pd.Series(datadict).reset_index(name='value').rename(columns={'index':'type'})
    data['angle'] = data['value']/data['value'].sum() * 2*pi




    data = pd.DataFrame(data)
    data['color'] = data['type'].apply(lambda x:mytypes.color_map[x])
    data['totaltime'] = data['value'].apply(lambda x:pretty_timedelta(x))
    data['type'] = data['type'].apply(lambda x:mytypes.workouttypes_ordered[x])


    p = figure(plot_height=350, title="Types", toolbar_location=None,
           tools="hover,save", tooltips="@type: @totaltime", x_range=(-0.5, 1.0))

    p.wedge(x=0, y=1, radius=0.4,
        start_angle=cumsum('angle', include_zero=True), end_angle=cumsum('angle'),
        line_color="white", fill_color='color', source=data,legend='type', )

    p.axis.axis_label=None
    p.axis.visible=False
    p.grid.grid_line_color = None
    p.outline_line_color = None
    p.toolbar_location = 'right'

    return components(p)



def interactive_boxchart(datadf,fieldname,extratitle='',
                         spmmin=0,spmmax=0,workmin=0,workmax=0):

    if datadf.empty:
        return '','It looks like there are no data matching your filter'

    tooltips = [
        ('Value', '@'+fieldname),
        ]

    hover = HoverTool(tooltips=tooltips)

    TOOLS = [hover]


    hv.extension('bokeh')

    boxwhiskers = hv.BoxWhisker(datadf,'date',fieldname)
    boxwhiskers.opts(tools=TOOLS,outlier_color='white')


    plot = hv.render(boxwhiskers)

    yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
    plot.y_range = yrange1
    plot.sizing_mode = 'scale_width'

    plot.xaxis.axis_label = 'Date'
    plot.yaxis.axis_label = axlabels[fieldname]


    plot.xaxis.formatter = DatetimeTickFormatter(
        days=["%d %B %Y"],
        months=["%d %B %Y"],
        years=["%d %B %Y"],
        )

    if fieldname == 'pace':
        plot.yaxis[0].formatter = DatetimeTickFormatter(
                seconds = ["%S"],
                minutes = ["%M"]
            )


    plot.xaxis.major_label_orientation = pi/4

    plot.plot_width=920
    plot.plot_height=600

    slidertext = 'SPM: {:.0f}-{:.0f}, WpS: {:.0f}-{:.0f}'.format(
        spmmin,spmmax,workmin,workmax
        )
    sliderlabel = Label(x=50,y=20,x_units='screen',y_units='screen',
                        text=slidertext,
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='black',text_font_size='10pt',
                        )

    plot.add_layout(sliderlabel)

    script, div = components(plot)

    return script,div


def interactive_planchart(data,startdate,enddate):
    source = ColumnDataSource(data)

    hv.extension('bokeh')


    yaxmaximum = data['executed'].max()
    if data['planned'].max() > yaxmaximum:
        yaxmaximum = data['planned'].max()

    if yaxmaximum == 0:
        yaxmaximum = 250

    yrange1 = Range1d(start=0,end=1.1*yaxmaximum)


    tidy_df = data.melt(id_vars=['startdate'],value_vars=['executed','planned'])
    bars = hv.Bars(tidy_df,['startdate','variable'],['value'])
    bars.opts(
        opts.Bars(show_legend=True,tools=['tap','hover'],legend_position='bottom',show_frame=True))

    p = hv.render(bars)

    p.plot_width=550
    p.plot_height=350
    p.y_range = yrange1
    p.toolbar_location = 'above'
    p.sizing_mode = 'scale_width'

    script,div = components(p)

    return script,div

def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_location=None):

    dates = []
    dates_sorting = []
    types = []
    rowers = []
    durations = []
    links = []


    rowersinitials = {}
    seen = ['seen']
    idseen = []

    startdate = datetime.datetime(year=startdate.year,month=startdate.month,day=startdate.day)
    enddate = datetime.datetime(year=enddate.year,month=enddate.month,day=enddate.day)

    duration = enddate-startdate

    totaldays = duration.total_seconds()/(24*3600)


    for w in workouts:
        aantal=1
        initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
        if w.user.id not in idseen:
            while initials in seen:
                aantal += 1
                initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]

            seen.append(initials)
            idseen.append(w.user.id)
            rowersinitials[w.user.id] = initials



    for w in workouts:
        dd = w.date.strftime('%m/%d')
        dd2 = w.date.strftime('%Y/%m/%d')
        dd3 = w.date.strftime('%Y/%m')
        du = w.duration.hour*60+w.duration.minute

        if totaldays<30:
            dates.append(dd)
            dates_sorting.append(dd2)
        else:
            dates.append(dd3)
            dates_sorting.append(dd3)
        durations.append(du)
        links.append(
            "{siteurl}/rowers/workout/{code}/".format(
                siteurl = settings.SITE_URL,
                code = encoder.encode_hex(w.id)
                )
        )


        types.append(w.workouttype)
        try:
            rowers.append(rowersinitials[w.user.id])
        except IndexError:
            rowers.append(str(w.user))

    try:
        d = utc.localize(startdate)
    except (ValueError,AttributeError):
        d = startdate

    try:
        enddate = utc.localize(enddate)
    except (ValueError,AttributeError):
        pass

    # add dates with no activity
    while d<=enddate:
        dd = d.strftime('%d')


        if totaldays<30:
            dates.append(d.strftime('%m/%d'))
            dates_sorting.append(d.strftime('%Y/%m/%d'))
        else:
            dates.append(d.strftime('%Y/%m'))
            dates_sorting.append(d.strftime('%Y/%m'))
        durations.append(0)
        links.append('')
        types.append('rower')

        try:
            rowers.append(rowers[0])
        except IndexError:
            try:
                rowers.append(str(workouts[0].user))
            except IndexError:
                rowers.append(' ')

        d += datetime.timedelta(days=1)


    thedict = {
        'date':dates,
        'date_sorting':dates_sorting,
        'duration':durations,
        'type':types,
        'rower':rowers,
        'link':links,
        }

    dim_expr = hv.dim('type').categorize(mytypes.color_map)

    df = pd.DataFrame(thedict)

    source = ColumnDataSource(df)

    df.sort_values('date_sorting',inplace=True)
    #clrs = hv.Cycle(df['colors'].values)

    hv.extension('bokeh')

    if stack == 'type':
        table = hv.Table(df,[('date','Date'),('type','Workout Type')],[('duration','Minutes'),('link','link')])

    else:
        table = hv.Table(df,[('date','Date'),('rower','Rower')],[('duration','Minutes'),('link','link')])


    bars=table.to.bars(['date',stack],['duration'])
    bars.opts(
        opts.Bars(color=hv.Cycle('Category10'), show_legend=True, stacked=True,
                  tools=['tap','hover'], width=550, xrotation=45,padding=(0,(0,.1)),
                  legend_position='bottom',show_frame=True))



    p = hv.render(bars)

    p.title.text = 'Activity {d1} to {d2}'.format(
                d1 = startdate.strftime("%Y-%m-%d"),
                d2 = enddate.strftime("%Y-%m-%d"),
                )

    p.plot_width=550
    p.plot_height=350
    p.toolbar_location = toolbar_location
    p.sizing_mode = 'scale_width'
    url = "http://rowsandall.com/rowers/workout/@duration/"
    taptool = p.select(type=TapTool)



    callback = CustomJS(args={'links':df.link}, code="""
      var index = cb_data.source.selected['1d'].indices[0];
      console.log(links);
      console.log(index);
      console.log(links[index]);
      window.location.href = links[index]
    """)

    taptool.callback = callback


    script,div = components(p)
    return script,div

def interactive_activitychart2(workouts,startdate,enddate,stack='type',toolbar_location=None):

    dates = []
    dates_sorting = []
    types = []
    rowers = []
    durations = []
    links = []


    rowersinitials = {}
    seen = ['seen']
    idseen = []

    startdate = datetime.datetime(year=startdate.year,month=startdate.month,day=startdate.day)
    enddate = datetime.datetime(year=enddate.year,month=enddate.month,day=enddate.day)

    duration = enddate-startdate

    totaldays = duration.total_seconds()/(24*3600)


    for w in workouts:
        aantal=1
        initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
        if w.user.id not in idseen:
            while initials in seen:
                aantal += 1
                initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]

            seen.append(initials)
            idseen.append(w.user.id)
            rowersinitials[w.user.id] = initials



    for w in workouts:
        dd = w.date.strftime('%m/%d')
        dd2 = w.date.strftime('%Y/%m/%d')
        dd3 = w.date.strftime('%Y/%m')
        du = w.duration.hour*60+w.duration.minute

        if totaldays<30:
            dates.append(dd)
            dates_sorting.append(dd2)
        else:
            dates.append(dd3)
            dates_sorting.append(dd3)
        durations.append(du)
        links.append(
            "{siteurl}/rowers/workout/{code}/".format(
                siteurl = settings.SITE_URL,
                code = encoder.encode_hex(w.id)
                )
        )


        types.append(w.workouttype)
        try:
            rowers.append(rowersinitials[w.user.id])
        except IndexError:
            rowers.append(str(w.user))

    try:
        d = utc.localize(startdate)
    except (ValueError,AttributeError):
        d = startdate

    try:
        enddate = utc.localize(enddate)
    except (ValueError,AttributeError):
        pass

    # add dates with no activity
    while d<=enddate:
        dd = d.strftime('%d')


        if totaldays<30:
            dates.append(d.strftime('%m/%d'))
            dates_sorting.append(d.strftime('%Y/%m/%d'))
        else:
            dates.append(d.strftime('%Y/%m'))
            dates_sorting.append(d.strftime('%Y/%m'))
        durations.append(0)
        links.append('')
        types.append('rower')

        try:
            rowers.append(rowers[0])
        except IndexError:
            try:
                rowers.append(str(workouts[0].user))
            except IndexError:
                rowers.append(' ')

        d += datetime.timedelta(days=1)


    thedict = {
        'date':dates,
        'date_sorting':dates_sorting,
        'duration':durations,
        'type':types,
        'rower':rowers,
        'link':links,
        }

    dim_expr = hv.dim('type').categorize(mytypes.color_map)

    df = pd.DataFrame(thedict)


    source = ColumnDataSource(df)

    df.sort_values('date_sorting',inplace=True)
    #clrs = hv.Cycle(df['colors'].values)

    hv.extension('bokeh')


    table = hv.Table(df,[('date','Date'),('type','Workout Type')],[('duration','Minutes'),('link','link')])


    bars=table.to.bars(['date',stack],['duration'])
    bars.opts(
        opts.Bars(color=dim_expr, show_legend=True, stacked=True,
                  tools=['tap','hover'], width=550, xrotation=45,padding=(0,(0,.1)),
                  legend_position='bottom',show_frame=True))



    p = hv.render(bars)

    p.title.text = 'Activity {d1} to {d2}'.format(
                d1 = startdate.strftime("%Y-%m-%d"),
                d2 = enddate.strftime("%Y-%m-%d"),
                )

    p.plot_width=550
    p.plot_height=350
    p.toolbar_location = toolbar_location
    p.sizing_mode = 'scale_width'
    url = "http://rowsandall.com/rowers/workout/@duration/"
    taptool = p.select(type=TapTool)



    callback = CustomJS(args={'links':df.link}, code="""
      var index = cb_data.source.selected['1d'].indices[0];
      console.log(links);
      console.log(index);
      console.log(links[index]);
      window.location.href = links[index]
    """)

    taptool.callback = callback


    script,div = components(p)
    return script,div

def interactive_forcecurve(theworkouts,workstrokesonly=True,plottype='scatter'):
    TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'

    ids = [int(w.id) for w in theworkouts]

    boattype = theworkouts[0].boattype

    columns = ['catch','slip','wash','finish','averageforce',
               'peakforceangle','peakforce','spm','distance',
               'workoutstate','driveenergy']


    rowdata = dataprep.getsmallrowdata_db(columns,ids=ids,
                                          workstrokesonly=workstrokesonly)

    rowdata.dropna(axis=1,how='all',inplace=True)
    rowdata.dropna(axis=0,how='any',inplace=True)

    workoutstateswork = [1,4,5,8,9,6,7]
    workoutstatesrest = [3]
    workoutstatetransition = [0,2,10,11,12,13]

    if workstrokesonly:
        try:
            rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
        except KeyError:
            pass

    if rowdata.empty:
        return "","No Valid Data Available","",""


    # quick linear regression
    # peakforce = slope*peakforceangle + intercept
    try:
        slope, intercept, r,p,stderr = linregress(rowdata['peakforceangle'],rowdata['peakforce'])
    except KeyError:
        slope = 0
        intercept = 0

    try:
        covariancematrix = np.cov(rowdata['peakforceangle'],y=rowdata['peakforce'])
        eig_vals, eig_vecs = np.linalg.eig(covariancematrix)

        a = rowdata['peakforceangle']-rowdata['peakforceangle'].median()
        F = rowdata['peakforce']-rowdata['peakforce'].median()

        Rinv = eig_vecs
        R = np.linalg.inv(Rinv)

        x = R[0,0]*a+R[0,1]*F
        y = R[1,0]*a+R[1,1]*F


        x05 = x.quantile(q=0.01)
        x25 = x.quantile(q=0.15)
        x75 = x.quantile(q=0.85)
        x95 = x.quantile(q=0.99)

        y05 = y.quantile(q=0.01)
        y25 = y.quantile(q=0.15)
        y75 = y.quantile(q=0.85)
        y95 = y.quantile(q=0.99)

        a25 = Rinv[0,0]*x25 + rowdata['peakforceangle'].median()
        F25 = Rinv[1,0]*x25 + rowdata['peakforce'].median()

        a25b = Rinv[0,1]*y25 + rowdata['peakforceangle'].median()
        F25b = Rinv[1,1]*y25 + rowdata['peakforce'].median()

        a75 = Rinv[0,0]*x75 + rowdata['peakforceangle'].median()
        F75 = Rinv[1,0]*x75 + rowdata['peakforce'].median()

        a75b = Rinv[0,1]*y75 + rowdata['peakforceangle'].median()
        F75b = Rinv[1,1]*y75 + rowdata['peakforce'].median()


        a05 = Rinv[0,0]*x05 + rowdata['peakforceangle'].median()
        F05 = Rinv[1,0]*x05 + rowdata['peakforce'].median()

        a05b = Rinv[0,1]*y05 + rowdata['peakforceangle'].median()
        F05b = Rinv[1,1]*y05 + rowdata['peakforce'].median()

        a95 = Rinv[0,0]*x95 + rowdata['peakforceangle'].median()
        F95 = Rinv[1,0]*x95 + rowdata['peakforce'].median()

        a95b = Rinv[0,1]*y95 + rowdata['peakforceangle'].median()
        F95b = Rinv[1,1]*y95 + rowdata['peakforce'].median()
    except KeyError:
        a25 = 0
        F25 = 0

        a25b = 0
        F25b = 0

        a75 = 0
        F75 = 0

        a75b = 0
        F75b = 0


        a05 = 0
        F05 = 0

        a05b = 0
        F05b = 0

        a95 = 0
        F95 = 0

        a95b = 0
        F95b = 0



    try:
        catchav = rowdata['catch'].median()
        catch25 = rowdata['catch'].quantile(q=0.25)
        catch75 = rowdata['catch'].quantile(q=0.75)
        catch05 = rowdata['catch'].quantile(q=0.05)
        catch95 = rowdata['catch'].quantile(q=0.95)
    except KeyError:
        catchav = 0
        catch25 = 0
        catch75 = 0
        catch05 = 0
        catch95 = 0

    try:
        finishav = rowdata['finish'].median()
        finish25 = rowdata['finish'].quantile(q=0.25)
        finish75 = rowdata['finish'].quantile(q=0.75)
        finish05 = rowdata['finish'].quantile(q=0.05)
        finish95 = rowdata['finish'].quantile(q=0.95)
    except KeyError:
        finishav = 0
        finish25 = 0
        finish75 = 0
        finish05 = 0
        finish95 = 0

    try:
        washav = (rowdata['finish']-rowdata['wash']).median()
        wash25 = (rowdata['finish']-rowdata['wash']).quantile(q=0.25)
        wash75 = (rowdata['finish']-rowdata['wash']).quantile(q=0.75)
        wash05 = (rowdata['finish']-rowdata['wash']).quantile(q=0.05)
        wash95 = (rowdata['finish']-rowdata['wash']).quantile(q=0.95)
    except KeyError:
        washav = 0
        wash25 = 0
        wash75 = 0
        wash05 = 0
        wash95 = 0

    try:
        slipav = (rowdata['slip']+rowdata['catch']).median()
        slip25 = (rowdata['slip']+rowdata['catch']).quantile(q=0.25)
        slip75 = (rowdata['slip']+rowdata['catch']).quantile(q=0.75)
        slip05 = (rowdata['slip']+rowdata['catch']).quantile(q=0.05)
        slip95 = (rowdata['slip']+rowdata['catch']).quantile(q=0.95)
    except KeyError:
        slipav = 0
        slip25 = 0
        slip75 = 0
        slip05 = 0
        slip95 = 0

    try:
        peakforceav = rowdata['peakforce'].median()
        peakforce25 = rowdata['peakforce'].quantile(q=0.25)
        peakforce75 = rowdata['peakforce'].quantile(q=0.75)
        peakforce05 = rowdata['peakforce'].quantile(q=0.05)
        peakforce95 = rowdata['peakforce'].quantile(q=0.95)
    except KeyError:
        peakforceav = 0
        peakforce25 = 0
        peakforce75 = 0
        peakforce05 = 0
        peakforce95 = 0


    try:
        averageforceav = rowdata['averageforce'].median()
    except KeyError:
        averageforceav = 0

    try:
        peakforceangleav = rowdata['peakforceangle'].median()
        peakforceangle05 = rowdata['peakforceangle'].quantile(q=0.05)
        peakforceangle25 = rowdata['peakforceangle'].quantile(q=0.25)
        peakforceangle75 = rowdata['peakforceangle'].quantile(q=0.75)
        peakforceangle95 = rowdata['peakforceangle'].quantile(q=0.95)
    except KeyError:
        peakforceangleav = 0
        peakforceangle25 = 0
        peakforceangle75 = 0
        peakforceangle05 = 0
        peakforceangle95 = 0


    #thresholdforce /= 4.45 # N to lbs
    thresholdforce = 100 if 'x' in boattype else 200
    points2575 = [
        (catch25,0),  #0
        (slip25,thresholdforce), #1
        (a75,F75),#4
        (a25b,F25b), #9
        (a25,F25), #2
        (wash75,thresholdforce), #5
        (finish75,0), #6
        (finish25,0), #7
        (wash25,thresholdforce), #8
        (a75b,F75b), #3
        (slip75,thresholdforce), #10
        (catch75,0), #11
        ]

    points0595 = [
        (catch05,0),  #0
        (slip05,thresholdforce), #1
        (a95,F95),#4
        (a05b,F05b), #9
        (a05,F05), #2
        (wash95,thresholdforce), #5
        (finish95,0), #6
        (finish05,0), #7
        (wash05,thresholdforce), #8
        (a95b,F95b), #3
        (slip95,thresholdforce), #10
        (catch95,0), #11
        ]



    angles2575 = []
    forces2575 = []

    for x,y in points2575:
        angles2575.append(x)
        forces2575.append(y)


    angles0595 = []
    forces0595 = []

    for x,y in points0595:
        angles0595.append(x)
        forces0595.append(y)





    x = [catchav,
         slipav,
         peakforceangleav,
         washav,
         finishav]

    y = [0,thresholdforce,
         peakforceav,
         thresholdforce,0]



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

    sourceslipwash = ColumnDataSource(
        data = dict(
            xslip = [slipav,washav],
            yslip = [thresholdforce,thresholdforce]
            )
        )

    sourcetrend = ColumnDataSource(
        data = dict(
            x = [peakforceangle25,peakforceangle75],
            y = [peakforce25,peakforce75]
            )
        )

    sourcefit = ColumnDataSource(
        data = dict(
            x = np.array([peakforceangle25,peakforceangle75]),
            y = slope*np.array([peakforceangle25,peakforceangle75])+intercept
            )
        )

    source2 = ColumnDataSource(
        rowdata
        )

    if plottype == 'scatter':
        try:
            sourcepoints = ColumnDataSource(
                data = dict(
                    peakforceangle = rowdata['peakforceangle'],
                    peakforce = rowdata['peakforce']
                )
            )
        except KeyError:
            sourcepoints = ColumnDataSource(
                data = dict(
                    peakforceangle = [],
                    peakforce = []
                    )
                )
    else:
        sourcepoints = ColumnDataSource(
            data = dict(
                peakforceangle = [],
                peakforce = []
                ))


    sourcerange = ColumnDataSource(
        data = dict(
            x2575 = angles2575,
            y2575 = forces2575,
            x0595 = angles0595,
            y0595 = forces0595,
            )
        )

    plot = Figure(tools=TOOLS,
                  toolbar_sticky=False,toolbar_location="above")

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],watermarkx,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    avf = Span(location=averageforceav,dimension='width',line_color='blue',
               line_dash=[6,6],line_width=2)

    plot.patch('x0595','y0595',source=sourcerange,color="red",alpha=0.05)
    plot.patch('x2575','y2575',source=sourcerange,color="red",alpha=0.2)
    plot.line('x','y',source=source,color="red")
    plot.circle('xslip','yslip',source=sourceslipwash,color="red")

    plot.circle('peakforceangle','peakforce',source=sourcepoints,color='black',alpha=0.1)

    if plottype == 'line':
        multilinedatax = []
        multilinedatay = []
        for i in range(len(rowdata)):
            try:
                x = [
                    rowdata['catch'].values[i],
                    rowdata['slip'].values[i]+rowdata['catch'].values[i],
                    rowdata['peakforceangle'].values[i],
                    rowdata['finish'].values[i]-rowdata['wash'].values[i],
                    rowdata['finish'].values[i]
                ]


                y = [
                    0,
                    thresholdforce,
                    rowdata['peakforce'].values[i],
                    thresholdforce,
                    0]
            except KeyError:
                x = [0,0]
                y = [0,0]

            multilinedatax.append(x)
            multilinedatay.append(y)

        sourcemultiline = ColumnDataSource(dict(
            x=multilinedatax,
            y=multilinedatay,
            ))

        sourcemultiline2 = ColumnDataSource(dict(
            x=multilinedatax,
            y=multilinedatay,
            ))

        glyph = MultiLine(xs='x',ys='y',line_color='black',line_alpha=0.05)
        plot.add_glyph(sourcemultiline,glyph)
    else:
        sourcemultiline = ColumnDataSource(dict(
            x=[],y=[]))

        sourcemultiline2 = ColumnDataSource(dict(
            x=[],y=[]))


    plot.line('x','y',source=source,color="red")

    plot.add_layout(avf)

    peakflabel = Label(x=410,y=460,x_units='screen',y_units='screen',
                       text="Fpeak: {peakforceav:6.2f}".format(peakforceav=peakforceav),
                       background_fill_alpha=.7,
                       background_fill_color='white',
                       text_color='blue',
    )

    avflabel = Label(x=420,y=430,x_units='screen',y_units='screen',
                     text="Favg: {averageforceav:6.2f}".format(averageforceav=averageforceav),
                     background_fill_alpha=.7,
                     background_fill_color='white',
                     text_color='blue',
    )

    catchlabel = Label(x=415,y=400,x_units='screen',y_units='screen',
                       text="Catch: {catchav:6.2f}".format(catchav=catchav),
                       background_fill_alpha=0.7,
                       background_fill_color='white',
                       text_color='red',
                       )

    peakforceanglelabel = Label(x=375,y=370,x_units='screen',y_units='screen',
                                text="Peak angle: {peakforceangleav:6.2f}".format(peakforceangleav=peakforceangleav),
                                background_fill_alpha=0.7,
                                background_fill_color='white',
                                text_color='red',
                       )

    finishlabel = Label(x=410,y=340,x_units='screen',y_units='screen',
                        text="Finish: {finishav:6.2f}".format(finishav=finishav),
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='red',
                       )

    sliplabel = Label(x=425,y=310,x_units='screen',y_units='screen',
                      text="Slip: {slipav:6.2f}".format(slipav=slipav-catchav),
                      background_fill_alpha=0.7,
                      background_fill_color='white',
                      text_color='red',
                       )

    washlabel = Label(x=415,y=280,x_units='screen',y_units='screen',
                      text="Wash: {washav:6.2f}".format(washav=finishav-washav),
                      background_fill_alpha=0.7,
                      background_fill_color='white',
                      text_color='red',
    )

    lengthlabel = Label(x=405,y=250, x_units='screen',y_units='screen',
                        text="Length: {length:6.2f}".format(length=finishav-catchav),
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='green'
                        )

    efflengthlabel = Label(x=340,y=220, x_units='screen',y_units='screen',
                        text="Effective Length: {length:6.2f}".format(length=washav-slipav),
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='green'
                        )

    annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
                      text='',
                      background_fill_alpha=0.7,
                      background_fill_color='white',
                      text_color='black',
    )

    sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
                        text='',
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='black',text_font_size='10pt',
                        )


    plot.add_layout(peakflabel)
    plot.add_layout(peakforceanglelabel)
    plot.add_layout(avflabel)
    plot.add_layout(catchlabel)
    plot.add_layout(sliplabel)
    plot.add_layout(washlabel)
    plot.add_layout(finishlabel)
    plot.add_layout(annolabel)
    plot.add_layout(sliderlabel)
    plot.add_layout(lengthlabel)
    plot.add_layout(efflengthlabel)

    plot.xaxis.axis_label = "Angle"
    plot.yaxis.axis_label = "Force (N)"
    plot.title.text = theworkouts[0].name
    plot.title.text_font_size=value("1.0em")

    yrange1 = Range1d(start=0,end=900)
    plot.y_range = yrange1

    xrange1 = Range1d(start=yaxmaxima['catch'],end=yaxmaxima['finish'])
    plot.x_range = xrange1

    callback = CustomJS(args = dict(
        source=source,
        source2=source2,
        sourceslipwash=sourceslipwash,
        sourcepoints=sourcepoints,
        avf=avf,
        avflabel=avflabel,
        catchlabel=catchlabel,
        finishlabel=finishlabel,
        sliplabel=sliplabel,
        washlabel=washlabel,
        peakflabel=peakflabel,
        peakforceanglelabel=peakforceanglelabel,
        annolabel=annolabel,
        sliderlabel=sliderlabel,
        lengthlabel=lengthlabel,
        efflengthlabel=efflengthlabel,
        plottype=plottype,
        sourcemultiline=sourcemultiline,
        sourcemultiline2=sourcemultiline2
    ), code="""
       var data = source.data
       var data2 = source2.data
       var dataslipwash = sourceslipwash.data
       var datapoints = sourcepoints.data
       var multilines = sourcemultiline.data
       var multilines2 = sourcemultiline2.data
       var plottype = plottype

       var multilinesx = multilines2['x']
       var multilinesy = multilines2['y']

       var x = data['x']
       var y = data['y']

       var xslip = dataslipwash['xslip']

       var spm1 = data2['spm']
       var distance1 = data2['distance']
       var driveenergy1 = data2['driveenergy']

       var thresholdforce = y[1]

       var c = source2.data['catch']
       var finish = data2['finish']
       var slip = data2['slip']
       var wash = data2['wash']
       var peakforceangle = data2['peakforceangle']
       var peakforce = data2['peakforce']
       var averageforce = data2['averageforce']

       var peakforcepoints = datapoints['peakforce']
       var peakforceanglepoints = datapoints['peakforceangle']

       var annotation = annotation.value
       var minspm = minspm.value
       var maxspm = maxspm.value
       var mindist = mindist.value
       var maxdist = maxdist.value
       var minwork = minwork.value
       var maxwork = maxwork.value

       sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
       sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
       sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)

       var catchav = 0
       var finishav = 0
       var slipav = 0
       var washav = 0
       var peakforceangleav = 0
       var averageforceav = 0
       var peakforceav = 0
       var count = 0

       datapoints['peakforceangle'] = []
       datapoints['peakforce'] = []
       multilines['x'] = []
       multilines['y'] = []

      for (i=0; i<c.length; i++) {
          if (spm1[i]>=minspm && spm1[i]<=maxspm) {
             if (distance1[i]>=mindist && distance1[i]<=maxdist) {
                if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
                   if (plottype=='scatter') {
                     datapoints['peakforceangle'].push(peakforceangle[i])
                     datapoints['peakforce'].push(peakforce[i])
                   }
                   if (plottype=='line') {
                     multilines['x'].push(multilinesx[i])
                     multilines['y'].push(multilinesy[i])
                   }
                   catchav += c[i]
                   finishav += finish[i]
                   slipav += slip[i]
                   washav += wash[i]
                   peakforceangleav += peakforceangle[i]
                   averageforceav += averageforce[i]
                   peakforceav += peakforce[i]
                   count += 1
                   }
                }
             }
       }

       catchav /= count
       finishav /= count
       slipav /= count
       washav /= count
       peakforceangleav /= count
       peakforceav /= count
       averageforceav /= count

       data['x'] = [catchav,catchav+slipav,peakforceangleav,finishav-washav,finishav]
       data['y'] = [0,thresholdforce,peakforceav,thresholdforce,0]

       dataslipwash['xslip'] = [catchav+slipav,finishav-washav]
       dataslipwash['yslip'] = [thresholdforce,thresholdforce]

       var length = finishav-catchav
       var efflength = length-slipav-washav

       avf.location = averageforceav
       avflabel.text = 'Favg: '+averageforceav.toFixed(2)
       catchlabel.text = 'Catch: '+catchav.toFixed(2)
       finishlabel.text = 'Finish: '+finishav.toFixed(2)
       sliplabel.text = 'Slip: '+slipav.toFixed(2)
       washlabel.text = 'Wash: '+washav.toFixed(2)
       peakflabel.text = 'Fpeak: '+peakforceav.toFixed(2)
       peakforceanglelabel.text = 'Peak angle: '+peakforceangleav.toFixed(2)
       annolabel.text = annotation
       lengthlabel.text = 'Length: '+length.toFixed(2)
       efflengthlabel.text = 'Effective Length: '+efflength.toFixed(2)

       console.log(count);
       console.log(multilines['x'].length);
       console.log(multilines['y'].length);

       // source.trigger('change');
       source.change.emit();
       sourceslipwash.change.emit()
       sourcepoints.change.emit();
       sourcemultiline.change.emit();
       """)

    annotation = TextInput(title="Type your plot notes here", value="",
                               callback=callback)
    callback.args["annotation"] = annotation

    slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
                title="Min SPM",callback=callback)
    callback.args["minspm"] = slider_spm_min


    slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
                title="Max SPM",callback=callback)
    callback.args["maxspm"] = slider_spm_max

    slider_work_min = Slider(start=0, end=1500,value=0, step=10,
                title="Min Work per Stroke",callback=callback)
    callback.args["minwork"] = slider_work_min


    slider_work_max = Slider(start=0, end=1500,value=1500, step=10,
                title="Max Work per Stroke",callback=callback)
    callback.args["maxwork"] = slider_work_max

    distmax = 100+100*int(rowdata['distance'].max()/100.)

    slider_dist_min = Slider(start=0,end=distmax,value=0,step=50,
                             title="Min Distance",callback=callback)
    callback.args["mindist"] = slider_dist_min

    slider_dist_max = Slider(start=0,end=distmax,value=distmax,
                             step=50,
                             title="Max Distance",callback=callback)
    callback.args["maxdist"] = slider_dist_max

    layout = layoutrow([layoutcolumn([annotation,
                                      slider_spm_min,
                                      slider_spm_max,
                                      slider_dist_min,
                                      slider_dist_max,
                                      slider_work_min,
                                      slider_work_max,
                               ],
                                     ),
                        plot])

    layout.sizing_mode = 'scale_width'

    script, div = components(layout)
    js_resources = INLINE.render_js()
    css_resources = INLINE.render_css()



    return [script,div,js_resources,css_resources]

def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower',startdate=None,
                        enddate=None):

    power4min = [int(m.PowerFourMin) for m in fitnessmetrics]
    power2k = [int(m.PowerTwoK) for m in fitnessmetrics]
    power1hr = [int(m.PowerOneHour) for m in fitnessmetrics]
    dates = [m.date for m in fitnessmetrics]

    mode = [m.workoutmode for m in fitnessmetrics]

    if len(power4min) == 0:
        return ['','']

    df = pd.DataFrame(
        {'power4min':power4min,
         'power2k':power2k,
         'power1hr':power1hr,
         'date':dates,
         'dates':dates,
         'mode':mode
         })


    delta = df['power4min'].astype('int').diff()

    mask = delta == 0

    df.loc[mask,'power4min'] = np.nan
    df.dropna(inplace=True,axis=0,how='any')


    df = df[df['power2k']>0]
    try:
        df = df[df['mode']==workoutmode]
    except TypeError:
        df = pd.DataFrame()

    if df.empty:
        return ["","no data"]

    groups = df.groupby(by='date').max()

    power4min = groups['power4min']
    date = groups['dates']
    power2k = groups['power2k']
    power1hr = groups['power1hr']

    source = ColumnDataSource(
        data = dict(
            power4min = power4min,
            power2k = power2k,
            date = date,
            power1hr = power1hr,
            fdate=groups['dates'].map(lambda x: x.strftime('%Y-%m-%d'))
        )
    )


    # fit

    resampled = groups.set_index('dates')
    resampled.index = pd.to_datetime(resampled.index)
    resampled = resampled.resample('D').interpolate(
        method='linear',order=2)

    power4min = resampled['power4min']
    date = resampled.index.values
    power2k = resampled['power2k']
    power1hr = resampled['power1hr']

    source2 = ColumnDataSource(
        data = dict(
            power4min = power4min,
            power2k = power2k,
            date = date,
            power1hr = power1hr,
            fdate=resampled.index.map(lambda x: x.strftime('%d-%m-%Y'))            )
        )



    TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'

    plot = Figure(tools=TOOLS,toolbar_location="above",
                  toolbar_sticky=False,width=900,
                  x_axis_type='datetime')

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}

    plot.image_url([watermarkurl],watermarkx,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    plot.circle('date','power2k',source=source,fill_color='red',size=10,
                legend='2k power')


    plot.circle('date','power1hr',source=source,fill_color='blue',size=10,
                legend='1 hr power')

    plot.circle('date','power4min',source=source,fill_color='green',size=10,
                legend='4 min power')

    plot.line('date','power4min',source=source2,color='green')
    plot.line('date','power2k',source=source2,color='red')
    plot.line('date','power1hr',source=source2,color='blue')

    plot.xaxis.axis_label = 'Date'
    plot.yaxis.axis_label = 'Power (W)'

    plot.xaxis.formatter = DatetimeTickFormatter(
        days=["%d %B %Y"],
        months=["%d %B %Y"],
        years=["%d %B %Y"],
        )

    plot.xaxis.major_label_orientation = pi/4
    plot.sizing_mode = 'scale_width'

    plot.y_range = Range1d(0,1.5*max(power4min))
    if not startdate:
        startdate = min(date)

    if not enddate:
        enddate = max(date)

    plot.x_range = Range1d(
        startdate,enddate,
    )
    plot.title.text = 'Power levels ('+workoutmode+') from workouts '+user.first_name

    hover = plot.select(dict(type=HoverTool))

    hover.tooltips = OrderedDict([
        ('Power 4 minutes','@power4min'),
        ('Power 2000 m','@power2k'),
        ('Power 1 hour','@power1hr'),
        ('Date','@fdate'),
    ])

    script,div = components(plot)

    return [script,div]

def interactive_histoall(theworkouts,histoparam,includereststrokes,
                         spmmin=0,spmmax=55,
                         workmin=0,workmax=1500):
    TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'

    ids = [int(w.id) for w in theworkouts]

    workstrokesonly = not includereststrokes
    rowdata = dataprep.getsmallrowdata_db([histoparam],ids=ids,doclean=True,workstrokesonly=workstrokesonly)

    rowdata.dropna(axis=0,how='any',inplace=True)

    rowdata = dataprep.filter_df(rowdata,'spm',spmmin,largerthan=True)
    rowdata = dataprep.filter_df(rowdata,'spm',spmmax,largerthan=False)

    rowdata = dataprep.filter_df(rowdata,'driveenergy',workmin,largerthan=True)
    rowdata = dataprep.filter_df(rowdata,'driveenergy',workmax,largerthan=False)

    if rowdata.empty:
        return "","No Valid Data Available"

    try:
        histopwr = rowdata[histoparam].values
    except KeyError:
        return "","No data"
    if len(histopwr) == 0:
        return "","No valid data available"

    # throw out nans
    histopwr = histopwr[~np.isinf(histopwr)]
    histopwr = histopwr[histopwr > yaxminima[histoparam]]
    histopwr = histopwr[histopwr < yaxmaxima[histoparam]]

    plot = Figure(tools=TOOLS,plot_width=900,
                  toolbar_sticky=False,
                  toolbar_location="above"
                  )

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}

    plot.image_url([watermarkurl],watermarkx,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    hist,edges = np.histogram(histopwr,bins=150)

    histsum = np.cumsum(hist)
    histsum = 100.*histsum/max(histsum)

    hist_norm = 100.*hist/float(hist.sum())

    source = ColumnDataSource(
        data = dict(
            left = edges[:-1],
            right = edges[1:],
            histsum = histsum,
            hist_norm = hist_norm,
            )
        )


#    plot.quad(top='hist_norm',bottom=0,left=edges[:-1],right=edges[1:])
    plot.quad(top='hist_norm',bottom=0,left='left',right='right',source=source)

    plot.xaxis.axis_label = axlabels[histoparam]
    plot.yaxis.axis_label = "% of strokes"
    plot.y_range = Range1d(0,1.05*max(hist_norm))


    hover = plot.select(dict(type=HoverTool))

    hover.tooltips = OrderedDict([
        (axlabels[histoparam],'@left{int}'),
        ('% of strokes','@hist_norm'),
        ('Cumulative %','@histsum{int}'),
        ])

    hover.mode = 'mouse'

    plot.extra_y_ranges["fraction"] = Range1d(start=0,end=105)
    plot.line('right','histsum',source=source,color="red",
              y_range_name="fraction")
    plot.add_layout(LinearAxis(y_range_name="fraction",
                               axis_label="Cumulative % of strokes"),'right')

    plot.sizing_mode = 'scale_width'

    annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
                      text='',
                      background_fill_alpha=0.7,
                      background_fill_color='white',
                      text_color='black',
    )

    plot.add_layout(annolabel)

    callback = CustomJS(args = dict(
        annolabel=annolabel,
        ), code="""
           var annotation = annotation.value
           annolabel.text = annotation
           """)

    annotation = TextInput(title="Type your plot notes here", value="",
                           callback=callback)
    callback.args["annotation"] = annotation

    layout = layoutcolumn([annotation,plot])

    try:
        script, div = components(layout)
    except ValueError:
        script = ''
        div = ''

    return [script,div]

def course_map(course):
    latmean,lonmean,coordinates = course_coord_center(course)
    lat_min, lat_max, long_min, long_max = course_coord_maxmin(course)

    coordinates = course_spline(coordinates)

    scoordinates = "["

    for index,row in coordinates.iterrows():
        scoordinates += """[{x},{y}],
        """.format(
            x=row['latitude'],
            y=row['longitude']
        )

    scoordinates +="]"

    polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")

    plabels = ''

    for p in polygons:
        coords = polygon_coord_center(p)

        plabels += """
        var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
        marker.bindPopup("<b>{name}</b>");

        """.format(
            latbegin = coords[0],
            longbegin = coords[1],
            name = p.name
            )

    pcoordinates = """[
    """

    for p in polygons:
        pcoordinates += """[
        ["""

        points = GeoPoint.objects.filter(polygon=p).order_by("order_in_poly")

        for pt in points:
            pcoordinates += "[{x},{y}],".format(
                x = pt.latitude,
                y = pt.longitude
                )

        # remove last comma
        pcoordinates = pcoordinates[:-1]
        pcoordinates += """]
        ],
        """

    pcoordinates += """
    ]"""



    script = """
    <script>


    var streets = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/streets-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    satellite = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/satellite-v9',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    outdoors = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/outdoors-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    );



    var mymap = L.map('map_canvas', {{
              center: [{latmean}, {lonmean}],
              zoom: 13,
              layers: [streets, satellite]
              }}).setView([{latmean},{lonmean}], 13);

    var navionics = new JNC.Leaflet.NavionicsOverlay({{
         navKey: 'Navionics_webapi_03205',
         chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
         isTransparent: true,
         zIndex: 1
    }});


   var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
   var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';


    //create two TileLayer
    var nautical=new L.TileLayer(osmUrl,{{
             maxZoom:18}});


    L.control.layers({{
        "Streets": streets,
        "Satellite": satellite,
        "Outdoors": outdoors,
        "Nautical": nautical,
    }},{{
        "Navionics":navionics,
    }}).addTo(mymap);

    var latlongs = {scoordinates}
    var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
    mymap.fitBounds(polyline.getBounds())

    var platlongs = {pcoordinates}
    var polygons = L.polygon(platlongs, {{color:'blue'}}).addTo(mymap)

    {plabels}

    </script>
      """.format(
          latmean=latmean,
          lonmean=lonmean,
          scoordinates=scoordinates,
          pcoordinates=pcoordinates,
          plabels = plabels
          )

    div = """
    <div id="map_canvas" style="width: 100%; height: 400px; margin:0; padding:0;grid-gap:0;"></div>
    """

    return script,div

def leaflet_chart(lat,lon,name=""):
    if lat.empty or lon.empty:
        return [0,"invalid coordinate data"]


    # Throw out 0,0
    df = pd.DataFrame({
        'lat':lat,
        'lon':lon
        })

    df = df.replace(0,np.nan)
    df = df.loc[(df!=0).any(axis=1)]
    df.fillna(method='bfill',axis=0,inplace=True)
    df.fillna(method='ffill',axis=0,inplace=True)
    lat = df['lat']
    lon = df['lon']
    if lat.empty or lon.empty:
        return [0,"invalid coordinate data"]

    latmean = lat.mean()
    lonmean = lon.mean()

    latbegin = lat[lat.index[0]]
    longbegin = lon[lon.index[0]]
    latend = lat[lat.index[-1]]
    longend = lon[lon.index[-1]]

    coordinates = zip(lat,lon)

    scoordinates = "["

    for x,y in coordinates:
        scoordinates += """[{x},{y}],
        """.format(
            x=x,
            y=y
            )

    scoordinates += "]"

    script = """
    <script>


    var streets = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/streets-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    satellite = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/satellite-v9',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    outdoors = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/outdoors-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    );



    var mymap = L.map('map_canvas', {{
              center: [{latmean}, {lonmean}],
              zoom: 13,
              layers: [streets, satellite]
              }}).setView([{latmean},{lonmean}], 13);

    var navionics = new JNC.Leaflet.NavionicsOverlay({{
         navKey: 'Navionics_webapi_03205',
         chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
         isTransparent: true,
         zIndex: 1
    }});


   var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
   var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';


    //create two TileLayer
    var nautical=new L.TileLayer(osmUrl,{{
             maxZoom:18}});


    L.control.layers({{
        "Streets": streets,
        "Satellite": satellite,
        "Outdoors": outdoors,
        "Nautical": nautical,
    }},{{
        "Navionics":navionics,
    }}).addTo(mymap);

    var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
    marker.bindPopup("<b>Start</b>");
    var emarker = new L.marker([{latend}, {longend}]).addTo(mymap);
    emarker.bindPopup("<b>End</b>");

    var latlongs = {scoordinates}
    var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
    mymap.fitBounds(polyline.getBounds())

    </script>
      """.format(
          latmean=latmean,
          lonmean=lonmean,
          latbegin = latbegin,
          latend=latend,
          longbegin=longbegin,
          longend=longend,
          scoordinates=scoordinates,
          )

    div = """
    <div id="map_canvas" style="width: 100%; height: 400px;"><p>&nbsp;</p></div>
    """



    return script,div

def leaflet_chart_compare(course,workoutids,labeldict={},startenddict={}):
    data = []
    for id in workoutids:
        w = Workout.objects.get(id=id)
        rowdata = rdata(w.csvfilename)
        time = rowdata.df['TimeStamp (sec)']
        df = pd.DataFrame({
            'workoutid':id,
            'lat':rowdata.df[' latitude'],
            'lon':rowdata.df[' longitude'],
            'time':time-time[0],
        })
        data.append(df)

    df = pd.concat(data,axis=0)


    latmean,lonmean,coordinates = course_coord_center(course)
    lat_min, lat_max, long_min, long_max = course_coord_maxmin(course)

    # Throw out 0,0
    df = df.replace(0,np.nan)
    df = df.loc[(df!=0).any(axis=1)]
    df.fillna(method='bfill',axis=0,inplace=True)
    df.fillna(method='ffill',axis=0,inplace=True)



    lat = df['lat']
    lon = df['lon']
    if lat.empty or lon.empty:
        return [0,"invalid coordinate data"]

    latbegin = lat.values[0]
    longbegin = lon.values[0]
    latend = lat.values[-1]
    longend = lon.values[-1]

    colors = itertools.cycle(palette)
    try:
        items = itertools.izip(workoutids,colors)
    except AttributeError:
        items = zip(workoutids,colors)

    coordinates = zip(lat,lon)

    scoordinates = "["

    for x,y in coordinates:
        scoordinates += """[{x},{y}],
        """.format(
            x=x,
            y=y
            )

    scoordinates += "]"

    script = """
    <script>

    var streets = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/streets-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),


    satellite = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/satellite-v9',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    outdoors = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/outdoors-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    );



    var mymap = L.map('map_canvas', {{
              center: [{latmean}, {lonmean}],
              zoom: 13,
              layers: [streets, satellite]
              }}).setView([{latmean},{lonmean}], 13);

    var navionics = new JNC.Leaflet.NavionicsOverlay({{
         navKey: 'Navionics_webapi_03205',
         chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
         isTransparent: true,
         zIndex: 1
    }});


   var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
   var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';


    //create two TileLayer
    var nautical=new L.TileLayer(osmUrl,{{
             maxZoom:18}});


    L.control.layers({{
        "Streets": streets,
        "Satellite": satellite,
        "Outdoors": outdoors,
        "Nautical": nautical,
    }},{{
        "Navionics":navionics,
    }}).addTo(mymap);



      """.format(
          latmean=latmean,
          lonmean=lonmean,
          latbegin = latbegin,
          latend=latend,
          longbegin=longbegin,
          longend=longend,
          scoordinates=scoordinates,
          )

    for id,color in items:
        group = df[df['workoutid']==int(id)].copy()
        try:
            startsecond,endsecond = startenddict[id]
        except KeyError:
            startsecond = 0
            endsecond = 0

        try:
            label = labeldict[id]
        except KeyError:
            label = str(id)

        group.sort_values(by='time',ascending=True,inplace=True)
        group.dropna(axis=0,how='any',inplace=True)
        if endsecond > 0:
            group['time'] = group['time'] - startsecond
            mask = group['time'] < 0
            group.mask(mask,inplace=True)
            mask = group['time'] > (endsecond-startsecond)
            group.mask(mask,inplace=True)

        lat = group['lat'].dropna()
        lon = group['lon'].dropna()

        coordinates = zip(lat,lon)

        scoordinates = "["
        for x,y in coordinates:
            scoordinates += """[{x},{y}],
            """.format(x=x,y=y)
        scoordinates += "]"

        script += """
        var latlongs = {scoordinates}
        var polyline = L.polyline(latlongs, {{color:'{color}'}}).addTo(mymap)
        polyline.bindPopup("<b>{label}</b>")
        polyline.on('mouseover',function(ev) {{
            ev.target.openPopup();
            }});
        mymap.fitBounds(polyline.getBounds())
        """.format(
            scoordinates=scoordinates,
            color=color,
            label=label
        )

    script += """

        </script>
        """




    div = """
    <div id="map_canvas" style="width: 100%; height: 100%; min-height: 100vh"><p>&nbsp;</p></div>
    """



    return script,div

def leaflet_chart2(lat,lon,name=""):
    if lat.empty or lon.empty:
        return [0,"invalid coordinate data"]


    # Throw out 0,0
    df = pd.DataFrame({
        'lat':lat,
        'lon':lon
        })

    df = df.replace(0,np.nan)
    df = df.loc[(df!=0).any(axis=1)]
    df.fillna(method='bfill',axis=0,inplace=True)
    df.fillna(method='ffill',axis=0,inplace=True)
    lat = df['lat']
    lon = df['lon']
    if lat.empty or lon.empty:
        return [0,"invalid coordinate data"]

    latmean = lat.mean()
    lonmean = lon.mean()
    latbegin = lat[lat.index[0]]
    longbegin = lon[lon.index[0]]
    latend = lat[lat.index[-1]]
    longend = lon[lon.index[-1]]

    coordinates = zip(lat,lon)

    scoordinates = "["

    for x,y in coordinates:
        scoordinates += """[{x},{y}],
        """.format(
            x=x,
            y=y
            )

    scoordinates += "]"

    script = """
    <script>

    var streets = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/streets-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),


    satellite = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/satellite-v9',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    outdoors = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/outdoors-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    );



    var mymap = L.map('map_canvas', {{
              center: [{latmean}, {lonmean}],
              zoom: 13,
              layers: [streets, satellite]
              }}).setView([{latmean},{lonmean}], 13);

    var navionics = new JNC.Leaflet.NavionicsOverlay({{
         navKey: 'Navionics_webapi_03205',
         chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
         isTransparent: true,
         zIndex: 1
    }});


   var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
   var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';


    //create two TileLayer
    var nautical=new L.TileLayer(osmUrl,{{
             maxZoom:18}});


    L.control.layers({{
        "Streets": streets,
        "Satellite": satellite,
        "Outdoors": outdoors,
        "Nautical": nautical,
    }},{{
        "Navionics":navionics,
    }}).addTo(mymap);

    var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
    marker.bindPopup("<b>Start</b>");
    var emarker = new L.marker([{latend}, {longend}]).addTo(mymap);
    emarker.bindPopup("<b>End</b>");

    var latlongs = {scoordinates}
    var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
    mymap.fitBounds(polyline.getBounds())

    </script>
      """.format(
          latmean=latmean,
          lonmean=lonmean,
          latbegin = latbegin,
          latend=latend,
          longbegin=longbegin,
          longend=longend,
          scoordinates=scoordinates,
          )

    div = """
    <div id="map_canvas" style="width: 100%; height: 100%; min-height: 100vh"><p>&nbsp;</p></div>
    """



    return script,div

def leaflet_chart_video(lat,lon,name=""):
    if not len(lat) or not len(lon):
        return [0,"invalid coordinate data"]


    # Throw out 0,0
    df = pd.DataFrame({
        'lat':lat,
        'lon':lon
        })

    df = df.replace(0,np.nan)
    df = df.loc[(df!=0).any(axis=1)]
    df.fillna(method='bfill',axis=0,inplace=True)
    df.fillna(method='ffill',axis=0,inplace=True)
    lat = df['lat']
    lon = df['lon']
    if lat.empty or lon.empty:
        return [0,"invalid coordinate data"]

    latmean = lat.mean()
    lonmean = lon.mean()
    latbegin = lat[lat.index[0]]
    longbegin = lon[lon.index[0]]
    latend = lat[lat.index[-1]]
    longend = lon[lon.index[-1]]

    coordinates = zip(lat,lon)

    scoordinates = "["

    for x,y in coordinates:
        scoordinates += """[{x},{y}],
        """.format(
            x=x,
            y=y
            )

    scoordinates += "]"

    script = """


    var streets = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/streets-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    satellite = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/satellite-v9',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    ),

    outdoors = L.tileLayer(
    'https://api.mapbox.com/styles/v1/{{id}}/tiles/{{z}}/{{x}}/{{y}}?access_token={{accessToken}}', {{
    attribution: '© <a href="https://www.mapbox.com/about/maps/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> <strong><a href="https://www.mapbox.com/map-feedback/" target="_blank">Improve this map</a></strong>',
    tileSize: 512,
    maxZoom: 18,
    zoomOffset: -1,
    id: 'mapbox/outdoors-v11',
    accessToken: 'pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA'
}}
    );



    var mymap = L.map('map_canvas', {{
              center: [{latmean}, {lonmean}],
              zoom: 13,
              layers: [streets, satellite]
              }}).setView([{latmean},{lonmean}], 13);

    var navionics = new JNC.Leaflet.NavionicsOverlay({{
         navKey: 'Navionics_webapi_03205',
         chartType: JNC.NAVIONICS_CHARTS.NAUTICAL,
         isTransparent: true,
         zIndex: 1
    }});


   var osmUrl2='http://tiles.openseamap.org/seamark/{{z}}/{{x}}/{{y}}.png';
   var osmUrl='http://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png';


    //create two TileLayer
    var nautical=new L.TileLayer(osmUrl,{{
             maxZoom:18}});


    L.control.layers({{
        "Streets": streets,
        "Satellite": satellite,
        "Outdoors": outdoors,
        "Nautical": nautical,
    }},{{
        "Navionics":navionics,
    }},
    {{
    position:'topleft'
    }}).addTo(mymap);

    var marker = L.marker([{latbegin}, {longbegin}]).addTo(mymap);
    marker.bindPopup("<b>Start</b>");

    var latlongs = {scoordinates}
    var polyline = L.polyline(latlongs, {{color:'red'}}).addTo(mymap)
    mymap.fitBounds(polyline.getBounds())

      """.format(
          latmean=latmean,
          lonmean=lonmean,
          latbegin = latbegin,
          latend=latend,
          longbegin=longbegin,
          longend=longend,
          scoordinates=scoordinates,
          )

    div = """
    <div id="map_canvas" style="width: 640px; height: 390px;"><p>&nbsp;</p></div>
    """



    return script,div


def interactive_agegroupcpchart(age,normalized=False):
    durations = [1,4,30,60]
    distances = [100,500,1000,2000,5000,6000,10000,21097,42195]

    fhduration = []
    fhpower = []

    for distance in distances:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='female',
            distance=distance,
            weightcategory='hwt'
        )
        velo = (worldclasspower/2.8)**(1./3.)
        try:
            duration = distance/velo
            fhduration.append(duration)
            fhpower.append(worldclasspower)
        except ZeroDivisionError:
            pass
    for duration in durations:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='female',
            duration=duration,
            weightcategory='hwt'
            )
        try:
            velo = (worldclasspower/2.8)**(1./3.)
            distance = int(60*duration*velo)
            fhduration.append(60.*duration)
            fhpower.append(worldclasspower)
        except ValueError:
            pass

    flduration = []
    flpower = []

    for distance in distances:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='female',
            distance=distance,
            weightcategory='lwt'
        )
        velo = (worldclasspower/2.8)**(1./3.)
        try:
            duration = distance/velo
            flduration.append(duration)
            flpower.append(worldclasspower)
        except ZeroDivisionError:
            pass
    for duration in durations:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='female',
            duration=duration,
            weightcategory='lwt'
            )
        try:
            velo = (worldclasspower/2.8)**(1./3.)
            distance = int(60*duration*velo)
            flduration.append(60.*duration)
            flpower.append(worldclasspower)
        except ValueError:
            pass

    mlduration = []
    mlpower = []

    for distance in distances:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='male',
            distance=distance,
            weightcategory='lwt'
        )
        velo = (worldclasspower/2.8)**(1./3.)
        try:
            duration = distance/velo
            mlduration.append(duration)
            mlpower.append(worldclasspower)
        except ZeroDivisionError:
            pass
    for duration in durations:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='male',
            duration=duration,
            weightcategory='lwt'
            )
        try:
            velo = (worldclasspower/2.8)**(1./3.)
            distance = int(60*duration*velo)
            mlduration.append(60.*duration)
            mlpower.append(worldclasspower)
        except ValueError:
            pass


    mhduration = []
    mhpower = []

    for distance in distances:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='male',
            distance=distance,
            weightcategory='hwt'
        )
        velo = (worldclasspower/2.8)**(1./3.)
        try:
            duration = distance/velo
            mhduration.append(duration)
            mhpower.append(worldclasspower)
        except ZeroDivisionError:
            pass
    for duration in durations:
        worldclasspower = c2stuff.getagegrouprecord(
            age,
            sex='male',
            duration=duration,
            weightcategory='hwt'
            )
        try:
            velo = (worldclasspower/2.8)**(1./3.)
            distance = int(60*duration*velo)
            mhduration.append(60.*duration)
            mhpower.append(worldclasspower)
        except ValueError:
            pass



    fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3]))
    errfunc = lambda pars,x,y: fitfunc(pars,x)-y

    #    p0 = [500,350,10,8000]

    # fitting WC data to three parameter CP model
    if len(fhduration)>=4:
        p1fh, success = optimize.leastsq(errfunc, p0[:],
                                       args = (fhduration,fhpower))
    else:
        p1fh = None

    # fitting WC data to three parameter CP model
    if len(flduration)>=4:
        p1fl, success = optimize.leastsq(errfunc, p0[:],
                                       args = (flduration,flpower))
    else:
        p1fl = None

    # fitting WC data to three parameter CP model
    if len(mlduration)>=4:
        p1ml, success = optimize.leastsq(errfunc, p0[:],
                                       args = (mlduration,mlpower))
    else:
        p1ml = None

    if len(mhduration)>=4:
        p1mh, success = optimize.leastsq(errfunc, p0[:],
                                       args = (mhduration,mhpower))
    else:
        p1mh = None

    fitt = pd.Series(10**(4*np.arange(100)/100.))

    fitpowerfh = fitfunc(p1fh,fitt)
    fitpowerfl = fitfunc(p1fl,fitt)
    fitpowerml = fitfunc(p1ml,fitt)
    fitpowermh = fitfunc(p1mh,fitt)

    if normalized:
        facfh = fitfunc(p1fh,60)
        facfl = fitfunc(p1fl,60)
        facml = fitfunc(p1ml,60)
        facmh = fitfunc(p1mh,60)
        fitpowerfh /= facfh
        fitpowerfl /= facfl
        fitpowermh /= facmh
        fitpowerml /= facml
        fhpower /= facfh
        flpower /= facfl
        mlpower /= facml
        mhpower /= facmh



    source = ColumnDataSource(
        data = dict(
            duration = fitt,
            fitpowerfh = fitpowerfh,
            fitpowerfl = fitpowerfl,
            fitpowerml = fitpowerml,
            fitpowermh = fitpowermh,
            flduration = flduration,
            flpower = flpower,
            fhduration = fhduration,
            fhpower = fhpower,
            mlduration = mlduration,
            mlpower = mlpower,
            mhduration = mhduration,
            mhpower = mhpower,
            )
        )

    x_axis_type = 'log'
    y_axis_type = 'linear'

    TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'

    plot = Figure(plot_width=900,x_axis_type=x_axis_type,
                  tools=TOOLS)
    plot.sizing_mode = 'scale_width'

    plot.line('duration','fitpowerfh',source=source,
              legend='Female HW',color='blue')
    plot.line('duration','fitpowerfl',source=source,
              legend='Female LW',color='red')

    plot.line('duration','fitpowerml',source=source,
              legend='Male LW',color='green')

    plot.line('duration','fitpowermh',source=source,
              legend='Male HW',color='orange')


    plot.circle('flduration','flpower',source=source,
                fill_color='red',size=15)

    plot.circle('fhduration','fhpower',source=source,
                fill_color='blue',size=15)

    plot.circle('mlduration','mlpower',source=source,
                fill_color='green',size=15)

    plot.circle('mhduration','mhpower',source=source,
                fill_color='orange',size=15)

    plot.title.text = 'age '+str(age)

    plot.xaxis.axis_label = "Duration (seconds)"
    if normalized:
        plot.yaxis.axis_label = "Power (normalized)"
    else:
        plot.yaxis.axis_label = "Power (W)"

    script,div = components(plot)

    return script,div


def interactive_otwcpchart(powerdf,promember=0,rowername=""):
    powerdf = powerdf[~(powerdf == 0).any(axis=1)]
    # plot tools
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'


    x_axis_type = 'log'
    y_axis_type = 'linear'

    deltas = powerdf['Delta'].apply(lambda x: timedeltaconv(x))
    powerdf['ftime'] = niceformat(deltas)


    source = ColumnDataSource(
        data = powerdf
        )

    # there is no Paul's law for OTW

    thesecs = powerdf['Delta']
    theavpower = powerdf['CP']

    p1,fitt,fitpower,ratio = datautils.cpfit(powerdf)

    message = ""
    #if len(fitpower[fitpower<0]) > 0:
        # message = "CP model fit didn't give correct results"


    deltas = fitt.apply(lambda x: timedeltaconv(x))
    ftime = niceformat(deltas)

    sourcecomplex = ColumnDataSource(
        data = dict(
            CP = fitpower,
            CPmax = ratio*fitpower,
            duration = fitt,
            ftime = ftime
            )
        )

        # making the plot
    plot = Figure(tools=TOOLS,x_axis_type=x_axis_type,
                  plot_width=900,
                  toolbar_location="above",
                  toolbar_sticky=False)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],1.8*max(thesecs),watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   y_range_name = "watermark",
                   )

    plot.circle('Delta','CP',source=source,fill_color='red',size=15,
                legend='Power Data')
    plot.xaxis.axis_label = "Duration (seconds)"
    plot.yaxis.axis_label = "Power (W)"

    plot.y_range = Range1d(0,1.5*max(theavpower))
    plot.x_range = Range1d(1,2*max(thesecs))
    plot.legend.orientation = "vertical"
    plot.title.text = "Critical Power for "+rowername

    hover = plot.select(dict(type=HoverTool))

    hover.tooltips = OrderedDict([
        ('Duration ','@ftime'),
        ('Power (W)','@CP{int}'),
        ('Power (W) upper','@CPmax{int}'),
        ])

    hover.mode = 'mouse'

    plot.line('duration','CP',source=sourcecomplex,legend="CP Model",
              color='green')

    plot.line('duration','CPmax',source=sourcecomplex,legend="CP Model",
              color='red')

    script, div = components(plot)

    return [script,div,p1,ratio,message]

def interactive_agegroup_plot(df,distance=2000,duration=None,
                              sex='male',weightcategory='hwt'):

    if df.empty:
        return '',''

    age = df['age']
    power = df['power']
    name = df['name']
    season = df['season']

    if duration:
        duration2 = int(duration/60.)
        plottitle = sex+' '+weightcategory+' %s min' % duration2
    else:
        plottitle = sex+' '+weightcategory+' %s m' % distance

#    poly_coefficients = np.polyfit(age,power,6)

    age2 = np.linspace(11,95)
#    poly_vals = np.polyval(poly_coefficients,age2)
#    poly_vals = 0.5*(np.abs(poly_vals)+poly_vals)

    fitfunc = lambda pars, x: np.abs(pars[0])*(1-x/max(120,pars[1]))-np.abs(pars[2])*np.exp(-x/np.abs(pars[3]))+np.abs(pars[4])*(np.sin(np.pi*x/max(50,pars[5])))
    errfunc = lambda pars, x,y: fitfunc(pars,x)-y

    p0age = [700,120,700,10,100,100]

    p1, success = optimize.leastsq(errfunc,p0age[:],
                                   args = (age,power))

    expo_vals = fitfunc(p1, age2)
    expo_vals = 0.5*(np.abs(expo_vals)+expo_vals)


    source = ColumnDataSource(
        data = dict(
            age = age,
            power = power,
            age2 = age2,
            expo_vals = expo_vals,
            season = season,
            name=name,
            )
    )

    TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'

    plot = Figure(tools=TOOLS,plot_width=900)
    plot.sizing_mode='scale_width'
    plot.circle('age','power',source=source,fill_color='red',size=15,
                legend='World Record')

    plot.line(age2,expo_vals)
    plot.xaxis.axis_label = "Age"
    plot.yaxis.axis_label = "Concept2 power"
    plot.title.text = plottitle

    hover = plot.select(dict(type=HoverTool))

    hover.tooltips = OrderedDict([
        ('Name ','@name'),
        ('Season ','@season'),
        ])

    hover.mode = 'mouse'

    script,div = components(plot)

    return script,div

def interactive_cpchart(rower,thedistances,thesecs,theavpower,
                        theworkouts,promember=0,
                        wcpower=[],wcdurations=[]):

    message = 0
    # plot tools
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'


    x_axis_type = 'log'
    y_axis_type = 'linear'

    thesecs = pd.Series(thesecs)

    velo = thedistances/thesecs
    p = pd.Series(500./velo)

    p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))

    source = ColumnDataSource(
        data = dict(
            dist = thedistances,
            duration = thesecs,
            spm = 0*theavpower,
            tim = niceformat(
                thesecs.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
                ),

            power = theavpower,
            fpace = nicepaceformat(p2),
            )
        )

    # fitting the data to Paul
    if len(thedistances)>=2:
        paulslope, paulintercept,r,p,stderr = linregress(np.log10(thedistances),p)
    else:
        paulslope = 5.0/np.log10(2.0)
        paulintercept = p[0]-paulslope*np.log10(thedistances[0])


    fitx = pd.Series(np.arange(100)*2*max(np.log10(thedistances))/100.)

    fitp = paulslope*fitx+paulintercept

    fitvelo = 500./fitp
    fitpower = 2.8*(fitvelo**3)
    fitt = 10**fitx/fitvelo
    fitp2 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))


    sourcepaul = ColumnDataSource(
        data = dict(
            dist = 10**fitx,
            duration = fitt,
            power = fitpower,
            spm = 0*fitpower,
            tim = niceformat(
                fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
                ),
            fpace = nicepaceformat(fitp2),
            )
        )


    fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3]))
    errfunc = lambda pars,x,y: fitfunc(pars,x)-y

    # p0 = [500,350,10,8000]
    wcpower = pd.Series(wcpower)
    wcdurations = pd.Series(wcdurations)

    # fitting WC data to three parameter CP model
    if len(wcdurations)>=4:
        p1wc, success = optimize.leastsq(errfunc, p0[:],
                                       args = (wcdurations,wcpower))
    else:
        p1wc = None

    # fitting the data to three parameter CP model

    success = 0
    p1 = p0
    if len(thesecs)>=4:
        p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower))
    else:
        factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
        p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
        success = 0


    # Get stayer score
    if success == 1:
        power1min = fitfunc(p1,60.)
        power4min = fitfunc(p1,240.)
        power6min = fitfunc(p1,360.)
        power30min = fitfunc(p1,1800.)
        power1h = fitfunc(p1,3600.)
        power10sec = fitfunc(p1,10.)
        r10sec4min = 100.*power10sec/power4min
        r1h4min = 100.*power1h/power4min
        r1min6min = 100.*power1min/power6min
        r30min6min = 100.*power30min/power6min

        combined = r1h4min-0.2*(r10sec4min-100)
        combined2 = r30min6min-1.5*(r1min6min-100)

        dataset = pd.read_csv('static/stats/combined_set.csv')
        dataset2 = pd.read_csv('static/stats/combined_set6min.csv')

        stayerscore = int(percentileofscore(dataset['combined'],combined))
        stayerscore2 = int(percentileofscore(dataset2['combined'],combined2))
    else:
        stayerscore = None
        stayerscore2 = None


    fitt = pd.Series(10**(4*np.arange(100)/100.))

    fitpower = fitfunc(p1,fitt)
    if p1wc is not None:
        fitpowerwc = 0.95*fitfunc(p1wc,fitt)
        fitpowerexcellent = 0.7*fitfunc(p1wc,fitt)
        fitpowergood = 0.6*fitfunc(p1wc,fitt)
        fitpowerfair = 0.5*fitfunc(p1wc,fitt)
        fitpoweraverage = 0.4*fitfunc(p1wc,fitt)

    else:
        fitpowerwc = 0*fitpower
        fitpowerexcellent = 0*fitpower
        fitpowergood = 0*fitpower
        fitpowerfair = 0*fitpower
        fitpoweraverage = 0*fitpower



    message = ""
    if len(fitpower[fitpower<0]) > 0:
        message = "CP model fit didn't give correct results"

    fitvelo = (fitpower/2.8)**(1./3.)
    fitdist = fitt*fitvelo
    fitp = 500./fitvelo
    fitp2 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x))

    sourcecomplex = ColumnDataSource(
        data = dict(
            dist = fitdist,
            duration = fitt,
            tim = niceformat(
                fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x))
                ),
            spm = 0*fitpower,
            power = fitpower,
            fitpowerwc = fitpowerwc,
            fitpowerexcellent = fitpowerexcellent,
            fitpowergood = fitpowergood,
            fitpowerfair = fitpowerfair,
            fitpoweraverage = fitpoweraverage,
            fpace = nicepaceformat(fitp2),
            )
        )



    # making the plot
    plot = Figure(tools=TOOLS,x_axis_type=x_axis_type,
                  plot_width=900,
                  toolbar_location="above",
                  toolbar_sticky=False)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],1.8*max(thesecs),watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   y_range_name = "watermark",
                   )

    plot.circle('duration','power',source=source,fill_color='red',size=15,
                legend='Power')
    plot.xaxis.axis_label = "Duration (seconds)"
    plot.yaxis.axis_label = "Power (W)"

    if stayerscore is not None:
        plot.add_layout(
            Label(x=100,y=100,x_units='screen',y_units='screen',
                  text='Stayer Score '+str(stayerscore)+'%',
                  background_fill_alpha=0.7,
                  background_fill_color='white',
                  text_color='black')
            )
#        plot.add_layout(
#            Label(x=100,y=120,x_units='screen',y_units='screen',
#                  text='Stayer Score (6min) '+str(stayerscore2)+'%',
#                  background_fill_alpha=0.7,
#                  background_fill_color='white',
#                  text_color='black')
#            )

    cpdata = dataprep.fetchcperg(rower, theworkouts)


    if cpdata.empty:
        message = 'Calculations are running in the background. Please refresh this page to see updated results'
        return ['','',paulslope,paulintercept,p1,message,p1wc]

    velo = cpdata['distance']/cpdata['delta']

    p = 500./velo

    p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x))

    source2 = ColumnDataSource(
        data = dict(
            duration = cpdata['delta'],
            power = cpdata['cp'],
            tim = niceformat(
                cpdata['delta'].fillna(method='ffill').apply(lambda x: timedeltaconv(x))
                ),
            dist = cpdata['distance'],
            pace = nicepaceformat(p2),
            )
        )

    plot.circle('duration','power',source=source2,
                fill_color='blue',size=3,
                legend = 'Power from segments')

    hover = plot.select(dict(type=HoverTool))

    hover.tooltips = OrderedDict([
        ('Duration ','@tim'),
        ('Power (W)','@power{int}'),
        ('Distance (m)','@dist{int}'),
        ('Pace (/500m)','@fpace'),
        ])

    hover.mode = 'mouse'

    plot.y_range = Range1d(0,1.5*max(theavpower))
    plot.x_range = Range1d(1,2*max(thesecs))
    plot.legend.orientation = "vertical"


    plot.line('duration','power',source=sourcepaul,legend="Paul's Law")
    plot.line('duration','power',source=sourcecomplex,legend="CP Model",
              color='green')
    if p1wc is not None:
        plot.line('duration','fitpowerwc',source=sourcecomplex,
                  legend="World Class",
                  color='Maroon',line_dash='dotted')

        plot.line('duration','fitpowerexcellent',source=sourcecomplex,
                  legend="90% percentile",
                  color='Purple',line_dash='dotted')

        plot.line('duration','fitpowergood',source=sourcecomplex,
                  legend="75% percentile",
                  color='Olive',line_dash='dotted')

        plot.line('duration','fitpowerfair',source=sourcecomplex,
                  legend="50% percentile",
                  color='Gray',line_dash='dotted')

        plot.line('duration','fitpoweraverage',source=sourcecomplex,
                  legend="25% percentile",
                  color='SkyBlue',line_dash='dotted')


    script, div = components(plot)


    return [script,div,paulslope,paulintercept,p1,message,p1wc]

def interactive_windchart(id=0,promember=0):
    # check if valid ID exists (workout exists)
    row = Workout.objects.get(id=id)
    # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")

    f1 = row.csvfilename

    # create interactive plot
    plot = Figure(plot_width=400,plot_height=300)

    # get user
    # u = User.objects.get(id=row.user.id)
    r = row.user
    u = r.user



    rr = rrower(hrmax=r.max,hrut2=r.ut2,
                hrut1=r.ut1,hrat=r.at,
                hrtr=r.tr,hran=r.an,ftp=r.ftp)

    rowdata = rdata(f1,rower=rr)
    if rowdata == 0:
        return 0

    try:
        dist = rowdata.df.loc[:,'cum_dist']
    except KeyError:
        return ['','No Data Found']

    try:
        vwind = rowdata.df.loc[:,'vwind']
        winddirection = rowdata.df.loc[:,'winddirection']
        bearing = rowdata.df.loc[:,'bearing']
    except KeyError:
        rowdata.add_wind(0,0)
        rowdata.add_bearing()
        vwind = rowdata.df.loc[:,'vwind']
        winddirection = rowdata.df.loc[:,'winddirection']
        bearing = rowdata.df.loc[:,'winddirection']
        rowdata.write_csv(f1,gzip=True)
        dataprep.update_strokedata(id,rowdata.df)

    winddirection = winddirection % 360
    winddirection = (winddirection + 360) % 360

    tw = tailwind(bearing,vwind,1.0*winddirection)


    source = ColumnDataSource(
        data = dict(
            dist=dist,
            vwind=vwind,
            tw=tw,
            winddirection=winddirection,
            )
        )

    # plot tools
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'



    # making the plot
    plot = Figure(tools=TOOLS,plot_width=400,height=500,
#                 toolbar_location="below",
                  toolbar_sticky=False,
                  )
    plot.line('dist','vwind',source=source,legend="Wind Speed (m/s)")
    plot.line('dist','tw',source=source,legend="Tail (+)/Head (-) Wind (m/s)",color='black')
    plot.title.text = row.name
    #    plot.title.text_font_size=value("1.0em")
    plot.title.text_font="1.0em"
    plot.xaxis.axis_label = "Distance (m)"
    plot.yaxis.axis_label = "Wind Speed (m/s)"
    plot.y_range = Range1d(-7,7)
    plot.sizing_mode = 'scale_width'


    plot.extra_y_ranges = {"winddirection": Range1d(start=0,end=360)}
    plot.line('dist','winddirection',source=source,
              legend='Wind Direction',color="red",
              y_range_name="winddirection")
    plot.add_layout(LinearAxis(y_range_name="winddirection",axis_label="Wind Direction (degree)"),'right')


    script, div = components(plot)

    return [script,div]

def interactive_streamchart(id=0,promember=0):
    # check if valid ID exists (workout exists)
    row = Workout.objects.get(id=id)
    # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")

    f1 = row.csvfilename

    # create interactive plot
    plot = Figure(plot_width=400,
                  )
    # get user
    # u = User.objects.get(id=row.user.id)
    r = row.user
    u = r.user



    rr = rrower(hrmax=r.max,hrut2=r.ut2,
                hrut1=r.ut1,hrat=r.at,
                hrtr=r.tr,hran=r.an,ftp=r.ftp)

    rowdata = rdata(f1,rower=rr)
    if rowdata == 0:
        return "","No Valid Data Available"

    try:
        dist = rowdata.df.loc[:,'cum_dist']
    except KeyError:
        return ['','No Data found']

    try:
        vstream = rowdata.df.loc[:,'vstream']
    except KeyError:
        rowdata.add_stream(0)
        vstream = rowdata.df.loc[:,'vstream']
        rowdata.write_csv(f1,gzip=True)
        dataprep.update_strokedata(id,rowdata.df)

    # plot tools
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'



    # making the plot
    plot = Figure(tools=TOOLS,plot_width=400,height=500,
#                 toolbar_location="below",
                  toolbar_sticky=False,
                  )
    plot.line(dist,vstream,legend="River Stream Velocity (m/s)")
    plot.title.text = row.name
    plot.title.text_font_size=value("1.0em")
    plot.xaxis.axis_label = "Distance (m)"
    plot.yaxis.axis_label = "River Current (m/s)"
    plot.y_range = Range1d(-2,2)
    plot.sizing_mode = 'scale_width'


    script, div = components(plot)

    return [script,div]

def interactive_chart(id=0,promember=0,intervaldata = {}):
    # Add hover to this comma-separated string and see what changes
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'


    columns = ['time','pace','hr','fpace','ftime','spm']
    datadf = dataprep.getsmallrowdata_db(columns,ids=[id])

    datadf.dropna(axis=0,how='any',inplace=True)

    row = Workout.objects.get(id=id)
    if datadf.empty:
        return "","No Valid Data Available"
    #else:
    #    try:
    #        datadf.sort_values(by='time',ascending=True,inplace=True)
    #    except KeyError:
    #        return "","No valid data available"

    try:
        spm = datadf['spm']
    except KeyError:
        datadf['spm'] = 0

    try:
        pace = datadf['pace']
    except KeyError:
        datadf['pace'] = 0

    source = ColumnDataSource(
        datadf
        )

    plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
                  plot_width=400,
                  plot_height=400,
                  toolbar_sticky=False,
                  tools=TOOLS)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}

    plot.image_url([watermarkurl],0.01,0.99,
                   0.5*watermarkw,0.5*watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor='top_left',
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    plot.line('time','pace',source=source,legend="Pace",name="pace")
    plot.title.text = row.name
    plot.title.text_font_size=value("1.0em")
    plot.sizing_mode = 'scale_width'
    plot.xaxis.axis_label = "Time"
    plot.yaxis.axis_label = "Pace (/500m)"
    plot.xaxis[0].formatter = DatetimeTickFormatter(
            hours = ["%H"],
            minutes = ["%M"],
            seconds = ["%S"],
            days = ["0"],
            months = [""],
            years = [""]
        )
    plot.yaxis[0].formatter = DatetimeTickFormatter(
            seconds = ["%S"],
            minutes = ["%M"]
        )
    ymax = 90.
    ymin = 150.

    if row.workouttype == 'water':
        ymax = 90.
        ymin = 210.

    plot.y_range = Range1d(1.e3*ymin,1.e3*ymax)


    plot.extra_y_ranges["spmax"] = Range1d(start=10,end=45)
    plot.line('time','spm',source=source,color="red",
              y_range_name="spmax", legend="Stroke Rate",name="spm")
    plot.add_layout(LinearAxis(y_range_name="spmax",axis_label="SPM"),'right')

    plot.legend.location = "bottom_right"

    # add shaded bar chart areas
    if intervaldata != {}:
        intervaldf = pd.DataFrame(intervaldata)
        intervaldf['itime'] = intervaldf['itime']*1.e3
        intervaldf['time'] = intervaldf['itime'].cumsum()
        intervaldf['time'] = intervaldf['time'].shift(1)
        intervaldf.loc[:,'time'].iloc[0] = 0
        intervaldf['time_r'] = intervaldf['time'] +intervaldf['itime']
        intervaldf['value'] = 100
        mask = intervaldf['itype'] == 3
        intervaldf.loc[mask,'value'] = 0
        intervaldf['bottom'] = 10

        intervalsource = ColumnDataSource(
            intervaldf
        )

        plot.quad(left='time',top='value',bottom='bottom',
                  right='time_r',source=intervalsource,color='mediumvioletred',
                  y_range_name='spmax',fill_alpha=0.2,line_alpha=0.2)


    hover = plot.select(dict(type=HoverTool))


    hover.tooltips = OrderedDict([
        ('Time','@ftime'),
        ('Pace','@fpace'),
        ('HR','@hr{int}'),
        ('SPM','@spm{1.1}'),
        ])

    hover.mode = 'mouse'
    hover.names = ["spm","pace"]

    script, div = components(plot)

    return [script,div]

def interactive_chart_video(videodata):

    spm = videodata['spm']
    time = range(len(spm))

    data = zip(time,spm)

    data2 = "["

    for t,s in data:
        data2 += "{x: %s, y: %s}, " % (t,s)

    data2 = data2[:-2] + "]"

    markerpoint = {
        'x': time[0],
        'y': spm[0],
        'r': 10,
    }

    div = """
    <canvas id="myChart">
    </canvas>
    """

    script = """
    var ctx = document.getElementById("myChart").getContext('2d');
    var data = %s

   var myChart = new Chart(ctx, {
        type: 'scatter',
        label: 'SPM',
        animationSteps: 10,
        options: {
            legend: {
                display: false,
            },
            animation: {
                duration: 100,
            },
            scales: {
                yAxes: [{
                    scaleLabel: {
                        display: true,
                        labelString: 'Stroke Rate'
                    }
                }],
                xAxes: [{
                    scaleLabel: {
                        type: 'linear',
                        display: true,
                        labelString: 'Time (seconds)'
                    }
                }],
            }
        },
        data:
        {
            datasets: [
            {
                type: 'bubble',
                label: 'now',
                data: [ %s ],
                backgroundColor: '#36a2eb',
            },
            {
                label: 'spm',
                data: data,
                backgroundColor: "#ff0000",
                borderColor: "#ff0000",
                fill: false,
                borderDash: [0, 0],
                pointRadius: 1,
                pointHoverRadius: 1,
                showLine: true,
                tension: 0,
            },

            ]
        },

    });

    var marker = {
     datapoint: %s ,
     setLatLng: function (LatLng) {
       var lat = LatLng.lat;
       var lng = LatLng.lng;
       this.datapoint = {
          'x': lat,
          'y': lng,
          'r': 10,
       }
       myChart.data.datasets[0].data[0] = this.datapoint;
       myChart.update();
    }
   }
   marker.setLatLng({
   'lat': data[0]['x'],
   'lng': data[0]['y']
   })

    """ % (data2, markerpoint, markerpoint)

    return [script,div]



def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
                          ploterrorbars=False,
                          title=None,binsize=1,colorlegend=[],
                          spmmin=0,spmmax=0,workmin=0,workmax=0):

    if datadf.empty:
        return ['','<p>No non-zero data in selection</p>']

    if xparam == 'workoutid':
        xparamname = 'Workout'
    else:
        xparamname = axlabels[xparam]

    if yparam == 'workoutid':
        yparamname = 'Workout'
    else:
        yparamname = axlabels[yparam]

    if groupby == 'workoutid':
        groupname = 'Workout'
    elif groupby == 'date':
        groupname = 'Date'
    else:
        groupname = axlabels[groupby]


    if title==None:
        title = '{y} vs {x} grouped by {gr}'.format(
            x = xparamname,
            y = yparamname,
            gr = groupname,
            )

    if xparam == 'cumdist':
        res = make_cumvalues(datadf[xparam])
        datadf[xparam] = res[0]
    if xparam=='distance':
        xaxmax = datadf[xparam].max()
        xaxmin = datadf[xparam].min()
    elif xparam=='time':
        tseconds = datadf.loc[:,'time']
        xaxmax = tseconds.max()
        xaxmin = 0
    elif xparam == 'workoutid':
        xaxmax = datadf[xparam].max()-5
        xaxmin = datadf[xparam].min()+5
    else:
        xaxmax = yaxmaxima[xparam]
        xaxmin = yaxminima[xparam]

    if yparam=='distance':
        yaxmax = datadf[yparam].max()
        yaxmin = datadf[yparam].min()
    elif yparam=='time':
        tseconds = datadf.loc[:,'time']
        yaxmax = tseconds.max()
        yaxmin = 0
    elif yparam == 'workoutid':
        yaxmax = datadf[yparam].max()-5
        yaxmin = datadf[yparam].min()+5
    else:
        yaxmax = yaxmaxima[yparam]
        yaxmin = yaxminima[yparam]

    x_axis_type = 'linear'
    y_axis_type = 'linear'
    if xparam == 'time':
        x_axis_type = 'datetime'
    if yparam == 'pace':
        y_axis_type = 'datetime'

    datadf.index.names = ['index']

    source = ColumnDataSource(
        datadf,
        )


    TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap'

    if groupby != 'date':
        hover = HoverTool(names=['data'],
                          tooltips = [
                              (groupby,'@groupval{1.1}'),
                              (xparamname,'@x{1.1}'),
                              (yparamname,'@y')
                          ])
    else:
        hover = HoverTool(names=['data'],
                          tooltips = [
                              (groupby,'@groupval'),
                              (xparamname,'@x{1.1}'),
                              (yparamname,'@y')
                              ,
                          ])

    hover.mode = 'mouse'
    TOOLS = [SaveTool(),PanTool(),BoxZoomTool(),WheelZoomTool(),
             ResetTool(),TapTool(),hover]


    plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
                  tools=TOOLS,
                  toolbar_location="above",
                  toolbar_sticky=False,plot_width=920)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}

    plot.title.text = title
    plot.title.text_font_size=value("1.0em")
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],watermarkx,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    errorbar(plot,xparam,yparam,source=source,
             xerr=ploterrorbars,
             yerr=ploterrorbars,
             point_kwargs={
                 'line_color':"#969696",
                 'size':"groupsize",
                 'fill_color':"color",
                 'fill_alpha':1.0,
             },
    )



    for nr, gvalue, color in colorlegend:
        box = BoxAnnotation(bottom=75+20*nr,left=50,top=95+20*nr,
                            right=70,
                            bottom_units='screen',
                            top_units='screen',
                            left_units='screen',
                            right_units='screen',
                            fill_color=color,
                            fill_alpha=1.0,
                            line_color=color)
        legendlabel = Label(x=71,y=78+20*nr,x_units='screen',
                            y_units='screen',
                            text = "{gvalue:3.0f}".format(gvalue=gvalue),
                            background_fill_alpha=1.0,
                            text_color='black',
                            text_font_size=value("0.7em"))
        plot.add_layout(box)
        plot.add_layout(legendlabel)

    if colorlegend:
        legendlabel = Label(x=322,y=250,x_units='screen',
                            y_units='screen',
                            text = 'group legend',
                            text_color='black',
                            text_font_size=value("0.7em"),
                            angle=90,
                            angle_units='deg')

    if xparam == 'workoutid':
        plot.xaxis.axis_label = 'Workout'
    else:
        plot.xaxis.axis_label = axlabels[xparam]

    if yparam == 'workoutid':
        plot.xaxis.axis_label = 'Workout'
    else:
        plot.yaxis.axis_label = axlabels[yparam]

    binlabel = Label(x=50,y=50,x_units='screen',
                     y_units='screen',
                     text="Bin size {binsize:3.1f}".format(binsize=binsize),
                     background_fill_alpha=0.7,
                     background_fill_color='white',
                     text_color='black',text_font_size='10pt',
                     )

    slidertext = 'SPM: {:.0f}-{:.0f}, WpS: {:.0f}-{:.0f}'.format(
        spmmin,spmmax,workmin,workmax
        )
    sliderlabel = Label(x=50,y=20,x_units='screen',y_units='screen',
                        text=slidertext,
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='black',text_font_size='10pt',
                        )


    plot.add_layout(binlabel)
    plot.add_layout(sliderlabel)

    yrange1 = Range1d(start=yaxmin,end=yaxmax)
    plot.y_range = yrange1

    xrange1 = Range1d(start=xaxmin,end=xaxmax)
    plot.x_range = xrange1

    if yparam == 'pace':
        plot.yaxis[0].formatter = DatetimeTickFormatter(
                seconds = ["%S"],
                minutes = ["%M"]
            )


    script,div = components(plot)


    return [script,div]

def interactive_cum_flex_chart2(theworkouts,promember=0,
                                xparam='spm',
                                yparam1='power',
                                yparam2='spm',
                                workstrokesonly=False):

    # datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2)
    ids = [int(w.id) for w in theworkouts]
    columns = [xparam,yparam1,yparam2,'spm','driveenergy','distance']
    datadf = dataprep.getsmallrowdata_db(columns,ids=ids,doclean=True,
                                         workstrokesonly=workstrokesonly)

    try:
        tests = datadf[yparam2]
    except KeyError:
        yparam2 = 'None'

    try:
        tests = datadf[yparam1]
    except KeyError:
        yparam1 = 'None'

    datadf.dropna(axis=1,how='all',inplace=True)
    datadf.dropna(axis=0,how='any',inplace=True)

    # test if we have drive energy
    nowork = 1
    try:
        test = datadf['driveenergy'].mean()
        nowork = 0
    except KeyError:
        datadf['driveenergy'] = 500.

    # test if we have power
    nopower = 1
    try:
        test = datadf['power'].mean()
        nopower = 0
    except KeyError:
        datadf['power'] = 50.


    yparamname1 = axlabels[yparam1]
    if yparam2 != 'None':
        yparamname2 = axlabels[yparam2]


    # check if dataframe not empty
    if datadf.empty:
        return ['','<p>No non-zero data in selection</p>','','']


    try:
        datadf['x1'] = datadf.loc[:,xparam]
    except KeyError:
        try:
            datadf['x1'] = datadf['distance']
        except KeyError:
            try:
                datadf['x1'] = datadf['time']
            except KeyError:
                return ['','<p>No non-zero data in selection</p>','','']

    try:
        datadf['y1'] = datadf.loc[:,yparam1]
    except KeyError:
        try:
            datadf['y1'] = datadf['pace']
        except KeyError:
            return ['','<p>No non-zero data in selection</p>','','']
    if yparam2 != 'None':
        try:
            datadf['y2'] = datadf.loc[:,yparam2]
        except KeyError:
            datadf['y2'] = datadf['y1']
    else:
        datadf['y2'] = datadf['y1']


    if xparam=='distance':
        xaxmax = datadf['x1'].max()
        xaxmin = datadf['x1'].min()
    else:
        xaxmax = yaxmaxima[xparam]
        xaxmin = yaxminima[xparam]

    # average values
    x1mean = datadf['x1'].mean()

    y1mean = datadf['y1'].mean()
    y2mean = datadf['y2'].mean()


    xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.)

    x_axis_type = 'linear'
    y_axis_type = 'linear'
    if xparam == 'time':
        x_axis_type = 'datetime'

    if yparam1 == 'pace':
        y_axis_type = 'datetime'
        y1mean = datadf.loc[:,'pace'].mean()

    datadf['xname'] = axlabels[xparam]
    datadf['yname1'] = axlabels[yparam1]
    if yparam2 != 'None':
        datadf['yname2'] = axlabels[yparam2]
    else:
        datadf['yname2'] = axlabels[yparam1]


    source = ColumnDataSource(
        datadf
        )

    source2 = ColumnDataSource(
        datadf.copy()
        )

    # Add hover to this comma-separated string and see what changes
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'

    plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
                  tools=TOOLS,
                  toolbar_location="above",
                  toolbar_sticky=False)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],watermarkx,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    x1means = Span(location=x1mean,dimension='height',line_color='green',
                   line_dash=[6,6], line_width=2)

    y1means = Span(location=y1mean,dimension='width',line_color='blue',
                   line_dash=[6,6],line_width=2)
    y2means = y1means

    xlabel = Label(x=50,y=80,x_units='screen',y_units='screen',
                   text=axlabels[xparam]+": {x1mean:6.2f}".format(x1mean=x1mean),
                   background_fill_alpha=.7,
                   background_fill_color='white',
                   text_color='green',
    )

    sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
                        text='',
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='black',text_font_size='10pt',
                        )


    plot.add_layout(x1means)
    plot.add_layout(xlabel)
    plot.add_layout(y1means)
    plot.add_layout(sliderlabel)

    y1label = Label(x=50,y=50,x_units='screen',y_units='screen',
                    text=axlabels[yparam1]+": {y1mean:6.2f}".format(y1mean=y1mean),
                    background_fill_alpha=.7,
                    background_fill_color='white',
                    text_color='blue',
    )

    if yparam1 != 'time' and yparam1 != 'pace':
        plot.add_layout(y1label)

    y2label = y1label
    plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None,
                 legend=yparamname1,
                 )

    plot.xaxis.axis_label = axlabels[xparam]
    plot.yaxis.axis_label = axlabels[yparam1]


    yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
    plot.y_range = yrange1

    xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
    plot.x_range = xrange1

    if yparam1 == 'pace':
        plot.yaxis[0].formatter = DatetimeTickFormatter(
                seconds = ["%S"],
                minutes = ["%M"]
            )

    if yparam2 != 'None':
        yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
        plot.extra_y_ranges["yax2"] = yrange2

        plot.circle('x1','y2',color="red",y_range_name="yax2",
                    legend=yparamname2,
                    source=source2,fill_alpha=0.3,line_color=None)

        plot.add_layout(LinearAxis(y_range_name="yax2",
                                   axis_label=axlabels[yparam2]),'right')

        y2means = Span(location=y2mean,dimension='width',line_color='red',
                       line_dash=[6,6],line_width=2,y_range_name="yax2")


        plot.add_layout(y2means)
        y2label = Label(x=50,y=20,x_units='screen',y_units='screen',
                        text=axlabels[yparam2]+": {y2mean:6.2f}".format(y2mean=y2mean),
                        background_fill_alpha=.7,
                        background_fill_color='white',
                        text_color='red',
        )
        if yparam2 != 'pace' and yparam2 != 'time':
            plot.add_layout(y2label)

    callback = CustomJS(args = dict(source=source,source2=source2,
                                    x1means=x1means,
                                    y1means=y1means,
                                    y1label=y1label,
                                    y2label=y2label,
                                    xlabel=xlabel,
                                    sliderlabel=sliderlabel,
                                    y2means=y2means), code="""
       var data = source.data
       var data2 = source2.data
       var x1 = data['x1']
       var y1 = data['y1']
       var y2 = data['y2']
       var spm1 = data['spm']

       var index1 = data['index']

       var distance1 = data['distance']
       var power1 = data['power']
       var driveenergy1 = data['driveenergy']
       var xname = data['xname']
       var yname1 = data['yname1']
       var yname2 = data['yname2']
       var workoutid1 = data['workoutid']

       var minspm = minspm.value
       var maxspm = maxspm.value
       var mindist = mindist.value
       var maxdist = maxdist.value
       var minwork = minwork.value
       var maxwork = maxwork.value

       sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
       sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
       sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)

       var xm = 0
       var ym1 = 0
       var ym2 = 0

       data2['x1'] = []
       data2['y1'] = []
       data2['y2'] = []
       data2['index'] = []
       data2['distance'] = []
       data2['power'] = []
       data2['x1mean'] = []
       data2['y1mean'] = []
       data2['y2mean'] = []
       data2['driveenergy'] = []
       data2['workoutid'] = []
       data2['xname'] = []
       data2['yname1'] = []
       data2['yname2'] = []
       data2['spm'] = []

       for (i=0; i<x1.length; i++) {
          if (spm1[i]>=minspm && spm1[i]<=maxspm) {
             if (distance1[i]>=mindist && distance1[i]<=maxdist) {
                if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
                   data2['x1'].push(x1[i])
                   data2['y1'].push(y1[i])
                   data2['y2'].push(y2[i])
                   data2['spm'].push(spm1[i])
                   data2['index'].push(index1[i])
                   data2['driveenergy'].push(driveenergy1[i])
                   data2['distance'].push(distance1[i])
                   data2['power'].push(power1[i])
                   data2['workoutid'].push(0)
                   data2['xname'].push(0)
                   data2['yname1'].push(0)
                   data2['yname2'].push(0)

                   xm += x1[i]
                   ym1 += y1[i]
                   ym2 += y2[i]
                   }
                }
             }
       }


       xm /= data2['x1'].length
       ym1 /= data2['x1'].length
       ym2 /= data2['x1'].length

       for (i=0; i<data2['x1'].length; i++) {
          data2['x1mean'].push(xm)
          data2['y1mean'].push(ym1)
          data2['y2mean'].push(ym2)
       }

       x1means.location = xm
       y1means.location = ym1
       y2means.location = ym2
       y1label.text = yname1[0]+': '+(ym1).toFixed(2)
       y2label.text = yname2[0]+': '+(ym2).toFixed(2)
       xlabel.text = xname[0]+': '+(xm).toFixed(2)

       source2.change.emit();
       """)

    slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
                title="Min SPM",callback=callback)
    callback.args["minspm"] = slider_spm_min


    slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
                title="Max SPM",callback=callback)
    callback.args["maxspm"] = slider_spm_max

    slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10,
                title="Min Work per Stroke",callback=callback)
    callback.args["minwork"] = slider_work_min


    slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10,
                title="Max Work per Stroke",callback=callback)
    callback.args["maxwork"] = slider_work_max

    try:
        distmax = 100+100*int(datadf['distance'].max()/100.)
    except KeyError:
        distmax = 1000.

    slider_dist_min = Slider(start=0,end=distmax,value=0,step=50,
                             title="Min Distance",callback=callback)
    callback.args["mindist"] = slider_dist_min

    slider_dist_max = Slider(start=0,end=distmax,value=distmax,
                             step=50,
                             title="Max Distance",callback=callback)
    callback.args["maxdist"] = slider_dist_max

    layout = layoutrow([layoutcolumn([slider_spm_min,
                                      slider_spm_max,
                                      slider_dist_min,
                                      slider_dist_max,
                                      slider_work_min,
                                      slider_work_max,
                               ],
                                     ),
                        plot])

    layout.sizing_mode = 'scale_width'

    script, div = components(layout)
    js_resources = INLINE.render_js()
    css_resources = INLINE.render_css()



    return [script,div,js_resources,css_resources]




def interactive_flex_chart2(id=0,promember=0,
                           xparam='time',
                           yparam1='pace',
                           yparam2='hr',
                           plottype='line',
                           workstrokesonly=False):

    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'

    #rowdata,row = dataprep.getrowdata_db(id=id)
    columns = [xparam,yparam1,yparam2,
               'ftime','distance','fpace',
               'power','hr','spm','driveenergy',
               'time','pace','workoutstate']

    rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
                                          workstrokesonly=workstrokesonly)


    if len(rowdata)<2:
        rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True,
                                              workstrokesonly=False)
        workstrokesonly=False
    if len(rowdata)<2:
        rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],
                                              doclean=False,
                                              workstrokesonly=False)
        workstrokesonly=False
    try:
        tests = rowdata[yparam2]
    except KeyError:
        yparam2 = 'None'



    try:
        tests = rowdata[yparam1]
    except KeyError:
        yparam1 = 'None'


    # test if we have drive energy
    nowork = 1
    try:
        test = rowdata['driveenergy'].mean()
        nowork = 0
    except KeyError:
        rowdata['driveenergy'] = 500.

    # test if we have power
    nopower = 1
    try:
        test = rowdata['power'].mean()
        nopower = 0
    except KeyError:
        rowdata['power'] = 50.

    # replace nans
    rowdata.fillna(value=0,inplace=True)

    row = Workout.objects.get(id=id)
    if rowdata.empty:
        return "","No valid data",'','',workstrokesonly


    workoutstateswork = [1,4,5,8,9,6,7]
    workoutstatesrest = [3]
    workoutstatetransition = [0,2,10,11,12,13]

    if workstrokesonly:
        try:
            rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
        except KeyError:
            pass

    try:
        tseconds = rowdata.loc[:,'time']
    except KeyError:
        return '','No time data - cannot make flex plot','','',workstrokesonly


    try:
        rowdata['x1'] = rowdata.loc[:,xparam]
        rowmin = rowdata[xparam].min()
    except KeyError:
        rowdata['x1'] = 0*rowdata.loc[:,'time']

    try:
        rowdata['y1'] = rowdata.loc[:,yparam1]
        rowmin = rowdata[yparam1].min()
    except KeyError:
        rowdata['y1'] = 0*rowdata.loc[:,'time']
        rowdata[yparam1] = rowdata['y1']

    if yparam2 != 'None':
        try:
            rowdata['y2'] = rowdata.loc[:,yparam2]
            rowmin = rowdata[yparam2].min()
        except KeyError:
            rowdata['y2'] = 0*rowdata.loc[:,'time']
            rowdata[yparam2] = rowdata['y2']
    else:
        rowdata['y2'] = rowdata['y1']

    if xparam=='time':
        xaxmax = tseconds.max()
        xaxmin = tseconds.min()
    elif xparam=='distance' or xparam=='cumdist':
        xaxmax = rowdata['x1'].max()
        xaxmin = rowdata['x1'].min()
    else:
        try:
            xaxmax = yaxmaxima[xparam]
            xaxmin = yaxminima[xparam]
        except KeyError:
            xaxmax = rowdata['x1'].max()
            xaxmin = rowdata['x1'].min()

    # average values
    if xparam != 'time':
        try:
            x1mean = rowdata['x1'].mean()
        except TypeError:
            x1mean = 0
    else:
        x1mean = 0

    y1mean = rowdata['y1'].mean()
    y2mean = rowdata['y2'].mean()

    if xparam != 'time':
        xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
    else:
        xvals = np.arange(100)

    # constant power plot
    if yparam1 == 'driveenergy':
        if xparam == 'spm':
            yconstantpower = rowdata['y1'].mean()*rowdata['x1'].mean()/xvals

    x_axis_type = 'linear'
    y_axis_type = 'linear'
    if xparam == 'time':
        x_axis_type = 'datetime'

    if yparam1 == 'pace':
        y_axis_type = 'datetime'
        try:
            y1mean = rowdata.loc[:,'pace'].mean()
        except KeyError:
            y1mean = 0

    try:
        rowdata['xname'] = axlabels[xparam]
    except KeyError:
        rowdata['xname'] = xparam
    try:
        rowdata['yname1'] = axlabels[yparam1]
    except KeyError:
        rowdata['yname1'] = yparam1
    if yparam2 != 'None':
        try:
            rowdata['yname2'] = axlabels[yparam2]
        except KeyError:
            rowdata['yname2'] = yparam2
    else:
        rowdata['yname2'] = rowdata['yname1']


    # prepare data
    source = ColumnDataSource(
        rowdata
        )



    # second source for filtering
    source2 = ColumnDataSource(
        rowdata.copy()
        )

    # Add hover to this comma-separated string and see what changes
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'



    plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
                  tools=TOOLS,toolbar_location='above',
                  toolbar_sticky=False
                  )



    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],watermarkx,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    x1means = Span(location=x1mean,dimension='height',line_color='green',
                   line_dash=[6,6], line_width=2)

    y1means = Span(location=y1mean,dimension='width',line_color='blue',
                   line_dash=[6,6],line_width=2)
    y2means = y1means

    try:
        xlabeltext = axlabels[xparam]+": {x1mean:6.2f}".format(
            x1mean=x1mean
        )
    except KeyError:
        xlabeltext = xparam+": {x1mean:6.2f}".format(x1mean=x1mean)

    xlabel = Label(x=50,y=80,x_units='screen',y_units='screen',
                   text=xlabeltext,
                   background_fill_alpha=.7,
                   background_fill_color='white',
                   text_color='green',
    )

    annolabel = Label(x=50,y=450,x_units='screen',y_units='screen',
                      text='',
                      background_fill_alpha=0.7,
                      background_fill_color='white',
                      text_color='black',
    )

    sliderlabel = Label(x=10,y=470,x_units='screen',y_units='screen',
                        text='',
                        background_fill_alpha=0.7,
                        background_fill_color='white',
                        text_color='black',text_font_size='10pt',
                        )


    if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
        plot.add_layout(x1means)
        plot.add_layout(xlabel)


    plot.add_layout(y1means)
    plot.add_layout(annolabel)
    plot.add_layout(sliderlabel)

    try:
        yaxlabel = axlabels[yparam1]
    except KeyError:
        yaxlabel = str(yparam1)+' '

    try:
        xaxlabel = axlabels[xparam]
    except KeyError:
        xaxlabel = xparam

    y1label = Label(x=50,y=50,x_units='screen',y_units='screen',
                    text=yaxlabel+": {y1mean:6.2f}".format(y1mean=y1mean),
                    background_fill_alpha=.7,
                    background_fill_color='white',
                    text_color='blue',
    )
    if yparam1 != 'time' and yparam1 != 'pace':
        plot.add_layout(y1label)
    y2label = y1label

    # average values
    if yparam1 == 'driveenergy':
        if xparam == 'spm':
            plot.line(xvals,yconstantpower,color="green",legend="Constant Power")

    if plottype=='line':
        plot.line('x1','y1',source=source2,legend=yaxlabel)
    elif plottype=='scatter':
        plot.scatter('x1','y1',source=source2,legend=yaxlabel,fill_alpha=0.4,
                     line_color=None)

    plot.title.text = row.name
    plot.title.text_font_size=value("1.0em")

    plot.sizing_mode = 'scale_width'
    plot.xaxis.axis_label = xaxlabel

    plot.yaxis.axis_label = yaxlabel



    try:
        yrange1 = Range1d(start=yaxminima[yparam1],
                              end=yaxmaxima[yparam1])
    except KeyError:
        yrange1 = Range1d(start=rowdata[yparam1].min(),
                          end=rowdata[yparam1].max())

    plot.y_range = yrange1

    if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
        try:
            xrange1 = Range1d(start=yaxminima[xparam],
                              end=yaxmaxima[xparam])
        except KeyError:
            xrange1 = Range1d(start=rowdata[xparam].min(),
                              end=rowdata[xparam].max())

        plot.x_range = xrange1

    if xparam == 'time':
        xrange1 = Range1d(start=xaxmin,end=xaxmax)
        plot.x_range = xrange1
        plot.xaxis[0].formatter = DatetimeTickFormatter(
                hours = ["%H"],
                minutes = ["%M"],
                seconds = ["%S"],
                days = ["0"],
                months = [""],
                years = [""]
            )


    if yparam1 == 'pace':
        plot.yaxis[0].formatter = DatetimeTickFormatter(
                seconds = ["%S"],
                minutes = ["%M"]
            )


    if yparam2 != 'None':
        try:
            yrange2 = Range1d(start=yaxminima[yparam2],
                              end=yaxmaxima[yparam2])
        except KeyError:
            yrange2 = Range1d(start=rowdata[yparam2].min(),
                              end=rowdata[yparam2].max())

        plot.extra_y_ranges["yax2"] = yrange2
        #= {"yax2": yrange2}
        try:
            axlegend = axlabels[yparam2]
        except KeyError:
            axlegend = str(yparam2)+' '

        if plottype=='line':
            plot.line('x1','y2',color="red",y_range_name="yax2",
                      legend=axlegend,
                      source=source2)

        elif plottype=='scatter':
            plot.scatter('x1','y2',source=source2,legend=axlegend,
                         fill_alpha=0.4,
                         line_color=None,color="red",y_range_name="yax2")

        plot.add_layout(LinearAxis(y_range_name="yax2",
                                   axis_label=axlegend),'right')

        y2means = Span(location=y2mean,dimension='width',line_color='red',
                       line_dash=[6,6],line_width=2,y_range_name="yax2")


        plot.add_layout(y2means)
        y2label = Label(x=50,y=20,x_units='screen',y_units='screen',
                        text=axlegend+": {y2mean:6.2f}".format(y2mean=y2mean),
                        background_fill_alpha=.7,
                        background_fill_color='white',
                        text_color='red',
        )
        if yparam2 != 'pace' and yparam2 != 'time':
            plot.add_layout(y2label)

    hover = plot.select(dict(type=HoverTool))


    hover.tooltips = OrderedDict([
        ('Time','@ftime'),
        ('Distance','@distance{int}'),
        ('Pace','@fpace'),
        ('HR','@hr{int}'),
        ('SPM','@spm{1.1}'),
        ('Power','@power{int}'),
        ])

    hover.mode = 'mouse'


    callback = CustomJS(args = dict(source=source,source2=source2,
                                    x1means=x1means,
                                    y1means=y1means,
                                    y1label=y1label,
                                    y2label=y2label,
                                    xlabel=xlabel,
                                    annolabel=annolabel,
                                    sliderlabel=sliderlabel,
                                    y2means=y2means,
    ), code="""
       var data = source.data
       var data2 = source2.data
       var x1 = data['x1']
       var y1 = data['y1']
       var y2 = data['y2']
       var spm1 = data['spm']
       var time1 = data['time']
       var ftime1 = data['ftime']
       var index1 = data['index']
       var pace1 = data['pace']
       var hr1 = data['hr']
       var fpace1 = data['fpace']
       var distance1 = data['distance']
       var power1 = data['power']
       var driveenergy1 = data['driveenergy']
       var xname = data['xname']
       var yname1 = data['yname1']
       var yname2 = data['yname2']
       var workoutid1 = data['workoutid']
       var workoutstate1 = data['workoutstate']

       var annotation = annotation.value
       var minspm = minspm.value
       var maxspm = maxspm.value
       var mindist = mindist.value
       var maxdist = maxdist.value
       var minwork = minwork.value
       var maxwork = maxwork.value

       sliderlabel.text = 'SPM: '+minspm.toFixed(0)+'-'+maxspm.toFixed(0)
       sliderlabel.text += ', Dist: '+mindist.toFixed(0)+'-'+maxdist.toFixed(0)
       sliderlabel.text += ', WpS: '+minwork.toFixed(0)+'-'+maxwork.toFixed(0)

       var xm = 0
       var ym1 = 0
       var ym2 = 0

       data2['x1'] = []
       data2['y1'] = []
       data2['y2'] = []
       data2['spm'] = []
       data2['time'] = []
       data2['ftime'] = []
       data2['pace'] = []
       data2['hr'] = []
       data2['fpace'] = []
       data2['index'] = []
       data2['distance'] = []
       data2['power'] = []
       data2['x1mean'] = []
       data2['y1mean'] = []
       data2['y2mean'] = []
       data2['driveenergy'] = []
       data2['workoutid'] = []
       data2['workoutstate'] = []
       data2['xname'] = []
       data2['yname1'] = []
       data2['yname2'] = []


       for (i=0; i<x1.length; i++) {
          if (spm1[i]>=minspm && spm1[i]<=maxspm) {
             if (distance1[i]>=mindist && distance1[i]<=maxdist) {
                if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) {
                   data2['x1'].push(x1[i])
                   data2['y1'].push(y1[i])
                   data2['y2'].push(y2[i])
                   data2['spm'].push(spm1[i])
                   data2['time'].push(time1[i])
                   data2['index'].push(index1[i])
                   data2['ftime'].push(ftime1[i])
                   data2['fpace'].push(fpace1[i])
                   data2['driveenergy'].push(driveenergy1[i])
                   data2['pace'].push(pace1[i])
                   data2['hr'].push(hr1[i])
                   data2['distance'].push(distance1[i])
                   data2['power'].push(power1[i])
                   data2['workoutid'].push(0)
                   data2['workoutstate'].push(0)
                   data2['xname'].push(0)
                   data2['yname1'].push(0)
                   data2['yname2'].push(0)


                   xm += x1[i]
                   ym1 += y1[i]
                   ym2 += y2[i]
                 }
                }
             }
       }

       xm /= data2['x1'].length
       ym1 /= data2['x1'].length
       ym2 /= data2['x1'].length

       for (i=0; i<data2['x1'].length; i++) {
          data2['x1mean'].push(xm)
          data2['y1mean'].push(ym1)
          data2['y2mean'].push(ym2)
       }



       x1means.location = xm
       y1means.location = ym1
       y2means.location = ym2
       y1label.text = yname1[0]+': '+ym1.toFixed(2)
       y2label.text = yname2[0]+': '+ym2.toFixed(2)
       xlabel.text = xname[0]+': '+xm.toFixed(2)
       annolabel.text = annotation

       source2.change.emit();
       """)

    annotation = TextInput(title="Type your plot notes here", value="",
                           callback=callback)
    callback.args["annotation"] = annotation

    slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
                title="Min SPM",callback=callback)
    callback.args["minspm"] = slider_spm_min


    slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
                title="Max SPM",callback=callback)
    callback.args["maxspm"] = slider_spm_max

    slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10,
                title="Min Work per Stroke",callback=callback)
    callback.args["minwork"] = slider_work_min


    slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10,
                title="Max Work per Stroke",callback=callback)
    callback.args["maxwork"] = slider_work_max

    try:
        distmax = 100+100*int(rowdata['distance'].max()/100.)
    except (KeyError,ValueError):
        distmax = 100

    slider_dist_min = Slider(start=0,end=distmax,value=0,step=50,
                             title="Min Distance",callback=callback)
    callback.args["mindist"] = slider_dist_min

    slider_dist_max = Slider(start=0,end=distmax,value=distmax,
                             step=50,
                             title="Max Distance",callback=callback)
    callback.args["maxdist"] = slider_dist_max

    thesliders = layoutcolumn([
        annotation,
        slider_spm_min,
        slider_spm_max,
        slider_dist_min,
        slider_dist_max,
        slider_work_min,
        slider_work_max,
    ])

    thesliders.sizing_mode = 'scale_width'

    layout = layoutrow([thesliders,
                        plot])

    #    layout.sizing_mode = 'scale_width'
    layout.sizing_mode = 'scale_width'

    script, div = components(layout)
    js_resources = INLINE.render_js()
    css_resources = INLINE.render_css()

    return [script,div,js_resources,css_resources,workstrokesonly]

def thumbnails_set(r,id,favorites):
    charts = []

    columns = [f.xparam for f in favorites]
    columns += [f.yparam1 for f in favorites]
    columns += [f.yparam2 for f in favorites]

    columns += ['time']
    rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True)

    rowdata.dropna(axis=1,how='all',inplace=True)

    if rowdata.empty:
        try:
            rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=False,
                                                  workstrokesonly=False)
        except:
            return [
                {'script':"",
                 'div':"",
                 'notes':""
                }]

    if rowdata.empty:
        return [
            {'script':"",
             'div':"",
             'notes':""
             }]

    #    else:
    #        try:
    #            rowdata.sort_values(by='time',ascending=True,inplace=True)
    #        except KeyError:
    #            pass

    l = len(rowdata)
    maxlength = 50
    if l > maxlength:
        try:
            bins = np.linspace(rowdata['time'].min(),rowdata['time'].max(),maxlength)
            groups = rowdata.groupby(np.digitize(rowdata['time'],bins))
            rowdata = groups.mean()
        except KeyError:
            pass

    for f in favorites:
        workstrokesonly = not f.reststrokes
        script,div = thumbnail_flex_chart(
            rowdata,
            id=id,
            xparam=f.xparam,
            yparam1=f.yparam1,
            yparam2=f.yparam2,
            plottype=f.plottype,
        )


        charts.append({
            'script':script,
            'div':div,
            'notes':f.notes})

    return charts


def thumbnail_flex_chart(rowdata,id=0,promember=0,
                         xparam='time',
                         yparam1='pace',
                         yparam2='hr',
                         plottype='line',
                         workstrokesonly=False):


    try:
        tests = rowdata[yparam2]
    except KeyError:
        yparam2 = 'None'

    try:
        tests = rowdata[yparam1]
    except KeyError:
        yparam1 = 'None'



    try:
        tseconds = rowdata.loc[:,'time']
    except KeyError:
        return '','No time data - cannot make flex plot'


    try:
        rowdata['x1'] = rowdata.loc[:,xparam]
    except KeyError:
        rowdata['x1'] = 0*rowdata.loc[:,'time']

    try:
        rowdata['y1'] = rowdata.loc[:,yparam1]
    except KeyError:
        rowdata['y1'] = 0*rowdata.loc[:,'time']

    if yparam2 != 'None':
        try:
            rowdata['y2'] = rowdata.loc[:,yparam2]
        except KeyError:
            rowdata['y2'] = 0*rowdata.loc[:,'time']
    else:
        rowdata['y2'] = rowdata['y1']

    if xparam=='time':
        xaxmax = tseconds.max()
        xaxmin = tseconds.min()
    elif xparam=='distance' or xparam=='cumdist':
        xaxmax = rowdata['x1'].max()
        xaxmin = rowdata['x1'].min()
    else:
        xaxmax = yaxmaxima[xparam]
        xaxmin = yaxminima[xparam]

    x_axis_type = 'linear'
    y_axis_type = 'linear'
    if xparam == 'time':
        x_axis_type = 'datetime'

    if yparam1 == 'pace':
        y_axis_type = 'datetime'
        y1mean = rowdata.loc[:,'pace'].mean()


    rowdata['xname'] = axlabels[xparam]
    try:
        rowdata['yname1'] = axlabels[yparam1]
    except KeyError:
        rowdata['yname1'] = axlabels[xparam]
    if yparam2 != 'None':
        rowdata['yname2'] = axlabels[yparam2]
    else:
        rowdata['yname2'] = axlabels[yparam1]


    # prepare data
    source = ColumnDataSource(
        rowdata
        )


    sizing_mode = 'fixed'  # 'scale_width' also looks nice with this example
    plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
                  plot_width=200,plot_height=150,
                  )



#    plot.sizing_mode = 'scale_width'
    plot.sizing_mode = 'fixed'
    plot.toolbar.logo = None
    plot.toolbar_location = None
    #plot.yaxis.visible = False
    plot.xaxis.axis_label_text_font_size = "7pt"
    plot.yaxis.axis_label_text_font_size = "7pt"
    plot.xaxis.major_label_text_font_size = "7pt"
    plot.yaxis.major_label_text_font_size = "7pt"

    if plottype=='line':
        plot.line('x1','y1',source=source)
    elif plottype=='scatter':
        plot.scatter('x1','y1',source=source,fill_alpha=0.4,
                     line_color=None)

    try:
        plot.xaxis.axis_label = axlabels[xparam]
    except KeyError:
        plot.xaxis.axis_label = 'X'
    try:
        plot.yaxis.axis_label = axlabels[yparam1]
    except KeyError:
        plot.yaxis.axis_label = 'Y'


    try:
        yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
    except KeyError:
        yrange1 = Range1d(start=yparam1.min(), end=yparam1.max())

    plot.y_range = yrange1

    if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
        xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
        plot.x_range = xrange1

    if xparam == 'time':
        xrange1 = Range1d(start=xaxmin,end=xaxmax)
        plot.x_range = xrange1
        plot.xaxis[0].formatter = DatetimeTickFormatter(
                hours = ["%H"],
                minutes = ["%M"],
                seconds = ["%S"],
                days = ["0"],
                months = [""],
                years = [""]
            )


    if yparam1 == 'pace':
        plot.yaxis[0].formatter = DatetimeTickFormatter(
                seconds = ["%S"],
                minutes = ["%M"]
            )


    if yparam2 != 'None':
        yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
        plot.extra_y_ranges["yax2"] = yrange2
        #= {"yax2": yrange2}

        if plottype=='line':
            plot.line('x1','y2',color="red",y_range_name="yax2",
                      source=source)

        elif plottype=='scatter':
            plot.scatter('x1','y2',source=source,
                         fill_alpha=0.4,
                         line_color=None,color="red",y_range_name="yax2")

        plot.add_layout(LinearAxis(y_range_name="yax2",
                                   axis_label=axlabels[yparam2],
                                   major_label_text_font_size="7pt",
                                   axis_label_text_font_size="7pt",
        ),'right',
        )


    script, div = components(plot)

    return [script,div]


def interactive_bar_chart(id=0,promember=0):
    # check if valid ID exists (workout exists)
    rowdata,row = dataprep.getrowdata_db(id=id)
    rowdata.dropna(axis=1,how='all',inplace=True)
    rowdata.dropna(axis=0,how='any',inplace=True)

    if rowdata.empty:
        return "","No Valid Data Available"

    # Add hover to this comma-separated string and see what changes
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'

    source = ColumnDataSource(
        rowdata
        )

    plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
                  toolbar_sticky=False,
                  plot_width=920,
                  tools=TOOLS)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],0.01,0.99,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor='top_left',
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    plot.title.text = row.name
    plot.title.text_font_size=value("1.0em")
    plot.xaxis.axis_label = "Time"
    plot.yaxis.axis_label = "Pace (/500m)"
    plot.xaxis[0].formatter = DatetimeTickFormatter(
        hours ="",
        minutes = ["%M"],
        seconds = ["%S"],
        days = ["0"],
        months = [""],
        years = [""]
        )

    plot.yaxis[0].formatter = DatetimeTickFormatter(
        hours = "",
        seconds = ["%S"],
        minutes = ["%M"],
        )
    ymax = 1.0e3*90
    ymin = 1.0e3*180

    if row.workouttype == 'water':
        ymax = 1.0e3*90
        ymin = 1.0e3*210

    plot.y_range = Range1d(ymin,ymax)


    hover = plot.select(dict(type=HoverTool))


    hover.tooltips = OrderedDict([
        ('Time','@ftime'),
        ('Pace','@fpace'),
        ('HR','@hr{int}'),
        ('SPM','@spm{1.1}'),
        ])

    hover.mode = 'mouse'

    plot.extra_y_ranges["hr"] = Range1d(start=100,end=200)
    plot.quad(left='time',top='hr_ut2',bottom='hr_bottom',
              right='x_right',source=source,color="gray",
              y_range_name="hr", legend="<UT2")
    plot.quad(left='time',top='hr_ut1',bottom='hr_bottom',
              right='x_right',source=source,color="tan",
              y_range_name="hr", legend="UT2")
    plot.quad(left='time',top='hr_at',bottom='hr_bottom',
              right='x_right',source=source,color="green",
              y_range_name="hr", legend="UT1")
    plot.quad(left='time',top='hr_tr',bottom='hr_bottom',
              right='x_right',source=source,color="blue",
              y_range_name="hr", legend="AT")
    plot.quad(left='time',top='hr_an',bottom='hr_bottom',
              right='x_right',source=source,color="violet",
              y_range_name="hr", legend="TR")
    plot.quad(left='time',top='hr_max',bottom='hr_bottom',
              right='x_right',source=source,color="red",
              y_range_name="hr", legend="AN")


    plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right')

    plot.line('time','pace',source=source,legend="Pace",color="black")


    script, div = components(plot)

    return [script,div]

def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
                                       promember=0,
                                       labeldict=None,startenddict={}):

    message = ''
    errormessage = ''


    columns = [xparam,yparam,
               'ftime','distance','fpace',
               'power','hr','spm',
               'time','pace','workoutstate',
               'workoutid']

    datadf = dataprep.getsmallrowdata_db(columns,ids=ids,doclean=False,compute=False)
    datadf.dropna(axis=1,how='all',inplace=True)
    datadf.dropna(axis=0,how='any',inplace=True)


    nrworkouts = len(ids)

    try:
        tseconds = datadf.loc[:,'time']
    except KeyError:
        try:
            tseconds = datadf.loc[:,xparam]
        except:
            return ['','<p>A chart data error occurred</p>','','A chart data error occurred']

    yparamname = axlabels[yparam]

    #datadf = datadf[datadf[yparam] > 0]

    #datadf = datadf[datadf[xparam] > 0]

    # check if dataframe not empty
    if datadf.empty:
        return ['','<p>No non-zero data in selection</p>','','No non-zero data in selection']

    if xparam != 'distance' and xparam != 'time' and xparam !=  'cumdist':
        xaxmax = yaxmaxima[xparam]
        xaxmin = yaxminima[xparam]
    elif xparam == 'time' and not startenddict:
        xaxmax = tseconds.max()
        xaxmin = tseconds.min()
    elif xparam == 'time' and startenddict:
        deltas = [pair[1]-pair[0] for key,pair in startenddict.items()]
        xaxmin = 0
        xaxmax = pd.Series(deltas).max()*1000.
        if xaxmax == 0:
            xaxmax = tseconds.max()
    else:
        xaxmax = datadf['distance'].max()
        xaxmin = datadf['distance'].min()

    if yparam == 'distance':
        yaxmin = datadf['distance'].min()
        yaxmax = datadf['distance'].max()
    elif yparam == 'cumdist':
        yaxmin = datadf['cumdist'].min()
        yaxmax = datadf['cumdist'].max()
    else:
        yaxmin = yaxminima[yparam]
        yaxmax = yaxmaxima[yparam]

    x_axis_type = 'linear'
    y_axis_type = 'linear'

    # Add hover to this comma-separated string and see what changes
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'

    if yparam == 'pace':
        y_axis_type = 'datetime'
        yaxmax = 90.*1e3
        yaxmin = 150.*1e3

    if xparam == 'time':
        x_axis_type = 'datetime'

    if xparam != 'time':
        xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
    else:
        xvals = np.arange(100)

    plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
                  tools=TOOLS,
                  toolbar_location="above",
                  plot_width=920,plot_height=500,
                  toolbar_sticky=False)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'


    plot.image_url([watermarkurl],0.05,0.9,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor='top_left',
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    colors = itertools.cycle(palette)

    cntr = 0
    l1 = []

    try:
        items = itertools.izip(ids,colors)
    except AttributeError:
        items = zip(ids,colors)

    for id,color in items:
        group = datadf[datadf['workoutid']==int(id)].copy()
        try:
            startsecond,endsecond = startenddict[id]
        except KeyError:
            startsecond = 0
            endsecond = 0

        group.sort_values(by='time',ascending=True,inplace=True)

        if endsecond > 0:
            group['time'] = group['time'] - 1.e3*startsecond
            mask = group['time'] < 0
            group.mask(mask,inplace=True)
            mask = group['time'] > 1.e3*(endsecond-startsecond)
            group.mask(mask,inplace=True)

        if xparam == 'cumdist':
            group['cumdist'] = group['cumdist'] - group['cumdist'].min()
            res = make_cumvalues(group[xparam])
            group[xparam] = res[0]
        elif xparam == 'distance':
            group['distance'] = group['distance'] - group['distance'].min()


        try:
            group['x'] = group[xparam]
        except KeyError:
            group['x'] = group['time']
            errormessage = xparam+' has no values. Plot invalid'
        try:
            group['y'] = group[yparam]
        except KeyError:
            group['y'] = 0.0*group['x']


        ymean = group['y'].mean()

        ylabel = Label(x=100,y=60+nrworkouts*20-20*cntr,
                       x_units='screen',y_units='screen',
                       text=axlabels[yparam]+": {ymean:6.2f}".format(ymean=ymean),
                       background_fill_alpha=.7,
                       background_fill_color='white',
                       text_color=color,
        )
        if yparam != 'time' and yparam != 'pace':
            plot.add_layout(ylabel)

        source = ColumnDataSource(
            group
            )

        TIPS = OrderedDict([
            ('time','@ftime'),
            ('pace','@fpace'),
            ('hr','@hr'),
            ('spm','@spm{1.1}'),
            ('distance','@distance{5}'),
        ])

        hover = plot.select(type=HoverTool)
        hover.tooltips = TIPS

        if labeldict:
            try:
                legend=labeldict[id]
            except KeyError:
                legend = str(id)
        else:
            legend=str(id)

        if plottype=='line':
            l1.append(plot.line('x','y',source=source,color=color,legend=legend,line_width=2))
        else:
            l1.append(plot.scatter('x','y',source=source,color=color,legend=legend,
                         fill_alpha=0.4,line_color=None))

        plot.add_tools(HoverTool(renderers=[l1[cntr]],tooltips=TIPS))
        cntr += 1

    plot.legend.location='top_right'
    plot.xaxis.axis_label = axlabels[xparam]
    plot.yaxis.axis_label = axlabels[yparam]

    if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
        xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
        plot.x_range = xrange1

    yrange1 = Range1d(start=yaxmin,end=yaxmax)
    plot.y_range = yrange1

    if xparam == 'time':
        xrange1 = Range1d(start=xaxmin,end=xaxmax)
        plot.x_range = xrange1
        plot.xaxis[0].formatter = DatetimeTickFormatter(
                hours = ["%H"],
                minutes = ["%M"],
                seconds = ["%S"],
                days = ["0"],
                months = [""],
                years = [""]
            )


    if yparam == 'pace':
        plot.yaxis[0].formatter = DatetimeTickFormatter(
                seconds = ["%S"],
                minutes = ["%M"]
            )

    script, div = components(plot)

    return [script,div,message,errormessage]



def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
                                 promember=0,plottype='line'):




    columns = [xparam,yparam,
               'ftime','distance','fpace',
               'power','hr','spm',
               'time','pace','workoutstate']

    # check if valid ID exists (workout exists)
    #rowdata1,row1 = dataprep.getrowdata_db(id=id1)
    #rowdata2,row2 = dataprep.getrowdata_db(id=id2)

    rowdata1 = dataprep.getsmallrowdata_db(columns,ids=[id1])
    rowdata2 = dataprep.getsmallrowdata_db(columns,ids=[id2])
    for n in ['distance','power','hr','spm','time','pace','workoutstate']:
        try:
            rowdata1[n].fillna(value=0,inplace=True)
        except KeyError:
            pass
        try:
            rowdata2[n].fillna(value=0,inplace=True)
        except KeyError:
            pass

    rowdata1.dropna(axis=1,how='all',inplace=True)
    rowdata1.dropna(axis=0,how='any',inplace=True)
    rowdata2.dropna(axis=1,how='all',inplace=True)
    rowdata2.dropna(axis=0,how='any',inplace=True)

    row1 = Workout.objects.get(id=id1)
    row2 = Workout.objects.get(id=id2)

    if rowdata1.empty:
        return "","No Valid Data Available"
#    else:
#        rowdata1.sort_values(by='time',ascending=True,inplace=True)

    if rowdata2.empty:
        return "","No Valid Data Available"
#    else:
#        rowdata2.sort_values(by='time',ascending=True,inplace=True)

    try:
        x1 = rowdata1.loc[:,xparam]
        x2 = rowdata2.loc[:,xparam]

        y1 = rowdata1.loc[:,yparam]
        y2 = rowdata2.loc[:,yparam]
    except KeyError:
        return "","No valid Data Available"

    x_axis_type = 'linear'
    y_axis_type = 'linear'
    if xparam == 'time':
        x_axis_type = 'datetime'

    if yparam == 'pace':
        y_axis_type = 'datetime'
        ymax = 1.0e3*90
        ymin = 1.0e3*180

        if row1.workouttype == 'water':
            ymax = 1.0e3*90
            ymin = 1.0e3*210

    ftime1 = rowdata1.loc[:,'ftime']
    ftime2 = rowdata2.loc[:,'ftime']

    hr1 = rowdata1.loc[:,'hr']
    hr2 = rowdata2.loc[:,'hr']


    fpace1 = rowdata1.loc[:,'fpace']
    fpace2 = rowdata2.loc[:,'fpace']

    distance1 = rowdata1.loc[:,'distance']
    distance2 = rowdata2.loc[:,'distance']

    spm1 = rowdata1.loc[:,'spm']
    spm2 = rowdata2.loc[:,'spm']

    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'


    data1 = pd.DataFrame(
        dict(
            x1=x1,
            y1=y1,
            ftime1=ftime1,
            fpace1=fpace1,
            hr1 = hr1,
            spm1 = spm1,
            distance1=distance1,
            )
        ).dropna()

    data2 = pd.DataFrame(
        dict(
            x2=x2,
            y2=y2,
            ftime2=ftime2,
            fpace2=fpace2,
            hr2 = hr2,
            spm2 = spm2,
            distance2=distance2,
            )
        ).dropna()



    source1 = ColumnDataSource(
        data1
        )

    source2 = ColumnDataSource(
        data2
        )

    ymean1 = data1['y1'].mean()
    ymean2 = data2['y2'].mean()

    # create interactive plot
    plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
                  tools=TOOLS,
                  plot_width=920,
                  toolbar_sticky=False)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],0.05,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor='bottom_left',
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    TIPS = OrderedDict([
        ('time','@ftime1'),
        ('pace','@fpace1'),
        ('hr','@hr1'),
        ('spm','@spm1{1.1}'),
        ('distance','@distance1{5}'),
        ])
    TIPS2 = OrderedDict([
        ('time','@ftime2'),
        ('pace','@fpace2'),
        ('hr','@hr2'),
        ('spm','@spm2{1.1}'),
        ('distance','@distance2{5}'),
        ])



    hover1 = plot.select(type=HoverTool)
    hover1.tooltips = TIPS
    hover2 = plot.select(type=HoverTool)
    hover2.tooltips = TIPS2


    if plottype=='line':
        l1 = plot.line('x1','y1',source=source1,
                       color="blue",legend=row1.name,
                       )
        l2 = plot.line('x2','y2',source=source2,
                       color="red",legend=row2.name,
                       )
    elif plottype=='scatter':
        l1 = plot.scatter('x1','y1',source=source1,legend=row1.name,
                          fill_alpha=0.4,
                          line_color=None)
        l2 = plot.scatter('x2','y2',source=source2,legend=row2.name,
                          fill_alpha=0.4,
                          line_color=None,color="red")

    plot.add_tools(HoverTool(renderers=[l1],tooltips=TIPS))
    plot.add_tools(HoverTool(renderers=[l2],tooltips=TIPS2))
    plot.legend.location = "bottom_right"

    plot.title.text = row1.name+' vs '+row2.name
    plot.title.text_font_size=value("1.2em")
    plot.xaxis.axis_label = axlabels[xparam]
    plot.yaxis.axis_label = axlabels[yparam]

    ylabel1 = Label(x=100,y=90,x_units='screen',y_units='screen',
                   text=axlabels[yparam]+": {ymean1:6.2f}".format(
                       ymean1=ymean1
                       ),
                   background_fill_alpha=.7,
                   background_fill_color='white',
                   text_color='blue'
                   )
    ylabel2 = Label(x=100,y=110,x_units='screen',y_units='screen',
                   text=axlabels[yparam]+": {ymean2:6.2f}".format(
                       ymean2=ymean2
                       ),
                   background_fill_alpha=.7,
                   background_fill_color='white',
                   text_color='red'
                   )
    plot.add_layout(ylabel1)
    plot.add_layout(ylabel2)

    if xparam == 'time':
        plot.xaxis[0].formatter = DatetimeTickFormatter(
                hours = ["%H"],
                minutes = ["%M"],
                seconds = ["%S"],
                days = ["0"],
                months = [""],
                years = [""]
            )


    if yparam == 'pace':
        plot.yaxis[0].formatter = DatetimeTickFormatter(
                seconds = ["%S"],
                minutes = ["%M"]
            )

        plot.y_range = Range1d(ymin,ymax)


    script, div = components(plot)

    return [script,div]

def interactive_otw_advanced_pace_chart(id=0,promember=0):
    # check if valid ID exists (workout exists)
    rowdata,row = dataprep.getrowdata_db(id=id)
    rowdata.dropna(axis=1,how='all',inplace=True)
    rowdata.dropna(axis=0,how='any',inplace=True)

    if rowdata.empty:
        return "","No Valid Data Available"

    # Add hover to this comma-separated string and see what changes
    if (promember==1):
        TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
    else:
        TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'

    source = ColumnDataSource(
        rowdata
        )





    plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
                  tools=TOOLS,
                  plot_width=920,
                  toolbar_sticky=False)

    # add watermark
    watermarkurl = "/static/img/logo7.png"
    watermarksource = ColumnDataSource(dict(
        url = [watermarkurl],))

    watermarkrange = Range1d(start=0,end=1)
    watermarkalpha = 0.6
    watermarkx = 0.99
    watermarky = 0.01
    watermarkw = 184
    watermarkh = 35
    watermarkanchor = 'bottom_right'
    plot.extra_y_ranges = {"watermark": watermarkrange}
    plot.extra_x_ranges = {"watermark": watermarkrange}
    plot.sizing_mode = 'scale_width'

    plot.image_url([watermarkurl],watermarkx,watermarky,
                   watermarkw,watermarkh,
                   global_alpha=watermarkalpha,
                   w_units='screen',
                   h_units='screen',
                   anchor=watermarkanchor,
                   dilate=True,
                   x_range_name = "watermark",
                   y_range_name = "watermark",
                   )

    plot.title.text = row.name
    plot.title.text_font_size=value("1.2em")
    plot.xaxis.axis_label = "Time"
    plot.yaxis.axis_label = "Pace (/500m)"
    plot.xaxis[0].formatter = DatetimeTickFormatter(
            hours = ["%H"],
            minutes = ["%M"],
            seconds = ["%S"],
            days = ["0"],
            months = [""],
            years = [""]
        )
    plot.yaxis[0].formatter = DatetimeTickFormatter(
            seconds = ["%S"],
            minutes = ["%M"]
        )

    ymax = 1.0e3*90
    ymin = 1.0e3*210

    plot.y_range = Range1d(ymin,ymax)


    hover = plot.select(dict(type=HoverTool))

    plot.line('time','pace',source=source,legend="Pace",color="black")
    plot.line('time','nowindpace',source=source,legend="Corrected Pace",color="red")

    hover.tooltips = OrderedDict([
        ('Time','@ftime'),
        ('Pace','@fpace'),
        ('Corrected Pace','@fnowindpace'),
        ('HR','@hr{int}'),
        ('SPM','@spm{1.1}'),
        ])

    hover.mode = 'mouse'

    try:
        script, div = components(plot)
    except:
        script = ''
        div = ''

    return [script,div]
