{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction: Intermediate Time Series methods with Plotly\n",
    "\n",
    "In this notebook, we will move beyond the basic plots in the `plotly-time-series` notebook and make plots with range sliders, update menus, and even animations. Although still not using the full capabilities of plotly, making these plots will show us how to take advantage of this powerful library to create effective visualizations. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-18T23:15:47.359326Z",
     "start_time": "2018-12-18T23:15:46.779138Z"
    }
   },
   "outputs": [],
   "source": [
    "# Standard data science libraries\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "# Display all cell outputs\n",
    "from IPython.core.interactiveshell import InteractiveShell\n",
    "InteractiveShell.ast_node_interactivity = 'all'\n",
    "\n",
    "# Visualization\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "plt.style.use('bmh')\n",
    "\n",
    "from collections import defaultdict"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Authenticate with plotly in the below cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-18T23:15:47.363845Z",
     "start_time": "2018-12-18T23:15:47.361507Z"
    }
   },
   "outputs": [],
   "source": [
    "## Replace with your credentials.\n",
    "\n",
    "# import plotly\n",
    "# plotly.tools.set_credentials_file(username='########', api_key='******')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These are the standard plotly imports. We set up the notebook to run offline which means our plots are not uploaded to the plot web interface."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-18T23:15:47.686108Z",
     "start_time": "2018-12-18T23:15:47.365799Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<script type=\"text/javascript\">window.PlotlyConfig = {MathJaxConfig: 'local'};</script><script type=\"text/javascript\">if (window.MathJax) {MathJax.Hub.Config({SVG: {font: \"STIX-Web\"}});}</script><script>requirejs.config({paths: { 'plotly': ['https://cdn.plot.ly/plotly-latest.min']},});if(!window._Plotly) {require(['plotly'],function(plotly) {window._Plotly=plotly;});}</script>"
      ],
      "text/vnd.plotly.v1+html": [
       "<script type=\"text/javascript\">window.PlotlyConfig = {MathJaxConfig: 'local'};</script><script type=\"text/javascript\">if (window.MathJax) {MathJax.Hub.Config({SVG: {font: \"STIX-Web\"}});}</script><script>requirejs.config({paths: { 'plotly': ['https://cdn.plot.ly/plotly-latest.min']},});if(!window._Plotly) {require(['plotly'],function(plotly) {window._Plotly=plotly;});}</script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Plot imports\n",
    "import plotly.plotly as py\n",
    "import plotly.graph_objs as go\n",
    "\n",
    "## Offline mode\n",
    "from plotly.offline import init_notebook_mode, iplot\n",
    "init_notebook_mode(connected=True)\n",
    "\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore', category=UserWarning)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Data Series\n",
    "\n",
    "As before, we are using real-world building energy, steam, and static pressure measurements. The data is in a dataframe with a _multi-index_ on the columns. This means we have to use _multi-dimensional_ indexing to select one column."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-18T23:15:47.797202Z",
     "start_time": "2018-12-18T23:15:47.687874Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe thead tr:last-of-type th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr>\n",
       "      <th>type</th>\n",
       "      <th colspan=\"2\" halign=\"left\">StaticPressure</th>\n",
       "      <th>Energy</th>\n",
       "      <th colspan=\"2\" halign=\"left\">Steam</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>sensor</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "      <th>5</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>measured_at</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2017-12-14 11:00:00</th>\n",
       "      <td>0.806723</td>\n",
       "      <td>1.500570</td>\n",
       "      <td>6035.214040</td>\n",
       "      <td>13.164377</td>\n",
       "      <td>10.367290</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2017-12-14 11:15:00</th>\n",
       "      <td>0.789395</td>\n",
       "      <td>1.490740</td>\n",
       "      <td>6182.405506</td>\n",
       "      <td>13.003065</td>\n",
       "      <td>9.801097</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2017-12-14 11:30:00</th>\n",
       "      <td>0.792908</td>\n",
       "      <td>1.473761</td>\n",
       "      <td>6035.187942</td>\n",
       "      <td>12.617836</td>\n",
       "      <td>9.794436</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2017-12-14 11:45:00</th>\n",
       "      <td>0.790165</td>\n",
       "      <td>1.485213</td>\n",
       "      <td>6035.192571</td>\n",
       "      <td>12.419816</td>\n",
       "      <td>9.597848</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2017-12-14 12:00:00</th>\n",
       "      <td>0.786861</td>\n",
       "      <td>1.482015</td>\n",
       "      <td>6035.198581</td>\n",
       "      <td>12.975920</td>\n",
       "      <td>10.041990</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "type                StaticPressure                 Energy      Steam  \\\n",
       "sensor                           1         2            3          4   \n",
       "measured_at                                                            \n",
       "2017-12-14 11:00:00       0.806723  1.500570  6035.214040  13.164377   \n",
       "2017-12-14 11:15:00       0.789395  1.490740  6182.405506  13.003065   \n",
       "2017-12-14 11:30:00       0.792908  1.473761  6035.187942  12.617836   \n",
       "2017-12-14 11:45:00       0.790165  1.485213  6035.192571  12.419816   \n",
       "2017-12-14 12:00:00       0.786861  1.482015  6035.198581  12.975920   \n",
       "\n",
       "type                            \n",
       "sensor                       5  \n",
       "measured_at                     \n",
       "2017-12-14 11:00:00  10.367290  \n",
       "2017-12-14 11:15:00   9.801097  \n",
       "2017-12-14 11:30:00   9.794436  \n",
       "2017-12-14 11:45:00   9.597848  \n",
       "2017-12-14 12:00:00  10.041990  "
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Read in data and convert index to a datetime\n",
    "df = pd.read_csv('building_one.csv', \n",
    "                 header=[0, 1], index_col=0)\n",
    "df.index = pd.to_datetime(df.index)\n",
    "df.sort_index(inplace=True)\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-18T23:16:37.768154Z",
     "start_time": "2018-12-18T23:16:33.865178Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The draw time for this plot will be slow for all clients.\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<iframe id=\"igraph\" scrolling=\"no\" style=\"border:none;\" seamless=\"seamless\" src=\"https://plot.ly/~wjk68/224.embed\" height=\"525px\" width=\"100%\"></iframe>"
      ],
      "text/plain": [
       "<plotly.tools.PlotlyDisplay object>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import cufflinks\n",
    "\n",
    "df['Steam'].iplot(xTitle='Date', yTitle='Steam (Mlbs/hr)', \n",
    "                  theme='white', title=\"Steam Plot\",\n",
    "                  xrange=(pd.datetime(2018, 1, 1), pd.datetime(2018, 1, 15)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we create several data series, spanning both the entire range of data, and subsetting out one week."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-18T23:11:27.729843Z",
     "start_time": "2018-12-18T23:11:27.718159Z"
    }
   },
   "outputs": [],
   "source": [
    "energy_series = df.loc[:, ('Energy', '3')].copy()\n",
    "steam_series = df.loc[:, ('Steam', '4')].copy()\n",
    "pressure_series = df.loc[:, ('StaticPressure', '2')].copy()\n",
    "\n",
    "df_short = df[df.index.week == 8].copy()\n",
    "\n",
    "steam_series_four = df_short.loc[:, ('Steam', '4')].copy()\n",
    "steam_series_five = df_short.loc[:, ('Steam', '5')].copy()\n",
    "\n",
    "static_series_one = df_short.loc[:, ('StaticPressure', '1')].copy()\n",
    "static_series_two = df_short.loc[:, ('StaticPressure', '2')].copy()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Time Scale and Time Window Selection with Range Select and Range Slider\n",
    "\n",
    "One way to add interactivity to our time-series plots and let users dig into the data is by adjusting the time scale and the time window. We can do this using a `rangeselect` and `rangslider` respectively. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:06:16.921502Z",
     "start_time": "2018-12-16T02:06:16.884602Z"
    }
   },
   "outputs": [],
   "source": [
    "# Create a layout with a rangeselector and rangeslider on the xaxis\n",
    "layout = go.Layout(\n",
    "    height=600,\n",
    "    width=900,\n",
    "    font=dict(size=16),\n",
    "    title='Energy Plot with Range Selection',\n",
    "    xaxis=dict(\n",
    "        title='Date',\n",
    "        # Range selector with buttons\n",
    "        rangeselector=dict(\n",
    "            font=dict(size=12),\n",
    "            # Buttons for selecting time scale\n",
    "            buttons=list([\n",
    "                # 1 month\n",
    "                dict(count=1, label='1m', step='month', stepmode='backward'),\n",
    "                # 1 week\n",
    "                dict(count=7, label='1w', step='day', stepmode='backward'),\n",
    "                # 1 day\n",
    "                dict(count=1, label='1d', step='day', stepmode='backward'),\n",
    "                # 12 hours\n",
    "                dict(count=12, label='12h', step='hour', stepmode='backward'),\n",
    "                # 4 hours\n",
    "                dict(count=4, label='4h', step='hour', stepmode='backward'),\n",
    "                # Entire scale\n",
    "                dict(step='all')\n",
    "            ])),\n",
    "        # Sliding for selecting time window\n",
    "        rangeslider=dict(visible=True),\n",
    "        # Type of xaxis\n",
    "        type='date'),\n",
    "    # yaxis is unchanged\n",
    "    yaxis=dict(title='Energy (kWh)'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:06:02.849158Z",
     "start_time": "2018-12-16T02:06:01.113768Z"
    }
   },
   "outputs": [],
   "source": [
    "# Create the same data object\n",
    "energy_data = go.Scatter(x=energy_series.index,\n",
    "                        y=energy_series.values,\n",
    "                        line=go.scatter.Line(color='red', width = 0.6),\n",
    "                        opacity=0.8,\n",
    "                        name='energy',\n",
    "                        text=[f'Energy: {x:.0f} kWh' for x in energy_series.values])\n",
    "\n",
    "# Create the figure and display\n",
    "fig = go.Figure(data=[energy_data], layout=layout)\n",
    "iplot(fig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Time Select with Double Y-Axis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:07:25.944698Z",
     "start_time": "2018-12-16T02:07:25.781876Z"
    }
   },
   "outputs": [],
   "source": [
    "steam_data = go.Scatter(x=steam_series.index,\n",
    "                        y=steam_series.values,\n",
    "                        line=dict(color='blue', width=0.8),\n",
    "                        opacity=0.8,\n",
    "                        name='Steam',\n",
    "                        yaxis='y2',\n",
    "                        text=[f'Steam: {x:.1f} Mlbs/hr' for x in steam_series.values])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:08:05.452688Z",
     "start_time": "2018-12-16T02:08:01.848994Z"
    }
   },
   "outputs": [],
   "source": [
    "# Create a layout with interactive elements and two yaxes\n",
    "layout = go.Layout(\n",
    "    height=600,\n",
    "    width=900,\n",
    "    font=dict(size=16),\n",
    "    title='Energy Plot with Range Selection',\n",
    "    xaxis=dict(\n",
    "        title='Date',\n",
    "        # Range selector with buttons\n",
    "        rangeselector=dict(\n",
    "            font=dict(size=12),\n",
    "            # Buttons for selecting time scale\n",
    "            buttons=list([\n",
    "                # 1 month\n",
    "                dict(count=1, label='1m', step='month', stepmode='backward'),\n",
    "                # 1 week\n",
    "                dict(count=7, label='1w', step='day', stepmode='backward'),\n",
    "                # 1 day\n",
    "                dict(count=1, label='1d', step='day', stepmode='backward'),\n",
    "                # 12 hours\n",
    "                dict(count=12, label='12h', step='hour', stepmode='backward'),\n",
    "                # 4 hours\n",
    "                dict(count=4, label='4h', step='hour', stepmode='backward'),\n",
    "                # Entire scale\n",
    "                dict(step='all')\n",
    "            ])),\n",
    "        # Sliding for selecting time window\n",
    "        rangeslider=dict(visible=True),\n",
    "        # Type of xaxis\n",
    "        type='date'),\n",
    "    yaxis=dict(title='Energy (kWh)', color='red'),\n",
    "    # Add a second yaxis to the right of the plot\n",
    "    yaxis2=dict(\n",
    "        title='Steam (Mlbs/hr)', color='blue', overlaying='y', side='right'))\n",
    "\n",
    "fig = go.Figure(data=[energy_data, steam_data], layout=layout)\n",
    "iplot(fig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Update Menu\n",
    "\n",
    "Next, we will add a dropdown menu to the plot allowing users to select the steam series they want to view. This is an `update` because it changes the data shown. We just need to create an `updatemenus` object that specify the actions to take when the button is selected in the `args` parameter. In this case, we change the data by setting the `visible` parameters and we change the title with the `title` parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:11:16.515028Z",
     "start_time": "2018-12-16T02:11:16.503059Z"
    }
   },
   "outputs": [],
   "source": [
    "updatemenus = list([\n",
    "    dict(\n",
    "        active=2,\n",
    "        buttons=list([\n",
    "            dict(\n",
    "                label='Sensor 4',\n",
    "                method='update',\n",
    "                args=[{\n",
    "                    'visible': [True, False]\n",
    "                }, {\n",
    "                    'title': 'Sensor 4'\n",
    "                }]),\n",
    "            dict(\n",
    "                label='Sensor 5',\n",
    "                method='update',\n",
    "                args=[{\n",
    "                    'visible': [False, True]\n",
    "                }, {\n",
    "                    'title': 'Sensor 5'\n",
    "                }]),\n",
    "            dict(\n",
    "                label='Both',\n",
    "                method='update',\n",
    "                args=[{\n",
    "                    'visible': [True, True]\n",
    "                }, {\n",
    "                    'title': 'Sensor Sensors'\n",
    "                }])\n",
    "        ]),\n",
    "    )\n",
    "])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Once we make the `updatemenus`, we pass in to the `layout`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:11:33.218448Z",
     "start_time": "2018-12-16T02:11:33.186536Z"
    }
   },
   "outputs": [],
   "source": [
    "layout = go.Layout(\n",
    "    height=800, width=1000, title='Steam Sensors', updatemenus=updatemenus)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we need to make our data. We will use two different steam series over the course of one week."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:11:34.846856Z",
     "start_time": "2018-12-16T02:11:34.822920Z"
    }
   },
   "outputs": [],
   "source": [
    "steam_data_four = go.Scatter(\n",
    "    x=steam_series_four.index,\n",
    "    y=steam_series_four.values,\n",
    "    line=dict(color='blue', width=1.1),\n",
    "    opacity=0.8,\n",
    "    name='Steam: Sensor 4',\n",
    "    text = [f'Sensor 4: {x:.1f} Mlbs/hr' for x in steam_series_four.values])\n",
    "\n",
    "steam_data_five = go.Scatter(\n",
    "    x=steam_series_five.index,\n",
    "    y=steam_series_five.values,\n",
    "    line=dict(color='orange', width=1.1),\n",
    "    opacity=0.8,\n",
    "    name='Steam: Sensor 5',\n",
    "    text=[f'Sensor 5: {x:.1f} Mlbs/hr' for x in steam_series_five.values])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we pass in the layout with the `updatemenus` to the figure."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:11:47.891288Z",
     "start_time": "2018-12-16T02:11:47.753688Z"
    }
   },
   "outputs": [],
   "source": [
    "fig = go.Figure(data=[steam_data_four, steam_data_five], layout=layout)\n",
    "iplot(fig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Update Menu with Annotations\n",
    "\n",
    "Now we will add in the annotations when the user selects a sensor. This is simply a matter of changing the visible annotations when a different sensor is selected using the `annotations` parameter."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we format all of the data. We are using weekly series and adding in annotations that show the maximum value on each day."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:15:06.565831Z",
     "start_time": "2018-12-16T02:15:06.513967Z"
    }
   },
   "outputs": [],
   "source": [
    "def find_daily_maxes(x):\n",
    "    \"\"\"Return maximum measurement on each day and when it occurred in a dataframe\"\"\"\n",
    "    x = x.copy().to_frame()\n",
    "    x['day'] = x.index.day\n",
    "    result =pd.concat([x.groupby('day').max(), \n",
    "                      x.groupby('day').idxmax()], axis = 1).iloc[:, [0, 1]]\n",
    "    result.columns = ['value', 'date']\n",
    "    return result.set_index('date')\n",
    "\n",
    "four_highs = find_daily_maxes(steam_series_four)\n",
    "five_highs = find_daily_maxes(steam_series_five)\n",
    "\n",
    "from datetime import datetime\n",
    "\n",
    "def format_time(dt):\n",
    "    if pd.isnull(dt):\n",
    "        return \"NaT\"\n",
    "    else:\n",
    "        return datetime.strftime(dt, \"%a <br> %H:%M %p\")\n",
    "    \n",
    "four_highs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The annotations are made using a list comprehension."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:15:43.288429Z",
     "start_time": "2018-12-16T02:15:43.280449Z"
    }
   },
   "outputs": [],
   "source": [
    "four_annotations = [\n",
    "    dict(\n",
    "        x=date,\n",
    "        y=value[0],\n",
    "        xref='x',\n",
    "        yref='y',\n",
    "        font=dict(color='blue'),\n",
    "        text=f'{format_time(date)}<br> {value[0]:.1f} Mlbs/hr')\n",
    "    for date, value in zip(four_highs.index, four_highs.values)\n",
    "]\n",
    "\n",
    "five_annotations = [\n",
    "    dict(\n",
    "        x=date,\n",
    "        y=value[0],\n",
    "        xref='x',\n",
    "        yref='y',\n",
    "        font=dict(color='orange'),\n",
    "        text=f'{format_time(date)}<br> {value[0]:.1f} Mlbs/hr')\n",
    "    for date, value in zip(five_highs.index, five_highs.values)\n",
    "]\n",
    "\n",
    "four_annotations[:2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the `updatemenus` is where we specify the `annotations` that appear when a button is selected. We will only show annotations when an individual sensor is selected."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:16:02.208082Z",
     "start_time": "2018-12-16T02:16:02.175197Z"
    }
   },
   "outputs": [],
   "source": [
    "updatemenus = list([\n",
    "    dict(\n",
    "        active=2,\n",
    "        buttons=list([\n",
    "            dict(\n",
    "                label='Sensor 4',\n",
    "                method='update',\n",
    "                args=[{\n",
    "                    'visible': [True, False]\n",
    "                }, {\n",
    "                    'title': 'Sensor 4',\n",
    "                    'annotations': four_annotations\n",
    "                }]),\n",
    "            dict(\n",
    "                label='Sensor 5',\n",
    "                method='update',\n",
    "                args=[{\n",
    "                    'visible': [False, True]\n",
    "                }, {\n",
    "                    'title': 'Sensor 5',\n",
    "                    'annotations': five_annotations\n",
    "                }]),\n",
    "            dict(\n",
    "                label='Both',\n",
    "                method='update',\n",
    "                args=[{\n",
    "                    'visible': [True, True]\n",
    "                }, {\n",
    "                    'title': 'Sensor Sensors'\n",
    "                }])\n",
    "        ]),\n",
    "    )\n",
    "])\n",
    "\n",
    "layout = go.Layout(\n",
    "    height=600,\n",
    "    width=800,\n",
    "    title='Steam Sensors',\n",
    "    xaxis=dict(tickformat='%a %b %d'),\n",
    "    updatemenus=updatemenus)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:16:03.491516Z",
     "start_time": "2018-12-16T02:16:03.349293Z"
    }
   },
   "outputs": [],
   "source": [
    "fig = go.Figure(data = [steam_data_four, steam_data_five], \n",
    "                layout=layout)\n",
    "\n",
    "iplot(fig)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Animations\n",
    "\n",
    "Finally, we will work on producing animated plots. This allows us to see how a figure may change over time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:22:48.020538Z",
     "start_time": "2018-12-16T02:22:48.016555Z"
    }
   },
   "outputs": [],
   "source": [
    "spring = [3, 4, 5]\n",
    "summer = [6, 7, 8]\n",
    "fall = [9, 10, 11]\n",
    "winter = [12, 1, 2]\n",
    "\n",
    "int_to_days = {0: 'Mon', 1: 'Tues', 2: 'Wed', 3: 'Thurs',\n",
    "               4: 'Fri', 5: 'Sat', 6: 'Sun'}\n",
    "\n",
    "color_mapping = {'spring': 'green', 'summer': 'orange', 'fall': 'brown', 'winter':' blue'}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:25:40.464791Z",
     "start_time": "2018-12-16T02:25:40.453817Z"
    }
   },
   "outputs": [],
   "source": [
    "def format_season(season_months, season_name, indexer = ('Energy', '3'), name = 'Energy', units = 'kWh'):\n",
    "    \"\"\"Format data for one season\"\"\"\n",
    "    data = df[df.index.month.isin(season_months)].copy()\n",
    "    data_x = defaultdict(list)\n",
    "    data_y = defaultdict(list)\n",
    "    \n",
    "    color = color_mapping[season_name]\n",
    "    \n",
    "    for (time, dow), grouped in data.groupby([data.index.time, data.index.dayofweek]):\n",
    "        x = pd.datetime(2018, 3, 5 + dow, 0 + time.hour, 0 + time.minute)\n",
    "        y = grouped[indexer].mean()\n",
    "        data_x[dow].append(x)\n",
    "        data_y[dow].append(y)\n",
    "    \n",
    "    data_obj = []\n",
    "    for dow, x in data_x.items():\n",
    "        y = data_y[dow]\n",
    "        text = [f'{season_name} <br> {name}: {m:.2f} {units}' for m in y]\n",
    "        data_obj.append(go.Scatter(x = x, y = y, text = text,\n",
    "                                   hoverinfo='text',\n",
    "                                   line = dict(color=color, width=0.75),\n",
    "                                   name = season_name))\n",
    "    \n",
    "    return data_obj"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:25:41.626101Z",
     "start_time": "2018-12-16T02:25:41.393342Z"
    }
   },
   "outputs": [],
   "source": [
    "winter_data_source = format_season(winter, 'winter')\n",
    "winter_data_source[0]['name']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:25:43.158647Z",
     "start_time": "2018-12-16T02:25:42.484581Z"
    }
   },
   "outputs": [],
   "source": [
    "summer_data_source = format_season(summer, 'summer')\n",
    "fall_data_source = format_season(fall, 'fall')\n",
    "spring_data_source = format_season(spring, 'spring')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-16T02:26:27.128403Z",
     "start_time": "2018-12-16T02:26:26.817724Z"
    }
   },
   "outputs": [],
   "source": [
    "layout = go.Layout(title = 'Seasonal Average Energy Use', \n",
    "                   xaxis=dict(nticks = 7, tickformat = '%A'))\n",
    "\n",
    "fig = go.Figure(data = summer_data_source + winter_data_source + fall_data_source + spring_data_source, \n",
    "                layout = layout)\n",
    "iplot(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-15T20:32:16.055454Z",
     "start_time": "2018-12-15T20:32:16.035375Z"
    }
   },
   "outputs": [],
   "source": [
    "spring_data['hours'] = spring_data.index.hour\n",
    "spring_data['minutes'] = spring_data.index.minute\n",
    "\n",
    "spring_weekly = spring_data.groupby([spring_data.index.time, \n",
    "                                     spring_data.index.dayofweek]).\\\n",
    "                            mean().\\\n",
    "                            reset_index().loc[:, ['level_0', 'measured_at', 'Energy', 'hours', 'minutes']]\n",
    "spring_weekly.columns = ['Time', 'Day of Week', 'Energy', 'hours', 'minutes']\n",
    "spring_weekly.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "spring_data_object = [go.Scatter(x = pd.datetime(2018, 3, 5 + row['Day of Week'], \n",
    "                                                 0 + row['hours'], 0 + row['minutes']),\n",
    "                                 y = row['Energy'])]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-12-15T20:30:10.550582Z",
     "start_time": "2018-12-15T20:30:10.358268Z"
    }
   },
   "outputs": [],
   "source": [
    "figure = {'data': [{'x': [0, 1], 'y': [0, 1]}],\n",
    "          'layout': {'xaxis': {'range': [0, 5], 'autorange': False},\n",
    "                     'yaxis': {'range': [0, 5], 'autorange': False},\n",
    "                     'title': 'Start Title',\n",
    "                     'updatemenus': [{'type': 'buttons',\n",
    "                                      'buttons': [{'label': 'Play',\n",
    "                                                   'method': 'animate',\n",
    "                                                   'args': [None]}]}]\n",
    "                    },\n",
    "          'frames': [{'data': [{'x': [1, 2], 'y': [1, 2]}]},\n",
    "                     {'data': [{'x': [1, 4], 'y': [1, 4]}]},\n",
    "                     {'data': [{'x': [3, 4], 'y': [3, 4]}],\n",
    "                      'layout': {'title': 'End Title'}}]}\n",
    "\n",
    "iplot(figure)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "hide_input": false,
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
