{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import panel as pn\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](../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",
    "* **``auto``** (boolean):  Whether to download the file the initial click (if `True`) or when clicking a second time (or via the right-click Save file menu).\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 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",
    "* **``button_type``** (str): A button theme; should be one of ``'default'`` (white), ``'primary'`` (blue), ``'success'`` (green), ``'info'`` (yellow), or ``'danger'`` (red)\n",
    "* **``label``** (str): A custom label for the download button (by default uses the filename)\n",
    "* **``name``** (str): The title of the widget\n",
    "\n",
    "___"
   ]
  },
  {
   "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": [
    "file_download = pn.widgets.FileDownload(file='FileDownload.ipynb', filename='custom_filename.ipynb')\n",
    "\n",
    "file_download"
   ]
  },
  {
   "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:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "pn.widgets.FileDownload(file='FileDownload.ipynb', embed=True)"
   ]
  },
  {
   "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 <file>\" to \"Download <file>\" 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": [
    "pn.widgets.FileDownload(\n",
    "    file='FileDownload.ipynb', button_type='success', auto=False,\n",
    "    embed=False, name=\"Right-click to download using 'Save as' dialog\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "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",
    "pn.widgets.FileDownload(sio, embed=True, filename='autompg.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "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 = pn.widgets.MultiChoice(\n",
    "    name='Years', options=years_options, value=[years_options[0]], margin=(0, 20, 0, 0)\n",
    ")\n",
    "mpg = pn.widgets.RangeSlider(\n",
    "    name='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 = pn.widgets.FileDownload(\n",
    "    callback=pn.bind(filtered_file, years, mpg), filename='filtered_autompg.csv'\n",
    ")\n",
    "\n",
    "pn.Column(\n",
    "    pn.Row(years, mpg),\n",
    "    fd,\n",
    "    pn.panel(pn.bind(filtered_mpg, years, mpg), width=600),\n",
    "    width=600\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
