import dash
import dash_html_components as html
import dash_core_components as dcc
import pandas as pd
import numpy as np
from datetime import datetime
import base64
import io
import dash_table
import plotly.graph_objs as go
import uuid
from flask_caching import Cache
import plotly.express as px
import dash_bootstrap_components as dbc
import colorlover as cl
import dash_daq as daq
from dash.dependencies import Input, Output, State
import functions as func
import random
from scipy import stats

#Create the app
app = dash.Dash(__name__, external_stylesheets=['/assets/toolbox_menu.css'])
'''
Turn callback exceptions off as we are generating callbacks that 
refer to things generated by other callbacks.
WARNING: THIS DOES DISABLE OTHER WARNINGS OR EXCEPTIONS FOR CALLBACKS
NOT BEING FOUND INSIDE THE PYTHON FILE
'''
app.config['suppress_callback_exceptions']=True
#Create the cache needed to store the dataframe
cache = Cache(app.server, config={
    'CACHE_TYPE' : 'filesystem',
    'CACHE_DIR' : 'cache',
})

#--------CONSTANT VARIABLES------------#
button_font_size='1.2em'
cardbody_font_size='1em'
cardheader_color='info'
cardbody_color='info'
main_panel_margin={'margin': '10px 0px'}
left_panel_margin={'width': '25%'}
right_panel_margin={'class': 'col-md-8', 'display':'block-inline'}
toggle_switch_color='#91c153'
default_alpha = 0.65
default_symbol_alpha = 1
box_color_saved = {}
percentile_color_saved = cl.to_rgb(cl.scales[str('5')]['qual']['Dark2'])
num_of_color=9
default_color = cl.to_rgb(cl.scales[str(num_of_color)]['qual']['Set1'])
dtick_value = None

# Initialising selected marker symbol
selected_marker_symbols = ['diamond', 'cross', 'triangle-up', 'star', 'x']
# generate default colors list
col_idx = 0
for i in default_color:
    start_idx = i.find('(')
    i = i[start_idx+1:len(i)-1]
    i = i.split(",")
    i = 'rgba({},{},{},{})'.format(i[0], i[1], i[2], default_alpha)
    default_color[col_idx] = i
    col_idx += 1
#Get the default colors for the percentiles in the Box Plot
col_idx = 0
for i in percentile_color_saved:
    start_idx = i.find('(')
    i = i[start_idx+1:len(i)-1]
    i = i.split(",")
    i = 'rgba({},{},{},{})'.format(i[0], i[1], i[2], default_symbol_alpha)
    percentile_color_saved[col_idx] = i
    col_idx += 1
#DICTIONARY FOR THE COLORSCALES
COLORSCALES_DICT = [
    {'value': 'Blackbody', 'label': 'Blackbody'},
    {'value': 'Bluered', 'label': 'Bluered'},
    {'value': 'Blues', 'label': 'Blues'},
    {'value': 'Earth', 'label': 'Earth'},
    {'value': 'Electric', 'label': 'Electric'},
    {'value': 'Greens', 'label': 'Greens'},
    {'value': 'Greys', 'label': 'Greys'},
    {'value': 'Hot', 'label': 'Hot'},
    {'value': 'Jet', 'label': 'Jet'},
    {'value': 'Picnic', 'label': 'Picnic'},
    {'value': 'Portland', 'label': 'Portland'},
    {'value': 'Rainbow', 'label': 'Rainbow'},
    {'value': 'RdBu', 'label': 'RdBu'},
    {'value': 'Reds', 'label': 'Reds'},
    {'value': 'Viridis', 'label': 'Viridis'},
    {'value': 'YlGnBu', 'label': 'YlGnBu'},
    {'value': 'YlOrRd', 'label': 'YlOrRd'},
]
#DICTIONARY FOR THE MARKERS
MARKERS_DICT = [
    {'value': 'circle', 'label': 'Circle'},
    {'value': 'square', 'label': 'Square'},
    {'value': 'diamond', 'label': 'Diamond'},
    {'value': 'cross', 'label': 'Cross'},
    {'value': 'x', 'label': 'X'},
    {'value': 'triangle-up', 'label': 'Triangle-up'},
    {'value': 'pentagon', 'label': 'Pentagon'},
    {'value': 'hexagon', 'label': 'Hexagon'},
    {'value': 'hexagon2', 'label': 'Hexagon2'},
    {'value': 'octagon', 'label': 'Octagon'},
    {'value': 'star', 'label': 'Star'},
    {'value': 'hexagram', 'label': 'Hexagram'},
    {'value': 'star-triangle-up', 'label': 'Star-triangle-up'},
    {'value': 'hourglass', 'label': 'Hourglass'},
    {'value': 'bowtie', 'label': 'Bowtie'},
]
#THE DICTIONARY FOR THE LABELS
DASH_DICT = [
    {'value': 'solid', 'label': 'Solid'},
    {'value': 'dash', 'label': 'Dash'},
    {'value': 'dot', 'label': 'Dot'},
    {'value': 'dashdot', 'label': 'Dash Dot'},
    {'value': 'longdash', 'label': 'Long Dash'},
    {'value': 'longdashdot', 'label': 'Long Dash Dot'}
]
# Users can choose lines only, lines and markers and lines, markers and text
LABELSTYLE_DICT = [
    {'label': 'Lines', 'value': 'lines'},
    {'label': 'Lines & Markers', 'value': 'lines+markers'},
    {'label': 'Lines, Markers & Text', 'value': 'lines+markers+text'}
]
#For Demas
line_style = ['Solid', 'Dash', 'Dot', 'Long Dash', 'Dash Dot', 'Long Dash Dot']
marker_symbols = ['Circle', 'Square', 'Diamond', 'Cross', 'X', 'Triangle-Up', 'Pentagon', 'Hexagon', 'Star']
#For Bo
MARKERS_LIST = ['circle', 'square', 'diamond', 'cross', 'x', 'triangle-up', 'pentagon', 'hexagon', 'hexagon2',
'octagon', 'star', 'hexagram', 'star-triangle-up', 'hourglass', 'bowtie']
markers_choice = dict()
markers_shape = dict()
#For Robin
bar_color_saved = {}
plottype = " "
#For Guobei
marker_dict = {}
linestyle_dict = {}
gap_dict = {}
label_dict = {}
LINECOLOR_DICT = {}
linefill = {}
linestyle_list = ['Solid', 'Dash', 'Dot', 'Long Dash', 'Dash Dot', 'Long Dash Dot']

#----------THE APP LAYOUT----------#
#Begin the layout of the app layout
app.layout = html.Div(children = [
    #Add the inviible session ID to header
    html.Div(str(uuid.uuid4()), id='session_id', style={'display': 'none'}),
    #Create the header
    html.Div(
        className = "header",
        children = [
            html.Img(
                src="https://skyraidnextcloud.duckdns.org/index.php/s/Axc37NW9wjaKMyr/preview",
                className="header-logo"
            ),
            html.H1("Earth Science Toolbox", className="header-title"),
        ]),
    #Add tabs to the page
    dcc.Tabs(
        id="tabs-styled-with-inline", 
        #Sets the default tab to open first
        value='upload',
        parent_className='custom-tabs', 
        className ='custom-tabs-container',
        children=[
            #Each tab has a label and different value, the value will determine what the output is
            dcc.Tab(label='Data Upload', value='upload', className='custom-tab', selected_className='custom-tab--selected'),
            dcc.Tab(label='Scatter Plot', value='scatter', className='custom-tab', selected_className='custom-tab--selected'),
            dcc.Tab(label='Line Plot', value='line', className='custom-tab', selected_className='custom-tab--selected'),
            dcc.Tab(label='Box and Whisker Plot', value='box', className='custom-tab', selected_className='custom-tab--selected'),
            dcc.Tab(label='Bar Plot', value='bar', className='custom-tab', selected_className='custom-tab--selected'),
        ]),
    #The HTML Division to show the content
    html.Div(
        id='tabs-content-inline',
        className="custom-tabs-inline",
    )
])
#Callbacks for the tabs
@app.callback(Output('tabs-content-inline', 'children'),
              [Input('tabs-styled-with-inline', 'value'),
              Input('session_id', 'children')])
