Table of Contents

Clustermap

Install: dotnet add package MatPlotLibNet

A clustermap combines a heatmap with optional row and column dendrograms in a single subplot. It follows the seaborn sns.clustermap pattern. When you supply trees, the clustermap reorders the rows and/or columns automatically to match the leaf traversal order of the dendrogram, so the cells line up with the tree.

Basic clustermap (heatmap only)

double[,] data =
{
    { 0.1, 0.9, 0.3 },
    { 0.8, 0.2, 0.7 },
    { 0.4, 0.6, 0.5 },
};

var figure = Plt.Create()
    .AddSubPlot(1, 1, 1, ax => ax.Clustermap(data))
    .ToSvg(); // or .ToPng(), .Build(), ...

With row dendrogram

Add a RowTree whose leaves carry the original row indices in TreeNode.Value. The ClustermapSeries renderer will reorder the rows to match the DFS leaf traversal of the tree and render the dendrogram in the left panel.

var rowTree = new TreeNode
{
    Value = 2.0, // merge distance
    Children =
    [
        new TreeNode { Value = 0 }, // original row 0
        new TreeNode
        {
            Value = 1.0,
            Children =
            [
                new TreeNode { Value = 1 }, // original row 1
                new TreeNode { Value = 2 }, // original row 2
            ]
        }
    ]
};

Plt.Create()
    .AddSubPlot(1, 1, 1, ax => ax.Clustermap(data, s =>
    {
        s.RowTree = rowTree;
        s.RowDendrogramWidth = 0.20; // fraction of total width, default 0.15
    }))
    .ToSvg();

With both dendrograms

Plt.Create()
    .AddSubPlot(1, 1, 1, ax => ax.Clustermap(data, s =>
    {
        s.RowTree = rowTree;
        s.ColumnTree = colTree;
        s.RowDendrogramWidth = 0.15;      // default
        s.ColumnDendrogramHeight = 0.15;  // default
    }))
    .ToSvg();

Custom colormap and labels

using MatPlotLibNet.Styling.ColorMaps;

Plt.Create()
    .AddSubPlot(1, 1, 1, ax => ax.Clustermap(data, s =>
    {
        s.ColorMap = DivergingColorMaps.RdBu;
        s.ShowLabels = true;
        s.LabelFormat = "F2";
    }))
    .ToSvg();

Names beside the rows and columns

FigureTemplates.Clustermap clusters the rows and the columns itself and takes a name for each. The names go with the rows and columns they were given for, wherever the clustering draws them: a name is never left standing at the place its row stood in the data.

double[,] expression =
{
    { 1.0, 2.0, 0.5 },
    { 5.0, 0.1, 4.0 },
    { 1.1, 1.9, 0.6 },
    { 4.8, 0.2, 3.9 },
};

var svg = FigureTemplates.Clustermap(
        expression,
        rowLabels: ["gene-a", "gene-b", "gene-c", "gene-d"],
        colLabels: ["sample-x", "sample-y", "sample-z"])
    .ToSvg();

Either list may be left out. A list with another length than the matrix has is refused, naming the parameter.

Tree leaf convention

Leaf TreeNode.Value must be the zero-based original index of the row or column in the data matrix (e.g. 0, 1, 2 for a 3-row matrix). Internal nodes carry the merge distance (any positive double). If the tree is malformed (out-of-range indices, duplicates, or wrong count) ResolveLeafOrder falls back to the identity order silently.

// A valid 3-row tree: leaves have Value = original index
var validTree = new TreeNode
{
    Value = 2.0,
    Children =
    [
        new TreeNode { Value = 2 }, // row 2 comes first in display order
        new TreeNode
        {
            Value = 1.0,
            Children =
            [
                new TreeNode { Value = 0 }, // then row 0
                new TreeNode { Value = 1 }, // then row 1
            ]
        }
    ]
};
// Resulting display order: row 2, row 0, row 1

Panel ratios

Property Type Default Range Effect
RowDendrogramWidth double 0.15 [0.0, 0.9] Fraction of width for row dendrogram. 0 suppresses it.
ColumnDendrogramHeight double 0.15 [0.0, 0.9] Fraction of height for column dendrogram. 0 suppresses it.

Values are clamped on assignment; no exception is thrown for out-of-range inputs.

See also