Clustering plots low data [CW-7275]

This commit is contained in:
Neil Horner 2026-05-26 17:10:46 +00:00
parent a4b08414cb
commit fa884c71c1
2 changed files with 48 additions and 31 deletions

View File

@ -1,10 +1,10 @@
"""Hierarchical clustering heatmap plots."""
from dataclasses import dataclass
from bokeh.layouts import column as bokeh_column, row as bokeh_row
from bokeh.models import (
ColorBar,
ColumnDataSource,
Div,
FixedTicker,
HoverTool,
LinearColorMapper,
@ -122,19 +122,10 @@ def _dendrogram_source(linked, orientation):
return ColumnDataSource({"xs": xs, "ys": ys})
def _empty_plot(message):
"""Return a BokehPlot containing a message instead of a heatmap."""
plot = BokehPlot()
plot._fig = Div(text=message)
return plot
def _sample_pca(matrix, sample_names):
"""Project samples onto the first two principal components."""
sample_matrix = np.asarray(matrix, dtype=float).T
centered = sample_matrix - sample_matrix.mean(axis=0, keepdims=True)
if centered.shape[0] < 2 or centered.shape[1] == 0:
return None
u, singular_values, _ = np.linalg.svd(centered, full_matrices=False)
scores = u * singular_values
@ -543,6 +534,16 @@ def pca_plot(matrix, col_order, sample_names, sample_metadata, condition_column)
return pca_and_legend
@dataclass
class ClusteringResult:
"""Container for hierarchical clustering results."""
heatmap: object | None # noqa: NT001
pca: object | None # noqa: NT001
distance: object | None # noqa: NT001
error: str | None = None # noqa: NT001
def hierarchical(
data,
id_column,
@ -559,11 +560,15 @@ def hierarchical(
)
if log2_matrix.shape[0] < 2 or log2_matrix.shape[1] < 2:
return _empty_plot(
"Hierarchical clustering requires at least two features and "
"two numeric sample columns."
return ClusteringResult(
heatmap=None,
pca=None,
distance=None,
error=(
"Generation of clustering plots requires at least two features "
"and two sample columns."
)
)
log2_matrix = np.log2(log2_matrix + 1)
log2_matrix, labels = _top_variable_rows(log2_matrix, labels, top_n=top_n)
log2_z_matrix = _row_zscore(log2_matrix)
@ -601,4 +606,8 @@ def hierarchical(
height=hm_height
)
return heatmap_plt, pca_plt, distance_plt
return ClusteringResult(
heatmap=heatmap_plt,
pca=pca_plt,
distance=distance_plt
)

View File

@ -1054,20 +1054,24 @@ def main(args):
_create_warning_banner(
"Cohort gene CPM table is missing or empty. ")
else:
heatmap, pca, dist = hierarchical(
hierarchical_result = hierarchical(
cohort_cpm["gene"],
id_column="GENEID",
samples=cohort_samples,
condition_column=condition_column,
top_n=150,
)
with div(cls="heatmap-table-grid"):
EZChart(heatmap, width="100%")
EZChart(pca, width="100%")
EZChart(dist, width="100%")
with div(cls="clustering-info"):
br()
clustering_info('gene')
if hierarchical_result.error is not None:
_create_warning_banner(
hierarchical_result.error, level='warning')
else:
with div(cls="heatmap-table-grid"):
EZChart(hierarchical_result.heatmap, width="100%")
EZChart(hierarchical_result.pca, width="100%")
EZChart(hierarchical_result.distance, width="100%")
with div(cls="clustering-info"):
br()
clustering_info('gene')
tabs = Tabs()
for contrast, table in _contrast_results(
args.de_dir, "results_dge.tsv", n=20
@ -1114,20 +1118,24 @@ def main(args):
_create_warning_banner(
"Cohort transcript CPM table is missing or empty.")
else:
tx_heatmap, tx_pca, tx_dist = hierarchical(
hierarchical_result = hierarchical(
cohort_cpm["transcript"],
id_column="TXNAME",
top_n=150,
samples=cohort_samples,
condition_column=condition_column
)
with div(cls="heatmap-table-grid"):
EZChart(tx_heatmap, width="100%")
EZChart(tx_pca, width="100%")
EZChart(tx_dist, width="100%")
with div(cls="clustering-info"):
br()
clustering_info('transcript')
if hierarchical_result.error is not None:
_create_warning_banner(
hierarchical_result.error, level='warning')
else:
with div(cls="heatmap-table-grid"):
EZChart(hierarchical_result.heatmap, width="100%")
EZChart(hierarchical_result.pca, width="100%")
EZChart(hierarchical_result.distance, width="100%")
with div(cls="clustering-info"):
br()
clustering_info('transcript')
tabs = Tabs()
dtu_tables = _contrast_results(