{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import panel as pn\n",
    "\n",
    "import plotly.express as px\n",
    "import plotly.io as pio\n",
    "import plotly.graph_objects as go\n",
    "\n",
    "pn.extension(\"plotly\", sizing_mode=\"stretch_width\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Styling Plotly for Panel\n",
    "\n",
    "In this example we will show how to style Plotly plots with Panel for both the `default` and the `dark` theme.\n",
    "\n",
    "![PlotlyStyle.gif](https://assets.holoviews.org/panel/thumbnails/gallery/styles/plotly-styles.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Get or set the theme\n",
    "\n",
    "When we use the Fast templates the `theme` can be found in the `session_args`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_theme():\n",
    "    return pn.state.session_args.get(\"theme\", [b'default'])[0].decode()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "theme=get_theme()\n",
    "theme"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Select a nice accent color\n",
    "\n",
    "Below we create some functionality to *cycle through* a list of nice accent colors. You would probably just set the `accent_color` and `color` for your specific use case."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nice_accent_colors = [\n",
    "    (\"#00A170\", \"white\"), # Mint\n",
    "    (\"#DAA520\", \"white\"), # Golden Rod\n",
    "    (\"#F08080\", \"white\"), # Light Coral\n",
    "    (\"#4099da\", \"white\"), # Summery Sky\n",
    "    (\"#2F4F4F\", \"white\"), # Dark Slate Grey\n",
    "    (\"#A01346\", \"white\"), # Fast\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_nice_accent_color():\n",
    "    \"\"\"Returns the 'next' nice accent color\"\"\"\n",
    "    if not \"color_index\" in pn.state.cache:\n",
    "        pn.state.cache[\"color_index\"]=0\n",
    "    elif pn.state.cache[\"color_index\"]==len(nice_accent_colors)-1:\n",
    "        pn.state.cache[\"color_index\"]=0\n",
    "    else:\n",
    "        pn.state.cache[\"color_index\"]+=1\n",
    "    return nice_accent_colors[pn.state.cache[\"color_index\"]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "accent_color, color = get_nice_accent_color()\n",
    "pn.pane.Markdown(f\"# Color: {accent_color}\", background=accent_color, height=70, margin=0, style={\"color\": color, \"padding\": \"10px\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotly\n",
    "\n",
    "Plotly provides a list of built in templates in `plotly.io.templates`. See the [Plotly Templates Guide](https://plotly.com/python/templates/).\n",
    "\n",
    "Let's define a [`Select`](https://panel.holoviz.org/reference/widgets/Select.html) widget to explore the templates. We will set the default value to `plotly` or `plotly_dark` depending on the theme."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plotly_template = pn.widgets.Select(options=sorted(pio.templates))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if theme==\"dark\":\n",
    "    plotly_template.value=\"plotly_dark\"\n",
    "else:\n",
    "    plotly_template.value=\"plotly\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotly Express\n",
    "\n",
    "Plotly Express provides a `template` argument. Let's try to use it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = pd.DataFrame(\n",
    "    [\n",
    "        (\"Monday\", 7),\n",
    "        (\"Tuesday\", 4),\n",
    "        (\"Wednesday\", 9),\n",
    "        (\"Thursday\", 4),\n",
    "        (\"Friday\", 4),\n",
    "        (\"Saturday\", 4),\n",
    "        (\"Sunay\", 4),\n",
    "    ],\n",
    "    columns=[\"Day\", \"Orders\"],\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_express_plot(template=plotly_template.value, accent_color=accent_color):\n",
    "    fig = px.line(\n",
    "        data,\n",
    "        x=\"Day\",\n",
    "        y=\"Orders\",\n",
    "        template=template,\n",
    "        color_discrete_sequence=(accent_color,),\n",
    "        title=f\"Orders: '{template}' theme\"\n",
    "    )\n",
    "    fig.update_traces(mode=\"lines+markers\", marker=dict(size=10), line=dict(width=4))\n",
    "    fig.layout.autosize = True\n",
    "    return fig"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's [bind](https://panel.holoviz.org/user_guide/APIs.html#reactive-functions) `get_express_plot` to the `plotly_template` widget and lay out the two in a `Column`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "get_express_plot=pn.bind(get_express_plot, template=plotly_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "express_plot=pn.pane.panel(get_express_plot, config={\"responsive\": True}, sizing_mode=\"stretch_both\", name=\"EXPRESS\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Column(plotly_template, express_plot, sizing_mode=\"stretch_both\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotly Graph Objects Figure\n",
    "\n",
    "You can set the theme of a Plotly Graph Objects Figure via the `update_layout` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "z_data = pd.read_csv(\"https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_go_plot(template=plotly_template.value, accent_color=accent_color):\n",
    "    figure = go.Figure(\n",
    "        data=go.Surface(z=z_data.values),\n",
    "        layout=go.Layout(\n",
    "            title=\"Mt Bruno Elevation\",\n",
    "        ))\n",
    "    figure.layout.autosize = True\n",
    "    figure.update_layout(template=template, title=\"Mt Bruno Elevation: '%s' theme\" % template)\n",
    "    return figure"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Letss [bind](https://panel.holoviz.org/user_guide/APIs.html#reactive-functions) `get_go_plot` to the `plotly_template` widget and lay everything using `Tabs`and `Column`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "get_go_plot=pn.bind(get_go_plot, template=plotly_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "go_plot=pn.pane.panel(get_go_plot, config={\"responsive\": True}, sizing_mode=\"stretch_both\", name=\"GRAPH OBJECTS\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Column(plotly_template, go_plot, min_height=600)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Wrap it up in a nice template\n",
    "\n",
    "Here we use the [`FastGridTemplate`](https://panel.holoviz.org/reference/templates/FastListTemplate.html#templates-gallery-fastgridtemplate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template = pn.template.FastGridTemplate(\n",
    "    site=\"Panel\",\n",
    "    title=\"Styling Plotly\",\n",
    "    sidebar=[plotly_template],\n",
    "    accent_base_color=accent_color,\n",
    "    header_background=accent_color,\n",
    "    header_color=color,\n",
    "    row_height=70, \n",
    "    save_layout=True, prevent_collision=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template.main[0:1,:]=plotly_template\n",
    "template.main[1:10,0:6]=express_plot\n",
    "template.main[1:10,6:12]=go_plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template.servable();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can serve the app via `panel serve PlotlyStyle.ipynb` and find it at `http://localhost:5006/PlotlyStyle`. You should add the `--autoreload` flag while developing for *hot reloading*."
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
