leda


Nameleda JSON
Version 0.5.0 PyPI version JSON
download
home_pagehttps://github.com/ansatzcapital/leda
SummaryGenerate static reports from Jupyter notebooks
upload_time2024-02-25 16:12:46
maintainer
docs_urlNone
author
requires_python>=3.8
licenseApache License 2.0
keywords reports jupyter notebooks data visualization
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # leda

Generate static HTML reports with interactive widgets from Jupyter notebooks

[![PyPI version](https://badge.fury.io/py/leda.svg)](https://badge.fury.io/py/leda)
[![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/leda.svg)](https://pypi.python.org/pypi/leda/)
[![GitHub Actions (Tests)](https://github.com/ansatzcapital/leda/workflows/Test/badge.svg)](https://github.com/ansatzcapital/leda)

## Installation

`leda` is available on [PyPI](https://pypi.org/project/leda/):

```bash
pip install leda
```

## Quick Start

### Generation

To generate a static HTML report from a Jupyter notebook, run:

```bash
python -m leda /path/to/nb.ipynb --output-dir ./outputs/

# Optional args:
python -m leda /path/to/nb.ipynb --output-dir ./outputs/ \
    -i "abc = 123" -k "other_kernel" --cell-timeout 100
```

This generation automatically includes tweaks to the notebook to make
the output look more report-like (e.g., hiding all input code)

See the [**static demos**](https://ansatzcapital.github.io/leda/leda/tests/integration/refs/) 
being served by GitHub Pages.

`leda` is like:
- [`voila`](https://voila.readthedocs.io/en/stable/using.html), 
but static, with no need for live kernels
- [`nbconvert`](https://github.com/jupyter/nbconvert)/
[`nbviewer`](https://nbviewer.org/), but with interactive widgets
- [`quarto`](https://quarto.org/), 
but with interactive widgets
- [`papermill`](https://papermill.readthedocs.io/en/latest/),
but with interactive widgets
- [`pretty-jupyter`](https://github.com/JanPalasek/pretty-jupyter), 
but with interactive widgets

The `-i` (`--inject`) arg is used to inject user code (and set report params) 
via a new cell prepended to the notebook during generation.

And the `--template_name`/`--theme` args allow you to choose between 
`classic`, `lab` (`light`/`dark`), and `lab_narrow` (`light`/`dark`).

**Note**: `leda` assumes that all code is run in a trusted environment, 
so please be careful.

### Interaction/Widgets

`leda` also provides an `%%interact` [magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html)
that makes it easy to create outputs based on widgets that work in both dynamic
and static modes, e.g.:

```python
# In[ ]:


import leda
import numpy as np
import pandas as pd


# In[ ]:


leda.init("matplotlib")  # Loads `interact` magic when running in Jupyter notebook


# In[ ]:


%%interact column=list("abcdefghij");mult=[1, 2, 3]
df = pd.DataFrame(
  np.random.RandomState(42).rand(100, 10), columns=list("abcdefghij")
)
title = f"column={column!r}, mult={mult}"
(df[[column]] * mult).plot(figsize=(15, 8), lw=2, title=title)
```

There are two types of interact modes: dynamic and static. 

**Dynamic mode** is when you're running the Jupyter notebook
live, in which case you will re-compute the cell output 
every time you select a different `mult`. We always use
[`ipywidgets`](https://ipywidgets.readthedocs.io/en/stable/) as the 
dynamic widget backend.

In a **static mode** (using whichever static widget backend is configured), 
the library will pre-compute all possible combinations of widget outputs 
([see Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product))
and then render a static HTML report that contains widgets 
that look and feel like the dynamic widgets (despite being pre-rendered).
See below for a list of supported static backends.

### Report Web UI Server

Unlike [`voila`](https://voila.readthedocs.io/en/stable/using.html), 
because all report output is _static HTML_,
you can stand up a report web UI server that suits your needs very easily. 
That means:
- It's trivial to set up in many cases.
- It's as scalable as your web server's ability to distribute static content.
- It's more cost-efficient because there are no runtimes whatsoever.
- You don't have to worry about old versions no longer working 
due to code or data changes, so the historical
archive of old reports never expires or changes or breaks.

For example, you can generate the report to a file, 
upload that file to a shared location, and then stand
up a bare-bones `nginx` server to serve the files. 
Instead of having a two-step process of generation + upload,
you could alternatively implement your own `leda.ReportPublisher` 
and create a generation script of your own--or use it as a library
in client script.

Another example is you can simply host a static S3 bucket, 
enable website hosting and then either use S3 as a web server 
publically or via locked down S3 endpoint.

You could also use [GitHub Pages](https://pages.github.com), 
much like the [static demos page](https://ansatzcapital.github.io/leda/leda/tests/integration/refs/).

### Params

Reports can be parametrized so that the user can set 
different values for each report run.

In the notebook, just use `leda.get_param()`:

```python
# In[ ]: 


import leda


# In[ ]: 


data_id = leda.get_param("data_id", dynamic_default=1, static_default=2)
```

And then change the injected code during each run:

```bash
python -m leda /path/to/nb.ipynb --output ./outputs/ -i "data_id = 100"
```

### Modular

`leda` is built to work with multiple visualization and widget libraries.

It works with these visualization libraries:
- [`matplotlib`](https://matplotlib.org/)
- [`plotly`](https://plotly.com/python/)

With the default dynamic widget library:
- [`ipywidgets`](https://ipywidgets.readthedocs.io/en/stable/)

And with these static widget libraries:
- [`static_ipywidgets`](https://github.com/jakevdp/ipywidgets-static) 
(vendored and modified)
- [`panel`](https://panel.holoviz.org/)

## Testing

See the `requirements-bundle*.txt` for version bundles 
that we currently test systematically.

## Known Issues

- There are multiple issues using `matplotlib` with `panel`, including:
  - The last widget output is not different from the penultimate one: https://github.com/holoviz/panel/issues/1222
  - All the widget outputs show up sequentially, 
    instead of being hidden until chosen. 
    This seems to be a known issue per the [`panel` FAQ](https://panel.holoviz.org/FAQ.html); 
    however, using the example fix provided does not work.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ansatzcapital/leda",
    "name": "leda",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "reports, Jupyter, notebooks, data visualization",
    "author": "",
    "author_email": "",
    "download_url": "",
    "platform": "any",
    "description": "# leda\n\nGenerate static HTML reports with interactive widgets from Jupyter notebooks\n\n[![PyPI version](https://badge.fury.io/py/leda.svg)](https://badge.fury.io/py/leda)\n[![PyPI Supported Python Versions](https://img.shields.io/pypi/pyversions/leda.svg)](https://pypi.python.org/pypi/leda/)\n[![GitHub Actions (Tests)](https://github.com/ansatzcapital/leda/workflows/Test/badge.svg)](https://github.com/ansatzcapital/leda)\n\n## Installation\n\n`leda` is available on [PyPI](https://pypi.org/project/leda/):\n\n```bash\npip install leda\n```\n\n## Quick Start\n\n### Generation\n\nTo generate a static HTML report from a Jupyter notebook, run:\n\n```bash\npython -m leda /path/to/nb.ipynb --output-dir ./outputs/\n\n# Optional args:\npython -m leda /path/to/nb.ipynb --output-dir ./outputs/ \\\n    -i \"abc = 123\" -k \"other_kernel\" --cell-timeout 100\n```\n\nThis generation automatically includes tweaks to the notebook to make\nthe output look more report-like (e.g., hiding all input code)\n\nSee the [**static demos**](https://ansatzcapital.github.io/leda/leda/tests/integration/refs/) \nbeing served by GitHub Pages.\n\n`leda` is like:\n- [`voila`](https://voila.readthedocs.io/en/stable/using.html), \nbut static, with no need for live kernels\n- [`nbconvert`](https://github.com/jupyter/nbconvert)/\n[`nbviewer`](https://nbviewer.org/), but with interactive widgets\n- [`quarto`](https://quarto.org/), \nbut with interactive widgets\n- [`papermill`](https://papermill.readthedocs.io/en/latest/),\nbut with interactive widgets\n- [`pretty-jupyter`](https://github.com/JanPalasek/pretty-jupyter), \nbut with interactive widgets\n\nThe `-i` (`--inject`) arg is used to inject user code (and set report params) \nvia a new cell prepended to the notebook during generation.\n\nAnd the `--template_name`/`--theme` args allow you to choose between \n`classic`, `lab` (`light`/`dark`), and `lab_narrow` (`light`/`dark`).\n\n**Note**: `leda` assumes that all code is run in a trusted environment, \nso please be careful.\n\n### Interaction/Widgets\n\n`leda` also provides an `%%interact` [magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html)\nthat makes it easy to create outputs based on widgets that work in both dynamic\nand static modes, e.g.:\n\n```python\n# In[ ]:\n\n\nimport leda\nimport numpy as np\nimport pandas as pd\n\n\n# In[ ]:\n\n\nleda.init(\"matplotlib\")  # Loads `interact` magic when running in Jupyter notebook\n\n\n# In[ ]:\n\n\n%%interact column=list(\"abcdefghij\");mult=[1, 2, 3]\ndf = pd.DataFrame(\n  np.random.RandomState(42).rand(100, 10), columns=list(\"abcdefghij\")\n)\ntitle = f\"column={column!r}, mult={mult}\"\n(df[[column]] * mult).plot(figsize=(15, 8), lw=2, title=title)\n```\n\nThere are two types of interact modes: dynamic and static. \n\n**Dynamic mode** is when you're running the Jupyter notebook\nlive, in which case you will re-compute the cell output \nevery time you select a different `mult`. We always use\n[`ipywidgets`](https://ipywidgets.readthedocs.io/en/stable/) as the \ndynamic widget backend.\n\nIn a **static mode** (using whichever static widget backend is configured), \nthe library will pre-compute all possible combinations of widget outputs \n([see Cartesian product](https://en.wikipedia.org/wiki/Cartesian_product))\nand then render a static HTML report that contains widgets \nthat look and feel like the dynamic widgets (despite being pre-rendered).\nSee below for a list of supported static backends.\n\n### Report Web UI Server\n\nUnlike [`voila`](https://voila.readthedocs.io/en/stable/using.html), \nbecause all report output is _static HTML_,\nyou can stand up a report web UI server that suits your needs very easily. \nThat means:\n- It's trivial to set up in many cases.\n- It's as scalable as your web server's ability to distribute static content.\n- It's more cost-efficient because there are no runtimes whatsoever.\n- You don't have to worry about old versions no longer working \ndue to code or data changes, so the historical\narchive of old reports never expires or changes or breaks.\n\nFor example, you can generate the report to a file, \nupload that file to a shared location, and then stand\nup a bare-bones `nginx` server to serve the files. \nInstead of having a two-step process of generation + upload,\nyou could alternatively implement your own `leda.ReportPublisher` \nand create a generation script of your own--or use it as a library\nin client script.\n\nAnother example is you can simply host a static S3 bucket, \nenable website hosting and then either use S3 as a web server \npublically or via locked down S3 endpoint.\n\nYou could also use [GitHub Pages](https://pages.github.com), \nmuch like the [static demos page](https://ansatzcapital.github.io/leda/leda/tests/integration/refs/).\n\n### Params\n\nReports can be parametrized so that the user can set \ndifferent values for each report run.\n\nIn the notebook, just use `leda.get_param()`:\n\n```python\n# In[ ]: \n\n\nimport leda\n\n\n# In[ ]: \n\n\ndata_id = leda.get_param(\"data_id\", dynamic_default=1, static_default=2)\n```\n\nAnd then change the injected code during each run:\n\n```bash\npython -m leda /path/to/nb.ipynb --output ./outputs/ -i \"data_id = 100\"\n```\n\n### Modular\n\n`leda` is built to work with multiple visualization and widget libraries.\n\nIt works with these visualization libraries:\n- [`matplotlib`](https://matplotlib.org/)\n- [`plotly`](https://plotly.com/python/)\n\nWith the default dynamic widget library:\n- [`ipywidgets`](https://ipywidgets.readthedocs.io/en/stable/)\n\nAnd with these static widget libraries:\n- [`static_ipywidgets`](https://github.com/jakevdp/ipywidgets-static) \n(vendored and modified)\n- [`panel`](https://panel.holoviz.org/)\n\n## Testing\n\nSee the `requirements-bundle*.txt` for version bundles \nthat we currently test systematically.\n\n## Known Issues\n\n- There are multiple issues using `matplotlib` with `panel`, including:\n  - The last widget output is not different from the penultimate one: https://github.com/holoviz/panel/issues/1222\n  - All the widget outputs show up sequentially, \n    instead of being hidden until chosen. \n    This seems to be a known issue per the [`panel` FAQ](https://panel.holoviz.org/FAQ.html); \n    however, using the example fix provided does not work.\n",
    "bugtrack_url": null,
    "license": "Apache License 2.0",
    "summary": "Generate static reports from Jupyter notebooks",
    "version": "0.5.0",
    "project_urls": {
        "Homepage": "https://github.com/ansatzcapital/leda",
        "Packaging": "https://pypi.org/project/leda/",
        "Source": "https://github.com/ansatzcapital/leda",
        "Tracker": "https://github.com/ansatzcapital/leda/issues"
    },
    "split_keywords": [
        "reports",
        " jupyter",
        " notebooks",
        " data visualization"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4f9d3072181abc5598aaf1472e32b10b8ac296720cf86a15ce9947eedb336f00",
                "md5": "2038e4ad5252c09d4a167972ac00db50",
                "sha256": "2a05237dbc4d7b910d186e4a886813ca24888419b0e41133cacf1d10da9444d7"
            },
            "downloads": -1,
            "filename": "leda-0.5.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2038e4ad5252c09d4a167972ac00db50",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 39686,
            "upload_time": "2024-02-25T16:12:46",
            "upload_time_iso_8601": "2024-02-25T16:12:46.731513Z",
            "url": "https://files.pythonhosted.org/packages/4f/9d/3072181abc5598aaf1472e32b10b8ac296720cf86a15ce9947eedb336f00/leda-0.5.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-25 16:12:46",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ansatzcapital",
    "github_project": "leda",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "leda"
}
        
Elapsed time: 0.18826s