{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import panel as pn\n",
    "import param\n",
    "\n",
    "pn.extension()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``panel.Param`` pane allows customizing the widgets, layout and style of the parameters of a `param.Parametrized` Class.\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "The basic parameters are:\n",
    "\n",
    "* **`object`** (param.parameterized.Parameters): The `param` attribute of a `param.Parameterized` Class\n",
    "* **`parameters`** (List[str]): A list identifying the subset of parameters to include in the Pane.\n",
    "* **`widgets`** (Dict): A Dictionary specifying which parameters and widgets to use for a given parameter. You can also specify widget attributes.\n",
    "\n",
    "The more advanced parameters which give you more control are:\n",
    " \n",
    "* **`default_layout`** (ClassSelector): A layout like Column, Row, etc. or a Custom GridBox.\n",
    "* **`display_threshold`** (float): Parameters with precedence below this value are not displayed.\n",
    "* **`expand`** (bool): Whether parameterized subobjects are expanded or collapsed on instantiation.\n",
    "* **`expand_button`** (bool): Whether to add buttons to expand and collapse sub-objects.\n",
    "* **`expand_layout`** (layout): Layout to expand sub-objects into.\n",
    "* **`name`** (str): The title of the pane.\n",
    "* **`show_labels`** (bool): Whether or not to show labels\n",
    "* **`show_name`** (bool): Whether or not to show the name of the Parameterized Class \n",
    "\n",
    "For more layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\n",
    "\n",
    "For an alternative example of using `panel.Param` see the [parameters user guide](../../user_guide/Param.ipynb).\n",
    "___"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's build a model of a cycling Athlete and her PowerCurve. \n",
    "\n",
    "The PowerCurve is a recording of her maximum power output in Watt per kg for fixed durations of time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import datetime\n",
    "import pandas as pd\n",
    "import hvplot.pandas\n",
    "\n",
    "DATE_BOUNDS = (datetime.date(1900, 1, 1), datetime.datetime.now().date())\n",
    "\n",
    "class PowerCurve(param.Parameterized):\n",
    "    ten_sec = param.Number(1079)\n",
    "    ten_sec_date = param.Date(datetime.date(2018, 8, 21), bounds=DATE_BOUNDS)\n",
    "    one_min = param.Number(684)\n",
    "    one_min_date = param.Date(datetime.date(2017, 8, 31), bounds=DATE_BOUNDS)\n",
    "    ten_min = param.Number(419)\n",
    "    ten_min_date = param.Date(datetime.date(2017, 9, 22), bounds=DATE_BOUNDS)\n",
    "    twenty_min = param.Number(398)\n",
    "    twenty_min_date = param.Date(datetime.date(2017, 9, 22), bounds=DATE_BOUNDS)\n",
    "    one_hour = param.Number(319)\n",
    "    one_hour_date = param.Date(datetime.date(2017, 8, 6), bounds=DATE_BOUNDS)\n",
    "    \n",
    "    @param.depends(\"ten_sec\", \"one_min\", \"ten_min\", \"twenty_min\", \"one_hour\")\n",
    "    def plot(self):\n",
    "        data = {\n",
    "            \"duration\": [10 / 60, 1, 10, 20, 60],\n",
    "            \"power\": [self.ten_sec, self.one_min, self.ten_min, self.twenty_min, self.one_hour],\n",
    "        }\n",
    "        dataframe = pd.DataFrame(data)\n",
    "        line_plot = dataframe.hvplot.line(\n",
    "            x=\"duration\", y=\"power\", line_color=\"#007BFF\", line_width=3, responsive=True,\n",
    "        )\n",
    "        scatter_plot = dataframe.hvplot.scatter(\n",
    "            x=\"duration\", y=\"power\", marker=\"o\", size=6, color=\"#007BFF\", responsive=True\n",
    "        )\n",
    "        fig = line_plot * scatter_plot\n",
    "        gridstyle = {\"grid_line_color\": \"black\", \"grid_line_width\": 0.1}\n",
    "        fig = fig.opts(\n",
    "            min_height=400,\n",
    "            toolbar=None,\n",
    "            yticks=list(range(0, 1600, 200)),\n",
    "            ylim=(0, 1500),\n",
    "            gridstyle=gridstyle,\n",
    "            show_grid=True,\n",
    "        )\n",
    "        return fig\n",
    "\n",
    "class Athlete(param.Parameterized):\n",
    "    name_ = param.String(\"P.A. Nelson\")\n",
    "    birthday = param.Date(datetime.date(1976, 9, 17), bounds=DATE_BOUNDS)\n",
    "    weight = param.Number(default=82, bounds=(20,300))\n",
    "    power_curve = param.ClassSelector(class_=PowerCurve, default=PowerCurve())\n",
    "    \n",
    "athlete = Athlete()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `pn.Param` pane can be used to view and edit the models.\n",
    "\n",
    "Try clicking the `...` button. This will expand the PowerCurve if running in an interactive notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Param(athlete)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The default Name and Birthday widgets are slow to use. So let's change them to a `DatePicker` and a `LiteralInput`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Param(athlete, widgets={\"birthday\": pn.widgets.DatePicker, \"weight\": pn.widgets.LiteralInput})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's expand the power curve by default:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Param(\n",
    "    athlete, \n",
    "    widgets={\n",
    "        \"birthday\": pn.widgets.DatePicker, \n",
    "        \"weight\": pn.widgets.LiteralInput\n",
    "    }, expand=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's try to display the Name and Birthday only and in a Row."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Param(\n",
    "    athlete,\n",
    "    widgets={\"birthday\": pn.widgets.DatePicker},\n",
    "    parameters=[\"name_\", \"birthday\"],\n",
    "    show_name=False,\n",
    "    default_layout=pn.Row,\n",
    "    width=400\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's customize the view of the `Athlete` some more."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "athlete_view = pn.Param(\n",
    "    athlete,\n",
    "    widgets={\n",
    "        \"birthday\": pn.widgets.DatePicker, \n",
    "        \"weight\": {\"type\": pn.widgets.LiteralInput, \"width\": 100}\n",
    "    },\n",
    "    parameters=[\"name_\", \"birthday\", \"weight\"],\n",
    "    show_name=False,\n",
    "    default_layout=pn.Row,\n",
    "    width=600\n",
    ")\n",
    "athlete_view"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's take a look at the PowerCurve."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Param(athlete.power_curve)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The PowerCurve layout is not that tidy. Let's change the layout to two columns."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def new_class(cls, **kwargs):\n",
    "    \"Creates a new class which overrides parameter defaults.\"\n",
    "    return type(type(cls).__name__, (cls,), kwargs)\n",
    "\n",
    "power_curve_columns_view = pn.Param(\n",
    "    athlete.power_curve,\n",
    "    default_layout=new_class(pn.GridBox, ncols=2),\n",
    "    show_name=False,\n",
    "    widgets = {\n",
    "        \"ten_sec_date\": pn.widgets.DatePicker, \n",
    "        \"one_min_date\": pn.widgets.DatePicker, \n",
    "        \"ten_min_date\": pn.widgets.DatePicker,\n",
    "        \"twenty_min_date\": pn.widgets.DatePicker, \n",
    "        \"one_hour_date\": pn.widgets.DatePicker\n",
    "    }\n",
    ")\n",
    "\n",
    "power_curve_columns_view"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's put a plot of the PowerCurve in the mix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sections = {'InputFiles': ['dirs', 'files'], 'Field': ['grps', 'varns']}\n",
    "\n",
    "def update(target, event):\n",
    "    target.set_param(options=sections[event.new], value=sections[event.new][0])\n",
    "\n",
    "sel = pn.widgets.Select(options=list(sections.keys()))\n",
    "rad = pn.widgets.RadioButtonGroup(options=sections[sel.value])\n",
    "sel.link(rad, callbacks={'value': update})\n",
    "\n",
    "pn.Column(sel, rad)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "power_curve_view = pn.Row(\n",
    "    power_curve_columns_view,\n",
    "    pn.layout.VSpacer(width=50),\n",
    "    athlete.power_curve.plot\n",
    ")\n",
    "power_curve_view"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And finally, let's put things together."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pn.Column(\n",
    "    pn.pane.Markdown(\"### Athlete\"), \n",
    "    athlete_view, \n",
    "    pn.pane.Markdown(\"#### Power Curve\"), \n",
    "    power_curve_view,\n",
    "    sizing_mode='stretch_width'\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
