{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "f00c0eca-5328-4670-bead-2732fa5af97d", "metadata": {}, "outputs": [], "source": [ "import panel as pn\n", "import panel_material_ui as pmui\n", "\n", "pn.extension()" ] }, { "cell_type": "markdown", "id": "f5ac1710-d375-41ba-ab1e-9db5fd63ce9e", "metadata": {}, "source": [ "The `Tabs` component organizes content into separate views that can be switched between.\n", "\n", "### Parameters:\n", "\n", "#### Core\n", "\n", "* **`active`** (`int`): Index of the currently active tab.\n", "* **`closable`** (`boolean`): Whether tabs can be closed.\n", "* **`disabled`** (`list[int]`): Integer indexes of disabled tabs.\n", "* **`dynamic`** (`boolean`): Whether to render tab contents only when active.\n", "\n", "### Display\n", "\n", "* **`centered`** (`boolean`): Whether to center the tab labels.\n", "* **`color`** (`Literal[\"default\", \"primary\", \"secondary\"]`): The color variant of the highlight indicating the active tab, which must be one of `'default'`, `'primary'`, or `'secondary'`.\n", "* **`tabs_location`** (`Literal[\"above\", \"below\", \"left\", \"right\"]`): Position of the tab labels relative to content.\n", "* **`wrapped`** (`boolean`): Whether labels should be wrapped.\n", "\n", "---" ] }, { "cell_type": "markdown", "id": "6d5288e4-0ed3-4194-9d72-e479a120b3d0", "metadata": {}, "source": [ "### Basic Usage\n", "\n", "The `Tabs` layout renders a list of items into a series of selectable tabs. The labels can be provided as tuples and the active tab is controlled via the `active` parameter:" ] }, { "cell_type": "code", "execution_count": null, "id": "cf296787-f0fb-46c7-90b8-88ec80f04b8c", "metadata": {}, "outputs": [], "source": [ "pmui.Tabs(\n", " ('Title 1', 'My content'),\n", " ('Title 2', 'My secondary content'),\n", " active=1\n", ")" ] }, { "cell_type": "markdown", "id": "f61d79d8-2998-4e15-9f99-f68315aa32fc", "metadata": {}, "source": [ "### Objects & Headers\n", "\n", "A `Tabs` layout can either be instantiated as empty and be populated after the fact, or using a list of objects provided as positional arguments. If the objects are not already Panel components they will each be converted to one using the `pn.panel` conversion method. Unlike other panel `Tabs` also accepts tuples to specify the title of each tab, if no name is supplied explicitly the name of the underlying object will be used." ] }, { "cell_type": "code", "execution_count": null, "id": "74bce8f6-a8f8-4087-ac01-85b17a72f06a", "metadata": {}, "outputs": [], "source": [ "from bokeh.plotting import figure\n", "\n", "p1 = figure(width=300, height=300, name='Scatter')\n", "p1.scatter([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0])\n", "\n", "p2 = figure(width=300, height=300, name='Line')\n", "p2.line([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0])\n", "\n", "tabs = pmui.Tabs(('Scatter', p1), p2)\n", "tabs" ] }, { "cell_type": "markdown", "id": "d91515dd-31c2-4bbf-9b79-648aa2dcca63", "metadata": {}, "source": [ "The ``Tabs`` objects should never be modified directly. Instead, it is recommended to modify tabs using the provided methods, except when replacing the list of ``objects`` entirely. Using the methods ensures that the rendered views of the ``Tabs`` are rerendered in response to the change, but even more importantly it ensures the tab titles are kept in sync with the objects. As a simple example we might add an additional widget to the ``tabs`` using the append method:" ] }, { "cell_type": "code", "execution_count": null, "id": "2317564b-72db-4aeb-b811-1ceef5b60aa4", "metadata": {}, "outputs": [], "source": [ "p3 = figure(width=300, height=300, name='Square')\n", "p3.scatter([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0], marker='square', size=10)\n", "\n", "tabs.append(p3)" ] }, { "cell_type": "markdown", "id": "cf2dda25-f78e-4d6a-8e42-377c813e664f", "metadata": {}, "source": [ "On a live server or in a notebook the `tabs` displayed above will dynamically expand to include the new tab. To see the effect in a statically rendered page, we will display the tabs a second time:" ] }, { "cell_type": "code", "execution_count": null, "id": "b82b1151-b4c4-47fe-804c-341f224ad0dd", "metadata": {}, "outputs": [], "source": [ "tabs" ] }, { "cell_type": "markdown", "id": "89d7b817-c15c-41ee-acbf-d08b0095ae86", "metadata": {}, "source": [ "#### HTML & Component Titles\n", "\n", "The titles of each card may also contain HTML or render Panel components:" ] }, { "cell_type": "code", "execution_count": null, "id": "0b8397a0-2f76-455f-b6b0-af0d5f154733", "metadata": {}, "outputs": [], "source": [ "component_title = pmui.Row(\n", " pmui.IconButton(icon='show_chart', size='small', margin=(10, 0)),\n", " '#### Line'\n", ")\n", "\n", "line = figure(width=300, height=300, name='Line')\n", "line.line([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0])\n", "\n", "html_title = \"\"\"\n", "

\n", " square\n", " Square\n", "

\"\"\"\n", "\n", "square = figure(width=300, height=300, name='Square')\n", "square.scatter([0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 2, 1, 0], marker='square', size=10)\n", "\n", "pmui.Tabs(\n", " (component_title, line),\n", " (html_title, square)\n", ")" ] }, { "cell_type": "markdown", "id": "f99e01bb-ed31-45cc-9ce9-cdf4ee2890e7", "metadata": {}, "source": [ "#### ``active``" ] }, { "cell_type": "markdown", "id": "14bcbfda-ca7b-40cf-9237-90d9101df5fb", "metadata": {}, "source": [ "In addition to being able to modify the ``objects`` using methods we can also get and set the currently ``active`` tab as an integer, which will update any rendered views of the object:" ] }, { "cell_type": "code", "execution_count": null, "id": "ea2518a9-ab69-4d5f-9844-780f3bbe23f8", "metadata": {}, "outputs": [], "source": [ "print(tabs.active)\n", "tabs.active = 0" ] }, { "cell_type": "markdown", "id": "9b8df613-d901-4574-914e-40b76dd191a8", "metadata": {}, "source": [ "#### ``dynamic``\n", "\n", "When enabled the dynamic option ensures that only the active tab is actually rendered, only when switching to a new Tab are the contents loaded. This can be very helpful in a server context or notebook context when displaying a lot of tabs or when rendering the individual objects are very large or expensive to render. Note however that without a live server the contents of the non-active tab will never load:" ] }, { "cell_type": "code", "execution_count": null, "id": "c4771a4c-79fb-4ad4-9a75-a34f325274f7", "metadata": {}, "outputs": [], "source": [ "tabs = pmui.Tabs(p1, p2, p3, dynamic=True)\n", "\n", "tabs" ] }, { "cell_type": "markdown", "id": "34679e09-e34f-41a4-b9e1-e898c20d5bfb", "metadata": {}, "source": [ "If you want the `Tabs` to be completely lazy when rendering some output you can leverage a [ParamFunction or ParamMethod](../../user_guide/Param.ipynb) to ensure that the output is not computed until you navigate to the tab:" ] }, { "cell_type": "code", "execution_count": null, "id": "31c46f9b-f739-4374-812a-86278cada0a1", "metadata": {}, "outputs": [], "source": [ "import time\n", "import numpy as np\n", "\n", "def plot():\n", " time.sleep(1) # some long running calculation\n", " np.random.seed(tabs.active)\n", " xs, ys = np.random.randn(2, 100)\n", " p = figure(width=300, height=300, name=f'Scatter Seed {tabs.active}')\n", " p.scatter(xs, ys)\n", " return p\n", "\n", "p1 = pn.param.ParamFunction(plot, lazy=True, name='Seed 0')\n", "p2 = pn.param.ParamFunction(plot, lazy=True, name='Seed 1')\n", "p3 = pn.param.ParamFunction(plot, lazy=True, name='Seed 2')\n", "\n", "tabs = pmui.Tabs(p1, p2, p3, dynamic=True)\n", "\n", "tabs" ] }, { "cell_type": "markdown", "id": "294a489b-36f8-4a9d-839e-80c7c1d77adc", "metadata": {}, "source": [ "#### ``closable``\n", "\n", "``Tabs`` may also be initialized as ``closable``, which provides an `x` widget in the GUI that makes it possible to remove tabs and therefore remove them from the list of ``objects``:" ] }, { "cell_type": "code", "execution_count": null, "id": "2640fa48-3c1a-4d32-9e53-6f0d8155da0d", "metadata": {}, "outputs": [], "source": [ "tabs = pmui.Tabs(\n", " ('red', pn.Spacer(styles=dict(background='red'), width=100, height=100)),\n", " ('blue', pn.Spacer(styles=dict(background='blue'), width=100, height=100)),\n", " ('green', pn.Spacer(styles=dict(background='green'), width=100, height=100)),\n", " closable=True\n", ")\n", "\n", "tabs" ] }, { "cell_type": "markdown", "id": "dc39a3f2-a83b-4105-bd5a-f7d991ac83f9", "metadata": {}, "source": [ "#### ``tabs_location``\n", "\n", "Lastly, it is possible to modify the location of the tabs header relative to the content using the ``tabs_location`` parameter:" ] }, { "cell_type": "code", "execution_count": null, "id": "49396370-ae82-40e8-9339-60313968c4b2", "metadata": {}, "outputs": [], "source": [ "pmui.Row(tabs, tabs.clone(active=1, tabs_location='right'), tabs.clone(active=2, tabs_location='below'), tabs.clone(tabs_location='left'))" ] } ], "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": 5 }