Skip to main content

pl2html

A fast, secure, and zero-dependency HTML engine for Polars.

pl2html compiles Polars DataFrame and LazyFrame workflows natively into HTML table structures entirely inside the Polars expression engine. By leveraging parallelized Rust memory environments, it bypasses slow Python row loops (.map_elements), making it an incredibly lightweight alternative to styling engines like great_tables or pandas .style.

Features

  • 🚀 Native Polars Performance: Runs entirely inside the Polars expression graph. Streamable and lazy-execution friendly.
  • 🛡️ Injection-Safe by Default: Automatically neutralizes sequential HTML injection vectors using a lookahead-free, native escaping algorithm.
  • 🎨 Advanced Formatting Toolkit: Human-readable display rules for numbers, integers, currencies, percentages, scientific notations, bytes, and booleans running entirely in Rust.
  • ➡️ Multicolumn Support: All formatting and substitution functions accept a single column string or an iterable list of columns automatically.
  • 🌗 Conditional Styling & Color Scales: Native linear interpolation pipelines to generate multi-segment background color heatmaps by value or percentile rank.
  • 🌌 Auto-Contrast Accessibility: Dynamic text foreground switches (#000000 vs #FFFFFF) calculated via WCAG relative luminance algorithms on the fly.
  • 📦 Afraid of Bloat? Zero Dependencies: Cleaned of heavy packages like numpy or matplotlib. It runs entirely on pure Python and Polars.

Installation

pip install pl2html

Quick Start

1. Basic HTML Rendering with Auto-Escaping

By default, pl2html infers datatypes to securely render human-readable tables. Strings are escaped, and integers/floats automatically get localized thousands separators.

import polars as pl
from pl2html.compiler import to_html

df = pl.DataFrame(
    {
        'company': ["<script>alert('malicious')</script> Corp", 'Acme Inc.'],
        'revenue': [1420500, -50200],
        'margin': [0.0451, -0.0512],
    }
)

# Compiles safely to a Polars LazyFrame containing the HTML output
html_table_string = to_html(df)

print(html_table_string)

Output:

company revenue margin
<script>alert('malicious')</script> Corp1,420,5000.045
Acme Inc.-50,200-0.051

2. Rich Data Formatting (Natively Vectorized)

pl2html exposes high-performance formatting expressions designed to prepare columns simultaneously before passing them to to_html. Every function natively supports passing lists of multiple columns at once.

import polars as pl
from pl2html.compiler import to_html
from pl2html import formats as fmt

df = pl.DataFrame(
    {
        "asset_a": [5400600, 2100],
        "asset_b": [45100000, -850000],
        "growth": [0.1256, -0.024],
        "is_active": [True, False],
        "status_code": [0, 404]
    }
)

# Format multiple financial asset columns compactly in one pass using lists
df_f = df.with_columns(
    fmt.fmt_integer(["asset_a", "asset_b"], compact=True, compact_system="financial"),
    fmt.fmt_percent("growth", decimals=1),
    fmt.fmt_tf("is_active", tf_style="check-mark"),
    fmt.sub_zero("status_code", zero_text="OK")
)

html = to_html(df_f)

3. Advanced Styling via Native Attributes (attrs)

Instead of embedding hacky structural HTML tags in your data, use the attrs parameter to inject dynamic CSS attributes purely. Use data_color or rank_color to construct high-performance heatmaps.

import polars as pl
from pl2html.compiler import to_html
from pl2html.styles import data_color, rank_color

df = pl.DataFrame(
    {
        'employee': ['Alice', 'Bob', 'Charlie', 'David'],
        'performance_score': [98.5, 42.0, 81.2, 12.0],
        'utilization': [0.02, 0.41, 0.78, 0.22],
    }
)

styles = {}

# 1. Color Heatmap by Absolute Value (Custom 3-color palette with auto-contrast text)
styles.update(
    data_color(
        column='performance_score',
        palette=['#ff7675', '#fdcb6e', '#00b894'],
        auto_contrast=True
    )
)

# 2. Color Heatmap by Percentile Rank Order (Continuous interpolation)
styles.update(
    rank_color(
        column='utilization',
        palette=['#000000', '#FFFFFF'],
        descending=False,
        auto_contrast=True
    )
)

html_table = to_html(df, attrs=styles)

Output (github may override table colors, but they are there):

employee performance_score utilization
Alice98.50.92
Bob42.00.41
Charlie81.20.78
David12.00.22

Architecture & Module Layout

The library is explicitly divided into three decoupled layers:

1. Core Compiler (compiler.py)

Responsible for reading the dataframe schema, iterating horizontally over visible columns, and joining tokens into structural row arrays natively in Rust.

  • Exposed via to_html(df, *, attrs=None, exclude_columns=None).
  • Automatically assigns high-performance format fallbacks:
    • is_integer(): Applies thousands separator reversals.
    • is_float(): Automatically base-truncates decimal positions and breaks layout chunks smoothly.
    • Catchall: Direct pass through _escape_polars_string() to secure against cross-site scripting (XSS).

2. Format Expressions (formats.py)

Contains native string-shaping expression generators wrapped in a @_multicolumn macro to cleanly display large datasets without dropping into slow Python loops.

  • fmt_number() / fmt_integer(): Supports precision rounding, thousands separators, accounting parentheses, and financial/engineering compact suffixing (K, M, B vs k, M, G).
  • fmt_percent() / fmt_currency(): Optimized wrappers handling percentage scaling and currency masking.
  • fmt_scientific(): Natively parses mantissas and exponents with flexible styling (x10n, e, E) and forced signs.
  • fmt_bytes(): Dynamically maps byte magnitudes to decimal (kB, MB) or binary (KiB, MiB) notations.
  • fmt_tf(): Transforms booleans to presets (arrows, check-mark, circles) with native na_val null overrides.
  • sub_missing() / sub_zero(): Clean conditional data substitution expressions for nulls and exact zeros.

3. Style Utilities (styles.py)

Generates structural Polars expression payloads mapped to specific HTML style attributes.

  • data_color(column, palette, domain=None, auto_contrast=True): Evaluates column boundaries (.min() / .max()) at evaluation time and maps row values via piece-wise linear RGB interpolation.
  • rank_color(column, palette, descending=False, auto_contrast=True): Replaces absolute numerical scaling with ordinal percentile ranks to smooth out heavily skewed datasets or extreme outliers.

Every style output returns a clean nested dictionary structure ({column: {attribute: expression}}) to feed directly into to_html(attrs=...).


Security

pl2html passes untrusted data arrays through a strict sequential escaping chain natively in Rust:

.str.replace_all('&', '&amp;')
.str.replace_all('<', '&lt;')
.str.replace_all('>', '&gt;')
.str.replace_all('"', '&quot;')
.str.replace_all("'", '&#x27;')

Design Inspiration & Why This Library Exists

Most of the API design and formatting parameters in this library are heavily inspired by great-tables. If you are looking for detailed descriptions or conceptual overviews of specific formatting arguments, the great-tables reference documentation serves as an excellent companion guide.

However, this library was born out of distinct architectural and environment constraints:

  • Zero Overhead Styling: While great-tables is incredibly feature-rich, it often produces dense HTML styles and boilerplate structures that were unnecessary for the target use cases. This library optimizes for minimal, highly clean HTML output.
  • Modern Python Compatibility (Py 3.14+): great-tables pulls in heavy external dependencies, including binary wheels like multimark. At the time of development, these dependencies did not support Python 3.14 (see multimark #3). To unblock workflows and maintain an ultra-lightweight, future-proof stack with zero complex binary dependencies, this native, Rust-backed Polars formatter was built from the ground up.

Metadata

Release files for pl2html 0.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pl2html 0.6.1
File Size Uploaded
pl2html-0.6.1.tar.gz 13.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pl2html 0.6.1
File Interpreter ABI Platform
pl2html-0.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 27.6 kB

Release files / pl2html-0.6.1.tar.gz

Download URL pl2html-0.6.1.tar.gz
Size 13.2 kB
Tags Source
SHA-256 checksum
How to use checksums
bef388d0c0308a90fca69c639783380b97a12bd264c224d540e194db5fed2a70
BLAKE2b-256 checksum
How to use checksums
7515519cccd8cfc0c7bcb1ab31bf5a801ee3382962a318656b6584b69282912b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / pl2html-0.6.1-py3-none-any.whl

Download URL pl2html-0.6.1-py3-none-any.whl
Size 14.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aca8b5a2458ad3dbffd8c422fb013297b3f01cacd77f3e199b01d1db179154bf
BLAKE2b-256 checksum
How to use checksums
20f3f90b2cba42e36e5d918006c70ebd40cd21f15405e5578a601e54461aa126
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.6.1 This release

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page