Skip to content

Plots

Six of these functions accept return_data=True and then return (Figure, DataFrame) instead of a bare figure. Schemas are registered in _RETURN_DATA_SCHEMAS and pinned by a regression test, so they are part of the public contract.

missing_mechanism() always returns (Figure, DataFrame), so it needs no flag. missing_abundance_density() returns a figure, and missing_matrix_html() returns an HTML string; neither has a tabular result to hand back.

Function return_data columns
missing_matrix feature, sample, missing
completeness_bars group, completeness, n_samples
detection_waterfall feature, detection_rate, rank
missing_runorder sample, run_order, missing_rate, group
comissing_heatmap feature_a, feature_b, comissingness
missing_upset feature, intersection_id, members, n_features, rank, plotted

The nullity matrix

missing_matrix

missing_matrix(
    df: DataFrame,
    *,
    title: str = "",
    subtitle: str = "",
    feature_type: str = "PROT",
    annotation_levels: list[int] | None = None,
    annotation_colors: dict[int | str, dict[str, str]]
    | None = None,
    label_level: int = -1,
    sort_features: str | None = "descending",
    cluster_samples: bool = True,
    cluster_method: str = "average",
    show_dendrogram: bool = True,
    color_present: str | tuple = "#2d2d2d",
    color_missing: str | tuple = "#f0f0f0",
    invert: bool = False,
    figsize: tuple[float, float] | None = None,
    fontsize: int = 10,
    fontsize_legend: int | None = None,
    fontsize_rows: int | None = None,
    fontsize_cols: int | None = None,
    fontsize_annotations: int | None = None,
    completeness: str = "below",
    completeness_threshold: float | None = None,
    legend_loc: str = "upper right",
    group_summary: int | str | None = None,
    split_by: int | str | None = None,
    save: str | None = None,
    dpi: int = 150,
    return_data: bool = False,
) -> plt.Figure

Pretty missing-data matrix with multi-level sample annotations.

Parameters:

Name Type Description Default
df DataFrame

Features (rows) x Samples (columns). Use MultiIndex columns for annotation strips; level names become strip labels automatically. NaN = missing / not detected.

required
title str

Figure title (empty string = no title).

''
subtitle str

Secondary line below title for dataset metadata.

''
feature_type str

Type of features: "PROT", "GENE", or "PEPTIDE". Used for labels.

'PROT'
annotation_levels list[int] | None

Column-index levels to show as colour bars. Default: all levels except the innermost (used for tick labels).

None
annotation_colors dict | None

Custom colours for annotation levels. Keys are level indices (int) or level names (str). Values are dicts mapping factor levels to hex colours.

None
label_level int

Column level for x-axis tick labels (-1 = innermost).

-1
sort_features 'ascending' | 'descending' | None

Sort features by completeness. Default "descending".

'descending'
cluster_samples bool

Cluster samples by nullity pattern (default True).

True
cluster_method str

scipy linkage method (default "average").

'average'
show_dendrogram bool

Draw dendrogram above annotations (default True).

True
color_present colour spec

Colours for detected vs missing cells.

'#2d2d2d'
color_missing colour spec

Colours for detected vs missing cells.

'#2d2d2d'
invert bool

Swap present and missing colours. When True, missing cells are dark and present cells are light — the inverse of the default.

False
figsize tuple | None

Figure size; auto-calculated if None.

None
fontsize int

Base font size used as fallback (default 10).

10
fontsize_legend int | None

Font size for legend entries.

None
fontsize_rows int | None

Font size for row (feature) labels.

None
fontsize_cols int | None

Font size for column (sample) labels.

None
fontsize_annotations int | None

Font size for annotation strip labels.

None
completeness 'below' | 'side'

Where to place the completeness sparkline.

'below'
completeness_threshold float | None

Draw a threshold line on the sparkline at this value (0-1). E.g. 0.5 draws a line at 50% completeness.

None
legend_loc str

Corner for the annotation legends: "upper right", "upper left", "lower right", "lower left" (default "upper right").

'upper right'
group_summary int | str | None