def render_content(tab, session):
    #Based on the value of the tabs....
    if tab == 'upload':
        #If Upload is selected then show the content for uploading and data cleaning recommendation
        return html.Div([
            dcc.Tabs(
                id='tabs-styled-in-upload',
                value='upload-data',
                className="custom-tabs-container-upload",
                #Tabs for inside the Data Cleaning Recommendation Page
                children=[
                    dcc.Tab(label='Upload Your Data', value='upload-data', className='custom-tab-upload', selected_className='custom-tab--selected-upload'),
                    dcc.Tab(label='Your Uploaded Data', value='uploaded', className='custom-tab-upload', selected_className='custom-tab--selected-upload'),
                    dcc.Tab(label='Basic Description of Data', value='description', className='custom-tab-upload', selected_className='custom-tab--selected-upload'),
                    dcc.Tab(label='Scatter Plot Matrix', value='scatterplot-matrix', className='custom-tab-upload', selected_className='custom-tab--selected-upload'),
                ],
            ),
             #The HTML Division to show the content
            html.Div(
                id='tabs-content-upload',
                className="custom-tabs-upload",
            ),
        ])
    elif tab == 'scatter':
        df = cache.get(session + '-df')
        if df is None:
            return dcc.Markdown('''
            # No Data Uploaded

            If you're seeing this message, then you haven't uploaded any data yet

            Please do so by navigating to the Data Upload and uploading some data.

            When you are ready, come back here to create a Scatter Plot.
            ''')
        elif len(df.select_dtypes(exclude=['number', 'datetime', 'datetime64']).columns.values) == 0 or len(df.select_dtypes(include='number').columns.values) == 0:
            return dcc.Markdown('''
            # Data Uploaded but with no Numerical Features

            If you're seeing this message, then you haven't uploaded any data that contains

            numerical features. All your columns are categorical or empty.
            
            To produce a scatter plot, you must have numerical values in the dataset.

            Otherwise, the dataset may have no categorical features, the reason why these are needed for

            this scatter plot is due to how it was made, with the options of grouping the markers by a category, this

            became necessary to enforce.
            ''')
        else:
            cnames = df.select_dtypes(include='number').columns.values
            cat_names = df.select_dtypes(exclude=['number', 'datetime', 'datetime64']).columns.values
            return html.Div(className='row', children=[
                        html.Div(children=[
                            html.Div(className='container', children=[
                                html.Div(className='accordion', children=[
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Select Data', id='scatter-group-1-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('X Axis Value')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('xaxis-column', options=cnames, value=cnames[0] ))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Y Axis Value')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('yaxis-column', options=cnames, value=cnames[-1] ))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                ),
                                            ],
                                            ), id='scatter-collapse-1'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size, }
                                    ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Plot Settings', id='scatter-group-2-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Swap Axis')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('swap', False))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Grid Lines')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('GL', True))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Zero Lines')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('OL', False))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Label')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('LB', False))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Legend')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('LD', True))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Colorbar')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('LS', True))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Set X Axis Type')),
                                                    dbc.CardBody(children=func.render_toggleswitch('xaxis-type', ['Linear', 'Logarithmic'], False))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Set Y Axis Type')),
                                                    dbc.CardBody(children=func.render_toggleswitch('yaxis-type', ['Linear', 'Logarithmic'], False))
                                                ], className='col-md-6',
                                                ),
                                            ],
                                            ), id='scatter-collapse-2'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size}
                                    ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Thresholds', id='scatter-group-3-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('X Axis Threshold')),
                                                    dbc.CardBody(children=func.render_input_number('X-thredshold', 'X Axis Threshold'))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Y Axis Threshold')),
                                                    dbc.CardBody(children=func.render_input_number('Y-thredshold', 'Y Axis Threshold'))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('X Threshold Line Style')),
                                                    dbc.CardBody(children=func.render_dropdown_dict_valued('x-threshold-style', DASH_DICT, 'solid'))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Y Threshold Line Style')),
                                                    dbc.CardBody(children=func.render_dropdown_dict_valued('y-threshold-style', DASH_DICT, 'solid'))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('X Threshold Line Color')),
                                                    dbc.CardBody(children=func.render_colorpicker_small('x-threshold-color', '#ffffff', 0, 0, 0, 1))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Y Threshold Line Color')),
                                                    dbc.CardBody(children=func.render_colorpicker_small('y-threshold-color', '#ffffff', 0, 0, 0, 1))
                                                ], className='col-md-6',
                                                ),
                                            ],
                                            ), id='scatter-collapse-3'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size}
                                    ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Statistics', id='scatter-group-4-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Linear Best Fit Line')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('linear', False))
                                                ]
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Best Fit Line Style')),
                                                    dbc.CardBody(children=func.render_dropdown_dict('change-dash', DASH_DICT))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Best Fit Line Color')),
                                                    dbc.CardBody(children=func.render_colorpicker_small('fit-color-picker', '#ffffff', 0, 0, 0, 1))
                                                ], className='col-md-6',
                                                ),
                                            ],
                                            ), id='scatter-collapse-4'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size}
                                    ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Marker Style', id='scatter-group-5-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Category Marker Style')),
                                                    dbc.CardBody(children=func.render_dropdown_dict_valued('alignment-markers-dropdown', MARKERS_DICT, 'circle'))
                                                ]
                                                ),
                                                dbc.Card([
                                                    dbc.CardBody(children=func.render_booleanswitch('marker-style-tog', 'Set Marker by a Group', False))
                                                ]
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Group By')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('marker-drop', cat_names, cat_names[0]))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Select Category')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('marker-selected-groupby', df[cat_names[0]].unique(), df[cat_names[0]].unique()[0]))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                ),
                                            ],
                                            ), id='scatter-collapse-5'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size}
                                    ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Marker Size', id='scatter-group-6-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardBody(children=func.render_booleanswitch('marker-size-tog', 'Set Marker Size by a Group', False))
                                                ]
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('The Maximum Size for the Markers')),
                                                    dbc.CardBody(children=func.render_input_number_min_value('marker-max', 1, 15))
                                                ]
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Marker Size Group')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('marker-size', cnames, cnames[0]))
                                                ], style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                ),
                                            ],
                                            ), id='scatter-collapse-6'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size}
                                    ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Plot Color', id='scatter-group-7-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Group By')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('color-drop', df.columns, df.columns[0]))
                                                ]
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Select Category')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('color-selected-groupby', df[cat_names[0]].unique(), df[cat_names[0]].unique()[0]))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Change Colorscale')),
                                                    dbc.CardBody(children=func.render_dropdown_dict_valued('alignment-colorscale-dropdown', COLORSCALES_DICT, 'Greys'))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Category Color')),
                                                    dbc.CardBody(children=func.render_colorpicker_small('my-color-picker', '#ffffff', 22, 222, 160, 1))
                                                ]
                                                ),
                                            ],
                                            ), id='scatter-collapse-7'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size}
                                    ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button('Graph Settings', id='scatter-group-8-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True, )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Height')),
                                                    dbc.CardBody(children=func.render_slider('graph-height', 600, 1200, 600, 50, [600, 700, 800, 900, 1000, 1100, 1200]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Width')),
                                                    dbc.CardBody(children=func.render_slider('graph-width', 800, 1400, 800, 50, [800, 900, 1000, 1100, 1200, 1300, 1400]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Opacity')),
                                                    dbc.CardBody(children=func.render_slider('opacity-slider', 0, 100, 70, 1, []))
                                                ], style={'width': '100%'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('X Tick Distance')),
                                                    dbc.CardBody(children=func.render_input_number_min('X-dtick', 'X Axis Delta Tick', 0))
                                                ], className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Y Tick Distance')),
                                                    dbc.CardBody(children=func.render_input_number_min('Y-dtick', 'Y Axis Delta Tick', 0))
                                                ], className='col-md-6',
                                                ),
                                            ],
                                            ), id='scatter-collapse-8'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size}
                                    ),
                                ],
                                ),
                            ],
                            ),
                        ], className='col-md-3'
                        ),
                        html.Div(children=[
                            dbc.Row(children=[
                                dcc.Graph(id='indicator-graphic',
                                        style={'width' : '90%', 'padding-left' : '3%'},
                                        config={'editable' : True, 'toImageButtonOptions': {'scale' : 10},'edits' : {'legendPosition' : True, 'legendText' : True, 'colorbarPosition' : True, 'colorbarTitleText' : True}}
                                ),
                            ],
                            ),
                        ], className='col-md-9'),
                    ], )
    elif tab == 'line':
        df = cache.get(session + '-df')
        if df is None:
            return dcc.Markdown('''
            # No Data Uploaded

            If you're seeing this message, then you haven't uploaded any data yet

            Please do so by navigating to the Data Upload and uploading some data.

            When you are ready, come back here to create a Line Plot.
            ''')
        elif len(df.select_dtypes(include=['datetime', 'datetime64']).columns.values) == 0 or len(df.select_dtypes(include='number').columns.values) == 0:
            return dcc.Markdown('''
            # Data Uploaded but with no Numerical Features or Date Values

            This line plot is a Time Series Graph exclusively.

            To use a dataset, you'll need to name your Date or Time Column to Date.

            Feel free to combine both date and time into one column. Using Python's datetime

            inferring of format it should deal with many time formats.
            ''')
        else:
            # Other data in ynames
            ynames = df.select_dtypes(include='number').columns.values
            # Features that are Categorical
            cat_features = df.select_dtypes(include = 'object').columns.values
            return html.Div(className='row', children=[
                        html.Div(children=[
                            html.Div(className='container', children=[
                                html.Div(className='accordion', children=[
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Select Data", id='line-group-1-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H6('Choose Variables to see over time')),
                                                    dbc.CardBody(children=func.render_dropdown_valued_multi('select-variables', ynames, ynames[0]))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardBody(children=func.render_booleanswitch('use-group-by', 'Group Lines By Category?', False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H6('Select Group By')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('line-select-groupby', cat_features, cat_features[0]))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='line-collapse-1'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Plot Setting", id='line-group-2-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardBody(children=func.render_booleanswitch('line-show-gridlines', 'Show Grid Lines', False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardBody(children=func.render_booleanswitch('line-show-zeroline-y', 'Show Y Zero Line', False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([ 
                                                    dbc.CardHeader(html.H6('Y Delta Ticks')),
                                                    dbc.CardBody(children=func.render_input_number_min('line-Y-dtick', 'Delta Ticks', 0))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ), 
                                            ]),
                                            id='line-collapse-2'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Statistic Information", id='line-group-3-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Data Transformation')),
                                                    dbc.CardBody(children=func.render_toggleswitch('line-data-transform', ['Linear', 'Logarithmic'], False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                )
                                            ]),
                                            id='line-collapse-3'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ), # <== TO HERE
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Line Setting", id='line-group-4-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H6('Select Category')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('line-select-group', df[cat_features[0]].unique(), df[cat_features[0]].unique()[0]))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardBody(children=func.render_booleanswitch('ALF', 'Line Fill', False))
                                                ], style={'margin': '0px 0px 10px 0px'},className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardBody(children=func.render_booleanswitch('show-gaps', 'Show Gaps', False))
                                                ], style={'margin': '0px 0px 10px 0px'},className='col-md-6',
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H6('Line Style')),
                                                    dbc.CardBody(children=func.render_dropdown_format('line-style', linestyle_list))
                                                ], style={'margin': '0px 0px 10px 0px'},className='col-md-6'
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H6('Marker Style')),
                                                    dbc.CardBody(children=func.render_dropdown_dict_valued('line-alignment-markers-dropdown', MARKERS_DICT, 'circle'))
                                                ], style={'margin': '0px 0px 10px 0px'},className='col-md-6'
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H6('Label Style')),
                                                    dbc.CardBody(children=func.render_dropdown_dict_valued('line-alignment-labelstyle-dropdown', LABELSTYLE_DICT, 'lines'))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H6('Line Color')),
                                                    dbc.CardBody(children=func.render_colorpicker_small('line-colorpicker', '#FFFFFF', 0, 0, 255, 1))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='line-collapse-4'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Graph Setting", id='line-group-5-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Height')),
                                                    dbc.CardBody(children=func.render_slider('line-graph-height', 600, 1200, 600, 50, [600, 700, 800, 900, 1000, 1100, 1200]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Width')),
                                                    dbc.CardBody(children=func.render_slider('line-graph-width', 800, 1400, 800, 50, [800, 900, 1000, 1100, 1200, 1300, 1400]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                                dbc.Card([ 
                                                    dbc.CardHeader(html.H6('Opacity')),
                                                    dbc.CardBody(children=func.render_slider('line-opacity-slider', 0, 100, 85, 1, []))
                                                ], style={'width' : '100%'}
                                                ), 
                                            ]),
                                            id='line-collapse-5'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                ])
                            ])
                        ], className='col-md-3'
                        ),
                        html.Div(children=[
                            dbc.Row(children=[
                                dcc.Graph(id='line-graphic',
                                    style={'width' : '90%', 'padding-left' : '3%', 'padding-top' : '3%'},
                                    config={'editable' : True, 'toImageButtonOptions': {'scale' : 10},'edits' : {'legendPosition' : True, 'legendText' : True, 'colorbarPosition' : True, 'colorbarTitleText' : True}}
                                ),
                            ])
                        ], className='col-md-9'
                        ),
                    ], style=main_panel_margin)
    elif tab == 'box':
        df = cache.get(session + '-df')
        if df is None:
            return dcc.Markdown('''
            # No Data Uploaded

            If you're seeing this message, then you haven't uploaded any data yet

            Please do so by navigating to the Data Upload and uploading some data.

            When you are ready, come back here to create a Box and Whisker Plot.
            ''')
        elif len(df.select_dtypes(exclude=['number', 'datetime', 'datetime64']).columns.values) == 0 or len(df.select_dtypes(include='number').columns.values) == 0:
            return dcc.Markdown('''
            # Data Uploaded but with all Categorical Features or all Numerical Features

            If you're seeing this message, then you haven't uploaded any data that contains

            categorical features. All your columns are numerical or empty, otherwise, all the columns

            could potentially be categorical. To produce a box plot, you must have both in the set.
            ''')
        else:
            #Get the numerical and categorical features
            features = df.select_dtypes(include='number').columns.values
            cat_features = cat_features = df.select_dtypes(exclude=['number', 'datetime', 'datetime64']).columns.values
            #Setup the layout
            return  html.Div(className='row', children=[
                        html.Div(children=[
                            html.Div(className='container', children=[
                                html.Div(className='accordion', children=[
                                    #SELECT THE DATA
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Select Data", id='box-group-1-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        #Do the Variable and Group by Dropdowns
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Variable')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('select-variable', features, features[0]))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Group by')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('select-groupby', cat_features, cat_features[0]))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                )
                                            ]),
                                            id='box-collapse-1'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    #PLOT SETTINGS
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Plot Setting", id='box-group-3-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        #Do all the toggle switches for graph orientation, legend, grid lines, zero lines and have input for tick step and grid width
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Orientation')),
                                                    dbc.CardBody(children=func.render_toggleswitch('graph-alignment', ['Vertical', 'Horizontal'], False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Legend')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-legend', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Grid Lines')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-gridlines', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('X Zero Line')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-zeroline-x', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Y Zero Line')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-zeroline-y', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Grid Width')),
                                                    dbc.CardBody(children=func.render_numinput('grid-width', 1, 5, 1))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Tick Step')),
                                                    dbc.CardBody(children=func.render_input_number('delta-tick', 'Tick Step'))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='box-collapse-3'
                                        ),
                                    ], color='info', outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Statistic Information", id='box-group-4-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        #DATA TRANSFORMATION
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                #Set all the options for the Box Plot specifics, the one below is linear or logarithmic
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Data Transformation')),
                                                    dbc.CardBody(children=func.render_toggleswitch('data-transform', ['Linear', 'Logarithmic'], False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Choose how to deal with outliers
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Boxplot type')),
                                                    dbc.CardBody(children=func.render_radio_outliers('select-outliers'))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Show the frequency annotations
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Frequency')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-ndata', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Show the mean
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Mean')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-mean', False))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Show the standard deviation
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Std. Dev.')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-sd', False))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Show all the labels
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Summary Stats')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-stats', False))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='box-collapse-4'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    #Deal with the PERCENTILES
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Percentiles", id='box-group-7-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        #Show the percentiles and have the ability to adjust them.
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Show Percentiles')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-percentiles', False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Choose the percentile to adjust
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Percentile')),
                                                    dbc.CardBody(children=func.render_dropdown('select-percentile', ['5%', '10%', '90%', '95%']))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Choose the marker for them
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Marker Symbol')),
                                                    dbc.CardBody(children=func.render_dropdown_format('marker-symbol', marker_symbols))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Choose the size
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Symbol Size'), className='card w-100'),
                                                    dbc.CardBody(children=func.render_numinput('symbol-size', 1, 15, 8))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Choose the color
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Color')),
                                                    dbc.CardBody(children=func.render_colorpicker('select-percentile-color', 'white', 100, 200, 255, 0.65))
                                                ],
                                                ),
                                            ]),
                                            id='box-collapse-7'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    #Do all the threshold settings
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Threshold Setting", id='box-group-5-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Threshold')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('show-treshold', False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Value')),
                                                    dbc.CardBody(children=func.render_input('treshold-value', 'Threshold Value'))
                                                ], className='col-md-6'
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Line Size')),
                                                    dbc.CardBody(children=func.render_numinput('treshold-line-size', 1, 10, 2))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Line Style')),
                                                    dbc.CardBody(children=func.render_dropdown_format('treshold-style', line_style))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Line Color')),
                                                    dbc.CardBody(children=func.render_colorpicker('treshold-line-color', 'white', 0, 0, 255, 1))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='box-collapse-5'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    #Do all the box colors
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Box Color", id='box-group-6-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        #Choose to fill
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Fill')),
                                                    dbc.CardBody(children=func.render_toggleswitch('box-color-fill', ['Transparent', 'Colored'], True))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Select the box to adjust
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Select Box'), className='card w-100'),
                                                    dbc.CardBody(children=func.render_dropdown_valued('select-box', df[cat_features[0]].unique(),df[cat_features[0]].unique()[0]))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                #Choose the color for the box
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Color')),
                                                    dbc.CardBody(children=func.render_colorpicker('box-color', 'white', 0, 0, 255, 0.65))
                                                ],
                                                ),
                                            ]),
                                            id='box-collapse-6'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    #Choose the graph size, height and width
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Graph Size", id='box-group-2-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Height')),
                                                    dbc.CardBody(children=func.render_slider('graph-height', 600, 1200, 600, 50, [600, 700, 800, 900, 1000, 1100, 1200]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Width')),
                                                    dbc.CardBody(children=func.render_slider('graph-width', 800, 1400, 800, 50, [800, 900, 1000, 1100, 1200, 1300, 1400]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                            ]),
                                            id='box-collapse-2'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                ])
                            ])
                        ], className='col-md-3'
                        ),
                        html.Div(children=[
                            dbc.Row(children=[
                                dcc.Graph(id='box-plot',
                                        style={'width' : '90%', 'padding-left' : '3%'},
                                        config={'editable' : True, 'toImageButtonOptions': {'scale' : 10},'edits' : {'titleText': True}},
                                ),
                            ])
                        ]),
                    ], style=main_panel_margin)

    elif tab == 'bar':
        df = cache.get(session + '-df')
        if df is None:
            return dcc.Markdown('''
            # No Data Uploaded

            If you're seeing this message, then you haven't uploaded any data yet

            Please do so by navigating to the Data Upload and uploading some data.

            When you are ready, come back here to create a Bar Plot.
            ''')
        elif len(df.select_dtypes(exclude=['number', 'datetime', 'datetime64']).columns.values) == 0:
            return dcc.Markdown('''
            # Data Uploaded but with no Categorical Features or all Numerical Features

            If you're seeing this message, then you haven't uploaded any data that contains

            categorical features. All your columns are numerical or empty.
            ''')
        else:
            # Loading non-Numeric Data from Dataframe
            cat_features = df.select_dtypes(exclude=['number', 'datetime', 'datetime64']).columns.values
            return html.Div(className='row', children=[
                        html.Div(children=[
                            html.Div(className='container', children=[
                                html.Div(className='accordion', children=[
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Select Data", id='bar-group-1-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Variable')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('bar-select-variable', cat_features, cat_features[0]))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Group by')),
                                                    dbc.CardBody(children=func.render_dropdown_valued('bar-select-groupby', cat_features, cat_features[0]))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px', 'height': '30em'}
                                                )
                                            ]),
                                            id='bar-collapse-1'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Select Bar Plottype", id='bar-group-2-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Barplot type')),
                                                    dbc.CardBody(children=func.render_radio_plotype('select-barplot'))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='bar-collapse-2'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),

                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Plot Setting", id='bar-group-3-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Orientation')),
                                                    dbc.CardBody(children=func.render_toggleswitch('bar-graph-alignment', ['Horizontal', 'Vertical'], True))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Legend')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('bar-show-legend', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Grid Lines')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('bar-show-gridlines', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('X Zero Line')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('bar-show-zeroline-x', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Y Zero Line')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('bar-show-zeroline-y', True))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Grid Width')),
                                                    dbc.CardBody(children=func.render_numinput('bar-grid-width', 1, 5, 1))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Tick Step')),
                                                    dbc.CardBody(children=func.render_input_number('bar-delta-tick', 'Tick Step'))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='bar-collapse-3'
                                        ),
                                    ], color='info', outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Statistic Information", id='bar-group-4-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Data Transformation')),
                                                    dbc.CardBody(children=func.render_toggleswitch('bar-data-transform', ['Linear', 'Logarithmic'], False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Frequency')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('bar-show-ndata', True))
                                                ],style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='bar-collapse-4'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Threshold Setting", id='bar-group-5-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Threshold')),
                                                    dbc.CardBody(children=func.render_booleanswitch_nolab('bar-show-treshold', False))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Value')),
                                                    dbc.CardBody(children=func.render_input('bar-treshold-value', 'Threshold Value'))
                                                ], className='col-md-6'
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Line Size')),
                                                    dbc.CardBody(children=func.render_numinput('bar-treshold-line-size', 1, 10, 2))
                                                ], className='col-md-6', style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Line Style')),
                                                    dbc.CardBody(children=func.render_dropdown_format('bar-treshold-style', line_style))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Line Color')),
                                                    dbc.CardBody(children=func.render_colorpicker('bar-treshold-line-color', 'white', 0, 0, 255, 1))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                            ]),
                                            id='bar-collapse-5'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button(
                                                "Bar Color", id='bar-group-6-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Select bar'), className='card w-100'),
                                                    dbc.CardBody(children=func.render_dropdown_valued('select-bar', df[cat_features[0]].unique(),df[cat_features[0]].unique()[0]))
                                                ], style={'margin': '0px 0px 10px 0px'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Color')),
                                                    dbc.CardBody(children=func.render_colorpicker('bar-color', 'white', 0, 0, 255, 0.65))
                                                ],
                                                ),
                                            ]),
                                            id='bar-collapse-6'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                    dbc.Card([
                                        dbc.CardHeader(
                                            dbc.Button("Graph Size", id='bar-group-7-toggle', color=cardheader_color, style={'font-size': button_font_size}, block=True,
                                            )
                                        ),
                                        dbc.Collapse(
                                            dbc.CardBody(children=[
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Height')),
                                                    dbc.CardBody(children=func.render_slider('bar-graph-height', 600, 1200, 600, 50, [600, 700, 800, 900, 1000, 1100, 1200]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                                dbc.Card([
                                                    dbc.CardHeader(html.H5('Graph Width')),
                                                    dbc.CardBody(children=func.render_slider('bar-graph-width', 800, 1400, 800, 50, [800, 900, 1000, 1100, 1200, 1300, 1400]), style={'padding':'5% 5% 10% 5%'})
                                                ], style={'width': '100%'}
                                                ),
                                            ]),
                                            id='bar-collapse-7'
                                        ),
                                    ], color=cardbody_color, outline=True, style={'font-size': cardbody_font_size} ),
                                ])
                            ])
                        ], className='col-md-3'
                        ),
                        html.Div(children=[
                            dbc.Row(children=[
                                dcc.Graph(id='bar-plot',
                                        style={'width' : '90%', 'padding-left' : '3%'},
                                        config={'editable' : True, 'toImageButtonOptions': {'scale' : 10},'edits' : {'titleText': True}},
                                ),
                            ]),
                        ], className='col-md-9'
                        ),
                    ], style=main_panel_margin)


