Tutorial: 3D Structure Visualization#

version: 2.25.0

This tutorial covers the interactive 3D visualization functions in gunz_cm.visualizations.structures and the ParaView export functions. After working through it you will know how to:

  • Render a single 3D chromosome structure as an interactive HTML file (plot_chromosome_3d).

  • Compare multiple 3D structures side-by-side in a 4x4 grid (plot_structure_grid).

  • Add a PCA-derived bounding ellipsoid to indicate structural uncertainty (plot_chromosome_3d_with_ellipsoid).

  • Export 3D structures to ParaView-compatible formats (write_vtp_polydata, write_vtk_points).

All examples use synthetic data only (fixed RNG seed for reproducibility).

import tempfile, pathlib
import numpy as np

rng = np.random.default_rng(42)
OUT = pathlib.Path(tempfile.mkdtemp())
print(f"Output directory: {OUT}")

# Build a synthetic 3D chromosome structure: a soft helix
n = 50
t = np.linspace(0, 4 * np.pi, n)
points = np.column_stack([
    np.cos(t) + 0.05 * rng.standard_normal(n),
    np.sin(t) + 0.05 * rng.standard_normal(n),
    t / (2 * np.pi) + 0.05 * rng.standard_normal(n),
])
print(f"Synthetic chromosome: {points.shape}")

Output directory: /tmp/tmpsxy8yqfj
Synthetic chromosome: (50, 3)

1. plot_chromosome_3d: interactive 3D rendering#

Use this to render a single 3D structure as an interactive Plotly HTML file. The user can pan, zoom, and rotate the structure in their browser.

The node_colors parameter accepts several input types:

  • 1D scalar array of length n — per-bins color value (e.g. log-fold-change, A/B compartment)

  • Array of {-1, 0, 1} — discrete A/B compartment assignment

  • RGB triples (shape (n, 3)) — per-bin color

  • Array of categorical strings — per-bin label

from gunz_cm.visualizations import plot_chromosome_3d

# Plain 3D rendering
out = OUT / "chromosome_3d.html"
plot_chromosome_3d(
    points=points,
    output_path=str(out),
    marker_size=6,
    line_width=3,  # don't try to display in this headless env
)
print(f"Saved: {out} ({out.stat().st_size:,} bytes)")

# Verify the file is a valid HTML
html_content = out.read_text()
assert html_content.startswith('<!DOCTYPE html>') or '<html' in html_content, "Not a valid HTML file"
print(f"HTML verified: starts with valid doctype/html tag")

Saved: /tmp/tmpsxy8yqfj/chromosome_3d.html (4,848,506 bytes)
HTML verified: starts with valid doctype/html tag
# Render with per-bin scalar node_colors (e.g. log-fold-change vs average)
node_colors = np.sin(t)  # some scalar value per bin
out = OUT / "chromosome_3d_colored.html"
plot_chromosome_3d(
    points=points,
    output_path=str(out),
    node_colors=node_colors,
    colorscale='RdBu',
)
print(f"Saved colored: {out} ({out.stat().st_size:,} bytes)")

Saved colored: /tmp/tmpsxy8yqfj/chromosome_3d_colored.html (4,849,096 bytes)
# Render with A/B compartment assignment ({-1, 0, 1} array)
ab_assignment = rng.choice([-1, 0, 1], size=n)  # synthetic A/B
out = OUT / "chromosome_3d_ab.html"
plot_chromosome_3d(
    points=points,
    output_path=str(out),
    node_colors=ab_assignment,
)
print(f"Saved A/B: {out} ({out.stat().st_size:,} bytes)")

Saved A/B: /tmp/tmpsxy8yqfj/chromosome_3d_ab.html (4,848,456 bytes)

2. plot_structure_grid: compare multiple structures#

Use this when you want to compare multiple reconstructed structures (e.g. from different methods, replicates, or time points) in a single 4x4 grid. The grid is rendered as a single interactive HTML page.

The grid_size parameter defaults to (4, 4) and accommodates up to 16 structures per page. For more, build multiple pages.

from gunz_cm.visualizations import plot_structure_grid

# Build 4 synthetic structures (each a perturbed copy of the helix)
structures = []
titles = []
for i, seed in enumerate([1, 2, 3, 4]):
    r = np.random.default_rng(seed)
    p = points + 0.1 * r.standard_normal(points.shape)
    structures.append(p)
    titles.append(f"Replicate {i+1}")

