reactable-py
  • Get Started
  • Examples
  • Reference
  • Blog

PyPI Downloads

import json
import polars as pl
import polars.selectors as cs
from reactable import Reactable, Column, Theme, embed_css
from reactable.tags import to_widget
from reactable.models import RowInfo
import htmltools as ht

embed_css()

monthly = pl.read_csv("./pypi-monthly.csv", row_index_name=None)
details = json.load(open("./pypi-details.json"))
outer_details = pl.DataFrame(
    [
        {
            "package": x["name"].lower().replace("_", "-"),
            "version": x["version"],
            "summary": x["summary"],
            "published_at": x["releases"][0]["published_at"],
        }
        for x in details
    ]
)

outer = monthly.join(outer_details, "package")


def detail_label(title, content):
    return ht.div(title, class_="detail-label"), content


def create_details(entry: RowInfo):
    pkg = details[entry.row_index]
    sub_frame = pl.DataFrame(pkg["releases"])

    sub_tbl = Reactable(
        sub_frame,
        pagination=False,
        default_col_def=Column(header_class="header"),
        columns={
            "published_at": Column(name="Published", align="right"),
        },
        class_="archived-table",
        theme=Theme(cell_padding="8px 16px"),
    )
    return ht.div(
        ht.div(
            pkg["name"],
            # ht.span(pkg["summary"], class_="detail-title"),
            class_="detail-header",
        ),
        ht.div(
            (pkg["summary"] or [])[:200],
            class_="detail-description",
        ),
        *detail_label("Version", pkg["version"]),
        *detail_label("Python Depends", pkg["requires_python"]),
        *detail_label("Depends", pkg["requires_dist"]),
        # *detail_label("Suggests", pkg[""]),
        *detail_label("AUTHOR", pkg["author"]),
        *detail_label("License", pkg["license"]),
        *detail_label("URL", pkg["home_page"]),
        *detail_label("Recent Versions", sub_tbl.to_widget()),
        class_="package-detail",
    )
from IPython.display import HTML, display

display(HTML(html))

tbl = Reactable(
    outer.head(50),
    default_sorted=["downloads_month"],
    default_page_size=10,
    show_page_size_options=True,
    page_size_options=[10, 20, 50, 100],
    on_click="expand",
    resizable=True,
    default_col_def=Column(header_class="header"),
    columns={
        "summary": Column(
            name="Summary",
            min_width=250,
            class_="package-title",
            cell=lambda ci: ht.span(ci.value, title=ci.value),
        ),
        "published_at": Column(name="Published", align="right"),
        "downloads_month": Column(
            name="Downloads",
            default_sort_order="desc",
            cell=lambda ci: f"{ci.value // 1_000_000:,}M",
        ),
        "package": Column(name="Package"),
        "version": Column(name="Version"),
    },
    wrap=False,
    details=create_details,
    class_="packages-table",
    row_style={"cursor": "pointer"},
    theme=Theme(cell_padding="8px 12px"),
)

to_widget(
    ht.div(
        # ht.h2("Top PyPI Monthly Downloads (Aug 1, 2024)"),
        tbl,
        class_="cran-packages",
    )
)

<link href="https://fonts.googleapis.com/css?family=Nunito:400,600,700&display=fallback rel="stylesheet">

<style>
.cran-packages {
  font-family: Nunito, "Helvetica Neue", Helvetica, Arial, sans-serif;
}

.title {
  font-size: 1.5rem;
}

.packages-table {
  margin-top: 1rem;
  font-size: 0.9375rem;
  border: 1px solid hsl(213, 33%, 93%);
  border-radius: 4px;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
}

.header {
  background-color: hsl(213, 45%, 97%);
  border-bottom-color: hsl(213, 33%, 93%);
  border-bottom-width: 1px;
  color: hsl(213, 13%, 33%);
}

.header[aria-sort]:hover,
.header[aria-sort]:focus {
  color: hsl(213, 55%, 50%);
}

.units {
  margin-left: 0.15em;
  color: rgba(0, 0, 0, 0.6);
}

.package-title {
  font-size: 0.875rem;
}

.package-detail {
  padding: 24px;
  box-shadow: inset 0 1px 3px #dbdbdb;
  background: hsl(213, 20%, 99%);
}

.detail-label {
  margin: 1.25rem 0 0.25rem;
  font-size: 0.875rem;
  color: rgba(0, 0, 0, 0.6);
}

.detail-header {
  margin-bottom: 1rem;
  font-size: 1.25rem;
  font-weight: 600;
}

.detail-title {
  margin-left: 1rem;
  font-size: 0.875rem;
  font-weight: 400;
  color: rgba(0, 0, 0, 0.6);
}

.detail-description {
  font-size: 0.875rem;
}

.archived-table {
  max-width: 15rem;
  border: 1px solid hsl(213, 33%, 93%);
  border-radius: 4px;
  box-shadow: 0 2px 7px 0 rgba(0, 0, 0, 0.05);
  font-size: 0.875rem;
}
</style>
print("yo2")
yo2