{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "import tempfile\n", "\n", "import panel as pn\n", "import panel_material_ui as pmui\n", "\n", "pn.extension()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `FileDownload` widget allows downloading a file on the frontend by sending the file data to the browser either on initialization (if `embed=True`) or when the button is clicked.\n", "\n", "Discover more on using widgets to add interactivity to your applications in the [how-to guides on interactivity](https://panel.holoviz.org/how_to/interactivity/index.html). Alternatively, learn [how to set up callbacks and (JS-)links between parameters](https://panel.holoviz.org/how_to/links/index.html) or [how to use them as part of declarative UIs with Param](https://panel.holoviz.org/how_to/param/index.html).\n", "\n", "#### Parameters:\n", "\n", "For details on other options for customizing the component see the [customization guides](https://panel-material-ui.holoviz.org/customization/index.html).\n", "\n", "##### Core\n", "\n", "* **`auto`** (boolean): Whether to download the file with the first click (if `True`) or only after clicking a second time (if `False`, enables right-click -> Save as).\n", "* **`callback`** (callable): A callable that returns a file or file-like object (takes precedence over `file` if set). \n", "* **`embed`** (boolean): Whether to embed the data on initialization.\n", "* **`file`** (str, Path or file-like object): A path to a file or a file-like object.\n", "* **`filename`** (str): The filename to save the file as.\n", "\n", "##### Display\n", "\n", "* **`color`** (str): The color variant of the button, which must be one of `'default'` (white), `'primary'` (blue), `'success'` (green), `'info'` (yellow), `'light'` (light), or `'danger'` (red).\n", "* **`description`** (str | Bokeh Tooltip | pn.widgets.TooltipIcon): A description which is shown when the widget is hovered.\n", "* **`disable_elevation`** (boolean): Whether to apply elevation to the `Button` to visually separate it from the background.\n", "* **`end_icon`** (str): An icon to render to the right of the button label. Either an SVG or an icon name which is loaded from [Material UI Icons](https://mui.com/material-ui/material-icons).\n", "* **`icon`** (str): An icon to render to the left of the button label. Either an SVG or an icon name which is loaded from [Material UI Icons](https://mui.com/material-ui/material-icons).\n", "* **`icon_size`** (str): Size of the icon as a string, e.g. 12px or 1em.\n", "* **`label`** (str): A custom label for the download button (by default uses the filename)\n", "* **`variant`** (str): The button style, either 'contained', 'outlined', 'text'.\n", "\n", "##### Styling\n", "\n", "- **`sx`** (dict): Component level styling API.\n", "- **`theme_config`** (dict): Theming API.\n", "\n", "##### Aliases\n", "\n", "For compatibility with Panel certain parameters are allowed as aliases:\n", "\n", "- **`button_style`**: Alias for `variant`\n", "- **`button_type`**: Alias for `color`\n", "- **`name`**: Alias for `label`\n", "\n", "___" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic Usage" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `FileDownload` widget accepts a path to a file or a file-like object (with a `.read` method) if the latter is provided a `filename` must also be set. By default (`auto=True` and `embed=False`) the file is only transferred to the browser after the button is clicked (this requires a live-server or notebook kernel):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "# Write file\n", "tmp = tempfile.NamedTemporaryFile(prefix='hello_', suffix='.txt', delete=False)\n", "text = \"\"\"\n", "Hello!\n", "\"\"\".encode('utf-8')\n", "tmp.write(text)\n", "tmp.seek(0)\n", "\n", "file_download = pmui.FileDownload(file=tmp.name)\n", "\n", "file_download" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Embedding data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The file data may also be embedded immediately using `embed` parameter, this allows using the widget even in a static export (such as in these docs):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "pmui.FileDownload(file=tmp.name, filename='hello.txt', embed=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Request data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If `auto=False` is set the file will not be downloaded on the initial click but will change the label from \"Transfer \" to \"Download \" once the data has been synced. This offers an opportunity to download using the `Save as` dialog once the data has been transferred." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "pmui.FileDownload(\n", " file=tmp.name, filename='hello.txt', button_type='success', auto=False, embed=False\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### In-memory files\n", "\n", "The `FileDownload` widget may also be given a file-like object, e.g. here we save a `pandas.DataFrame` as a CSV to a `StringIO` object and pass that to the widget:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "from bokeh.sampledata.autompg import autompg\n", "\n", "from io import StringIO\n", "sio = StringIO()\n", "autompg.to_csv(sio)\n", "sio.seek(0)\n", "\n", "pmui.FileDownload(file=sio, embed=True, filename='autompg.csv')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ":::note\n", "When providing an in-memory file object you must define a `filename`.\n", "::" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dynamic data\n", "\n", "If you want to generate the file dynamically, e.g. because it depends on the parameters of some widget you can also supply a callback (which may be decorated with the widgets and/or parameters it depends on):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "years_options = list(autompg.yr.unique())\n", "years = pmui.MultiChoice(\n", " label='Years', options=years_options, value=[years_options[0]], margin=(0, 20, 0, 0)\n", ")\n", "mpg = pmui.RangeSlider(\n", " label='Mile per Gallon', start=autompg.mpg.min(), end=autompg.mpg.max()\n", ")\n", "\n", "def filtered_mpg(yrs, mpg):\n", " df = autompg\n", " if years.value:\n", " df = autompg[autompg.yr.isin(yrs)]\n", " return df[(df.mpg >= mpg[0]) & (df.mpg <= mpg[1])]\n", "\n", "def filtered_file(yr, mpg):\n", " df = filtered_mpg(yr, mpg)\n", " sio = StringIO()\n", " df.to_csv(sio)\n", " sio.seek(0)\n", " return sio\n", "\n", "fd = pmui.FileDownload(\n", " callback=pn.bind(filtered_file, years, mpg), filename='filtered_autompg.csv'\n", ")\n", "\n", "pmui.Column(\n", " pmui.Row(years, mpg),\n", " fd,\n", " pn.pane.DataFrame(pn.bind(filtered_mpg, years, mpg), width=600),\n", " width=600, margin=10\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Disabled and Loading\n", "\n", "Like any other widget the `Button` can be `disabled` and / or set to `loading`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.FileDownload(label=\"Loading\", disabled=True, loading=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sizes\n", "\n", "For larger or smaller buttons, use the `size` parameter." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.Row(\n", " pmui.FileDownload(size=\"small\", label=\"Small\", file=tmp.name), \n", " pmui.FileDownload(size=\"medium\", label=\"Medium\", file=tmp.name),\n", " pmui.FileDownload(size=\"large\", label=\"Large\", file=tmp.name)\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Colors and Variants\n", "\n", "The color of the `FileDownload` button can be set by selecting one of the available `color` values and the `variant` can be `'filled'`, `'outlined'` or `'text'`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.Row(\n", " *(pmui.Column(*(\n", " pmui.FileDownload(color=color, variant=variant, file=f'{color}.png', width=225)\n", " for color in pmui.Button.param.color.objects\n", " ))\n", " for variant in pmui.Button.param.variant.objects)\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Icons\n", "\n", "However you can also provide an explicit `icon`, either as a named icon loaded from [Material Icons](https://fonts.google.com/icons?icon.set=Material+Icons):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.Row(\n", " pmui.FileDownload(icon='warning', color='warning', file='FileDownload.ipynb'),\n", " pmui.FileDownload(icon='bug_report', color='error', file='FileDownload.ipynb')\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "or as an explicit SVG:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "search_icon = \"\"\"\n", "\n", "\"\"\"\n", "\n", "pmui.Row(\n", " pmui.FileDownload(icon=search_icon, icon_size='1em', label='Search', variant=\"outlined\"),\n", " pmui.FileDownload(icon=search_icon, icon_size='2em', label='Search', variant=\"contained\"),\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also provide an end icon:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pmui.FileDownload(variant=\"contained\", end_icon=\"send_icon\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### API Reference\n", "\n", "The `FileDownload` widget exposes a number of options which can be changed from both Python and Javascript. Try out the effect of these parameters interactively:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "file_download.api(jslink=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### References\n", "\n", "**Panel Documentation:**\n", "\n", "- [How-to guides on interactivity](https://panel.holoviz.org/how_to/interactivity/index.html) - Learn how to add interactivity to your applications using widgets\n", "- [Setting up callbacks and links](https://panel.holoviz.org/how_to/links/index.html) - Connect parameters between components and create reactive interfaces\n", "- [Declarative UIs with Param](https://panel.holoviz.org/how_to/param/index.html) - Build parameter-driven applications\n", "\n", "**Material UI Button:**\n", "\n", "- [Material UI Button Reference](https://mui.com/material-ui/react-button/) - Complete documentation for the underlying Material UI component\n", "- [Material UI Button API](https://mui.com/material-ui/api/button/) - Detailed API reference and configuration options" ] } ], "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 }