{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "import panel as pn\n", "import panel_material_ui as pmui\n", "\n", "pn.extension()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `Tree` component belongs to `Menu` family of components in `panel-material-ui`. Like `MenuList` it allows renders hierarchical data, but unlike `MenuList` allows selecting more than one node. It is implemented using the MUI `RichTreeView`, optionally showing checkboxes, supporting multi-selection, buttons, actions and dropdown menus.\n", "\n", "Each tree entry is a dictionary with a number of supported keys. Unless you explicitly supply an `id`, one is generated automatically from the node's position, meaning simple `{\"label\": \"Node\"}` entries are perfectly valid." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Item Structure\n", "\n", "Supported keys on each item:\n", "\n", "- **`label`** (`str`, required): Display text for the node.\n", "- **`items`** (`list[dict]`, optional): Nested child items.\n", "- **`icon`** (`str`, optional): Material icon name.\n", "- **`file_type`** (`str`, optional): Convenience helper (`\"image\"`, `\"pdf\"`, `\"doc\"`, `\"video\"`, `\"folder\"`, `\"pinned\"`, `\"trash\"`).\n", "- **`secondary`** (`str`, optional): Supporting caption.\n", "- **`color`** (`str`, optional): Palette key used when the node is selected.\n", "- **`actions`** (`list`, optional): Inline or menu actions (same schema as `MenuList`).\n", "- **`buttons`** (`list`, optional): Call-to-action buttons rendered next to the node label.\n", "- **`selectable`** (`bool`, optional): Disable selection for a node when `False` (still expandable).\n", "- **`disabled`** (`bool`, optional): Fully disables and greys out this item if `True`\n", " \n", "Extra keys are preserved in Python so you can look up arbitrary metadata when handling callbacks.\n", "\n", "## Parameters:\n", "\n", "### Core\n", "\n", "- **`items`** (`list[dict]`): Tree data.\n", "- **`selected`** (`list[tuple]`): List of tuple paths of the active nodes (e.g. `(0, 1)` for the second child of the first root).\n", "- **`expanded`** (`list[tuple]`): Paths of expanded nodes.\n", "- **`multi_select`** (`bool`): Allow selecting multiple nodes via clicks.\n", "- **`checkboxes`** (`bool`): Show per-node checkboxes; implies multi-select semantics.\n", "- **`propagate_to_child` / `propagate_to_parent`** (`bool`): Mirror checkbox state downwards/upwards.\n", "\n", "##### Display\n", "\n", "* **`color`** (`str`): The color variant indicating the selected list item, which must be one of `'default'` (white), `'primary'` (blue), `'success'` (green), `'info'` (yellow), `'light'` (light), or `'danger'` (red).\n", "* **`item_children_indentation`** (`int`): Pixels to indent each level.\n", "* **`level_indent`** (`int`): Number of pixels each nested level is indented by.\n", "* **`show_children`** (`boolean`): Whether to render child items nested under `'items'`.\n", "\n", "##### Styling\n", "\n", "- **`sx`** (`dict`): Component level styling API.\n", "- **`theme_config`** (`dict`): Theming API.\n", "\n", "---\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Like all `Menu`-like components `Tree` accepts a list of `items`, which each support sub-`items`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "basic_tree = pmui.Tree(\n", " items=[\n", " {\n", " \"label\": \"Content\",\n", " \"file_type\": \"folder\",\n", " \"items\": [\n", " {\"label\": \"Blog\", \"file_type\": \"doc\"},\n", " {\"label\": \"Media\", \"file_type\": \"image\"},\n", " ],\n", " },\n", " {\n", " \"label\": \"Archive\",\n", " \"file_type\": \"folder\",\n", " \"items\": [\n", " {\"label\": \"2023\", \"file_type\": \"pdf\"},\n", " {\"label\": \"2022\", \"file_type\": \"pdf\"},\n", " ],\n", " },\n", " ],\n", " expanded=[(0,)],\n", ")\n", "\n", "basic_tree" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Selecting a node updates both the `active` and `value` parameters on the Python side. `active` stores a list of the tuple indexes, while `value` returns a list of the original item dictionary:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "pn.Row(\n", " pn.Column(\n", " pn.pane.Markdown(\"**Selection path:**\"),\n", " pn.pane.JSON(basic_tree.param.active, depth=2),\n", " ),\n", " pn.Column(\n", " pn.pane.Markdown(\"**Selected item:**\"),\n", " pn.pane.JSON(basic_tree.param.value, depth=2)\n", " )\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Checkboxes & Multi-selection\n", "\n", "Set `checkboxes=True` to render checkboxes and capture multiple selections as a list of tuple paths. You can optionally enable propagation so parent/child nodes stay in sync." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "checkbox_tree = pmui.Tree(\n", " items=[\n", " {\n", " \"label\": \"Projects\",\n", " \"items\": [\n", " {\n", " \"label\": \"Alpha\",\n", " \"items\": [\n", " {\"label\": \"Docs\"},\n", " {\"label\": \"Reports\"},\n", " ],\n", " },\n", " {\n", " \"label\": \"Beta\",\n", " \"items\": [\n", " {\"label\": \"Analytics\"},\n", " {\"label\": \"Dashboards\"},\n", " ],\n", " },\n", " ],\n", " }\n", " ],\n", " checkboxes=True,\n", " propagate_to_child=True,\n", " propagate_to_parent=True,\n", " active=[(0, 1, 1)],\n", " expanded=[(0,), (0, 1)],\n", " \n", ")\n", "\n", "pn.Row(\n", " checkbox_tree,\n", " pn.Column(\n", " \"**Checked paths**\",\n", " pn.pane.JSON(checkbox_tree.param.active)\n", " )\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When `checkboxes=False` to select multiple independent items, press `Ctrl/⌘ + click` and to select a range press `Shift + click`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Actions & Buttons\n", "\n", "Tree nodes support the same action schema as `MenuList`, plus a `buttons` list for inline call-to-action buttons. Inline actions can toggle state, while menu actions appear inside a kebab menu.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "actions = [\n", " {\"label\": \"Favorite\", \"icon\": \"star\", \"inline\": True, \"toggle\": True, \"value\": False},\n", " {\"label\": \"Delete\", \"icon\": \"delete\"},\n", "]\n", "\n", "actions_log = pn.Column()\n", "\n", "actions_tree = pmui.Tree(\n", " items=[\n", " {\n", " \"label\": \"Notebooks\",\n", " \"items\": [\n", " {\n", " \"label\": \"Explorations\",\n", " \"secondary\": \"Last updated today\",\n", " \"actions\": actions,\n", " \"buttons\": [\n", " {\"label\": \"Open\", \"icon\": \"open_in_new\", \"color\": \"primary\"},\n", " ],\n", " },\n", " {\n", " \"label\": \"Reports\",\n", " \"secondary\": \"Last updated yesterday\",\n", " \"actions\": actions,\n", " \"buttons\": [\n", " {\"label\": \"Share\", \"icon\": \"share\", \"variant\": \"outlined\"},\n", " ],\n", " },\n", " ],\n", " }\n", " ],\n", " active=[(0, 0)],\n", " expanded=[(0,)]\n", ")\n", "\n", "actions_tree.on_action(\"Favorite\", lambda item: actions_log.append(f\"Favorite toggled: {item['label']}, value={item['actions'][0]['value']}\"))\n", "actions_tree.on_action(\"Delete\", lambda item: actions_log.append(f\"Delete clicked: {item['label']}\"))\n", "\n", "pn.Row(actions_tree, actions_log)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Item Options\n", "\n", "Additional options can be used to `disable` specific items or toggle whether they are `selectable`. Instead of passing the `expanded` indexes it is also possible to set an item to `open` (note that these values are only used for initialization and `open` will not be updated) as items are expanded or collapsed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.Tree(\n", " items=[\n", " {\"label\": \"Project\", \"open\": True, \"items\": [\n", " {\"label\": \"Overview\"},\n", " {\"label\": \"Roadmap\", \"selectable\": False},\n", " {\"label\": \"Specs\", \"disabled\": True, \"items\": [\n", " {\"label\": \"Draft\"},\n", " {\"label\": \"Final\"},\n", " ]}\n", " ]},\n", " {\"label\": \"Team\", \"open\": True, \"items\": [\n", " {\"label\": \"Members\"},\n", " {\"label\": \"Archived\", \"disabled\": True}\n", " ]},\n", " ],\n", " multi_select=False, # single-select for clarity\n", " checkboxes=False, # optional\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Display Options\n", "\n", "#### `color`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pn.GridBox(*(\n", " basic_tree.clone(color=color, label=color, active=[(0,), (0, 1)], margin=10)\n", " for color in pmui.MenuList.param.color.objects\n", "), ncols=5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### API Reference\n", "\n", "Experiment with the available parameters directly in the browser:\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "vscode": { "languageId": "plaintext" } }, "outputs": [], "source": [ "pmui.Tree(\n", " items=[\n", " {\"label\": \"Documents\", \"items\": [\n", " {\"label\": \"Invoices\"},\n", " {\"label\": \"Contracts\"},\n", " ]},\n", " {\"label\": \"Media\", \"items\": [\n", " {\"label\": \"Images\"},\n", " {\"label\": \"Video\"},\n", " ]},\n", " ],\n", " expanded=[(0,)],\n", ").api(jslink=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### References\n", "\n", "- [Panel Interactivity Guides](https://panel.holoviz.org/how_to/interactivity/) – Wiring up callbacks, linking parameters, and reacting to state changes.\n", "- [Material UI Tree View](https://mui.com/x/react-tree-view/rich-tree-view/) – Underlying component API and styling guidance.\n", "- [Panel Material UI Documentation](https://panel-material-ui.holoviz.org/reference/menus/Tree.html) – Latest reference entry for this widget.\n", "\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.12.2" } }, "nbformat": 4, "nbformat_minor": 4 }