<jupyter_start><jupyter_text>Panel PracticeA practice to use [Panel](https://panel.holoviz.org/index.html) and [Plotly](https://plotly.com/python/) to create a simple stock price dashboard app.<jupyter_code>import os
import datetime
import pandas as pd
import plotly.graph_objects as go<jupyter_output><empty_output><jupyter_text>Stock Market Dataset* Downloaded from Kaggle: [Stock Market Dataset](https://www.kaggle.com/jacksoncrow/stock-market-dataset)* This dataset contain historical daily prices for all tickers currently trading on NASDAQ.* In this pratice I only use 5 tickers (APPL, AMZN, FB, GOOGL, MSFT) for panel demostration.<jupyter_code>from google.colab import drive
drive.mount("/content/drive", force_remount=True)
%cd /content/drive/MyDrive/Python_Learning/Signal_Prediction/panel_demo

%ls
files = os.listdir('data')
files
# Read and Preprocessing Data
AAFMG = []
for f in files:
    data = pd.read_csv('data/' + f)
    data['Symbol'] = f.replace('.csv', '')
    AAFMG.append(data)
AAFMG = pd.concat(AAFMG)
AAFMG['Date'] = pd.to_datetime(AAFMG['Date'])
# Check Data
AAFMG.head()<jupyter_output><empty_output><jupyter_text>Before using Panel:We can write a function that shows the price trend, moving average curve with parameters: symbol, value to observe, and window of moving average.<jupyter_code>def get_plot(symbol = 'AAPL', value = 'Close', window = 30):
    
    ## filter specific symbol and calculate the moving average
    df = AAFMG.loc[AAFMG['Symbol'] == symbol]
    df = df.sort_values('Date')
    df['MA'] = df[value].rolling(window = window).mean()
    df = df.loc[(df['Date'] >= '2017-04-01') & (df['Date'] <= '2020-04-01')]
    
    ## create plotly object
    fig = go.Figure(layout = go.Layout(plot_bgcolor = '#EEEEEE'))
    fig.add_trace(go.Scatter(
        x = df["Date"], y = df[value],
        name = '%s/%s' %(symbol, value),
        fill = 'tozeroy',
        line_width = 0,
        line_color = 'rgba(72,89,110,1)',
        fillcolor = 'rgba(72,89,110,0.8)',
    ))
    fig.add_trace(go.Scatter(
        x = df["Date"], y = df["MA"],
        name = '%s/%s/MA%d' %(symbol, value, window),
        mode = "lines",
        line_color = '#a57571',
        line_width = 2.5
    ))
    fig.update_layout(
        width = 600, height = 400,
        margin=dict(l = 20, r = 20, t = 20, b = 20),
        legend = dict(
            orientation = "h",
            yanchor = "bottom",
            y = 1.02,
            xanchor = "right",
            x = 1
        )
    )
    
    return fig
get_plot(symbol = 'GOOGL', value = 'Open', window = 60)<jupyter_output><empty_output><jupyter_text>It works, but exploring all symbols, values, and different window size by passing arguments to this function is tedious and too manual. User may not have ability to use your python function.  Start using Panel:<jupyter_code>import panel as pn
pn.extension("plotly")<jupyter_output><empty_output><jupyter_text>we can easily turn our python function into interactive graph with `pn.interact()`<jupyter_code>pn.interact(get_plot, symbol = 'AAPL', value = 'Close', window = 30)<jupyter_output><empty_output><jupyter_text>but it still have some drawbacks:* the value of symbol and value need to key in by user, user may not have information about which symbol and value are available.* the range of window size contains negative value which doesn't make any sence obviously!* the layout of dashboard we cannot control.we can specify the possible value of arguments and pass it into `pn.interact()`<jupyter_code>kw = dict(
    symbol = ['AAPL', 'AMZN', 'FB', 'GOOGL', 'MSFT'],
    value = ['Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume'],
    window = (7, 365)
)
i = pn.interact(get_plot, **kw)
i<jupyter_output><empty_output><jupyter_text>Components of of Paneltake a look of what `pn.interact` creates:<jupyter_code>i.pprint()<jupyter_output>Column
    [0] Column
        [0] Select(name='symbol', options=['AAPL', 'AMZN', ...], value='AAPL')
        [1] Select(name='value', options=['Open', 'High', ...], value='Close')
        [2] IntSlider(end=365, name='window', start=7, value=30, value_throttled=186)
    [1] Row
        [0] Plotly(Figure, name='interactive00019')<jupyter_text>`pn.interact` created a `pn.Column` object consisting of a WidgetBox with 3 widgets and a `pn.Row` with one Plotly figure object. So our dashboard have layout like that:<jupyter_code>i[0][0]
i[1][0]<jupyter_output><empty_output><jupyter_text>Panel is compositional, so you can recomposite these components any way you like, or adding other objects:<jupyter_code>text = "# Stock Market Data\nSelect a symbol, value, and the time window for moving average"

p = pn.Row(i[1][0], pn.Column(text, i[0][0], i[0][1], i[0][2]))
p.pprint()
p<jupyter_output><empty_output><jupyter_text>The widgets stay linked to their plot even if they are in a different notebook cell:<jupyter_code>i[0][2]<jupyter_output><empty_output><jupyter_text>Panel widgets are reactive, so they will update even if you set the values by hand:<jupyter_code>i[0][2].value = 30<jupyter_output><empty_output><jupyter_text>Using Panel Widgets<jupyter_code>import panel.widgets as pnw<jupyter_output><empty_output><jupyter_text>There are many [widgets in Panel](https://panel.holoviz.org/user_guide/Widgets.html), here I use `Select`, `RadioButtonGroup`, `IntSlider`, `DateRangeSlider` to build the stock price dashboard.<jupyter_code># Create Widget Components
symbol = pnw.Select(name = 'symbol', options = ['AAPL', 'AMZN', 'FB', 'GOOGL', 'MSFT'])
value = pnw.RadioButtonGroup(name = 'value', options = ['Open', 'High', 'Low', 'Close', 'Adj Close', 'Volume'])
window = pnw.IntSlider(name = 'window', start = 7, end = 365, value = 30)
date_range = pnw.DateRangeSlider(name = 'date range',
                                 start = datetime.datetime(1980, 12, 12), end = datetime.datetime(2020, 4, 1),
                                 value = (datetime.datetime(2017, 4, 1), datetime.datetime(2020, 4, 1)))
# Define Reactive Plot Function
@pn.depends(symbol, value, window, date_range)
def reactive_plot(symbol, value, window, date_range):
    df = AAFMG.loc[AAFMG['Symbol'] == symbol]
    df = df.sort_values('Date')
    df['MA'] = df[value].rolling(window = window).mean()
    df = df.loc[(df['Date'] >= date_range[0]) & (df['Date'] <= date_range[1])]
    
    fig = go.Figure(layout = go.Layout(plot_bgcolor = '#EEEEEE'))
    fig.add_trace(go.Scatter(
        x = df["Date"], y = df[value],
        name = '%s/%s' %(symbol, value),
        fill = 'tozeroy',
        line_width = 0,
        line_color = 'rgba(72,89,110,1)',
        fillcolor = 'rgba(72,89,110,0.8)',
    ))
    fig.add_trace(go.Scatter(
        x = df["Date"], y = df["MA"],
        name = '%s/%s/MA%d' %(symbol, value, window),
        mode = "lines",
        line_color = '#a57571',
        line_width = 2.5
    ))
    fig.update_layout(
        width = 600, height = 400,
        margin=dict(l = 20, r = 20, t = 20, b = 20),
        legend = dict(
            orientation = "h",
            yanchor = "bottom",
            y = 1.02,
            xanchor = "right",
            x = 1
        )
    )
    
    return fig
widgets = pn.Column(text, symbol, value, window, date_range)
dashboard = pn.Row(reactive_plot, widgets)
dashboard<jupyter_output><empty_output><jupyter_text>Deploying Panelsyou can simply deploy panel in the separate web page with .servable(), and then run the shell command `panel serve --show panel_practice.ipynb` to launch a server containing that object.<jupyter_code>dashboard.servable();<jupyter_output><empty_output><jupyter_text>Other widgets in Panel<jupyter_code>widgets = pn.Column(
    "### __Categorical - Single Values__",
    pn.Row("* __AutoCompleteInput__: ", pnw.AutocompleteInput(options=['Biology', 'Chemistry', 'Physics'], placeholder='Write something here')),
    pn.Row("* __RadioButtomGroup__: ", pnw.RadioButtonGroup(options=['Biology', 'Chemistry', 'Physics'])),
    pn.Row("* __RadioBoxGroup__: ", pnw.RadioBoxGroup(options=['Biology', 'Chemistry', 'Physics'], inline=True)),
    pn.Row("* __Select__: ", pnw.Select(options=['Biology', 'Chemistry', 'Physics'])),
    
    "### __Categorical - Multiple Values__",
    pn.Row("* __CheckBoxGroup__: ", pnw.CheckBoxGroup(value=['Apple', 'Pear'], options=['Apple', 'Banana', 'Pear', 'Strawberry'],inline=True)),
    pn.Row("* __CheckButtonGroup__: ", pnw.CheckButtonGroup(value=['Apple', 'Pear'], options=['Apple', 'Banana', 'Pear', 'Strawberry'])),
    pn.Row("* __CrossSelecter__: ", pnw.CrossSelector(value=['Apple', 'Pear'], options=['Apple', 'Banana', 'Pear', 'Strawberry'])),
    pn.Row("* __MultiSelect__: ", pnw.MultiSelect(value=['Apple', 'Pear'], options=['Apple', 'Banana', 'Pear', 'Strawberry'])),
    
    
    "### __Numeric - Int__",
    pn.Row("* __IntSlider__: ", pnw.IntSlider(start=0, end=8, step=2, value=4)),
    pn.Row("* __IntRangeSlider__: ", pnw.IntRangeSlider(start=0, end=10, value=(2, 8), step=2)),
    pn.Row("* __Player__: ", pnw.Player(start=0, end=100, value=32, loop_policy='loop')),
    pn.Row("* __DiscreteSlider__: ", pnw.DiscreteSlider(options=[2, 4, 8, 16, 32, 64, 128], value=32)),
    pn.Row("* __DiscretePlayer__: ", pnw.DiscretePlayer(options=[2, 4, 8, 16, 32, 64, 128], value=32, loop_policy='loop')),
    
    "### __Numeric - Float__",
    pn.Row("* __FloatSlider__: ", pnw.FloatSlider(start=0, end=3.141, step=0.01, value=1.57)),
    pn.Row("* __RangeSlider__: ", pnw.RangeSlider(format='0.0a', start=100000, end=1000000)),
    
    "### __Boolean__",
    pn.Row("* __Checkbox__: ", pnw.Checkbox(name='Checkbox')),
    pn.Row("* __Toogle__: ", pnw.Toggle(name='Toggle')),
    
    "### __Dates__",
    pn.Row("* __DatetimeInput__: ", pnw.DatetimeInput(value=datetime.datetime(2019, 2, 8))),
    pn.Row("* __DatePicker__: ", pnw.DatePicker()),
    pn.Row("* __DateRangeSlider__: ", pnw.DateRangeSlider(start=datetime.datetime(2019, 1, 1), end=datetime.datetime(2019, 6, 1))),
    
    "### __Text__",
    pn.Row("* __TextInput__: ", pnw.TextInput(placeholder='Enter a string here...')),
    pn.Row("* __PasswordInput__: ", pnw.PasswordInput(placeholder='Enter a string here...')),
    pn.Row("* __TextAreaInput__: ", pnw.TextAreaInput(placeholder='Enter a string here...')),
    
    "### __Other__",
    pn.Row("* __ColorPicker__: ", pnw.ColorPicker(value='#99ef78')),
    pn.Row("* __FileInput__: ", pnw.FileInput(accept='.csv,.json')),
    pn.Row("* __LiteralInput__: ", pnw.LiteralInput(value={'key': [1, 2, 3]}, type=dict)),
    pn.Row("* __Button__: ", pnw.Button(name='Click me', button_type='primary')),
    pn.Row("* __DataFrame__: ", pnw.DataFrame(pd.DataFrame({'int': [1, 2, 3], 'float': [3.14, 6.28, 9.42], 'str': ['A', 'B', 'C']}, index=[1, 2, 3]))),
    pn.Row("* __FileDownload__: ", pnw.FileDownload(file='FileDownload.ipynb', filename='custom_filename.ipynb')),
    pn.Row("* __Progress__: ", pnw.Progress(width=200))
)
widgets<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.16896394340483797, 'fraction_numerical': 0.027293473299863077, 'mean_word_length': 4.177693761814745, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 62, 'https://': 4, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '213747', 'license': 'Apache-2.0', 'n_tokens_mistral': 4078, 'n_tokens_neox': 3778, 'n_words': 900, 'path': 'panel_practice.ipynb', 'repo_name': 'NTU-Sherlock/FinMind', 'size': '10955'}