#----------------------ACCORDIAN CALLBACKS USED IN EVERY SINGLE PLOT--------------------#
# Accordion Toggle Callback
@app.callback(
    [Output(f'scatter-collapse-{i}', 'is_open') for i in range(1,9)],
    [Input(f'scatter-group-{i}-toggle', 'n_clicks') for i in range(1,9)],
    [State(f'scatter-collapse-{i}', 'is_open') for i in range(1,9)]
)
def toggle_accordion(n1, n2, n3, n4, n5, n6, n7, n8, is_open1, is_open2, is_open3, is_open4, is_open5, is_open6, is_open7, is_open8):
    ctx = dash.callback_context

    if not ctx.triggered:
        return ""
    else:
        button_id = ctx.triggered[0]['prop_id'].split('.')[0]

    if button_id ==  'scatter-group-1-toggle' and n1:
        return not is_open1, False, False, False, False, False, False, False
    elif button_id ==  'scatter-group-2-toggle' and n2:
        return False, not is_open2, False, False, False, False, False, False
    elif button_id ==  'scatter-group-3-toggle' and n3:
        return False, False, not is_open3, False, False, False, False, False
    elif button_id ==  'scatter-group-4-toggle' and n4:
        return False, False, False, not is_open4, False, False, False, False
    elif button_id ==  'scatter-group-5-toggle' and n5:
        return False, False, False, False, not is_open5, False, False, False
    elif button_id ==  'scatter-group-6-toggle' and n6:
        return False, False, False, False, False, not is_open6, False, False
    elif button_id ==  'scatter-group-7-toggle' and n7:
        return False, False, False, False, False, False, not is_open7, False
    elif button_id ==  'scatter-group-8-toggle' and n8:
        return False, False, False, False, False, False, False, not is_open8
    return False, False, False, False, False, False, False, False

# Accordion Toggle Callback
@app.callback(
    [Output(f'line-collapse-{i}', 'is_open') for i in range(1,6)],
    [Input(f'line-group-{i}-toggle', 'n_clicks') for i in range(1,6)],
    [State(f'line-collapse-{i}', 'is_open') for i in range(1,6)]
)
def toggle_accordion(n1, n2, n3, n4, n5, is_open1, is_open2, is_open3, is_open4, is_open5):
    ctx = dash.callback_context

    if not ctx.triggered:
        return ""
    else:
        button_id = ctx.triggered[0]['prop_id'].split('.')[0]

    if button_id ==  'line-group-1-toggle' and n1:
        return not is_open1, False, False, False, False
    elif button_id ==  'line-group-2-toggle' and n2:
        return False, not is_open2, False, False, False
    elif button_id ==  'line-group-3-toggle' and n3:
        return False, False, not is_open3, False, False
    elif button_id ==  'line-group-4-toggle' and n4:
        return False, False, False, not is_open4, False
    elif button_id ==  'line-group-5-toggle' and n5:
        return False, False, False, False, not is_open5

    return False, False, False, False, False

# Accordion Toggle Callback
@app.callback(
    [Output(f'box-collapse-{i}', 'is_open') for i in range(1,8)],
    [Input(f'box-group-{i}-toggle', 'n_clicks') for i in range(1,8)],
    [State(f'box-collapse-{i}', 'is_open') for i in range(1,8)]
)
def toggle_accordion(n1, n2, n3, n4, n5, n6, n7, is_open1, is_open2, is_open3, is_open4, is_open5, is_open6, is_open7):
    ctx = dash.callback_context

    if not ctx.triggered:
        return ""
    else:
        button_id = ctx.triggered[0]['prop_id'].split('.')[0]

    if button_id ==  'box-group-1-toggle' and n1:
        return not is_open1, False, False, False, False, False, False
    elif button_id ==  'box-group-2-toggle' and n2:
        return False, not is_open2, False, False, False, False, False
    elif button_id ==  'box-group-3-toggle' and n3:
        return False, False, not is_open3, False, False, False, False
    elif button_id ==  'box-group-4-toggle' and n4:
        return False, False, False, not is_open4, False, False, False
    elif button_id ==  'box-group-5-toggle' and n5:
        return False, False, False, False, not is_open5, False, False
    elif button_id ==  'box-group-6-toggle' and n6:
        return False, False, False, False, False, not is_open6, False
    elif button_id ==  'box-group-7-toggle' and n7:
        return False, False, False, False, False, False, not is_open7
    return False, False, False, False, False, False, False

# Accordion Toggle Callback
@app.callback(
    [Output(f'bar-collapse-{i}', 'is_open') for i in range(1,8)],
    [Input(f'bar-group-{i}-toggle', 'n_clicks') for i in range(1,8)],
    [State(f'bar-collapse-{i}', 'is_open') for i in range(1,8)]
)
def toggle_accordion(n1, n2, n3, n4, n5, n6, n7, is_open1, is_open2, is_open3, is_open4, is_open5, is_open6, is_open7):
    ctx = dash.callback_context

    if not ctx.triggered:
        return ""
    else:
        button_id = ctx.triggered[0]['prop_id'].split('.')[0]

    if button_id ==  'bar-group-1-toggle' and n1:
        return not is_open1, False, False, False, False, False, False
    elif button_id ==  'bar-group-2-toggle' and n2:
        return False, not is_open2, False, False, False, False, False
    elif button_id ==  'bar-group-3-toggle' and n3:
        return False, False, not is_open3, False, False, False, False
    elif button_id ==  'bar-group-4-toggle' and n4:
        return False, False, False, not is_open4, False, False, False
    elif button_id ==  'bar-group-5-toggle' and n5:
        return False, False, False, False, not is_open5, False, False
    elif button_id ==  'bar-group-6-toggle' and n6:
        return False, False, False, False, False, not is_open6, False
    elif button_id ==  'bar-group-7-toggle' and n7:
        return False, False, False, False, False, False, not is_open7
    return False, False, False, False, False, False, False

