Tutorial: Visualizing Hi-C contact matrices with gunz_cm.visualizations#

This tutorial walks through the three display helpers in gunz_cm.visualizations.display:

  • display_matrix - full square heatmap with optional row/column value bars, log or linear normalization, and centered colormap

  • display_triangle - upper-triangular half-matrix view (useful when the matrix is symmetric)

  • display_compartments - 2x2 A/B quadrant grid that aggregates a binary compartment vector

All three render into the current matplotlib figure. We use matplotlib.use('Agg') for a non-interactive backend and call plt.gcf().savefig(...) after each call to write the plot to disk instead of opening a window.

## Initialization

%load_ext autoreload
%autoreload 2

import sys
from git.repo import Repo

repo = Repo('.', search_parent_directories=True)
ROOT = repo.working_tree_dir

assert isinstance(ROOT, str)
sys.path.append(ROOT)
print(f'Repo root: {ROOT}')

Repo root: /home/adhisant/workspace/gunz-cm
## Imports

from pathlib import Path

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from numpy.typing import NDArray

np.bool8 = bool  # shim: numpy 2.x removed np.bool8 referenced in source annotations

from gunz_cm.visualizations.display import (
    display_matrix,
    display_triangle,
    display_compartments,
)

## Create synthetic data: 10x10 matrix with distance decay + log-normal visibility bias,
## plus a 4-block A/B compartment vector that drives display_compartments below.

rng = np.random.default_rng(42)
n = 10

linear_coords = np.arange(n, dtype=float)
genomic_dist = np.abs(linear_coords[:, None] - linear_coords[None, :])

bias = rng.lognormal(mean=0.0, sigma=0.6, size=n)
decay = np.exp(-genomic_dist / 3.0)
cm_dense = bias[:, None] * bias[None, :] * decay * 100.0
np.fill_diagonal(cm_dense, 0.0)
matrix: NDArray = cm_dense

compartments = np.array([0, 0, 0, 1, 1, 0, 0, 1, 1, 1], dtype=bool)
row_values = bias

print('Synthetic contact matrix:')
print(f'  shape     = {matrix.shape}')
print(f'  bias      =', np.round(bias, 2))
print(f'  sum       =', round(float(matrix.sum()), 2))
print('Compartments (A=False / B=True):', compartments.astype(int).tolist())

Synthetic contact matrix:
  shape     = (10, 10)
  bias      = [1.2  0.54 1.57 1.76 0.31 0.46 1.08 0.83 0.99 0.6 ]
  sum       = 2811.42
Compartments (A=False / B=True): [0, 0, 0, 1, 1, 0, 0, 1, 1, 1]
## Step 1: display_matrix with log=True and row_values for a per-bin value bar.

out1 = str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_matrix.png')

try:
    display_matrix(
        matrix,
        log=True,
        title='Step 1: display_matrix (log, row_values=bias)',
        row_values=row_values,
        row_values_title='bias',
        row_values_log=True,
    )
    plt.gcf().savefig(out1, dpi=100, bbox_inches='tight')
    plt.close('all')
    print(f'Saved: {out1}')
except Exception as exc:
    plt.close('all')
    print(f'[skip] display_matrix failed: {exc!r}')

/home/adhisant/workspace/gunz-cm/src/gunz_cm/visualizations/display.py:575: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  figure.show()


Saved: /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_matrix.png
## Step 2: display_triangle renders only the upper triangle of a symmetric matrix
## with an optional values bar on the hypotenuse.

out2 = str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_triangle.png')

try:
    display_triangle(
        matrix,
        log=True,
        title='Step 2: display_triangle (log, upper triangle)',
        values=row_values,
        values_log=True,
        values_title='bias',
    )
    plt.gcf().savefig(out2, dpi=100, bbox_inches='tight')
    plt.close('all')
    print(f'Saved: {out2}')
except Exception as exc:
    plt.close('all')
    print(f'[skip] display_triangle failed: {exc!r}')