Column level (int index or str name) to group by for a per-group completeness summary printed to the console. Only works when there is more than one factor level. Default None (disabled).

None
split_by int | str | None

Split the matrix into side-by-side panels by this column level (int index or str name). Each factor value gets its own panel.

None
save str | None

Save figure to this path if set.

None
dpi int

Save resolution (default 150).

150

Returns:

Type Description
Figure

Examples:

>>> fig = missing_matrix(df, title="Protein detection")
>>> fig = missing_matrix(df, cluster_samples=False, sort_features=None)
>>> fig = missing_matrix(df, split_by="Condition", annotation_levels=[0])
>>> fig, table = missing_matrix(df, return_data=True)

missing_matrix_html

missing_matrix_html(
    df: DataFrame,
    *,
    title: str = "Missing Data Matrix",
    subtitle: str = "",
    feature_type: str = "PROT",
    annotation_levels: list[int] | None = None,
    annotation_colors: dict[int | str, dict[str, str]]
    | None = None,
    label_level: int = -1,
    sort_features: str | None = "descending",
    cluster_samples: bool = True,
    cluster_method: str = "average",
    color_present: str = "#2d2d2d",
    color_missing: str = "#f0f0f0",
    invert: bool = False,
    completeness: str = "below",
    completeness_threshold: float | None = None,
    width: int | None = None,
    height: int | None = None,
    save: str | None = None,
) -> str

Interactive HTML missing-data matrix using plotly.

Hover tooltips show the feature name, sample ID, every annotation level, and detection status. Supports the same clustering, sorting, annotation and completeness options as :func:missing_matrix.

Requires the optional plotly dependency (pip install mismap-qc[interactive]).

Parameters:

Name Type Description Default
df DataFrame

Features (rows) x samples (columns). NaN marks a missing value.

required
title str

Figure title.

'Missing Data Matrix'
subtitle str

Secondary line below the title, for dataset metadata.

''
feature_type str

Type of features: "PROT", "GENE", or "PEPTIDE". Used for hover labels.

'PROT'
annotation_levels list of int

Column levels to draw as annotation strips. Defaults to all levels except the innermost.

None
annotation_colors dict

Per-level colour overrides, keyed by level index or level name. Levels left unspecified fall back to the built-in palettes.

None
label_level int

Which column level supplies the x-axis tick labels.

-1
sort_features ('ascending', 'descending')

Sort features by completeness. None leaves the input order.

"ascending"
cluster_samples bool

Cluster samples by their binary nullity pattern.

True
cluster_method str

scipy linkage method used when cluster_samples is True.

'average'
color_present str

Colour for detected cells.

'#2d2d2d'
color_missing str

Colour for missing cells.

'#f0f0f0'
invert bool

Swap the present and missing colours.

False
completeness ('below', 'side')

Place the completeness sparkline below (per sample) or to the side (per feature).

"below"
completeness_threshold float

Draw a reference line at this completeness value, between 0 and 1.

None
width int

Plot dimensions in pixels. Calculated from the data when None.

None
height int

Plot dimensions in pixels. Calculated from the data when None.

None
save str

Write the HTML to this path in addition to returning it.

None

Returns:

Type Description
str

The rendered HTML document.

Examples:

>>> html = missing_matrix_html(df, title="Protein detection")
>>> html = missing_matrix_html(df, completeness_threshold=0.5, invert=True)

Per-check plots

completeness_bars

completeness_bars(
    df: DataFrame,
    group_level: int | str,
    *,
    threshold: float | None = None,
    color: str | dict | None = None,
    orientation: str = "horizontal",
    title: str = "Per-Group Completeness",
    fontsize: int = 10,
    save: str | None = None,
    dpi: int = 150,
    return_data: bool = False,
) -> plt.Figure

Horizontal (or vertical) bar chart of per-group detection completeness.

For each group, shows the mean fraction of features detected across all samples in that group. Replaces the console-only group_summary output of missing_matrix with a publishable figure.

Parameters:

Name Type Description Default
df DataFrame

Features (rows) x Samples (columns). NaN = missing / not detected. Columns may be a MultiIndex; use group_level to select the grouping.