'''
#------------------ DATA CLEANING RECOMMENDATION PAGE AND DATA UPLOAD --------------------------------#
Content for the Data Upload Page is below
Please look into the comments for what each one is for
Some of it is derived by https://dash.plot.ly/dash-core-components/upload
As it provides a good base to start from in order to upload files.
'''
def parse_contents(contents, filename, date, session_id):
    content_type, content_string = contents.split(',')
    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))
        elif 'xlsx' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded)) 
        
        #Process potential datetieme columns
        for col in df.columns.values:
            if 'date' in col.lower():
                df[col] = pd.to_datetime(df[col], infer_datetime_format=True)

        #Add Filename to cache
        cache.set(session_id + '-name', filename)
        #Add File Last Modified Datetime to cache
        cache.set(session_id + '-date', str(datetime.fromtimestamp(date)))
        #Add Dataframe to Cache
        cache.set(session_id + '-df', df)
        

        return html.Div([
                #Show the uploaded file name and last modified timestamp
                html.H3("Uploaded File: {}".format(filename)),
                html.H3("Last Modified: {}".format(str(datetime.fromtimestamp(date)))),
            ]
        )
        
    #If an exception occured when uploading the file
    except Exception as e:
        #Print the exception in the terminal
        print(e)
        #Let User know there was a problem
        return html.Div([
            'There was an error processing this file.'
        ])

@app.callback(Output('tabs-content-upload', 'children'),
              [Input('tabs-styled-in-upload', 'value'),
              Input('session_id', 'children')])
def render_upload_content(tab, session_id):
    #Retrieve the Dataframe from Cache
    df = cache.get(session_id + '-df')
    if tab == "upload-data":
        #If no data has been uploaded then show the content below
        if df is None:
            return html.Div([
                    #The upload area!
                    html.H1('Upload Your Dataset'),
                    #Click on it or drag and drop into it
                    dcc.Upload(
                        id = 'data',
                        children=html.Div(['Drag and Drop or ', html.A('Select Files')]),
                        className='data-upload',
                    ),
                    #Here is our no file uploaded message
                    html.Div(id='markdown-message', children=[
                        dcc.Markdown("""
                            If you are seeing this message, then you haven't uploaded any data.

                            Please use the box above to drag a file into the box, or

                            Click on the box to select a file from your device.

                            Files should be **Excel** (.xls or .xlsx) or **CSV** (.csv).
                            """)
                    ]),
                    #The output to show filename and data last modified date
                    html.Div(id='upload-data-output'),
                ]
            )
        else:
            #I dislike repeating code, but it works as it should, its not worth the extra effort to condense it right now
            return html.Div([
                #The upload area!
                    html.H1('Upload Your Dataset'),
                    dcc.Upload(
                        id = 'data',
                        children=html.Div(['Drag and Drop or ', html.A('Select Files')]),
                        className='data-upload',
                    ),
                    #Our message shows the cached content, will be hidden when things change
                    html.Div(id='markdown-message', children=[
                        html.H3("Uploaded File: {}".format(cache.get(session_id + '-name'))),
                        html.H3("Last Modified: {}".format(cache.get(session_id + '-date'))),
                    ]),
                    #Show the uploaded file name and last modified timestamp 
                    html.Div(id='upload-data-output'),
                ],
            )
    elif tab == 'uploaded':
        if df is None:
            #Take a look at the uploaded data in a table
            return html.Div([
                #However if we have no data, we leave a message.
                dcc.Markdown('''
                ## No Data Uploaded
                Please go to **Upload Your Data** and select an Excel or CSV file to upload
                Once you have done this, your data will appear here.
                '''),
            ])
        else:
            #Create the conditionals list of dictionaries, starting by highlighting each odd row
            conditionals = [
                {
                    'if': {'row_index': 'odd'},
                    'backgroundColor': 'rgb(248, 248, 248)'
                },
            ]
            #Create the conditionals to highlight the cells which are empty
            for col in df.columns:
                conditionals.append(
                    {
                        #If the data in the cell is None, NaN, NA, null then highlight in orange red
                        'if': {
                            'column_id': col,
                            'filter_query': '{{{}}} is nil'.format(col)
                        },
                    'backgroundColor': 'orangered'
                    }
                )
            #Get the size of the dataframe in number of cells
            size = df.shape[0] * df.shape[1]
            #Get the number of missing cells (its a sum of the missing cells in each column)
            missing_cells = df.isna().sum().sum()
            #Put it in terms of percentage to 3 decimal places.
            missing_stat = round((missing_cells / size)*100,3)

            return html.Div([
                #Give some headers and show filename and date last modified
                html.H1("Your Uploaded Data"),
                html.P("It contains {} cells, of which {} are missing values.".format(size, missing_cells)),
                html.P("The missing data accounts for {}% of the data set.".format(missing_stat)),
                #Show the data
                dash_table.DataTable(
                    data=df.to_dict('records'),
                    columns=[{'name': i, 'id': i} for i in df.columns],
                    #Fix the headers on the table
                    fixed_rows={ 'headers': True, 'data': 0 },
                    #Ensure scrolling for smaller screens, but also ensure it fills the container
                    style_table={
                        'overflowX' : 'scroll', 
                        'overflowY' : 'scroll',
                        'min-width' : '70%',
                        'min-height' : '70%',
                    },
                    #Each cell should be a minimum of 100 pixels in width
                    style_cell={
                        'minWidth' : '100px',
                    },
                    #Apply the conditionals to the cells to highlight missing values
                    style_data_conditional=conditionals,
                    #Chnage the style of the header
                    style_header={
                        'backgroundColor': 'rgb(230, 230, 230)',
                        'fontWeight': 'bold'
                    }
                ),
            ])
    elif tab == 'description':
        if df is None:
            return html.Div([
                #There is no data so leave a message
                dcc.Markdown('''
                ## No Data Uploaded
                Please go to **Upload Your Data** and select an Excel or CSV file to upload
                Once you have done this, your data description will appear here.
                '''),
            ])
        else:
            #Use describe to get basic stats from numerical columns including percentiles
            num_describe = df.describe(percentiles=[0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.95])
            #Reset the index to have the Features column appear in describe result
            num_describe = num_describe.reset_index()
            #Rename the index column to Features
            num_describe = num_describe.rename(columns={'index' : 'Features'})
            #Check if all the columns are numerical, if they're not then generate information about the rest
            if len(df.select_dtypes(include='number').columns.values) != len(df.columns):
                #Now apply the same steps but for categorical columns too
                cat_describe = df.describe(exclude='number')
                cat_describe = cat_describe.reset_index()
                cat_describe = cat_describe.rename(columns={'index' : 'Features'})
                cat_content = html.Div([
                    html.H1("Data About the Non-Numerical Columns in {}".format(cache.get(session_id + '-name'))),
                    #Show the contents of cat_describe
                    dash_table.DataTable(
                        data=cat_describe.to_dict('records'),
                        columns=[{'name': i, 'id': i} for i in cat_describe.columns],
                        #Fix the First column containing the feature indexes
                        fixed_columns={ 'headers': True, 'data': 1 },
                        style_table={'min-width' : '100%'},
                        style_cell={
                            'minWidth' : '100px',
                        },
                        style_data_conditional=[
                        {
                            'if': {'row_index': 'odd'},
                            'backgroundColor': 'rgb(248, 248, 248)'
                        }
                    ],
                    ),
                ]
            )
            else:
                cat_content = None
            return html.Div([
                html.H1("Data About the Numerical Columns in {}".format(cache.get(session_id + '-name'))),
                #Show the contents of num_describe in a data table
                dash_table.DataTable(
                    data=num_describe.to_dict('records'),
                    columns=[{'name': i, 'id': i} for i in num_describe.columns],
                    #Fix the First column containing the feature indexes
                    fixed_columns={ 'headers': True, 'data': 1 },
                    style_table={'min-width' : '100%'},
                    style_cell={
                        'minWidth' : '100px',
                    },
                    style_data_conditional=[
                        {
                            'if': {'row_index': 'odd'},
                            'backgroundColor': 'rgb(248, 248, 248)'
                        }
                    ],
                ),
                cat_content,
            ], className='description')
    elif tab == 'scatterplot-matrix':
        if df is None:
            #Leave a message as there is no data
            return html.Div([
                dcc.Markdown('''
                ## No Data Uploaded
                Please go to **Upload Your Data** and select an Excel or CSV file to upload
                Once you have done this, a scatter plot matrix will appear here.
                '''),
            ])
        else:
            #Get all the numerical columns
            num_column_names = df.select_dtypes(include='number').columns.values
            return html.Div([
                html.Div([
                    #HEre's the multichoice dropdown for the splom
                    html.H3("Choose Your Features"),
                    dcc.Dropdown(
                        id='splom-column',
                        options=[{'label': i, 'value': i} for i in num_column_names],
                        value=[num_column_names[0]],
                        multi=True,
                    ),
                ], className='splom-choices'),
                #Choose the colorscale for the splom
                html.Div([
                    html.H3("Choose your Colorscale"),
                    dcc.Dropdown(
                        id='splom-colorscale',
                        options=COLORSCALES_DICT,
                        value='Greys',
                    ),
                ], className='splom-choices'),
                #Choose what value to group the splom by
                html.Div([
                    html.H3("Group By"),
                    dcc.Dropdown(
                        id='splom-color-chooser',
                        options=[{'label': i, 'value': i} for i in num_column_names],
                        value=df.columns[0],
                    ),
                ], className='splom-choices'),
                dcc.Graph(id="scatter-matrix-fig"),
            ])

'''
This callback feeds the parse contents function, which processes a file,
reads it and gets basic info and saves its content inside the cache.
'''
@app.callback([Output('upload-data-output', 'children'),
               Output('markdown-message', 'hidden')],
              [Input('data', 'contents'),
              Input('session_id', 'children')],
              [State('data', 'filename'),
               State('data', 'last_modified')]
            )
def update_output(content, session, name, date):
    if content is not None:
        return parse_contents(content, name, date, session), True

#Do the scatter plot matrix
@app.callback(Output('scatter-matrix-fig', 'figure'),
              [Input('splom-column', 'value'),
              Input('splom-colorscale', 'value'),
              Input('splom-color-chooser', 'value'),
              Input('session_id', 'children')])
def render_splom(columns, colorscale, color, session_id):
    #Get the dataframe
    df = cache.get(session_id + '-df')
    #Get all the number columns
    num_column_names = df.select_dtypes(include='number').columns.values
    #If we choose a categorical variable for matching colors
    if color not in num_column_names:
        #Show scale is false
        showscale=False
        #Get the category codes
        marker_color = df[color].astype('category').cat.codes
        #Show the legend
        showlegend = True

    else:
        marker_color = df[color]
        showscale = True
        #Show legend is false
        showlegend = False


    #Do the Sploms data
    return {'data': [
                go.Splom(
                    dimensions=[{'label': i, 'values': df[i]} for i in columns],
                    text=df[color],
                    marker=dict(
                        colorscale=colorscale,
                        color=marker_color,
                        showscale=showscale,
                        colorbar={'title' : color},

                    ),    
                )
            ],
            'layout' : go.Layout(
                title="Scatter Plot Matrix for {}".format(cache.get(session_id + '-name')),
                dragmode='select',
                width=1500,
                height=900,
            )
        }

'''
#--------------------SCATTER PLOT CALLBACKS--------------------#
The following are coded by Bo Yang, Demas Dasa and Joel Dunstan, Bo Yang
was responsible for the original forms and callbacks (mostly). Demas provided the
layout, Joel integrated it to here and did the Markers Tabs.
'''
'''
The function below will update the color picker with the value from the class
'''
@app.callback(
    Output('my-color-picker', 'value'),
    [Input('alignment-markers-dropdown', 'value')]
)
def update_scatter_color_selector(box):
    #Get the current class and its colors
    temp_str = markers_choice.get(box, dict(rgb=dict(r=222, g=110, b=75, a=default_alpha)))
    #If its an instance, reformat it into the rgb string
    if isinstance(temp_str, str):
        start_idx = temp_str.find('(')
        temp_str = temp_str[start_idx+1:len(temp_str)-1]
        temp_str = temp_str.split(",")
        temp_str = dict(rgb=dict(r=temp_str[0], g=temp_str[1], b=temp_str[2], a=temp_str[3]))
    #Return RGB String
    return temp_str

