{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import panel as pn\n", "pn.extension()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Discover more on using widgets to add interactivity to your applications in the [how-to guides on interactivity](../how_to/interactivity/index.md). Alternatively, learn [how to set up callbacks and (JS-)links between parameters](../../how_to/links/index.md) or [how to use them as part of declarative UIs with Param](../../how_to/param/index.html).\n", "\n", "#### Parameters:\n", "\n", "For details on other options for customizing the component see the [layout](../../how_to/layout/index.md) and [styling](../../how_to/styling/index.md) how-to guides.\n", "\n", "##### Core\n", "\n", "* **``options``** (dict | callable): The options to select from. The options may be nested dictionaries, lists, or callables that return those types. If callables are used, the callables must accept `level` and `value` keyword arguments, where `level` is the level that updated and `value` is a dictionary of the current values, containing keys up to the level that was updated.\n", "* **``value``** (dict): The value from all the Select widgets; the keys are the levels names. If no levels names are specified, the keys are the levels indices.\n", "* **``layout``** (ListPanel | dict): The layout type of the widgets. If a dictionary, a \"type\" key can be provided, to specify the layout type of the widgets, and any additional keyword arguments will be used to instantiate the layout.\n", "* **``levels``** (list): Either a list of strings or a list of dictionaries. If a list of strings, the strings are used as the names of the levels. If a list of dictionaries, each dictionary may have a \"name\" key, which is used as the name of the level, a \"type\" key, which is used as the type of widget, and any corresponding widget keyword arguments. Must be specified if options is callable.\n", "\n", "##### Display\n", "\n", "* **``disabled``** (boolean): Whether the widget is editable\n", "* **``name``** (str): The title of the widget\n", "\n", "___" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " \"NAME\": {\n", " \"12 km\": [\"00Z\", \"12Z\"],\n", " \"3 km\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", " levels=[\"Model\", \"Resolution\", \"Initialization\"],\n", ")\n", "select" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like most other widgets, ``NestedSelect`` has a value parameter that can be accessed or set:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select.value" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A different `layout` type can be provided to the `NestedSelect` to change the layout of the widgets." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " \"NAME\": {\n", " \"12 km\": [\"00Z\", \"12Z\"],\n", " \"3 km\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", " levels=[\"Model\", \"Resolution\", \"Initialization\"],\n", " layout=pn.Row\n", ")\n", "select" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If a dict is provided, a \"type\" key can be provided, to specify the layout type of the widgets, and any additional keyword arguments will be used to instantiate the layout." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " \"NAME\": {\n", " \"12 km\": [\"00Z\", \"12Z\"],\n", " \"3 km\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", " levels=[\"Model\", \"Resolution\", \"Initialization\"],\n", " layout={\"type\": pn.GridBox, \"ncols\": 2}\n", ")\n", "select" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If ``levels`` names are not set, the value is keyed off the level index." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " \"NAME\": {\n", " \"12 km\": [\"00Z\", \"12Z\"],\n", " \"3 km\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", ")\n", "select.value" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also define the default value by providing a dict." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " \"NAME\": {\n", " \"12 km\": [\"00Z\", \"12Z\"],\n", " \"3 km\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", " value={\"Model\": \"NAME\", \"Resolution\": \"12 km\", \"Initialization\": \"12Z\"},\n", " levels=[\"Model\", \"Resolution\", \"Initialization\"],\n", ")\n", "select" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Not all keys of the value need to be specified, and the keys can be specified in any order." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " \"NAME\": {\n", " \"12 km\": [\"00Z\", \"12Z\"],\n", " \"3 km\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", " value={\"Initialization\": \"12Z\", \"Resolution\": \"0.5 deg\"},\n", " levels=[\"Model\", \"Resolution\", \"Initialization\"],\n", ")\n", "select" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An incomplete definition of options can also be used. The corresponding subsequent widgets will be hidden." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"NAME\": {},\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", " levels=[\"Model\", \"Resolution\", \"Initialization\"],\n", ")\n", "select" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The value for the hidden widgets will be `None`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select.value = {\"Model\": \"NAME\"}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, `options` can be a callable. Its nested levels too: e.g. `options={\"Daily\": list_options, \"Monthly\": list_options}`.\n", "\n", "If callables are used, the callables must accept `level` and `value` keyword arguments, where `level` is the level that updated and `value` is a dictionary of the current values, containing keys up to the level that was updated.\n", "\n", "Note, the callable can vary across `options`, and `levels` must be provided if any of the `options` is callable." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def list_options(level, value):\n", " if level == \"time_step\":\n", " options = {\"Daily\": list_options, \"Monthly\": list_options}\n", " elif level == \"level_type\":\n", " options = {f\"{value['time_step']}_upper\": list_options, f\"{value['time_step']}_lower\": list_options}\n", " else:\n", " options = [f\"{value['level_type']}.json\", f\"{value['level_type']}.csv\"]\n", "\n", " return options\n", "\n", "pn.widgets.NestedSelect(\n", " options=list_options,\n", " levels=[\"time_step\", \"level_type\", \"file_type\"],\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is useful if you are trying to use options from a hosted source.\n", "\n", "Using `pn.cache` here can help improve user experience and reduce the risk of rate limits.\n", "\n", "```python\n", "import panel as pn\n", "pn.extension()\n", "\n", "@pn.cache()\n", "def list_options(level, value):\n", " value_path = \"/\".join(list(value.values()))\n", " url = f\"https://downloads.psl.noaa.gov/Datasets/ncep.reanalysis/{value_path}\"\n", "\n", " options = [var.rstrip(\"/\") for var in pd.read_html(url)[0][\"Name\"].dropna()[1:]]\n", " if level == \"time_step\":\n", " options = {option: list_options for option in options if option[0].isupper()}\n", " elif level == \"level_type\":\n", " options = {option: list_options for option in options if option[0].islower()}\n", " else:\n", " options = [option for option in options if option.endswith(\".nc\")]\n", "\n", " return options\n", "\n", "\n", "select = pn.widgets.NestedSelect(\n", " options=list_options,\n", " levels=[\"time_step\", \"level_type\", \"file\"],\n", ")\n", "select\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`levels` also accepts a list of dicts, where each dict contains the type of widget and its corresponding kwargs." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "select = pn.widgets.NestedSelect(\n", " options={\n", " \"GFS\": {\n", " \"0.25 deg\": [\"00Z\", \"06Z\", \"12Z\", \"18Z\"],\n", " \"0.5 deg\": [\"00Z\", \"12Z\"],\n", " \"1 deg\": [\"00Z\", \"12Z\"],\n", " },\n", " \"NAME\": {\n", " \"12 km\": [\"00Z\", \"12Z\"],\n", " \"3 km\": [\"00Z\", \"12Z\"],\n", " },\n", " },\n", " value={\"Model\": \"NAME\", \"Resolution\": \"12 km\", \"Initialization\": \"00Z\"},\n", " levels=[\n", " {\"name\": \"Model\", \"type\": pn.widgets.RadioButtonGroup, \"button_type\": \"primary\"},\n", " {\"name\": \"Resolution\", \"type\": pn.widgets.Select, \"width\": 100},\n", " {\"name\": \"Initialization\", \"type\": pn.widgets.DiscreteSlider, \"width\": 100},\n", " ],\n", ")\n", "select" ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 4 }