required
group_level int or str

Column level (index or name) to group samples by. If df has flat columns, pass 0 or any label — the whole dataset is treated as one group (useful for a single-bar sanity check).

required
threshold float or None

Draw a dashed red line at this completeness value (0–1). E.g. 0.7 marks the 70% completeness threshold.

None
color str, dict, or None

Single hex colour for all bars, or {group_label: hex} dict for per-group colours. Uses the built-in palette if None.

None
orientation 'horizontal' or 'vertical'

Bar orientation. Horizontal (default) is easier to read with long group names.

'horizontal'
title str

Figure title.

'Per-Group Completeness'
fontsize int

Base font size (default 10).

10
save str or None

Save figure to this path if set.

None
dpi int

Save resolution (default 150).

150

Returns:

Type Description
Figure

Examples:

>>> fig = completeness_bars(df, "Condition")
>>> fig = completeness_bars(df, "Condition", threshold=0.8, orientation="vertical")
>>> fig, table = completeness_bars(df, "Condition", return_data=True)

detection_waterfall

detection_waterfall(
    df: DataFrame,
    thresholds: list[float] | None = None,
    group_level: int | str | None = None,
    feature_type: str = "PROT",
    color: str = "#2d2d2d",
    title: str | None = None,
    subtitle: str = "",
    figsize: tuple[float, float] | None = None,
    fontsize: int = 10,
    save: str | None = None,
    dpi: int = 150,
    return_data: bool = False,
) -> plt.Figure

Waterfall plot showing features ranked by detection rate.

Features are ranked by their detection rate across samples and plotted as a cumulative curve. Threshold lines show how many features survive at different filtering cutoffs.

Parameters:

Name Type Description Default
df DataFrame

Features (rows) x samples (columns). NaN = missing/not detected.

required
thresholds list of float or None

Detection rate thresholds to draw as horizontal lines (0-1 scale). Default: [0.5, 0.7, 0.9].

None
group_level int, str, or None

If set, compute and plot separate curves per group (MultiIndex level).

None
feature_type str

Type of features: "PROT", "GENE", or "PEPTIDE". Used for axis labels.

'PROT'
color str

Colour for the curve when not grouping. Default "#2d2d2d".

'#2d2d2d'
title str or None

Figure title. Auto-generated from feature_type if None.

None
subtitle str

Italic line below title.

''
figsize tuple or None

Figure size. Auto-calculated if None.

None
fontsize int

Base font size (default 10).

10
save str or None

Save figure to this path if set.

None
dpi int

Save resolution (default 150).

150

Returns:

Type Description
Figure

Examples:

>>> fig = detection_waterfall(df, thresholds=[0.5, 0.7])
>>> fig = detection_waterfall(df, group_level="Condition", feature_type="GENE")

missing_runorder

missing_runorder(
    df: DataFrame,
    run_order: list | Series | ndarray | None = None,
    group_level: int | str | None = None,
    smooth: bool = True,
    smooth_window: int = 5,
    title: str = "Missingness Over Run Order",
    subtitle: str = "",
    figsize: tuple[float, float] | None = None,
    fontsize: int = 10,
    save: str | None = None,
    dpi: int = 150,
    return_data: bool = False,
) -> plt.Figure

Plot per-sample missingness rate against run order.

Shows how missingness varies across sample acquisition order. Useful for detecting instrument drift or batch effects in proteomics experiments.

Parameters:

Name Type Description Default
df DataFrame

Features (rows) x samples (columns). NaN = missing/not detected.

required
run_order array - like or None

Explicit run order values (one per sample). Uses column index if None.

None
group_level int, str, or None

If set, colour points by this MultiIndex level (e.g. batch, condition).

None
smooth bool

Add a rolling mean smoother line. Default True.

True
smooth_window int

Window size for rolling mean. Default 5.

5
title str

Figure title.

'Missingness Over Run Order'
subtitle str

Italic line below title.

''
figsize tuple or None

Figure size. Auto-calculated if None.

None
fontsize int

Base font size (default 10).

10
save str or None

Save figure to this path if set.

None
dpi int

Save resolution (default 150).