/home/adhisant/workspace/gunz-cm/src/gunz_cm/visualizations/display.py:747: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  figure.show()


Saved: /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_triangle.png
## Step 3: display_compartments partitions the matrix into the four A/A, A/B, B/A, B/B
## quadrants from a boolean compartment vector (A=False, B=True) and plots them in a 2x2 grid.

out3 = str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_compartments.png')

try:
    display_compartments(
        matrix,
        compartments,
        log=True,
        title='Step 3: display_compartments (A=False, B=True)',
    )
    plt.gcf().savefig(out3, dpi=100, bbox_inches='tight')
    plt.close('all')
    print(f'Saved: {out3}')
except Exception as exc:
    plt.close('all')
    print(f'[skip] display_compartments failed: {exc!r}')

/home/adhisant/workspace/gunz-cm/src/gunz_cm/visualizations/display.py:833: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  figure.show()


Saved: /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_compartments.png
## Step 4: Common parameters - linear (log=False), divergent colormap centered at 1,
## and hlines/vlines marking A/B compartment boundaries.

boundaries = np.where(np.diff(compartments.astype(int)))[0] + 1
out4 = str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_centered.png')

try:
    display_matrix(
        matrix,
        log=False,
        center=1,
        title='Step 4: display_matrix (linear, center=1, hlines at A/B boundaries)',
        hlines=boundaries,
        vlines=boundaries,
    )
    plt.gcf().savefig(out4, dpi=100, bbox_inches='tight')
    plt.close('all')
    print(f'Saved: {out4}')
    print(f'A/B boundaries drawn at indices: {boundaries.tolist()}')
except Exception as exc:
    plt.close('all')
    print(f'[skip] display_matrix (centered) failed: {exc!r}')

Saved: /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_centered.png
A/B boundaries drawn at indices: [3, 5, 7]


/home/adhisant/workspace/gunz-cm/src/gunz_cm/visualizations/display.py:575: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  figure.show()

Summary#

In this tutorial you learned how to:

  1. Build a synthetic Hi-C matrix with distance decay and visibility bias, plus a synthetic A/B compartment vector.

  2. Render a full heatmap with display_matrix(..., log=True, row_values=...) to attach a per-bin value bar.

  3. Render the upper triangle with display_triangle(..., log=True, values=...) for symmetric matrices.

  4. Render the 2x2 A/B quadrant grid with display_compartments(matrix, compartments, log=True).

  5. Switch to a divergent colormap with display_matrix(..., log=False, center=1, hlines=..., vlines=...) and overlay reference lines at compartment boundaries.

All three helpers return a matplotlib figure that the caller saves to disk via plt.gcf().savefig(...) (or shows interactively with %matplotlib inline / widget). The same pattern works on real data: load a contact matrix with gunz_cm.loaders.load_cm_data(...) and pass coo_matrix(...).toarray() as the matrix argument.

Next steps:

  • tutorial_load_cooler.ipynb - loading a real .cool/.mcool matrix

  • tutorial_compartments.ipynb - computing A/B compartments from a real matrix

  • tutorial_filter_normalize.ipynb - filtering and balancing before display

## Cleanup - confirm the four PNGs were written next to the notebook.

import os

saved = [
    str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_matrix.png'),
    str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_triangle.png'),
    str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_compartments.png'),
    str(Path(ROOT) / 'notebooks' / 'tutorial_visualize_centered.png'),
]
for p in saved:
    if os.path.exists(p):
        size_kb = os.path.getsize(p) / 1024.0
        print(f'kept:   {p}  ({size_kb:.1f} KB)')
    else:
        print(f'missing: {p}')
plt.close('all')

kept:   /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_matrix.png  (30.4 KB)
kept:   /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_triangle.png  (35.5 KB)
kept:   /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_compartments.png  (27.6 KB)
kept:   /home/adhisant/workspace/gunz-cm/notebooks/tutorial_visualize_centered.png  (25.6 KB)