import pandas as pd
import numpy as np
from bokeh.plotting import show, output_file
from bokeh.models import Plot, LinearAxis, Grid, Span, LabelSet, ColumnDataSource, Label, Range1d, NumeralTickFormatter, Title, BasicTicker, Circle, Triangle, InvertedTriangle

playernames=['K. Irving', 'R. Jefferson','I. Shumpert', 'H. Barnes',
            'J.R. Smith','S. Curry', 'L. James', 'A. Iguodala', 'A. Bogut',
            'K. Thompson', 'D. Green', 'K. Love', 'T. Thompson', 'S. Livingston']
teams = ['Cavs','Warriors']
nba = pd.DataFrame({'player':playernames, 'off':np.random.uniform(-3, 3, size=14), 'def':np.random.uniform(-3, 3, size=14), 'team':np.repeat(teams,7)})

nba['fill_col'] = nba['team'].map({'Cavs':'#BB7894','Warriors':'#60B6E0'})
nba['line_col'] = nba['team'].map({'Cavs':'#89083E','Warriors':'#0390D5'})

back_col='#F0F0F0'

def wspan(text, pix, fsize, var, df): 
    return (((np.floor(df[var].max()) + 1.6) - (np.floor(df[var].min()) - 0.6)) * len(text) * fsize)/(pix)

output_file('five42.html')

nba_cds = ColumnDataSource(nba)

p = Plot(plot_width=500, plot_height=600,background_fill_color=back_col,
          x_range=Range1d(np.floor(nba.off.min()) - 0.6, np.floor(nba.off.max()) + 1.6),
          y_range=Range1d(np.floor(nba['def'].min()) - 0.6,np.floor(nba['def'].max()) + 1.6),
        min_border_right=40, min_border_left=40, border_fill_color=back_col,
        outline_line_color=None, logo=None, toolbar_location=None)

tick = BasicTicker()
xaxis = LinearAxis(ticker=tick, axis_label='Point contribution on offense')
p.add_layout(xaxis, 'below')

yaxis = LinearAxis(ticker=tick, axis_label='Point contribution on defense')
p.add_layout(yaxis, 'left')

# p.grid.grid_line_width=1.0
grx = Grid(dimension=0, ticker=tick)
p.add_layout(grx)

gry = Grid(dimension=1, ticker=tick)
p.add_layout(gry)

p.grid.grid_line_color='#CBCBCB'
p.grid.grid_line_width=1.0

p.axis.axis_line_color=None
p.axis.major_tick_line_color=None
p.axis.minor_tick_line_color=None
p.axis.major_label_text_color='#999999'
p.axis.major_label_text_font_size='15px'
p.axis.formatter=NumeralTickFormatter(format="+0")
p.axis.axis_label_text_font_style='bold'
p.axis.axis_label_standoff = 10

xax = Span(location=0,dimension='width', level='glyph')
p.add_layout(xax)
yax = Span(location=0,dimension='height', level='glyph')
p.add_layout(yax)

gly = Circle(x='off',y='def',fill_color='fill_col', size=10, line_width=1.5, line_color='line_col')
p.add_glyph(nba_cds, gly)

lab = LabelSet(x='off', y='def', text='player', 
                  x_offset=6, y_offset=-5, 
                  render_mode='canvas', source=nba_cds,
                 text_font_size='14px', text_font_style='normal',
                 text_color='line_col')
p.add_layout(lab)


mark1 = Label(x=np.floor(nba.off.min()) - 0.2, y=np.floor(nba['def'].max()) + 1 - 0.1 - (0.8 * wspan('WORSE DEFENSE', 600, 12, 'def', nba)), x_units='data', y_units='data',
                 text='WORSE DEFENSE', text_color='#999999',
              text_font_size='12px',render_mode='canvas',
                 angle=90, angle_units='deg',
             background_fill_color='#F0F0F0')
mark2 = Label(x=np.floor(nba.off.min()) - 0.2, y=np.floor(nba['def'].min()) + 0.1, x_units='data', y_units='data',
                 text='BETTER DEFENSE', text_color='#999999',
              text_font_size='12px',render_mode='canvas',
                 angle=90, angle_units='deg',
             background_fill_color='#F0F0F0')
mark3 = Label(x=np.floor(nba.off.min()) + 0.1, y=np.floor(nba['def'].min()) - 0.3, x_units='data', y_units='data',
                 text='WORSE OFFENSE', text_color='#999999',
              text_font_size='12px',render_mode='canvas',
             background_fill_color='#F0F0F0')
mark4 = Label(x=np.floor(nba['off'].max()) + 1 - 0.1 - (0.8 * wspan('BETTER OFFENSE', 500, 12, 'off', nba)), y=np.floor(nba['def'].min()) - 0.3, x_units='data', y_units='data',
                 text='BETTER OFFENSE', text_color='#999999',
              text_font_size='12px',render_mode='canvas',
             background_fill_color='#F0F0F0')

p.add_layout(mark1)
p.add_layout(mark2)
p.add_layout(mark3)
p.add_layout(mark4)

mark5 = Triangle(x=np.floor(nba.off.min()) - 0.3, y=np.floor(nba['def'].max()) + 1, size=10,fill_color="#999999", line_color='#999999')
mark6 = InvertedTriangle(x=np.floor(nba.off.min()) - 0.3, y=np.floor(nba['def'].min()), size=10,fill_color="#999999",  line_color='#999999')
mark7 = Triangle(x=np.floor(nba.off.min()), y=np.floor(nba['def'].min()) - 0.2, size=10,fill_color="#999999",  line_color='#999999',angle=90, angle_units='deg')
mark8 = InvertedTriangle(x=np.floor(nba.off.max()) + 1, y=np.floor(nba['def'].min()) - 0.2, size=10,fill_color="#999999",  line_color='#999999',angle=90, angle_units='deg')

p.add_glyph(mark5)
p.add_glyph(mark6)
p.add_glyph(mark7)
p.add_glyph(mark8)

msg1 = 'Subtitle1'
caption1 = Label(text=msg1)
p.add_layout(caption1, 'below')

msg2 = 'Subtitle2'
caption2 = Label(text=msg2)
p.add_layout(caption2, 'above')

msg3 = 'Subtitle3'
caption3 = Label(text=msg3)
p.add_layout(caption3, 'above')

show(p)