150

Returns:

Type Description
Figure

Examples:

>>> fig = missing_runorder(df)
>>> fig = missing_runorder(df, group_level="Batch", smooth=True)

missing_mechanism

missing_mechanism(
    df: DataFrame,
    *,
    method: str = "mannwhitneyu",
    alpha: float = 0.05,
    min_present: int = 3,
    feature_type: str = "PROT",
    show_scatter: bool = True,
    title: str | None = None,
    subtitle: str = "",
    figsize: tuple[float, float] | None = None,
    fontsize: int = 10,
    save: str | None = None,
    dpi: int = 150,
) -> tuple[plt.Figure, pd.DataFrame]

Classify per-feature missing-data mechanism and plot the result.

For each feature, compares the per-sample mean abundance of samples where the feature is detected against samples where it is missing (one-sided Mann-Whitney U). Significantly higher present-side means => MNAR (the feature drops out preferentially in low-abundance samples).

Parameters:

Name Type Description Default
df DataFrame

features (rows) x samples (columns). NaN = missing.

required
method str

Classification method. Only "mannwhitneyu" is implemented for v0.2.0.

'mannwhitneyu'
alpha float

Significance threshold for the MNAR call.

0.05
min_present int

Minimum non-missing AND non-present samples required to test a feature. Features below this threshold are classified "INSUFFICIENT".

3
feature_type str

"PROT" | "GENE" | "PEPTIDE".

'PROT'
show_scatter bool

Show the abundance-vs-missing-rate scatter panel.

True
title str

Figure title. None => auto from feature_type.

None
subtitle str

Italic line below the title.

''
figsize tuple

Auto-sized when None.

None
fontsize int

Base font size.

10
save str

Path to save the figure.

None
dpi int

Save resolution.

150

Returns:

Name Type Description
fig Figure
classification DataFrame

Columns: feature, mechanism, missing_rate, mean_abundance, p_value. mechanism is one of {"MNAR", "MAR", "MCAR", "INSUFFICIENT"}.

Examples:

>>> fig, table = missing_mechanism(df)
>>> fig, table = missing_mechanism(df, alpha=0.01, show_scatter=False)
>>> table.query("mechanism == 'MNAR'")

comissing_heatmap

comissing_heatmap(
    df: DataFrame,
    *,
    top_n: int = 50,
    cluster: bool = True,
    method: str = "average",
    feature_type: str = "PROT",
    cmap: str = "Blues",
    title: str | None = None,
    subtitle: str = "",
    figsize: tuple[float, float] | None = None,
    fontsize: int = 10,
    save: str | None = None,
    dpi: int = 150,
    return_data: bool = False,
) -> plt.Figure

Heatmap of pairwise co-missingness for the top_n most-missing features.

Cell (i, j) = fraction of samples where features i and j are simultaneously missing. Tight clusters indicate co-dropping protein complexes, batch failures, or correlated low-abundance features.

Parameters:

Name Type Description Default
df DataFrame

features (rows) x samples (columns). NaN = missing.

required
top_n int

Number of most-missing features to display.

50
cluster bool

Hierarchically cluster features by co-missingness pattern.

True
method str

scipy linkage method ("average", "complete", "ward", etc.).

'average'
feature_type str

"PROT" | "GENE" | "PEPTIDE".

'PROT'
cmap str

matplotlib colormap.

'Blues'
title str

Title / subtitle.

None
subtitle str

Title / subtitle.

None
figsize tuple

Auto-sized when None.

None
fontsize int

Base font size.

10
save str

Path to save the figure.

None
dpi int

Save resolution.

150

Returns:

Type Description
Figure

Examples:

>>> fig = comissing_heatmap(df)
>>> fig = comissing_heatmap(df, top_n=20, cluster=False)
>>> fig, table = comissing_heatmap(df, return_data=True)

missing_upset

missing_upset(
    df: DataFrame,
    *,
    by="sample",
    group_min_frac: float = 0.5,
    min_size: int = 1,
    max_intersections: int = 50,
    feature_type: str = "PROT",
    title: str | None = None,
    subtitle: str = "",
    figsize: tuple[float, float] | None = None,
    fontsize: int = 10,
    save: str | None = None,
    dpi: int = 150,
    return_data: bool = False,
) -> plt.Figure