'''
Function will enable or disable the line of best fit function
if either of the axes are put into logarithmic mode.
'''
@app.callback(
	[Output('linear', 'on'),
	Output('linear', 'disabled')
	],
	[Input('xaxis-type', 'value'),
	Input('yaxis-type', 'value'),
	]
	)
def show_fitline(xv, yv):
	if xv=='Log' or yv=='Log':
		return False,True
	else:
		return False,False

'''
This will disable the threshold options if the threshold forms are empty
'''
@app.callback(
    [Output('x-threshold-style', 'disabled'),
    Output('y-threshold-style', 'disabled'),
    Output('x-threshold-color', 'disabled'),
    Output('y-threshold-color', 'disabled')],
    [Input('X-thredshold', 'value'),
     Input('Y-thredshold', 'value'),]
)
def enable_threshold_styles(x_t, y_t):
    #If the x threshold isnt empty
    if x_t is not None:
        x_style = False
        x_color= False
    #If it is empty
    else:
        x_style = True
        x_color = True
    #If y threshold is empty
    if y_t is not None:
        y_style = False
        y_color = False
    #If Y threshold
    else:
        y_style = True
        y_color = True
    return x_style, y_style, x_color, y_color

'''
This will adjust the options for the colors, if a categorical column is chosen
then it will disable the colorscale options and enable the color picker. If a numerical
column is chosen it will do the opposite
'''
@app.callback(
	[Output('color-selected-groupby', 'options'),
	Output('alignment-colorscale-dropdown', 'disabled'),
	Output('my-color-picker','disabled'),
	Output('LS', 'disabled'),
	Output('color-selected-groupby', 'disabled'),
    Output('color-selected-groupby', 'value'),
	],
	[Input('color-drop', 'value'),
    Input('session_id', 'children')]
	)
def scatter_traces_groupby(color_drop, session):
    #Get the dataframe
    df = cache.get(session + '-df')
    #If the column chosen is categorical
    if df[color_drop].dtypes =='object':
        idx =0
        #Go through each unique one
        for i in df[color_drop].unique():
            #Assign the default colors
            markers_choice[i] = default_color[idx % num_of_color]
            idx += 1
        #Return the labels
        return [{'label': i, 'value': i} for i in df[color_drop].unique()], True, False, True, False,df[color_drop].unique()[0]
    else:
        #Return single label
        return [{'label': color_drop, 'value': color_drop}], False, True, False, True, color_drop

'''
This will assign all the markers to a category
and return the options, and the value.
'''
@app.callback(
    [Output('marker-selected-group', 'value'),
    Output('marker-selected-groupby', 'options'),
    Output('marker-selected-groupby', 'disabled'),
    Output('marker-drop', 'disabled'),
    Output('marker-selected-groupby', 'value')],
    [Input('marker-style-tog', 'on'),
    Input('marker-drop', 'value'),
    Input('session_id', 'children')]
)
def scatter_markers_groupby(marker_on, marker_drop, session):
    #Get the dataframe
    df = cache.get(session + '-df')
    idx = 0
    dictionary = dict()
    #If we're grouping by the marker
    if marker_on:
        #For every unique category
        for i in df[marker_drop].unique():
            #Pick a marker
            markers_shape[i] = random.choice(MARKERS_LIST)
            idx += 1
        #Return the necessary values
        return df[marker_drop].unique()[0], [{'label': i, 'value': i} for i in df[marker_drop].unique()], False, False, df[marker_drop].unique()[0]
    else:
        return marker_drop, [{'label': marker_drop, 'value': marker_drop}], True, True, marker_drop

'''
Adjusts the linear functions options availability depending on if
the linear line of best fit has been enabled or not.
'''
@app.callback(
	[Output('change-dash', 'disabled'),
    Output('fit-color-picker', 'disabled')],
	[Input('linear', 'on'),]
	)
def show_linear(on):
	if on:
		return False, False
	else:
		return True, True

'''
This is the main function of the scatter plot, its the function that updates
the graph!
'''
@app.callback(
    Output('indicator-graphic', 'figure'),
    [Input('xaxis-column', 'value'),
     Input('yaxis-column', 'value'),
     Input('xaxis-type', 'value'),
     Input('yaxis-type', 'value'),
     Input('alignment-colorscale-dropdown', 'value'),
     Input('swap', 'on'),
     Input('linear', 'on'),
     Input('GL', 'on'),
     Input('OL', 'on'),
     Input('alignment-markers-dropdown', 'value'),
     Input('color-drop', 'value'),
     Input('LD', 'on'),
     Input('opacity-slider', 'value'),
     Input('X-dtick', 'value'),
     Input('Y-dtick', 'value'),
     Input('X-thredshold', 'value'),
     Input('Y-thredshold', 'value'),
     Input('color-selected-groupby', 'value'),
     Input('my-color-picker', 'value'),
     Input('LB', 'on'),
     Input('LS', 'on'),
     Input('change-dash', 'value'),
     Input('graph-height', 'value'),
     Input('graph-width', 'value'),
     Input('fit-color-picker', 'value'),
     Input('x-threshold-style', 'value'),
     Input('y-threshold-style', 'value'),
     Input('x-threshold-color', 'value'),
     Input('y-threshold-color', 'value'),
     Input('marker-size-tog', 'on'),
     Input('marker-size', 'value'),
     Input('marker-max', 'value'),
     Input('marker-drop', 'value'),
     Input('marker-selected-groupby', 'value'),
     Input('marker-style-tog', 'on'),
     Input('session_id', 'children'),
     ])
def scatter_update_graph(xaxis_column_name, yaxis_column_name,
                 xaxis_type, yaxis_type,
                 alignment_colorscale_dropdown, 
                 swap, linear, GL, OL, 
                 alignment_markers_dropdown, color_var, 
                 LD, OS, X_D, Y_D, X_T, Y_T, G_t, C_P, LB,
                 LS, CD, graph_height, graph_width, 
                 fit_color_picker, x_t_style, y_t_style,
                 x_t_color, y_t_color, use_size, marker_size, marker_max, 
                 marker_drop, marker_groupby, marker_on, session):
    #Get the dataframe
    df = cache.get(session + '-df')
    #If Swap Axes is enabled
    if swap:
    	# Swapping the x and y axes names
        tmp = xaxis_column_name
        xaxis_column_name = yaxis_column_name
        yaxis_column_name = tmp

    #Generate the Line of Best Fit
    slope, intercept, r_value, p_value, std_err = stats.linregress(df[xaxis_column_name],df[yaxis_column_name])
    line = slope*df[xaxis_column_name]+intercept

    #Do the setup for the thresholds
    threshold_shape = []
    #Take the x threshold color
    x_color = 'rgba({}, {}, {}, {})'.format(
        x_t_color['rgb']['r'],
        x_t_color['rgb']['g'],
        x_t_color['rgb']['b'],
        x_t_color['rgb']['a'],)
    #Take the y threshold color
    y_color = 'rgba({}, {}, {}, {})'.format(
        y_t_color['rgb']['r'],
        y_t_color['rgb']['g'],
        y_t_color['rgb']['b'],
        y_t_color['rgb']['a'],)

    #if users set a threshold for X, then show this line
    if X_T !=None:
    	threshold_shape.append(dict(
    	type='line',
    	x0=X_T,
    	x1=X_T,
    	y0=df[yaxis_column_name].min(),
    	y1=df[yaxis_column_name].max(),
        line=dict(
            color=x_color,
            dash=x_t_style
        )
    	))

    #if users set a threshold for Y, then show this line
    if Y_T !=None:{
    	threshold_shape.append(dict(
    	type='line',
    	x0=df[xaxis_column_name].min(),
    	x1=df[xaxis_column_name].max(),
    	y0=Y_T,
    	y1=Y_T,
        line=dict(
            color=y_color,
            dash=y_t_style
        )
    	))}

    #Set the mode, if someone wants to show labels then do so.
    mode_t='markers'
    if LB:
    	mode_t='markers+text'
    #Get the color for the plots categories
    picker_markers_color = 'rgba({}, {}, {}, {})'.format(
        C_P['rgb']['r'],
        C_P['rgb']['g'],
        C_P['rgb']['b'],
        C_P['rgb']['a'],)
    #If we are using a category then apply the color just grabbed from the color picker
    if df[color_var].dtypes=='object':
    	for i in df[color_var].unique():
            if color_var is not None:
                #We only edit the necessary one, which we select via a drop down
                if i == G_t:
                    markers_choice[i] = picker_markers_color
                    print(markers_choice[i])
    #If the markers are on, then apply the marker via the group by marker, similar to the color above
    if marker_on:
        for cat in df[marker_drop].unique():
            if marker_drop is not None:
                if cat == marker_groupby:
                    markers_shape[cat] = alignment_markers_dropdown
            else:
                markers_shape[cat] = random.choice(MARKERS_LIST)
    #If use size has been enabled then..
    if use_size:
        #Take the data as a numpy float array
        marker_data = np.array(df[marker_size], dtype='float64')
        #Use numpy's interp to scale the data between 1 and some specified range
        marker_size = list(np.interp(marker_data, (marker_data.min(), marker_data.max()), (1, marker_max)))
    #Else use the marker size 15
    else:
        marker_size=15

    traces = []
    #If the data is categorical, then do the traces by category
    if df[color_var].dtypes=='object' and not marker_on:
        #If the marker is not on, then do the traces by the color var category
    	for i in df[color_var].unique():
    		df_by = df[df[color_var] == i]
            #Append the trace
    		traces.append(go.Scatter(
	    		x=df_by[xaxis_column_name],
	       		y=df_by[yaxis_column_name],
                #Take the mode
	       		mode=mode_t,	       		
	       		text=i,
	       		textposition='top center',
	       		opacity=OS/100,
                #Set the markers to all a single marker
	       		marker={
	       			'size': marker_size,
	       			'line': {'width' :0.5, 'color': 'white'},
	       			'symbol': alignment_markers_dropdown,
                    #But use a different color for all of them
	       			'color': markers_choice[i],
	       		},
                #Name is simply the category
	       		name=i
	       	    )
            )
    #If dealing with categorical variables in color, and the marker is on
    elif df[color_var].dtypes=='object' and marker_on:
        for i in df[color_var].unique():
            for j in df[marker_drop].unique():
                #Then for each trace we grab the subset from color var and marker drop together
                df_by = df[df[color_var] == i][df[marker_drop] == j]
                traces.append(go.Scatter(
                    x=df_by[xaxis_column_name],
                    y=df_by[yaxis_column_name],
                    mode=mode_t,
                    text=i,
                    textposition='top center',
                    opacity=OS/100,
                    #The main differences to others are below
                    marker={
                        'size': marker_size,
                        'line': {'width' :0.5, 'color': 'white'},
                        #Both color and markers are set per individual trace
                        'color': markers_choice[i],
                        'symbol':markers_shape[j]
                        },
                        #Name is a combination of both things
                        name=str(i) + ' : ' + str(j)
                    )
                )
    #if the data type of the group by column is int or float, it will show the VS, and the color based on the X values
    elif (df[color_var].dtypes=='int64' or df[color_var].dtypes=='float64') and not marker_on:
        #Marker not on
	    traces.append(go.Scatter(
	    	x=df[xaxis_column_name],
	    	y=df[yaxis_column_name],
	    	mode=mode_t,
	    	text = color_var,
	    	opacity=OS/100,
	    	marker=dict(
	    		size = marker_size,
	        	line = {'width': 0.5, 'color': 'white'},
                #Scale the colors to some numerical array
	        	color = df[color_var],
                #Use the colorscale
	        	colorscale = alignment_colorscale_dropdown,
	        	colorbar=dict(
	        		title=color_var
	        		),
	        	showscale = LS,
                #Use the same marker for everyone
	        	symbol = alignment_markers_dropdown
	    	),
	    	name='{} VS {}'.format(xaxis_column_name, yaxis_column_name)
	    ))
    #If numerical and marker is on then
    elif (df[color_var].dtypes=='int64' or df[color_var].dtypes=='float64') and marker_on:
        for cat in df[marker_drop].unique():
            #Grab the category
            df_by = df[df[marker_drop] == cat]
            showScale = False
            #If its the last one, the enable the colorscale, otherwise it adds one for every trace
            if cat == df[marker_drop].unique()[-1]:
                showScale = LS
            traces.append(go.Scatter(
                x=df_by[xaxis_column_name],
                y=df_by[yaxis_column_name],
                mode=mode_t,
                text = color_var,
                opacity=OS/100,
                marker=dict(
                    size = marker_size,
                    line = {'width': 0.5, 'color': 'white'},
                    #Stiull use colorscale
                    color = df[color_var],
                    colorscale = alignment_colorscale_dropdown,
                    colorbar=dict(
                        title=color_var
                        ),
                    showscale = showScale,
                    #Set the marker for each trace
                    symbol = markers_shape[cat]
                ),
                #Name is now the category
                name=cat,
            ))
    #Set all the options for line of best fit
    # Get the color first   
    fit_color = 'rgba({}, {}, {}, {})'.format(
        fit_color_picker['rgb']['r'],
        fit_color_picker['rgb']['g'],
        fit_color_picker['rgb']['b'],
        fit_color_picker['rgb']['a'],)
    #Now add the trace
    traces.append(go.Scatter(
    	x=df[xaxis_column_name],
        y=line,
        mode='lines',
        name='Y = {:.3f}*X + {:.3f}'.format(slope, intercept),
        marker=dict(
            size = 15,
            opacity = 0.5,
            line = {'width': 0.5, 'color': 'white'},
            color = fit_color,
            showscale = LD
        ),
        line = dict(
            #Uses a set line style
        	dash=CD
        	),
        #Will only be visible if its enabled
        visible=linear
    ))
    #Do the layout, most if it is self explanatory via the variable names
    layou_t=dict(
    	xaxis={
            'title': xaxis_column_name,
            'type': 'log' if xaxis_type else 'linear',
           	'showgrid': GL,
           	'zeroline': OL,
            'dtick': X_D
        },
        yaxis={
            'title': yaxis_column_name,
            'type': 'log' if yaxis_type else 'linear',
            'showgrid': GL,
            'zeroline': OL,
            'dtick': Y_D
        },
        title= xaxis_column_name + ' vs. ' + yaxis_column_name,
        showlegend = LD,
        shapes=threshold_shape,
        hovermode='closest',
        height=graph_height,
        width=graph_width
    	)
    #Return everything!
    return {
       	'data': 
       		traces,

       	'layout': go.Layout(
           	layou_t
       	)
    }

