{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "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",
    "For more information about listening to widget events and laying out widgets refer to the [widgets user guide](../../user_guide/Widgets.ipynb). Alternatively you can learn how to build GUIs by declaring parameters independently of any specific widgets in the [param user guide](../../user_guide/Param.ipynb). To express interactivity entirely using Javascript without the need for a Python server take a look at the [links user guide](../../user_guide/Param.ipynb).\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "For layout and styling related parameters see the [customization user guide](../../user_guide/Customization.ipynb).\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": {},
   "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": {},
   "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 \"Tranfer <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": {},
   "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": {},
   "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": {},
   "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",
    "@pn.depends(years, mpg)\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",
    "@pn.depends(years, mpg)\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=filtered_file, filename='filtered_autompg.csv'\n",
    ")\n",
    "\n",
    "pn.Column(pn.Row(years, mpg), fd, pn.panel(filtered_mpg, width=600), width=600)"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
