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 colormapdisplay_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:
Build a synthetic Hi-C matrix with distance decay and visibility bias, plus a synthetic A/B compartment vector.
Render a full heatmap with
display_matrix(..., log=True, row_values=...)to attach a per-bin value bar.Render the upper triangle with
display_triangle(..., log=True, values=...)for symmetric matrices.Render the 2x2 A/B quadrant grid with
display_compartments(matrix, compartments, log=True).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/.mcoolmatrixtutorial_compartments.ipynb- computing A/B compartments from a real matrixtutorial_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)