UpSet plot of which sample combinations share missing features.

For each intersection of samples (or groups), shows how many features are missing in exactly that combination and no others. Bar charts show totals and Venn diagrams stop working past three sets; this answers whether particular replicates lose the same features together, which is what separates technical dropout from biology at small n.

Every feature with at least one missing value belongs to exactly one intersection. Fully detected features carry no intersection information and are excluded.

Requires upsetplot (pip install mismap-qc[upset]).

Parameters:

Name Type Description Default
df DataFrame

features (rows) x samples (columns). NaN = missing.

required
by str or int

"sample" (default) for one set per sample, or a MultiIndex level name or index for one set per group.

'sample'
group_min_frac float

Group mode only. A feature counts as missing in a group when it is missing in at least this fraction of that group's samples. The 0.5 default treats a feature as lost in a group once it is absent from the majority of it.

0.5
min_size int

Intersections smaller than this are not drawn.

1
max_intersections int

Draw at most this many intersections, largest first. Intersection count grows quickly with sample count, and an uncapped plot is unreadable past a few dozen samples. Truncation is annotated on the figure, and return_data=True still returns every intersection.

50
feature_type str

"PROT" | "GENE" | "PEPTIDE".

'PROT'
title str

Title / subtitle. Title is auto-generated when None.

None
subtitle str

Title / subtitle. Title is auto-generated when None.

None
figsize tuple

Auto-sized when None.

None
fontsize int

Base font size.

10
save str

Path to save the figure.

None
dpi int

Save resolution.

150
return_data bool

Return (Figure, DataFrame) instead of just the Figure. Schema: [feature, members, n_features, rank, plotted].

False

Returns:

Type Description
Figure

Examples:

>>> fig = missing_upset(df)
>>> fig = missing_upset(df, by="Condition", group_min_frac=0.5)
>>> fig, table = missing_upset(df, min_size=2, return_data=True)
>>> table.query("~plotted")

missing_abundance_density

missing_abundance_density(
    df: DataFrame,
    *,
    groups: Series | ndarray | list | None = None,
    max_na_levels: int = 6,
    title: str = "Abundance by Missingness",
    xlabel: str = "Mean Abundance",
    ylabel: str = "Density",
    figsize: tuple[float, float] | None = None,
    fontsize: int = 10,
    palette: list[str] | None = None,
    alpha: float = 0.7,
    linewidth: float = 1.5,
    legend_title: str = "# Missing",
    save: str | None = None,
    dpi: int = 150,
) -> plt.Figure

Density plot of mean abundance stratified by missingness count.

This diagnostic plot reveals whether missing data follows the MNAR (Missing Not At Random) pattern typical of proteomics/mass-spec data, where low-abundance features are more likely to be missing due to detection limits.

Parameters:

Name Type Description Default
df DataFrame

Genes/proteins (rows) x Samples (columns). NaN = missing.

required
groups Series, array, or list

Group labels for each sample (same length as df.columns). If provided, creates faceted subplots, one per group.

None
max_na_levels int

Maximum number of distinct missingness levels to show (default 6). Higher counts are binned into "N+" category.

6
title str

Figure title.

'Abundance by Missingness'
xlabel str

Axis labels.

'Mean Abundance'
ylabel str

Axis labels.

'Mean Abundance'
figsize tuple

Figure size. Auto-calculated if None.

None
fontsize int

Base font size.

10
palette list[str]

Colors for missingness levels. Uses built-in palette if None.

None
alpha float

Line/fill transparency (default 0.7).

0.7
linewidth float

Density line width (default 1.5).

1.5
legend_title str

Legend title (default "# Missing").

'# Missing'
save str

Save figure to this path.

None
dpi int

Save resolution (default 150).

150

Returns:

Type Description
Figure

Examples:

>>> fig = missing_abundance_density(df)
>>> fig = missing_abundance_density(df, groups=df.columns.get_level_values("Condition"))