Skip to main content

pydiceplot

PyPI - Version PyPI - Python Version PyPI - License PyPI - Downloads PyPI Downloads GitHub Actions

pydiceplot draws dice plots: grids of die-face icons that encode up to nine categorical variables (one per pip slot) plus optional continuous fill and size mappings. It also ships a refactored domino_plot(...) API for two-contrast feature-by-celltype panels. Both plot types share matplotlib and plotly backends with seaborn-style entry points.

It's the Python sibling of the R package ggdiceplot. The grid geometry and legend stack are ports of kuva's DicePlot, which is itself a port of ggdiceplot::geom_dice — so all three packages produce the same visual layout (with one intentional fix: n=6 is the traditional two-column die face rather than ggdiceplot's transposed two-row layout).

Install

pip install pydiceplot

For development against this repo:

git clone https://github.com/maflot/pydiceplot.git
cd pydiceplot
pixi install
pixi run test     # run the test suite
pixi run example  # regenerates the showcase images under images/
pixi run build    # sdist + wheel in dist/
pixi run precommit

Quick start

Categorical mode — each pip is coloured by its pips value:

import matplotlib.pyplot as plt
import pydiceplot
from pydiceplot import dice_plot
from pydiceplot.plots.backends._dice_utils import (
    get_diceplot_example_data, get_example_cat_c_colors,
)

pydiceplot.set_backend("matplotlib")
data = get_diceplot_example_data(4)
colors = dict(list(get_example_cat_c_colors().items())[:4])

fig, ax = dice_plot(
    data,
    x="CellType", y="Pathway", pips="PathologyVariable",
    pip_colors=colors,
    title="Dice Plot with 4 Pathology Variables",
    figsize=(9, 10),
)
fig.savefig("dice_4.png", dpi=150, bbox_inches="tight")

Per-pip continuous fill + size — mirrors ggdiceplot's geom_dice(aes(dots=..., fill=lfc, size=-log10(q))) (we rename dots → pips since the marks on a die are formally called pips):

import numpy as np
from pydiceplot import dice_plot

rng = np.random.default_rng(1)
data = get_diceplot_example_data(4)
data["lfc"] = rng.normal(0, 1.2, len(data))
data["nlq"] = rng.uniform(0.5, 4, len(data))

fig, ax = dice_plot(
    data,
    x="CellType", y="Pathway", pips="PathologyVariable",
    fill="lfc", size="nlq",
    fill_label="Log2FC", size_label="-log10(q)",
    cmap="RdBu_r",
    title="Per-dot continuous",
)

Plotly — same API, returns a plotly.graph_objects.Figure:

pydiceplot.set_backend("plotly")
fig = dice_plot(data, x="CellType", y="Pathway", pips="PathologyVariable",
                fill="lfc", size="nlq", cmap="RdBu_r",
                width=900, height=650)
fig.write_image("dice.png")

Drawing into an existing axes (skips the built-in right-side legend stack so you can compose your own multi-panel figure):

fig, axes = plt.subplots(1, 2, figsize=(14, 6))
dice_plot(data, x="CellType", y="Pathway", pips="PathologyVariable",
          pip_colors=colors, ax=axes[0])
axes[1].plot(range(10))

Domino plots use a matching column-first API. Each tile is a (feature, celltype) pair with exactly two contrast slots:

from pydiceplot import domino_plot
from pydiceplot.plots.backends._domino_utils import get_domino_example_data

data = get_domino_example_data()

fig, ax = domino_plot(
    data,
    "gene", "Cell_Type", "Group",
    features=["GeneA", "GeneB", "GeneC"],
    label="var",
    fill="logFC",
    size="neg_log10_adj_p",
    contrast_order=["Type1", "Type2"],
    contrast_labels=["Type 1", "Type 2"],
    fill_label="Log2FC",
    size_label="-log10(adj p)",
    figsize=(9, 5.5),
)

Modes

dice_plot has three input modes, picked by which arguments you pass:

Mode Trigger What each pip encodes
Categorical pip_colors={label: hex, ...} filled circle in its category colour when present
Per-pip continuous fill="col" and/or size="col" continuous colour and/or size from numeric columns
Per-pip discrete fill="col" + fill_palette={value: hex, ...} colour per discrete fill value; pip slot still comes from pips

The legend stack on the right always includes a position legend showing which pip slot maps to which pips value, plus a colorbar and size legend when continuous mappings are active. That stacking matches ggdiceplot::draw_key semantics.

Sample output

Everything below is produced by example_code/example.py. Regenerate with pixi run example.

Quick tour

4-category dice plot

6-category dice plot (traditional two-column face)

9-category dice plot (fully populated 3×3 face)

Per-dot continuous fill and size

Domino example

The standalone domino example lives in example_code/example_domino.py.

Domino plot example

1-to-1 ports of ggdiceplot's demo plots

Each script in example_code/ reproduces one of the figures from ggdiceplot/demo_output/, loading the original R sample data exported to CSV under example_code/data/.

Oral microbiome — 8 taxa × 5 specimens × 4 diseases, per-pip Log2FC and -log10 q. Mirrors sample_dice_data2 / example2.png.

Oral microbiome

Oral microbiome, fill-only — same data but size is constant and pip_scale=1.0 fills the die face fully. Mirrors example4_fill_only.png.

Oral microbiome — fill only

miRNA × compound × organ, discrete direction — the pip slot selects the organ, the pip colour encodes the regulation direction (Down / Unchanged / Up) via fill_palette. Mirrors sample_dice_miRNA.

miRNA dysregulation direction

ZEBRA Sex DEGs domino plot — 9 genes × 27 cell types × 5 disease contrasts, filtered to PValue < 0.05. Mirrors ZEBRA_domino_example.png.

ZEBRA domino

Creative n=9 example

A fully populated 3×3 die face: nine canonical signaling pathways (Wnt, Notch, Hedgehog, TGF-β, Hippo, PI3K-AKT, MAPK, JAK-STAT, NF-κB) per cell-type × treatment tile. Pip colour = Log2FC, pip size = -log10 q. The synthetic data boosts biologically plausible pathway hits: fibroblasts respond to TGF-β1 via TGF-β, macrophages activate NF-κB / JAK-STAT / MAPK under LPS, intestinal stem cells light up Wnt under WNT3A, and so on.

9 signaling pathways per die face

API

dice_plot(data, x, y, pips, *, ...)

dice_plot(
    data, x, y, pips, *,
    # pip encoding
    pip_colors=None,       # dict {pips value: hex} — categorical colour per pip
    fill=None,             # str — per-pip fill column (continuous or discrete)
    fill_palette=None,     # dict {fill value: hex} — discrete fill lookup
    size=None,             # str — numeric per-pip size column
    # ordering
    x_order=None, y_order=None, pips_order=None,
    # dice geometry
    pip_scale=0.85, tile_size=0.85, grid_lines=False,
    # colour scales
    fill_range=None, size_range=None, cmap="viridis",
    # labels
    title=None, xlabel=None, ylabel=None,
    fill_label=None, size_label=None, pips_label=None,
    # plot target
    ax=None,                  # matplotlib: existing Axes (skips legend stack)
    fig=None,                 # plotly: existing Figure (skips legend stack)
    figsize=None,             # matplotlib: (width_in, height_in)
    width=None, height=None,  # plotly: pixels
    max_pips=9,
)

Returns

  • matplotlib: (Figure, Axes) when we create the figure, just Axes when the caller supplies ax=.
  • plotly: plotly.graph_objects.Figure.

Use the native save/show methods on the return value: fig.savefig(...) / plt.show() for matplotlib, fig.write_image(...) / fig.show() for plotly.

domino_plot(data, feature, celltype, contrast, *, ...)

domino_plot(
    data, feature, celltype, contrast, *,
    features=None,          # optional feature filter; also sets order by default
    label=None,             # optional hover/annotation column
    fill="logFC",           # numeric fill column
    size="neg_log10_adj_p", # numeric size column
    feature_order=None, celltype_order=None,
    contrast_order=None,    # must contain exactly two contrast values
    contrast_labels=None,   # human-readable labels for those two slots
    switch_axis=False,
    fill_range=None, size_range=None, cmap="RdBu_r",
    title=None, xlabel=None, ylabel=None,
    fill_label=None, size_label=None,
    ax=None,                  # matplotlib: existing Axes
    fig=None,                 # plotly: existing Figure
    figsize=None,             # matplotlib: (width_in, height_in)
    width=None, height=None,  # plotly: pixels
)

Returns

  • matplotlib: (Figure, Axes) when we create the figure, just Axes when the caller supplies ax=.
  • plotly: plotly.graph_objects.Figure.

Pip slot layout

The 3×3 pip grid uses natural row-major reading order:

pos 1 (TL)  pos 2 (TM)  pos 3 (TR)
pos 4 (ML)  pos 5 (MM)  pos 6 (MR)
pos 7 (BL)  pos 8 (BM)  pos 9 (BR)

Dice sizes pick from this table (traditional die faces; n=6 is two vertical columns, unlike ggdiceplot::make_offsets which returns the transposed two-row layout — we deliberately diverge here):

n positions visual
1 [5] center
2 [1, 9] diagonal (TL + BR)
3 [1, 5, 9] diagonal + center
4 [1, 3, 7, 9] four corners
5 [1, 3, 5, 7, 9] corners + center
6 [1, 3, 4, 6, 7, 9] two vertical columns
7 [1, 3, 4, 5, 6, 7, 9] 6 + center
8 [1, 2, 3, 4, 6, 7, 8, 9] 3×3 minus center
9 [1, 2, 3, 4, 5, 6, 7, 8, 9] fully populated 3×3

Citation

If you use this package, please cite:

M. Flotho, P. Flotho, A. Keller, "DicePlot: a package for high-dimensional categorical data visualization," Bioinformatics, vol. 42, no. 2, btaf337, 2026.

@article{flotho2026diceplot,
  title   = {DicePlot: a package for high-dimensional categorical data visualization},
  author  = {Flotho, Matthias and Flotho, Philipp and Keller, Andreas},
  journal = {Bioinformatics},
  volume  = {42},
  number  = {2},
  pages   = {btaf337},
  year    = {2026},
  publisher = {Oxford University Press}
}

Related packages

  • ggdiceplot — the R / ggplot2 sibling
  • kuva — a Rust plotting library that ships a dice plot

License

MIT — see LICENSE.

Metadata

Release files for pydiceplot 1.0.0

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

Source distribution (sdist)

Source distribution for pydiceplot 1.0.0
File Size Uploaded
pydiceplot-1.0.0.tar.gz 1.4 MB Details

Built distribution (wheel)

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

Total release size: 1.5 MB

Release files / pydiceplot-1.0.0.tar.gz

Download URL pydiceplot-1.0.0.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
38bea845e3ded27f282b07876333e47aeb481acb01c09bb2534084531c26aca9
BLAKE2b-256 checksum
How to use checksums
8ee31750f96ce9eb9d1cf2d3aa4f0bad7539616daa1516f103dd52abcde329d1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 20, 2026.

Transparency log

Release files / pydiceplot-1.0.0-py3-none-any.whl

Download URL pydiceplot-1.0.0-py3-none-any.whl
Size 30.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
036e49911066c29abe075a9a7b0ecbb38fc9142f2ea819dbe38698b65fd24f36
BLAKE2b-256 checksum
How to use checksums
d2cd59eaf4b1f44de8470e220e6a3fb22973d9aa049011f8d526acd8d53cce3b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 20, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.0.3

2 release files

0.0.2

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