.. _report-elements: =================== Elements and Assets =================== Element Catalog =============== :mod:`coco_pipe.report.elements` provides 19 reusable HTML primitives. Every section adder in the report module — and any custom adder you write — ultimately renders one or more of these. The primitives are data-first: they accept Python objects (DataFrames, Plotly figures, strings, byte buffers) and emit standalone HTML. All elements share a common contract: - Subclass of :class:`~coco_pipe.report.elements.Element`. - ``render() -> str`` returns an HTML fragment. - ``collect_payload(registry)`` (optional) pushes heavy data into the global registry under a UUID; the rendered fragment references that UUID via ``data-id``. --- 1. Catalog at a Glance ---------------------- .. list-table:: :header-rows: 1 * - Element - Use * - :class:`~coco_pipe.report.elements.HtmlElement` - Raw HTML string passthrough. * - :class:`~coco_pipe.report.elements.ImageElement` - Base64-encoded image from bytes, file, ``Path``, or a matplotlib :class:`~matplotlib.figure.Figure`. * - :class:`~coco_pipe.report.elements.PlotlyElement` - Plotly figure with lazy hydration. * - :class:`~coco_pipe.report.elements.TableElement` - Static HTML table from a DataFrame / dict / list. * - :class:`~coco_pipe.report.elements.InteractiveTableElement` - Searchable, sortable, paged table with CSV export. * - :class:`~coco_pipe.report.elements.MetricsTableElement` - Table with per-column "best" highlighting. * - :class:`~coco_pipe.report.elements.StatCardElement` - Big-number stat with delta and unit. * - :class:`~coco_pipe.report.elements.CalloutElement` - Boxed info/warning/error/success message. * - :class:`~coco_pipe.report.elements.CodeBlockElement` - Syntax-tagged ``
`` with copy.
   * - :class:`~coco_pipe.report.elements.MarkdownElement`
     - Markdown → HTML (graceful fallback).
   * - :class:`~coco_pipe.report.elements.BadgeElement`
     - Pill label with color.
   * - :class:`~coco_pipe.report.elements.ProgressBarElement`
     - Inline progress bar.
   * - :class:`~coco_pipe.report.elements.TimelineElement`
     - Ordered list of timestamped events.
   * - :class:`~coco_pipe.report.elements.TabsElement`
     - Tabbed container holding other elements.
   * - :class:`~coco_pipe.report.elements.AccordionElement`
     - ``
