<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Creating interactive dashboards
Step1:  In the Data Processing Pipelines section we discovered how to declare a DynamicMap and control multiple processing steps with the use of custom streams as described in the Responding to Events guide. Here we will use the same example exploring a dataset of stock timeseries and build a small dashboard using the Panel library, which allows us to declare easily declare custom widgets and link them to our streams. We will begin by once again declaring our function that loads the stock data
Step2:  Building dashboards
Controlling stream events manually from the Python prompt can be a bit cumbersome. However since you can now trigger events from Python we can easily bind any Python based widget framework to the stream. HoloViews itself is based on param and param has various UI toolkits that accompany it and allow you to quickly generate a set of widgets. Here we will use panel, which is based on bokeh to control our stream values.
To do so we will declare a StockExplorer class subclassing Parameterized and defines two parameters, the rolling_window as an integer and the symbol as an ObjectSelector. Additionally we define a view method, which defines the DynamicMap and applies the two operations we have already played with, returning an overlay of the smoothed Curve and outlier Scatter.
Step3:  You will have noticed the param.depends decorator on the load_symbol method above, this declares that the method depends on these two parameters. When we pass the method to a DynamicMap it will now automatically listen to changes to the 'symbol', and 'variable' parameters. To generate a set of widgets to control these parameters we can simply supply the explorer.param accessor to a panel layout, and combining the two we can quickly build a little GUI
Step4:  The rolling_window parameter is not yet connected to anything however, so just like in the Data Processing Pipelines section we will see  how we can get the widget to control the parameters of an operation. Both the rolling and rolling_outlier_std operations accept a rolling_window parameter, so we create a Params stream to listen to that parameter and then pass it to the operations. Finally we compose everything into a panel Row
Step5:  Replacing the output
Updating plots using a DynamicMap is a very efficient means of updating a plot since it will only update the data that has changed. In some cases it is either necessary or more convenient to redraw a plot entirely. Panel makes this easy by annotating a method with any dependencies that should trigger the plot to be redrawn. In the example below we extend the StockExplorer by adding a datashade boolean and a view method which will flip between a datashaded and regular view of the plot
Step6:  In the previous example we explicitly called the view method, but to allow panel to update the plot when the datashade parameter is toggled we instead pass it the actual view method. Whenever the datashade parameter is toggled panel will call the method and update the plot with whatever is returned
<ASSISTANT_TASK:>
Python Code:
import pandas as pd
import holoviews as hv
from bokeh.sampledata import stocks
from holoviews.operation.timeseries import rolling, rolling_outlier_std
hv.extension('bokeh')
Explanation: Creating interactive dashboards
End of explanation
def load_symbol(symbol, variable='adj_close', **kwargs):
    df = pd.DataFrame(getattr(stocks, symbol))
    df['date'] = df.date.astype('datetime64[ns]')
    return hv.Curve(df, ('date', 'Date'), variable)
stock_symbols = ['AAPL', 'IBM', 'FB', 'GOOG', 'MSFT']
dmap = hv.DynamicMap(load_symbol, kdims='Symbol').redim.values(Symbol=stock_symbols)
dmap.opts(framewise=True)
Explanation: In the Data Processing Pipelines section we discovered how to declare a DynamicMap and control multiple processing steps with the use of custom streams as described in the Responding to Events guide. Here we will use the same example exploring a dataset of stock timeseries and build a small dashboard using the Panel library, which allows us to declare easily declare custom widgets and link them to our streams. We will begin by once again declaring our function that loads the stock data:
End of explanation
import param
import panel as pn
from holoviews.streams import Params
class StockExplorer(param.Parameterized):
    rolling_window = param.Integer(default=10, bounds=(1, 365))
    
    symbol = param.ObjectSelector(default='AAPL', objects=stock_symbols)
    
    variable = param.ObjectSelector(default='adj_close', objects=[
        'date', 'open', 'high', 'low', 'close', 'volume', 'adj_close'])
    @param.depends('symbol', 'variable')
    def load_symbol(self):
        df = pd.DataFrame(getattr(stocks, self.symbol))
        df['date'] = df.date.astype('datetime64[ns]')
        return hv.Curve(df, ('date', 'Date'), self.variable).opts(framewise=True)
Explanation: Building dashboards
Controlling stream events manually from the Python prompt can be a bit cumbersome. However since you can now trigger events from Python we can easily bind any Python based widget framework to the stream. HoloViews itself is based on param and param has various UI toolkits that accompany it and allow you to quickly generate a set of widgets. Here we will use panel, which is based on bokeh to control our stream values.
To do so we will declare a StockExplorer class subclassing Parameterized and defines two parameters, the rolling_window as an integer and the symbol as an ObjectSelector. Additionally we define a view method, which defines the DynamicMap and applies the two operations we have already played with, returning an overlay of the smoothed Curve and outlier Scatter.
End of explanation
explorer = StockExplorer()
stock_dmap = hv.DynamicMap(explorer.load_symbol)
pn.Row(explorer.param, stock_dmap)
Explanation: You will have noticed the param.depends decorator on the load_symbol method above, this declares that the method depends on these two parameters. When we pass the method to a DynamicMap it will now automatically listen to changes to the 'symbol', and 'variable' parameters. To generate a set of widgets to control these parameters we can simply supply the explorer.param accessor to a panel layout, and combining the two we can quickly build a little GUI:
End of explanation
# Apply rolling mean
window = Params(explorer, ['rolling_window'])
smoothed = rolling(stock_dmap, streams=[window])
# Find outliers
outliers = rolling_outlier_std(stock_dmap, streams=[window]).opts(
    hv.opts.Scatter(color='red', marker='triangle')
)
pn.Row(explorer.param, (smoothed * outliers).opts(width=600))
Explanation: The rolling_window parameter is not yet connected to anything however, so just like in the Data Processing Pipelines section we will see  how we can get the widget to control the parameters of an operation. Both the rolling and rolling_outlier_std operations accept a rolling_window parameter, so we create a Params stream to listen to that parameter and then pass it to the operations. Finally we compose everything into a panel Row:
End of explanation
from holoviews.operation.datashader import datashade, dynspread
class AdvancedStockExplorer(StockExplorer):    
    datashade = param.Boolean(default=False)
    @param.depends('datashade')
    def view(self):
        stocks = hv.DynamicMap(self.load_symbol)
        # Apply rolling mean
        window = Params(self, ['rolling_window'])
        smoothed = rolling(stocks, streams=[window])
        if self.datashade:
            smoothed = dynspread(datashade(smoothed)).opts(framewise=True)
        # Find outliers
        outliers = rolling_outlier_std(stocks, streams=[window]).opts(
            width=600, color='red', marker='triangle', framewise=True)
        return (smoothed * outliers)
Explanation: Replacing the output
Updating plots using a DynamicMap is a very efficient means of updating a plot since it will only update the data that has changed. In some cases it is either necessary or more convenient to redraw a plot entirely. Panel makes this easy by annotating a method with any dependencies that should trigger the plot to be redrawn. In the example below we extend the StockExplorer by adding a datashade boolean and a view method which will flip between a datashaded and regular view of the plot:
End of explanation
explorer = AdvancedStockExplorer()
pn.Row(explorer.param, explorer.view)
Explanation: In the previous example we explicitly called the view method, but to allow panel to update the plot when the datashade parameter is toggled we instead pass it the actual view method. Whenever the datashade parameter is toggled panel will call the method and update the plot with whatever is returned:
End of explanation
<END_TASK>