'''
#--------------------LINE PLOT CALLBACKS--------------------#
The Callbacks were mainly done by Guobei and edited by Joel.
'''
@app.callback(
    Output('line-colorpicker', 'value'),
    [Input('line-select-group', 'value'),]
)
def update_line(select_group):
    temp_str = LINECOLOR_DICT.get(select_group, dict(rgb = dict(r = 222, g = 110, b = 75, a = default_alpha)))
    if isinstance(temp_str, str):
        start_idx = temp_str.find('(')
        temp_str = temp_str[start_idx+1:len(temp_str)-1]
        temp_str = temp_str.split(",")
        temp_str = dict(rgb = dict(r = temp_str[0], g = temp_str[1], b = temp_str[2], a = temp_str[3]))
    return temp_str


@app.callback(
    [Output('line-select-group', 'options'),
    Output('line-select-groupby', 'disabled'),
    Output('line-select-group', 'value')],
    [Input('line-select-groupby', 'value'),
    Input('use-group-by', 'on'),
    Input('select-variables', 'value'),
    Input('session_id', 'children')]
)
def line_update_group(groupby, usegroup, selected, session):
    df = cache.get(session + '-df')
    idx = 0
    if usegroup:
        groups = []
        for s in selected:
            for i in df[groupby].unique():
                LINECOLOR_DICT[s + ' : '+ i] = default_color[idx % 5]
                marker_dict[s + ' : '+ i] = MARKERS_DICT[idx % 5]['value']
                linestyle_dict[s + ' : '+ i] = linestyle_list[idx % 6].replace(' ', '').lower()
                gap_dict[s + ' : '+ i] = True
                label_dict[s + ' : '+ i] = LABELSTYLE_DICT[0]['value']
                linefill[s + ' : '+ i] = False
                idx += 1
                groups.append(s + ' : '+ i)
            return [{'label': i, 'value': i} for i in groups], False, groups[0]
    else:
        for i in selected:
            LINECOLOR_DICT[i] = default_color[idx % 5]
            marker_dict[i] = MARKERS_DICT[idx % 5]['value']
            linestyle_dict[i] = linestyle_list[idx % 6].replace(' ', '').lower()
            gap_dict[i] = True
            label_dict[i] = LABELSTYLE_DICT[0]['value']
            linefill[i] = False
            idx += 1
        return [{'label': i, 'value': i} for i in selected], True, selected[0]


# Main callback
@app.callback(
    Output('line-graphic', 'figure'),
    [Input('select-variables', 'value'),
     Input('line-data-transform', 'value'),
     Input('line-show-gridlines', 'on'),
     Input('line-show-zeroline-y', 'on'),
     Input('line-alignment-markers-dropdown', 'value'),
     Input('line-alignment-labelstyle-dropdown', 'value'),
     Input('show-gaps', 'on'),
     Input('ALF', 'on'),
     Input('line-opacity-slider', 'value'),
     Input('line-colorpicker', 'value'),
     Input('line-style', 'value'),
     Input('line-select-groupby', 'value'),
     Input('line-Y-dtick', 'value'),
     Input('line-select-group', 'value'),
     Input('use-group-by', 'on'),
     Input('line-graph-width', 'value'),
     Input('line-graph-height', 'value'),
     Input('session_id', 'children'),
     ])
def update_line_graph(select_variables, data_transform,
                 show_gridlines, show_zeroline_y,
                 alignment_markers_dropdown, alignment_labelstyle_dropdown,
                 show_gaps, ALF, OS, colorPicker, line_style,
                 groupby, y_dtick, select_group, use_group_by,
                 width, height, session
                 ):
    df = cache.get(session + '-df')
    datetime = []
    for col in df.columns.values:
        if 'date' in col.lower():
            datetime = df[col]

    if use_group_by == True:
        group_list = df[groupby].unique()
        type_y = None
        if data_transform:
            type_y = 'log'

        picker_line_color = 'rgba({}, {}, {}, {})'.format(
            colorPicker['rgb']['r'],
            colorPicker['rgb']['g'],
            colorPicker['rgb']['b'],
            colorPicker['rgb']['a'])

        traces_list = []
        for variable in select_variables:
            for selection in group_list:
                reference = variable + ' : '+ selection
                if reference == select_group:
                    LINECOLOR_DICT[reference] = picker_line_color
                    marker_dict[reference] = alignment_markers_dropdown
                    linestyle_dict[reference] = line_style
                    gap_dict[reference] = show_gaps
                    label_dict[reference] = alignment_labelstyle_dropdown
                    linefill[reference] = ALF
                traces_list.append(
                    go.Scatter(
                        x=datetime,
                        y=df[df[groupby] == selection][variable],
                        text=df[df[groupby] == selection][variable],
                        mode=label_dict[reference],
                        name=reference,
                        connectgaps = gap_dict[reference],
                        fill = "toself" if linefill[reference] else "none",
                        opacity = OS/100,
                        marker = dict(
                            size = 8,
                            opacity = 0.8,
                            symbol = marker_dict[reference]
                        ),
                        line = dict(color=LINECOLOR_DICT[reference], width=3, dash=linestyle_dict[reference])
                    )
                )    
        return {
            'data': traces_list,
            'layout': go.Layout(
                xaxis={
                    'title' : 'Time',
                    'showgrid': show_gridlines,
                    'rangeslider': {'visible': True}, 'type': 'date'
                },
                yaxis={
                    'title' : ', '.join(select_variables),
                    'type' : type_y,
                    'showgrid': show_gridlines,
                    'zeroline': show_zeroline_y,
                    'dtick': y_dtick
                },
                margin={'l': 40, 'b': 40, 't': 10, 'r': 0},
                title= "Time-Series-Edit Me Last",
                hovermode='closest',
                height=height,
                width=width,
            )
        }

    else:
        type_y = None
        if data_transform:
            type_y = 'log'

        picker_line_color = 'rgba({}, {}, {}, {})'.format(
            colorPicker['rgb']['r'],
            colorPicker['rgb']['g'],
            colorPicker['rgb']['b'],
            colorPicker['rgb']['a'])

        Fill = "none"
        if ALF:
            Fill = "toself"

        traces_list = []
        for variable in select_variables:
            if select_group is not None:
                if variable == select_group:
                    LINECOLOR_DICT[variable] = picker_line_color
                    marker_dict[variable] = alignment_markers_dropdown
                    linestyle_dict[variable] = line_style
                    gap_dict[variable] = show_gaps
                    label_dict[variable] = alignment_labelstyle_dropdown
                    linefill[variable] = ALF
            traces_list.append(
                go.Scatter(
                    x=datetime,
                    y=df[variable],
                    text=df[variable],
                    mode=label_dict[variable],
                    name=str(variable).replace('[', '').replace(']', '').replace("\'", ""),
                    connectgaps = gap_dict[variable],
                    fill = "toself" if linefill[variable] else "none",
                    opacity = OS/100,
                    marker = dict(
                        size = 8,
                        opacity = 0.8,
                        symbol = marker_dict[variable]
                    ),
                    line = dict(color=LINECOLOR_DICT[variable], width=3, dash=linestyle_dict[variable])
                    )
                )

        return {
            'data': traces_list,
            'layout': go.Layout(
                xaxis={
                    'title' : 'Time',
                    'showgrid': show_gridlines,
                    'rangeslider': {'visible': True}, 
                    'type': 'date'
                },
                yaxis={
                    'title' : ', '.join(select_variables),
                    'type' : type_y,
                    'showgrid': show_gridlines,
                    'zeroline': show_zeroline_y,
                    'dtick': y_dtick
                },
                margin={'l': 40, 'b': 40, 't': 10, 'r': 0},
                title= "Time-Series-Edit Me Last",
                hovermode='closest',
                height=height,
                width=width,
            )
        }   

'''
#---------------------BOX PLOT CALLBACKS--------------------#
The following was coded by Demas Dasa (this includes the layout for the Box Plot), 
these are all the callbacks for the plot below.
'''

# Update marker symbol when percentile selected
@app.callback(
    Output('marker-symbol', 'value'),
    [Input('select-percentile', 'value')]
)
def update_marker_symbol(percentile):
    i = 0
    if percentile == '5%':
        i = 0
    elif percentile == '10%':
        i = 1
    elif percentile == '90%':
        i = 2
    else:
        i = 3
    return selected_marker_symbols[i]

# Update Percentile Symbol Color Picker
@app.callback(
    Output('select-percentile-color', 'value'),
    [Input('select-percentile', 'value')]
)
def update_percentile_color_selector(percentile):
    i = 0
    if percentile == '5%':
        i = 0
    elif percentile == '10%':
        i = 1
    elif percentile == '90%':
        i = 2
    else:
        i = 3

    temp_str = percentile_color_saved[i]
    start_idx = temp_str.find('(')
    temp_str = temp_str[start_idx+1:len(temp_str)-1]
    temp_str = temp_str.split(",")
    temp_str = dict(rgb=dict(r=temp_str[0], g=temp_str[1], b=temp_str[2], a=temp_str[3]))
    return temp_str


# Turn Y Tick Disabled when in Logarithmic and Enabled when in Linear
# Turn Y Tick Value to None when in Logarithmic end recall previous value when turn back to Linear
@app.callback(
    [Output('delta-tick', 'disabled'),
     Output('delta-tick', 'value')],
    [Input('data-transform', 'value')]
)
def update_delta_tick_disabled(is_log):
    return is_log, None if is_log else dtick_value

# Box Color Selector Callback
@app.callback(
    Output('box-color', 'value'),
    [Input('select-box', 'value')])
def update_box_color_selector(box):
    temp_str = box_color_saved.get(box, dict(rgb=dict(r=222, g=110, b=75, a=default_alpha)))
    if isinstance(temp_str, str):
        start_idx = temp_str.find('(')
        temp_str = temp_str[start_idx+1:len(temp_str)-1]
        temp_str = temp_str.split(",")
        temp_str = dict(rgb=dict(r=temp_str[0], g=temp_str[1], b=temp_str[2], a=temp_str[3]))
    return temp_str

# Box Selector Callback, adjusts the options of the categories drop down
@app.callback(
    [Output('select-box', 'options'),
    Output('select-box', 'value')],
    [Input('select-groupby', 'value'),
    Input('session_id', 'children')]
)
def update_select_box(groupby, session):
    df = cache.get(session + '-df')
    idx = 0
    for i in df[groupby].unique():
        box_color_saved[i] = default_color[idx % num_of_color]
        idx += 1
    return [{'label': i, 'value': i} for i in df[groupby].unique()], df[groupby].unique()[0]