``-backed collapsible section. * - :class:`~coco_pipe.report.elements.ColumnsElement` - CSS-grid row of side-by-side elements. * - :class:`~coco_pipe.report.elements.ContainerElement` - Base class for any container; itself adds ``add_element`` / ``add_markdown``. * - :class:`~coco_pipe.report.elements.DownloadAssetElement` - ```` button backed by inline base64 payload (CSV, JSON, bytes). * - :class:`~coco_pipe.report.elements.Element` - Abstract base; subclass for custom widgets. --- 2. Data Elements ---------------- 2.1 ``HtmlElement`` ~~~~~~~~~~~~~~~~~~~ Bare HTML wrapper — bypass the typed elements when you need a one-off fragment. .. code-block:: python from coco_pipe.report.elements import HtmlElement sec.add_element(HtmlElement("
raw HTML
")) 2.2 ``ImageElement`` ~~~~~~~~~~~~~~~~~~~~ Embeds any image as a base64 data URI. Accepts: - ``bytes`` — raw image bytes (any format the browser supports). - ``str`` or :class:`~pathlib.Path` — read from disk. - :class:`~matplotlib.figure.Figure` — saved at 150 DPI to PNG. .. code-block:: python from coco_pipe.report.elements import ImageElement ImageElement(matplotlib_fig, caption="ROC curve", width="600px") ImageElement(Path("logo.png")) ImageElement(raw_bytes) # accepts any browser-supported image format Every image also emits an inline "Download PNG" link so the reader can extract the asset. 2.3 ``PlotlyElement`` ~~~~~~~~~~~~~~~~~~~~~ Plotly figure with lazy hydration: the figure JSON is collected into the global payload registry; the rendered HTML emits a ``
`` placeholder. The browser hydrates each placeholder when it scrolls into view. .. code-block:: python import plotly.graph_objects as go from coco_pipe.report.elements import PlotlyElement fig = go.Figure(data=[go.Scatter(x=[1, 2], y=[3, 4])]) sec.add_element(PlotlyElement(fig, height="400px")) PlotlyElement understands Plotly's optimization that base64-encodes large numeric arrays (``{"dtype": "f8", "bdata": "…"}``) and decodes them so the rendered JSON is roundtrip-stable. 2.4 ``TableElement`` ~~~~~~~~~~~~~~~~~~~~ Static HTML table. Accepts a DataFrame, a dict (rendered as one-row key/value), a list of records, or a dict of lists. .. code-block:: python from coco_pipe.report.elements import TableElement TableElement(scores_df, title="Per-fold scores") TableElement({"Accuracy": 0.84, "ROC AUC": 0.91}) TableElement([{"x": 1}, {"x": 2}]) Tables include an inline "Download CSV" button. 2.5 ``InteractiveTableElement`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Same input as :class:`TableElement` but client-side searchable, sortable, paged, with per-column "selector" dropdowns. Useful for exploratory tables with hundreds of rows. .. code-block:: python from coco_pipe.report.elements import InteractiveTableElement InteractiveTableElement( big_df, selector_columns=["dataset", "model"], default_sort={"column": "score", "direction": "desc"}, page_size=25, ) 2.6 ``MetricsTableElement`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ A :class:`TableElement` that highlights the "best" value in each metric column. Pass ``higher_is_better=`` to control direction per column (``True`` / ``False`` / per-column list). .. code-block:: python from coco_pipe.report.elements import MetricsTableElement MetricsTableElement( scores_df, highlight_cols=["accuracy", "log_loss"], higher_is_better=["accuracy"], # lower is better for log_loss ) --- 3. UI Primitives ---------------- 3.1 ``StatCardElement`` ~~~~~~~~~~~~~~~~~~~~~~~ Large-number card with unit, delta, and a color tag. Use :meth:`Report.add_summary_card` to render a row of these at the top of a report. .. code-block:: python from coco_pipe.report.elements import StatCardElement StatCardElement("Accuracy", 0.95, unit="%", delta="+2.1%", color="green") 3.2 ``CalloutElement`` ~~~~~~~~~~~~~~~~~~~~~~ Boxed message with an icon. ``kind`` is one of ``"info"``, ``"warning"``, ``"error"``, ``"success"``. .. code-block:: python from coco_pipe.report.elements import CalloutElement CalloutElement("Result includes 3 outliers.", kind="warning", title="Outliers detected") 3.3 ``CodeBlockElement`` ~~~~~~~~~~~~~~~~~~~~~~~~ Syntax-tagged ``
`` block. Adds a "Copy" button when
``copyable=True``.

.. code-block:: python

   from coco_pipe.report.elements import CodeBlockElement

   CodeBlockElement(
       'reducer.fit(X, y=labels)',
       language="python",
       title="Reproducer",
       copyable=True,
   )

3.4 ``MarkdownElement``
~~~~~~~~~~~~~~~~~~~~~~~

Markdown → HTML using the ``markdown`` package when available; falls
back to ``
`` rendering when not.

.. code-block:: python

   from coco_pipe.report.elements import MarkdownElement

   MarkdownElement("# Notes\n* Item 1\n* Item 2")

3.5 ``BadgeElement`` / ``ProgressBarElement`` / ``TimelineElement``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

   from coco_pipe.report.elements import (
       BadgeElement, ProgressBarElement, TimelineElement,
   )

   BadgeElement("Experimental", color="red")
   ProgressBarElement(value=75, max_value=100, label="Accuracy", color="green")
   TimelineElement([
       {"title": "Start",  "time": "10:00", "description": "Fit reducer"},
       {"title": "End",    "time": "10:42", "description": "Score complete",
        "status": "green"},
   ])

---

4. Layout Primitives
--------------------

4.1 ``TabsElement``
~~~~~~~~~~~~~~~~~~~

Tabbed container; keys are tab labels, values are any element.

.. code-block:: python

   from coco_pipe.report.elements import TabsElement, PlotlyElement

   TabsElement({
       "ROC":    PlotlyElement(roc_fig),
       "PR":     PlotlyElement(pr_fig),
       "Calibr": PlotlyElement(cal_fig),
   })

4.2 ``AccordionElement``
~~~~~~~~~~~~~~~~~~~~~~~~

Collapsible section backed by ``
``. .. code-block:: python from coco_pipe.report.elements import AccordionElement, CodeBlockElement acc = AccordionElement("Show training script", open=False) acc.add_element(CodeBlockElement(open("train.py").read(), language="python")) sec.add_element(acc) 4.3 ``ColumnsElement`` ~~~~~~~~~~~~~~~~~~~~~~ CSS-grid row. Sub-elements are placed side by side. .. code-block:: python from coco_pipe.report.elements import ColumnsElement, PlotlyElement ColumnsElement( [PlotlyElement(roc_fig), PlotlyElement(pr_fig)], cols=2, gap="gap-4", ) :meth:`Section.add_columns` is a shortcut for the same pattern. 4.4 ``ContainerElement`` ~~~~~~~~~~~~~~~~~~~~~~~~ Base class. :class:`Section` and :class:`Report` inherit from it. Useful when subclassing for custom containers. --- 5. Download Helpers ------------------- ``DownloadAssetElement`` embeds binary or text payloads as base64 data and produces a ```` link. Useful for shipping the source data alongside the chart. .. code-block:: python from coco_pipe.report.elements import DownloadAssetElement DownloadAssetElement( data=csv_bytes, filename="scores.csv", mime_type="text/csv", label="Download per-fold scores", style="gray", ) The payload is captured into the global registry and decoded on-demand when the user clicks; the HTML stays small. --- 6. Custom Elements ------------------ To add a new element type, subclass :class:`~coco_pipe.report.elements.Element`: .. code-block:: python from coco_pipe.report.elements import Element class KPIElement(Element): def __init__(self, label, value): self.label, self.value = label, value def render(self) -> str: return ( f"
" f"{self.label}" f"{self.value}" f"
" ) If your element holds heavy data, override ``collect_payload`` and use ``data-id="…"`` in the rendered fragment. See :class:`PlotlyElement` and :class:`DownloadAssetElement` for canonical implementations. See :ref:`report-extensions` for binding custom adders to ``Report``. .. _report-assets: JavaScript Asset Modes ====================== Rendered reports rely on three JavaScript bundles: - **Plotly** — interactive plot rendering. - **Tailwind Play CDN** — runtime CSS compiler driven by the markup. - **pako** — gzip decompression of the embedded data payload. How those bundles are served is controlled by the ``asset_urls`` constructor argument on :class:`~coco_pipe.report.core.Report` and every factory in :mod:`coco_pipe.report.api`. --- 1. Three Modes -------------- .. list-table:: :header-rows: 1 * - ``asset_urls`` argument - Behavior * - ``None`` (default) - ```` tags. Resulting HTML opens fully offline. The current mode is exposed on the report as ``Report.asset_mode`` (``"cdn"`` / ``"custom"`` / ``"inline"``) and surfaced in the Run Info drawer. --- 2. CDN Mode (Default) --------------------- .. code-block:: python from coco_pipe.report import Report report = Report(title="Online") report.save("online.html") The rendered HTML loads: - ``https://cdn.plot.ly/plotly-2.27.0.min.js`` - ``https://cdn.tailwindcss.com`` - ``https://cdnjs.cloudflare.com/ajax/libs/pako/2.1.0/pako.min.js`` Pros: nothing to host, small HTML. Cons: requires network when the report is opened. --- 3. Self-Hosted URLs ------------------- Pass a dict to point at your own bundle URLs: .. code-block:: python report = Report( title="Self-hosted", asset_urls={ "plotly": "/static/plotly-2.27.0.min.js", "tailwind": "/static/tailwind.min.js", "pako": "/static/pako-2.1.0.min.js", }, ) Only override the URLs you want to change; unspecified slots fall back to the CDN defaults. The mode is set to ``"custom"``. Useful when your team intranet hosts vendored JS, or when you need a specific Plotly version different from the default. --- 4. Inline Mode (Fully Offline) ------------------------------ .. code-block:: python report = Report(title="Air-gapped", asset_urls="inline") report.save("standalone.html") On the first run, :func:`~coco_pipe.report._assets.get_vendored_contents` downloads the three bundles into ``~/.cache/coco-pipe/report-assets/`` and reads them as strings. The template then inlines them in ```` tags instead of ``