import pandas as pd
import numpy as np
# The server and widgets library
import panel as pn
# enabling panel backend
pn.extension()

# the plotting libs
import holoviews as hv
from holoviews.operation.datashader import inspect, rasterize
from holoviews.element.tiles import ESRI
# provides the color maps
import colorcet as cc

# using bokeh as a backend for holoviews, it works better than plotly wiith panel
hv.extension('bokeh')


# The options for the operators and thier colour maps
COLORS = {"Operator A": cc.kr, "Operator B": cc.kg, "Operator C": cc.kb}
PLOT_WIDTH = 900
PLOT_HEIGHT= 700

Downlink_traffic = pd.read_csv("Downlink_traffic.csv")


# Using the map tiles provided by Esri. OpenStreetMaps can be used as well
esri = ESRI().opts(alpha=0.2, width=PLOT_WIDTH, height=PLOT_HEIGHT, bgcolor='black', xaxis=None, yaxis=None)

operator_select = pn.widgets.Select(options=list(COLORS.keys()))

def traffic_plot(operator_name):
    """Plots a hexbin for each operator where the size of each hex depends on the counts of values that falls inside this hex"""
    df_operator = Downlink_traffic[Downlink_traffic["RadioOperatorName"] == operator_name].copy()
    if (len(df_operator) == 0 ):
        return esri
    operator_tiles =  hv.element.HexTiles(df_operator, kdims=["LocationLongitude", "LocationLatitude"], vdims=["TrafficVolume", "RadioOperatorName"])
    operator_tiles.opts(cmap=COLORS[operator_name], alpha=0.8, cnorm="linear", tools=["hover"], width=PLOT_WIDTH, height=PLOT_HEIGHT, scale=(hv.dim('Count').norm()*0.5)+0.5)
    return esri * operator_tiles

Traffic_maps = pn.bind(traffic_plot, operator_select)
app = pn.Row(Traffic_maps, operator_select).servable()

def operator_map(operator_name):
    df_operator = Downlink_traffic[Downlink_traffic["RadioOperatorName"] == operator_name].copy()
    return df_operator.plot.hexbin(x="LocationLongitude", y="LocationLatitude", C="TrafficVolume", reduce_C_function=np.sum, cmap="viridis", figsize=(20,15))

interactive = pn.bind(operator_map, operator_select)
first_app = pn.Column(operator_select, interactive).servable()