# Threshold Line Callback
@app.callback(
    Output('treshold-value', 'value'),
    [Input('show-treshold', 'on'),
     Input('select-variable', 'value'),
     Input('session_id', 'children')
     ]
)
def update_treshold_value(
    is_tresholdshow, variable, session
):
    df = cache.get(session + '-df')
    return np.around(np.mean(df[variable]), 0) if is_tresholdshow else ' '

# Statistics Show Hide Callback
@app.callback(
    Output('show-stats', 'on'),
    [Input('select-outliers', 'value'), ]
)
def update_showstat(outliersshow):
    return False if outliersshow == 'all' else None

# Figure Callback
@app.callback(
    Output('box-plot', 'figure'),
    [
        Input('select-variable', 'value'), Input('select-groupby', 'value'),
        Input('show-gridlines', 'on'),
        Input('show-zeroline-x', 'on'), Input('show-zeroline-y', 'on'),
        Input('show-legend', 'on'), Input('show-percentiles', 'on'),
        Input('graph-alignment', 'value'), Input('data-transform', 'value'),
        Input('select-outliers', 'value'), Input('show-ndata', 'on'),
        Input('show-percentiles', 'on'), Input('show-mean', 'on'),
        Input('show-sd', 'on'), Input('show-treshold', 'on'),
        Input('treshold-value', 'value'), Input('treshold-style', 'value'),
        Input('treshold-line-color', 'value'),
        Input('treshold-line-size', 'value'),
        Input('show-stats', 'on'), Input('graph-height', 'value'),
        Input('graph-width', 'value'),
        Input('select-box', 'value'), Input('box-color', 'value'),
        Input('grid-width', 'value'), Input('delta-tick', 'value'),
        Input('box-color-fill', 'value'),
        Input('select-percentile', 'value'), Input('marker-symbol', 'value'),
        Input('select-percentile-color', 'value'), Input('symbol-size', 'value'),
        Input('session_id', 'children'),
    ]
)
def box_update_figure(
    variable, groupby,
    gridshow, xzeroline, yzeroline, legendshow,
    datapointsshow, is_vertical, is_log, outliersshow, is_ndatashow,
    is_percentileshow, is_meanshow, is_sdshow, is_tresholdshow, treshold_value,
    treshold_style, treshold_color, treshold_size, is_statshow, graph_height,
    graph_width, selected_box, box_color, grid_width, dtick, is_color_filled,
    select_percentile, marker_symbol, select_percentile_color, symbol_size,
    session
):
    df = cache.get(session + '-df')
    # Update dtick_value
    if dtick != None:
        dtick_value = dtick

    # Title and axises label modificator
    xaxis_title = groupby
    yaxis_title = variable
    main_title = str(variable + " VS " + groupby)

    # Outliers Selector
    showpoints = ""
    if (outliersshow == 'False'):
        showpoints = False
    elif (outliersshow == 'suspectedoutliers'):
        showpoints = outliersshow
    else:
        showpoints = outliersshow

    # Initialising data list
    group_list = df[groupby].unique()
    data_list = []
    n_data = []
    data_mean = []
    data_median = []
    data_max = []
    data_min = []
    percentile_5 = []
    percentile_10 = []
    percentile_90 = []
    percentile_95 = []
    percentile_25 = []
    percentile_75 = []
    annots_ndata = []
    annots_mean = []
    annots_median = []
    annots_max = []
    annots_min = []
    annots_p5 = []
    annots_p10 = []
    annots_p25 = []
    annots_p75 = []
    annots_p90 = []
    annots_p95 = []
    annots_idx = 0

    # Computing N Data
    max_n = df[variable].max()
    max_n = 1.05*np.log10(max_n) if is_log else 1.05*max_n

    picker_percentile_color = 'rgba({}, {}, {}, {})'.format(
        select_percentile_color['rgb']['r'],
        select_percentile_color['rgb']['g'],
        select_percentile_color['rgb']['b'],
        select_percentile_color['rgb']['a'],)

    picker_box_color = 'rgba({}, {}, {}, {})'.format(
        box_color['rgb']['r'],
        box_color['rgb']['g'],
        box_color['rgb']['b'],
        box_color['rgb']['a'],)

    color_idx = 0
    # Generate boxplot
    for i in group_list:
        if selected_box is not None:
            if i == selected_box:
                box_color_saved[i] = picker_box_color
        color_idx += 1
        if (not is_vertical):
            data_list.append(
                go.Box(
                    y=df[df[groupby] == i][variable],
                    name=i,
                    boxpoints=showpoints,
                    boxmean='sd' if is_sdshow else None,
                    marker_color=box_color_saved[i],
                    fillcolor=box_color_saved[i] if is_color_filled else 'rgba(255,255,255,0)',
                )
            )
        else:
            data_list.append(
                go.Box(
                    x=df[df[groupby] == i][variable],
                    name=i,
                    orientation='h',
                    boxpoints=showpoints,
                    boxmean='sd' if is_sdshow else None,
                    marker_color=box_color_saved[i],
                    fillcolor=box_color_saved[i] if is_color_filled else 'rgba(255,255,255,0)',
                )
            )

        # Counting percentiles
        percentile_5.append(np.around(np.percentile((df[df[groupby] == i][variable]), 5), 2))
        percentile_10.append(np.around(np.percentile((df[df[groupby] == i][variable]), 10), 2))
        percentile_90.append(np.around(np.percentile((df[df[groupby] == i][variable]), 90), 2))
        percentile_95.append(np.around(np.percentile((df[df[groupby] == i][variable]), 95), 2))
        percentile_25.append(np.around(np.percentile((df[df[groupby] == i][variable]), 25), 2))
        percentile_75.append(np.around(np.percentile((df[df[groupby] == i][variable]), 75), 2))
        data_max.append(np.around(np.max((df[df[groupby] == i][variable])), 2))
        data_min.append(np.around(np.min((df[df[groupby] == i][variable])), 2))

        # Calculating mean and median
        data_mean.append(np.around(np.mean((df[df[groupby] == i][variable])), 2))
        data_median.append(np.around(np.median((df[df[groupby] == i][variable])), 2))

        # Counting number of data for each category
        df_shape = df[df[groupby] == i][variable].shape
        n_data.append(df_shape[0])

        # Generating annotations of n of data
        annots_ndata.append(go.layout.Annotation(
            x=max_n if is_vertical else annots_idx,
            y=annots_idx if is_vertical else max_n,
            xref='x',
            yref='y',
            text='N = {}'.format(n_data[annots_idx]),
            showarrow=False,
            ax=0 if is_vertical else annots_idx,
            ay=annots_idx if is_vertical else 0,
            )
        )

        # Generating annotations of mean
        annots_mean.append(go.layout.Annotation(
            x=(np.log10(data_mean[annots_idx]) if is_log else data_mean[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(data_mean[annots_idx]) if is_log else data_mean[annots_idx]),
            xref='x',
            yref='y',
            text='Mean: {}'.format(data_mean[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (100/len(group_list))*5,
            ay=(100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of mean
        annots_median.append(go.layout.Annotation(
            x=(np.log10(data_median[annots_idx]) if is_log else data_median[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(data_median[annots_idx]) if is_log else data_median[annots_idx]),
            xref='x',
            yref='y',
            text='Med: {}'.format(data_median[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (-100/len(group_list))*4,
            ay=(-100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of percentile 5
        annots_p5.append(go.layout.Annotation(
            x=(np.log10(percentile_5[annots_idx]) if is_log else percentile_5[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(percentile_5[annots_idx]) if is_log else percentile_5[annots_idx]),
            xref='x',
            yref='y',
            text='P5: {}'.format(percentile_5[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (-100/len(group_list))*4,
            ay=(-100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of percentile 10
        annots_p10.append(go.layout.Annotation(
            x=(np.log10(percentile_10[annots_idx]) if is_log else percentile_10[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(percentile_10[annots_idx]) if is_log else percentile_10[annots_idx]),
            xref='x',
            yref='y',
            text='P10: {}'.format(percentile_10[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (100/len(group_list))*5,
            ay=(100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of percentile 25
        annots_p25.append(go.layout.Annotation(
            x=(np.log10(percentile_25[annots_idx]) if is_log else percentile_25[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(percentile_25[annots_idx]) if is_log else percentile_25[annots_idx]),
            xref='x',
            yref='y',
            text='Q1: {}'.format(np.around(percentile_25[annots_idx], 2)),
            showarrow=True,
            ax=0 if is_vertical else (-100/len(group_list))*4,
            ay=(-100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of percentile 75
        annots_p75.append(go.layout.Annotation(
            x=(np.log10(percentile_75[annots_idx]) if is_log else percentile_75[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(percentile_75[annots_idx]) if is_log else percentile_75[annots_idx]),
            xref='x',
            yref='y',
            text='Q3: {}'.format(np.around(percentile_75[annots_idx], 2)),
            showarrow=True,
            ax=0 if is_vertical else (100/len(group_list))*5,
            ay=(100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of percentile 90
        annots_p90.append(go.layout.Annotation(
            x=(np.log10(percentile_90[annots_idx]) if is_log else percentile_90[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(percentile_90[annots_idx]) if is_log else percentile_90[annots_idx]),
            xref='x',
            yref='y',
            text='P90: {}'.format(percentile_90[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (-100/len(group_list))*4,
            ay=(-100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of percentile 95
        annots_p95.append(go.layout.Annotation(
            x=(np.log10(percentile_95[annots_idx]) if is_log else percentile_95[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(percentile_95[annots_idx]) if is_log else percentile_95[annots_idx]),
            xref='x',
            yref='y',
            text='P95: {}'.format(percentile_95[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (100/len(group_list))*5,
            ay=(100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        # Generating annotations of max
        annots_max.append(go.layout.Annotation(
            x=(np.log10(data_max[annots_idx]) if is_log else data_max[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(data_max[annots_idx]) if is_log else data_max[annots_idx]),
            xref='x',
            yref='y',
            text='Max: {}'.format(data_max[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (-100/len(group_list))*4,
            ay=(-100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        annots_min.append(go.layout.Annotation(
            x=(np.log10(data_min[annots_idx]) if is_log else data_min[annots_idx]) if is_vertical else annots_idx,
            y=annots_idx if is_vertical else (np.log10(data_min[annots_idx]) if is_log else data_min[annots_idx]),
            xref='x',
            yref='y',
            text='Min: {}'.format(data_min[annots_idx]),
            showarrow=True,
            ax=0 if is_vertical else (100/len(group_list))*5,
            ay=(100/len(group_list))*2 if is_vertical else 0,
            arrowhead=7,
        ))

        annots_idx = annots_idx + 1

    if (not is_ndatashow):
        annots_ndata = []

    if (not is_statshow):
        annots_mean = []
        annots_median = []
        annots_p5 = []
        annots_p10 = []
        annots_p25 = []
        annots_p90 = []
        annots_p75 = []
        annots_p95 = []
        annots_max = []
        annots_min = []

    annots_ndata = annots_ndata + annots_mean + annots_median + annots_p5 + annots_p10 + annots_p25 + annots_p75 + annots_p90 + annots_p95 + annots_max + annots_min

    # Convert selected percentile values
    ip = 0
    if select_percentile == '5%':
        ip = 0
    elif select_percentile == '10%':
        ip = 1
    elif select_percentile == '90%':
        ip = 2
    else:
        ip = 3
    #Change the percentile markers and color
    selected_marker_symbols[ip] = marker_symbol
    percentile_color_saved[ip] = picker_percentile_color

    # Change Orientation
    type_x = None
    type_y = None
    if (is_vertical):
        xaxis_title, yaxis_title = yaxis_title, xaxis_title
        type_x = 'log' if is_log else None
        if(is_meanshow):
            data_list.append(go.Scatter(x=data_mean, y=group_list, mode='markers', name='Mean', marker=dict(symbol=selected_marker_symbols[4], size=symbol_size)))
        # Generating Percentiles to Figure
        if (is_percentileshow):
            data_list.append(go.Scatter(y=group_list, x=percentile_5, mode='markers', name='5%', marker_color=percentile_color_saved[0], marker=dict(symbol=selected_marker_symbols[0], size=symbol_size)))
            data_list.append(go.Scatter(y=group_list, x=percentile_10, mode='markers', name='10%', marker_color=percentile_color_saved[1], marker=dict(symbol=selected_marker_symbols[1], size=symbol_size)))
            data_list.append(go.Scatter(y=group_list, x=percentile_90, mode='markers', name='90%', marker_color=percentile_color_saved[2], marker=dict(symbol=selected_marker_symbols[2], size=symbol_size)))
            data_list.append(go.Scatter(y=group_list, x=percentile_95, mode='markers', name='95%', marker_color=percentile_color_saved[3], marker=dict(symbol=selected_marker_symbols[3], size=symbol_size)))
    else:
        type_y = 'log' if is_log else None
        if(is_meanshow):
            data_list.append(go.Scatter(x=group_list, y=data_mean, mode='markers', name='Mean', marker=dict(symbol=selected_marker_symbols[4], size=symbol_size)))
        # Generating Percentiles to Figure
        if (is_percentileshow):
            data_list.append(go.Scatter(x=group_list, y=percentile_5, mode='markers', name='5%', marker_color=percentile_color_saved[0], marker=dict(symbol=selected_marker_symbols[0], size=symbol_size)))
            data_list.append(go.Scatter(x=group_list, y=percentile_10, mode='markers', name='10%', marker_color=percentile_color_saved[1], marker=dict(symbol=selected_marker_symbols[1], size=symbol_size)))
            data_list.append(go.Scatter(x=group_list, y=percentile_90, mode='markers', name='90%', marker_color=percentile_color_saved[2], marker=dict(symbol=selected_marker_symbols[2], size=symbol_size)))
            data_list.append(go.Scatter(x=group_list, y=percentile_95, mode='markers', name='95%', marker_color=percentile_color_saved[3], marker=dict(symbol=selected_marker_symbols[3], size=symbol_size)))

    treshold_shape = []

    if is_tresholdshow:
        treshold_shape.append(dict(line=dict(
                                # color="rgba(68, 68, 68, 0.5)",
                                color='rgba({}, {}, {}, {})'.format(
                                    treshold_color['rgb']['r'],
                                    treshold_color['rgb']['g'],
                                    treshold_color['rgb']['b'],
                                    treshold_color['rgb']['a'], ),
                                width=treshold_size, dash=treshold_style,
                                ),
            type='line',
            x0=-0.5 if not is_vertical else treshold_value,
            x1=len(group_list)-0.5 if not is_vertical else treshold_value,
            y0=treshold_value if not is_vertical else -0.5,
            y1=treshold_value if not is_vertical else len(group_list)-0.5,
        ))

    # Returning figure
    return{
        'data': data_list,
        'layout': go.Layout(
            xaxis=go.layout.XAxis(
                title=xaxis_title,
                showgrid=gridshow,
                zeroline=xzeroline,
                type=type_x,
                gridwidth=grid_width,
                gridcolor='lightgrey',
                dtick=dtick if is_vertical else None,
            ),
            yaxis=go.layout.YAxis(
                title=yaxis_title,
                showgrid=gridshow,
                zeroline=yzeroline,
                type=type_y,
                gridwidth=grid_width,
                gridcolor='lightgrey',
                dtick=None if is_vertical else dtick,
            ),
            title=main_title,
            showlegend=legendshow,
            height=graph_height,
            width=graph_width,
            annotations=annots_ndata,
            shapes=treshold_shape,
        )
    }

'''
#---------------------BAR PLOT CALLBACKS--------------------#
Below is the callbacks which were developed by Robin with help from Demas
'''
# Turn Y Tick Disabled when in Logarithmic and Enabled when in Linear
# Turn Y Tick Value to None when in Logarithmic end recall previous value when turn back to Linear
@app.callback(
    [Output('bar-delta-tick', 'disabled'),
     Output('bar-delta-tick', 'value')],
    [Input('bar-data-transform', 'value')]
)
def update_delta_tick_disabled(is_log):
    return is_log, None if is_log else dtick_value

# Bar Color Selector Callback
@app.callback(
    Output('bar-color', 'value'),
    [Input('select-bar', 'value')]
)
def update_bar_color_selector(bar):
    temp_str = bar_color_saved.get(bar, dict(rgb=dict(r=222, g=110, b=75, a=default_alpha)))
    if isinstance(temp_str, str):
        start_idx = temp_str.find('(')
        temp_str = temp_str[start_idx+1:len(temp_str)-1]
        temp_str = temp_str.split(",")
        temp_str = dict(rgb=dict(r=temp_str[0], g=temp_str[1], b=temp_str[2], a=temp_str[3]))
    return temp_str

# Bar Selector Callback
@app.callback(
    [Output('select-bar', 'options'),
    Output('select-bar', 'value')],
    [Input('bar-select-groupby', 'value'),
    Input('session_id', 'children') ]
)
def update_select_bar(groupby, session):
    df = cache.get(session + '-df')
    idx = 0
    for i in df[groupby].unique():
        bar_color_saved[i] = default_color[idx % 5]
        idx += 1
    return [{'label': i, 'value': i} for i in df[groupby].unique()], df[groupby].unique()[0]

# Threshold Line Callback
@app.callback(
    Output('bar-treshold-value', 'value'),
    [Input('bar-show-treshold', 'on'),
     ]
)
def update_treshold_value(
    is_tresholdshow
):
    return '25' if is_tresholdshow else ' '

# Figure Callback
@app.callback(
    Output('bar-plot', 'figure'),
    [
        Input('bar-select-variable', 'value'),
        Input('bar-select-groupby', 'value'),
        Input('select-barplot', 'value'),
        Input('bar-show-gridlines', 'on'),
        Input('bar-show-zeroline-x', 'on'),
        Input('bar-show-zeroline-y', 'on'),
        Input('bar-show-legend', 'on'),
        Input('bar-graph-alignment', 'value'),
        Input('bar-data-transform', 'value'),
        Input('bar-show-ndata', 'on'),
        Input('bar-show-treshold', 'on'),
        Input('bar-treshold-value', 'value'),
        Input('bar-treshold-style', 'value'),
        Input('bar-treshold-line-color', 'value'),
        Input('bar-treshold-line-size', 'value'),
        Input('bar-graph-height', 'value'),
        Input('bar-graph-width', 'value'),
        Input('select-bar', 'value'),
        Input('bar-color', 'value'),
        Input('bar-grid-width', 'value'),
        Input('bar-delta-tick', 'value'),
        Input('session_id', 'children'),
    ]
)
def bar_update_figure(
    variable, groupby,plottype,
    gridshow, xzeroline, yzeroline, legendshow,
    is_vertical, is_log,is_ndatashow,is_tresholdshow, treshold_value,
    treshold_style, treshold_color, treshold_size, graph_height,
    graph_width, selected_bar, bar_color, grid_width, dtick, session
):
    df = cache.get(session + '-df')
    # Update dtick_value
    if dtick != None:
        dtick_value = dtick

    # Title and axis default title for stacked percentage
    if(plottype=="Stacked_Percentage"):
        xaxis_title = str("Percentage % ")
        yaxis_title = variable
        main_title = str("BarPlot")
    #Title and axis default title for stacked and side by side barplot
    else:
        xaxis_title = str("Count")
        yaxis_title = variable
        main_title = str("BarPlot")


    # Initialising data list
    data_list = []
    pct = []
    cnt = []
    pct_text = []
    cnt_idx = []
    cnt_text = []
    annots_idx = 0



    picker_bar_color = 'rgba({}, {}, {}, {})'.format(
        bar_color['rgb']['r'],
        bar_color['rgb']['g'],
        bar_color['rgb']['b'],
        bar_color['rgb']['a'],)

    color_idx = 0
    # generate the unique variables in groupby
    group_list = df[groupby].unique()
    # generate the unique variables in variable
    var_list = df[variable].unique()
    # Generate barplot
    idx=0
    # Loop for stacked percentage barplot
    if(plottype== "Stacked_Percentage"):
        for i in group_list:
            pct_idx=0
            if selected_bar is not None:
                print('selected_bar : {}'.format(selected_bar))
                print('bar color 1 : {}'.format(bar_color_saved))
                if i == selected_bar:
                    bar_color_saved[i] = picker_bar_color
                    print('bar color 2 : {}'.format(bar_color_saved))
            color_idx += 1

            for j in var_list:
                # counting all elements for each var_list
                count_all=df[df[variable]==j][variable].count()
                # counting all elements for each var_list for each group_list
                count_me=df[df[variable]==j][df[groupby]==i][groupby].count()
                # store percentage in array
                pct.append(count_me*100/count_all)
                # store percentage format in array
                pct_text.append("{}%".format(round(count_me*100/count_all)))
            if (is_vertical):
                data_list.append(
                        go.Bar(
                            x=var_list,
                            y=pct,
                            name=i,
                            text =pct_text if is_ndatashow else None,
                            textposition ="auto",
                            marker_color=bar_color_saved[i],
                        )
                    )
                # reset the array
                pct=[]
                idx +=1
                pct_idx += 1
                pct_text=[]
            else:
                data_list.append(
                        go.Bar(
                            x=pct,
                            y=var_list,
                            name=i,
                            orientation='h',
                            text =pct_text if is_ndatashow else None,
                            textposition ="auto",
                            marker_color=bar_color_saved[i],
                        )
                    )
                #reset the array
                pct =[]
                idx +=1
                pct_idx += 1
                pct_text=[]
    # Loop for side by side and stacked barplot
    elif(plottype=="Side_by_Side" or plottype== "Stacked"):
        for i in group_list:
            if selected_bar is not None:
                print('selected_bar : {}'.format(selected_bar))
                print('bar color 1 : {}'.format(bar_color_saved))
                if i == selected_bar:
                    bar_color_saved[i] = picker_bar_color
                    print('bar color 2 : {}'.format(bar_color_saved))
            color_idx += 1

            cnt_idx=0
            for j in var_list:
                # counting all elements for each var_list
                count_all=df[df[variable]==j][variable].count()
                # counting all elements for each var_list for each group_list
                count_me=df[df[variable]==j][df[groupby]==i][groupby].count()
                # store the count
                cnt.append(count_me)
                # store the count with format for display
                cnt_text.append("{}".format(count_me))
            # trace for vertical bar chart
            if (is_vertical):
                data_list.append(
                        go.Bar(
                            x=var_list,
                            y=cnt,
                            name=i,
                            text =cnt_text if is_ndatashow else None,
                            textposition ="auto",
                            marker_color=bar_color_saved[i]
                        )
                    )
                # reset the array for count
                cnt = []
                idx +=1
                cnt_idx += 1
                cnt_text=[]
            else:
                # trace for horizontal bar chart
                data_list.append(
                        go.Bar(
                            x=cnt,
                            y=var_list,
                            name=i,
                            orientation='h',
                            text =cnt_text if is_ndatashow else None,
                            textposition ="auto",
                            marker_color=bar_color_saved[i]
                        )
                    )
                # reset the array for count
                idx +=1
                cnt_idx += 1
                cnt = []
                cnt_text=[]
    # Change Orientation
    type_x = None
    type_y = None
    # check the graph orientation and change the title and scale
    if (is_vertical):
        xaxis_title, yaxis_title = yaxis_title, xaxis_title
        type_y = 'log' if is_log else None

    else:
        #check the graph orientation and change the title and scale
        type_x = 'log' if is_log else None

    if (plottype== "Side_by_Side"):
            is_side = True
    else:
            is_side = False

    treshold_shape = []
    # threshold line
    if is_tresholdshow:
        treshold_shape.append(dict(line=dict(
                                # color="rgba(68, 68, 68, 0.5)",
                                color='rgba({}, {}, {}, {})'.format(
                                    treshold_color['rgb']['r'],
                                    treshold_color['rgb']['g'],
                                    treshold_color['rgb']['b'],
                                    treshold_color['rgb']['a'], ),
                                width=treshold_size, dash=treshold_style,
                                ),
            type='line',
            # set the x and y for threshold line
            x0=-0.5 if is_vertical else treshold_value,
            x1=len(var_list)-0.5 if is_vertical else treshold_value,
            y0=treshold_value if is_vertical else -0.5,
            y1=treshold_value if is_vertical else len(var_list)-0.5,
        ))

    # Returning figure
    return{
        'data': data_list,
        'layout': go.Layout(
            xaxis=go.layout.XAxis(
                title=xaxis_title,
                showgrid=gridshow,
                zeroline=xzeroline,
                type=type_x,
                gridwidth=grid_width,
                gridcolor='lightgrey',
                dtick=None if is_vertical else dtick,
            ),
            yaxis=go.layout.YAxis(
                title=yaxis_title,
                showgrid=gridshow,
                zeroline=yzeroline,
                type=type_y,
                gridwidth=grid_width,
                gridcolor='lightgrey',
                dtick=dtick if is_vertical else None,
            ),
            barmode = "group" if is_side else "stack",
            title=main_title,
            showlegend=legendshow,
            height=graph_height,
            width=graph_width,
            shapes=treshold_shape,
        )
    }
if __name__ == '__main__':
    app.run_server(debug=False, host='0.0.0.0')