out = OUT / "structure_grid.html"
plot_structure_grid(
    structures=structures,
    titles=titles,
    output_path=str(out),
    main_title="4 Replicate Structures",
    grid_size=(2, 2),  # 2x2 instead of 4x4 for these 4 structures
    use_cdn=True,
    showscale=True,
)
print(f"Saved grid: {out} ({out.stat().st_size:,} bytes)")
print(f"Structures: {len(structures)}, titles: {titles}")

Saved grid: /tmp/tmpsxy8yqfj/structure_grid.html (19,470 bytes)
Structures: 4, titles: ['Replicate 1', 'Replicate 2', 'Replicate 3', 'Replicate 4']

3. plot_chromosome_3d_with_ellipsoid: PCA uncertainty#

Use this to show the structural uncertainty of a 3D structure by drawing a PCA-derived bounding ellipsoid around the points. This is useful when you have an ensemble of reconstructions and want to show the spread.

The confidence parameter controls the ellipsoid size:

  • confidence=1.0 — 1σ (~68% of points)

  • confidence=2.0 (default) — 2σ (~95% of points)

  • confidence=3.0 — 3σ (~99.7% of points)

from gunz_cm.visualizations import plot_chromosome_3d_with_ellipsoid

out = OUT / "chromosome_3d_ellipsoid.html"
plot_chromosome_3d_with_ellipsoid(
    points=points,
    output_path=str(out),
    ellipsoid_color="rgba(0, 200, 200, 0.2)",
    confidence=2.0,
    n_mesh=20,
    use_cdn=True,
)
print(f"Saved with ellipsoid: {out} ({out.stat().st_size:,} bytes)")

Saved with ellipsoid: /tmp/tmpsxy8yqfj/chromosome_3d_ellipsoid.html (28,975 bytes)
# Try different confidence levels
for sigma in [1.0, 2.0, 3.0]:
    out = OUT / f"chromosome_3d_ellipsoid_{sigma}sigma.html"
    plot_chromosome_3d_with_ellipsoid(
        points=points,
        output_path=str(out),
        confidence=sigma,
        n_mesh=15,  # coarser mesh = faster
    )
    size_kb = out.stat().st_size / 1024
    print(f"  {sigma}σ: {out.name} ({size_kb:.1f} KB)")

  1.0σ: chromosome_3d_ellipsoid_1.0sigma.html (20.6 KB)


  2.0σ: chromosome_3d_ellipsoid_2.0sigma.html (20.8 KB)
  3.0σ: chromosome_3d_ellipsoid_3.0sigma.html (20.6 KB)

4. ParaView export: write_vtp_polydata and write_vtk_points#

ParaView is the standard tool for high-quality 3D visualization of scientific data. write_vtp_polydata writes a .vtp file (ParaView’s modern XML format) that renders each point as a sphere; write_vtk_points writes a .vtk legacy ASCII file.

Use write_vtp_polydata for new projects; write_vtk_points for legacy pipelines.

Summary#

Decision tree for choosing a 3D visualization function:

Use case

Function

Output format

Render single 3D structure for browser viewing

plot_chromosome_3d

HTML (Plotly)

Compare multiple reconstructions side-by-side

plot_structure_grid

HTML (Plotly)

Show structural uncertainty via PCA ellipsoid

plot_chromosome_3d_with_ellipsoid

HTML (Plotly)

Export for high-quality rendering in ParaView

write_vtp_polydata

.vtp (XML)

Export for legacy pipelines

write_vtk_points

.vtk (ASCII)

All plot_* functions default to use_cdn=True (Plotly loaded from CDN, smaller file size) and produce a single self-contained HTML file. Set use_cdn=False for offline viewing (larger file size).

4. ParaView export (requires vtk extra)#

ParaView is the standard tool for high-quality 3D visualization. The functions write_vtp_polydata and write_vtk_points are available in gunz_cm.reconstructions.utils.vtk_writer and gunz_cm.visualizations.paraview_exporter respectively, but require the vtk Python package:

pip install vtk  # or: pip install gunz-cm[3dr] (includes vtk)

After installing vtk, the function signatures are:

from gunz_cm.reconstructions.utils.vtk_writer import write_vtp_polydata
from gunz_cm.visualizations.paraview_exporter import write_vtk_points

write_vtp_polydata(
    points=points, fpath="structure.vtp",
    sphere_radius=0.05,        # VTP renders each point as a sphere of this radius
    add_index_based_color=True,  # color by index for ParaView visualisation
)
write_vtk_points(points=points, filename="structure.vtk")  # legacy ASCII

Use write_vtp_polydata for new projects; write_vtk_points for legacy pipelines.