Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions _quarto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ website:
href: docs/quickstart.qmd
- text: Track Construction
href: docs/quickstart_tracks.qmd
- text: Examples
href: docs/examples.qmd
- text: Guides
menu:
- text: Track Catalog
Expand Down Expand Up @@ -75,7 +73,7 @@ format:
toc-depth: 4
code-copy: true
code-overflow: wrap
page-layout: article
page-layout: full

execute:
enabled: true
Expand Down
145 changes: 142 additions & 3 deletions docs/_examples.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,142 @@
# Re-export shim — all names live in plotnado.examples.
# Quarto docs import from here; user code should import from plotnado.examples directly.
from plotnado.examples import * # noqa: F401, F403
from __future__ import annotations

import importlib.util

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from plotnado import GenomicFigure

REGION = "chr1:1,010,000-1,080,000"
WIDE_REGION = "chr1:1,000,000-1,110,000"


def has_module(module_name: str) -> bool:
return importlib.util.find_spec(module_name) is not None


def unavailable_figure(title: str, requirement: str):
fig, ax = plt.subplots(figsize=(9, 1.8))
ax.axis("off")
ax.text(
0.5,
0.5,
f"{title} requires {requirement}",
ha="center",
va="center",
fontsize=10,
)
plt.close(fig)
return fig


def signal(
start: int = 1_000_000,
end: int = 1_100_000,
step: int = 1_000,
phase: float = 0.0,
scale: float = 1.0,
baseline: float = 5.0,
) -> pd.DataFrame:
bins = np.arange(start, end, step)
values = scale * (
baseline + 2.0 * np.sin(np.linspace(phase, 6 * np.pi + phase, bins.shape[0]))
)
return pd.DataFrame({"chrom": "chr1", "start": bins, "end": bins + step, "value": values})


def review_signal(scale: float = 1.0, phase: float = 0.0) -> pd.DataFrame:
bins = np.arange(1_000_000, 1_120_000, 1_000)
values = scale * (1.2 + np.sin(np.linspace(phase, 6 + phase, bins.shape[0])))
return pd.DataFrame({"chrom": "chr1", "start": bins, "end": bins + 1_000, "value": values})


def intervals() -> pd.DataFrame:
return pd.DataFrame(
{
"chrom": ["chr1", "chr1", "chr1", "chr1"],
"start": [1_008_000, 1_020_000, 1_050_000, 1_066_000],
"end": [1_014_000, 1_032_000, 1_061_000, 1_074_000],
"name": ["enhancer_a", "enhancer_b", "promoter", "domain"],
}
)


def narrowpeaks() -> pd.DataFrame:
return pd.DataFrame(
{
"chrom": ["chr1", "chr1", "chr1"],
"start": [1_012_000, 1_038_000, 1_060_000],
"end": [1_018_000, 1_047_000, 1_070_000],
"name": ["np1", "np2", "np3"],
"score": [300, 700, 500],
"strand": [".", ".", "."],
"signalValue": [12.0, 48.0, 30.0],
"pValue": [5.2, 12.3, 8.1],
"qValue": [4.1, 10.0, 6.2],
"peak": [1200, 1800, 2200],
}
)


def links() -> pd.DataFrame:
return pd.DataFrame(
{
"chrom1": ["chr1", "chr1", "chr1"],
"start1": [1_010_000, 1_022_000, 1_042_000],
"end1": [1_012_000, 1_024_000, 1_045_000],
"chrom2": ["chr1", "chr1", "chr1"],
"start2": [1_035_000, 1_054_000, 1_072_000],
"end2": [1_037_000, 1_056_000, 1_074_000],
"score": [2.2, 6.5, 9.8],
}
)


def quickstart_figure() -> GenomicFigure:
fig = GenomicFigure(width=11, track_height=1.25)
fig.scalebar()
fig.axis()
fig.bigwig(signal(scale=1.15), title="Synthetic signal", style="fill", color="#1f77b4")
fig.bed(intervals(), title="Intervals", display="expanded", show_labels=True)
return fig


def style_comparison() -> GenomicFigure:
fig = GenomicFigure(track_height=1.15)
fig.scalebar()
fig.bigwig(signal(phase=0.0), title="fill", style="fill", color="#1f77b4")
fig.bigwig(signal(phase=0.8), title="fragment", style="fragment", color="#d62728")
fig.bigwig(
signal(phase=1.6),
title="scatter",
style="scatter",
color="#2ca02c",
scatter_point_size=10,
)
fig.bigwig(signal(phase=2.4), title="std", style="std", color="#9467bd")
return fig


def overlay_comparison() -> GenomicFigure:
fig = GenomicFigure(track_height=1.2)
fig.autoscale(True)
fig.highlight("chr1:1,032,000-1,046,000")
fig.highlight_style(color="#ffdd57", alpha=0.22)
fig.axis()
fig.bigwig(review_signal(2.0), title="Control", autoscale_group="signal", color="#1f77b4")
fig.bigwig(
review_signal(10.0, 1.2),
title="Treatment",
autoscale_group="signal",
color="#d62728",
)
fig.overlay(
[review_signal(5.5, 2.0), review_signal(6.5, 2.8)],
title="Overlay",
autoscale_group="signal",
colors=["#2ca02c", "#9467bd"],
alpha=0.55,
)
return fig
124 changes: 25 additions & 99 deletions docs/aesthetics.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -14,62 +14,19 @@ This page focuses on choices you can see: signal styles, color grouping, label p
`style` changes how a quantitative signal is drawn.

```{python}
#| fig-cap: "`fill` is the default for continuous signal, `fragment` emphasizes bins, `scatter` shows individual values, and `std` draws a band-style summary."
from plotnado import GenomicFigure
from plotnado.examples import REGION, signal
# signal() returns a synthetic ChIP-seq-like DataFrame(chrom, start, end, value)
# In real use pass a BigWig path/URL or any DataFrame with those columns
# REGION is a string like "chr1:1,000,000-1,100,000"


fig = GenomicFigure(track_height=1.15)
fig.scalebar()
fig.bigwig(signal(phase=0.0), title="fill", style="fill", color="#1f77b4")
fig.bigwig(signal(phase=0.8), title="fragment", style="fragment", color="#d62728")
fig.bigwig(signal(phase=1.6), title="scatter", style="scatter", color="#2ca02c", scatter_point_size=10)
fig.bigwig(signal(phase=2.4), title="std", style="std", color="#9467bd")
fig.plot(REGION)
```

## Signal resolution
from docs._examples import REGION, style_comparison

`n_bins` divides the plotted region into a fixed number of equal bins regardless of the source resolution. `bin_size` sets the bin width in base pairs instead. Both work with BigWig files and DataFrames; overlapping source intervals are averaged by overlap length.

```{python}
#| fig-cap: "Coarser binning compresses the signal into broader summaries; finer bins preserve peak shape. The bottom track is the native 200 bp resolution from the synthetic data."
from plotnado import GenomicFigure
from plotnado.examples import REGION, signal
# signal() returns a synthetic ChIP-seq-like DataFrame(chrom, start, end, value) at 200 bp bins
# In real use pass a BigWig path/URL or any DataFrame with those columns

fig = GenomicFigure(track_height=1.15)
fig.scalebar()
fig.bigwig(signal(), title="bin_size=5000 (coarse)", style="fill", color="#9467bd", bin_size=5000)
fig.bigwig(signal(), title="bin_size=1000", style="fill", color="#d62728", bin_size=1000)
fig.bigwig(signal(), title="bin_size=200 (native)", style="fill", color="#1f77b4")
fig.bigwig(signal(), title="n_bins=50", style="fill", color="#2ca02c", n_bins=50)
fig.bigwig(signal(), title="n_bins=200", style="fill", color="#ff7f0e", n_bins=200)
fig.axis()
fig = style_comparison()
fig.plot(REGION)
```

Use `n_bins` when you want consistent resolution across regions of different sizes:

```python
# Always 200 bins regardless of zoom level
fig.bigwig("signal.bw", n_bins=200)

# Fixed bin width across any region
fig.bigwig("signal.bw", bin_size=500)
```
Caption: `fill` is the default for continuous signal, `fragment` emphasizes bins, `scatter` shows individual values, and `std` draws a band-style summary.

## Color and alpha

```{python}
#| fig-cap: "Use opacity to reduce visual dominance when several panels are compared."
from plotnado import GenomicFigure
from plotnado.examples import REGION, signal
# signal() → DataFrame(chrom, start, end, value) — replace with a BigWig path/URL or DataFrame
from docs._examples import REGION, signal

fig = GenomicFigure(track_height=1.0)
fig.bigwig(signal(), title="alpha=1.0", style="fill", color="#1f77b4", alpha=1.0)
Expand All @@ -78,16 +35,15 @@ fig.bigwig(signal(phase=1.6), title="alpha=0.35", style="fill", color="#2ca02c",
fig.plot(REGION)
```

Caption: use opacity to reduce visual dominance when several panels are compared.

## Autocolor and groups

Use `autocolor()` once, then assign related tracks the same `color_group`.

```{python}
#| fig-cap: "Color groups keep semantically related tracks aligned without hard-coding every color."
from plotnado import GenomicFigure
from plotnado.examples import REGION, intervals, signal
# signal() → DataFrame(chrom, start, end, value) — replace with a BigWig path/URL or DataFrame
# intervals() → DataFrame(chrom, start, end, name) — replace with a BED/BigBed path, URL, or DataFrame
from docs._examples import REGION, intervals, signal

fig = GenomicFigure(track_height=1.1).autocolor("Set2")
fig.bigwig(signal(phase=0.0), title="Sample A signal", color_group="A")
Expand All @@ -97,86 +53,56 @@ fig.bed(intervals().assign(name=["b1", "b2", "b3", "b4"]), title="Sample B peaks
fig.plot(REGION)
```

Caption: color groups keep semantically related tracks aligned without hard-coding every color.

## Label placement

```{python}
#| fig-cap: "`title_location` anchors the label left or right; `label_box_enabled` adds a legibility box; `label_on_track` with the box is useful for compact multi-track figures."
from plotnado import GenomicFigure
from plotnado.examples import REGION, signal
# signal() → DataFrame(chrom, start, end, value) — replace with a BigWig path/URL or DataFrame
from docs._examples import REGION, signal

fig = GenomicFigure(track_height=1.0)
fig.bigwig(signal(), title="title_location='left'", title_location="left")
fig.bigwig(signal(phase=0.7), title="title_location='right'", title_location="right")
fig.bigwig(signal(phase=1.4), title="label_on_track, no box", label_on_track=True, label_box_enabled=False)
fig.bigwig(signal(phase=2.1), title="label_on_track + label_box_enabled", label_on_track=True, label_box_enabled=True)
fig.bigwig(signal(), title="left margin", title_location="left")
fig.bigwig(signal(phase=0.7), title="right margin", title_location="right")
fig.bigwig(signal(phase=1.4), title="on track", label_on_track=True, label_box_enabled=True)
fig.plot(REGION)
```

Caption: on-track labels are useful for compact figures, especially with a label box.

## Overlay, autoscale, and highlights

```{python}
#| fig-cap: "`highlight()` marks a locus without changing y-limits; `autoscale_group` on the overlay synchronizes the panel with neighboring signal tracks."
from plotnado import GenomicFigure
from plotnado.examples import REGION, review_signal
# review_signal() → DataFrame(chrom, start, end, value) — replace with BigWig paths/URLs or DataFrames

signal_a = review_signal(2.0)
signal_b = review_signal(10.0, 1.2)


fig = GenomicFigure(track_height=1.2)
fig.autoscale(True)
fig.highlight("chr1:1,032,000-1,046,000")
fig.highlight_style(color="#ffdd57", alpha=0.22)
fig.bigwig(signal_a, title="Control", autoscale_group="signal", color="#1f77b4")
fig.bigwig(signal_b, title="Treatment", autoscale_group="signal", color="#d62728")
fig.overlay(
[signal_a, signal_b],
title="Overlay",
autoscale_group="signal",
colors=["#1f77b4", "#d62728"],
alpha=0.55,
)
from docs._examples import REGION, overlay_comparison

fig = overlay_comparison()
fig.plot(REGION)
```

Caption: `highlight()` marks a locus without changing y-limits; `autoscale_group` on the overlay synchronizes the panel with neighboring signal tracks.

## BED, narrowPeak, and links

```{python}
#| fig-cap: "Interval, peak, and link tracks use tabular inputs with genomic coordinate columns."
from plotnado import GenomicFigure
from plotnado.examples import REGION, intervals, links, narrowpeaks
# intervals() → DataFrame(chrom, start, end, name) — replace with a BED/BigBed path, URL, or DataFrame
# narrowpeaks() → DataFrame(chrom, start, end, name, score, strand, signalValue, pValue, qValue, peak) — replace with a .narrowPeak path or DataFrame
# links() → DataFrame(chrom1, start1, end1, chrom2, start2, end2, score) — replace with a BEDPE path or DataFrame
from docs._examples import REGION, intervals, links, narrowpeaks

fig = GenomicFigure(track_height=1.1)
fig.axis()
fig.bed(intervals(), title="BED intervals", display="expanded", show_labels=True)
fig.narrowpeak(narrowpeaks(), title="narrowPeak", color_by="signalValue", cmap="Oranges", show_summit=True)
fig.links(links(), title="Links", color_by_score=True, cmap="viridis", alpha=0.8)
fig.axis()
fig.plot(REGION)
```

Caption: interval, peak, and link tracks use tabular inputs with genomic coordinate columns.

## Themes

```{python}
```python
from plotnado import GenomicFigure
from plotnado.examples import signal, REGION

fig = GenomicFigure(theme="publication")
fig.scalebar()
fig.bigwig(signal(), title="Publication theme", style="fill", color="#1f77b4")
fig.axis()
fig.plot("chr1:1,000,000-1,100,000", show=True)

fig = GenomicFigure(theme="minimal")
fig.scalebar()
fig.bigwig(signal(), title="Minimal theme", style="fill", color="#1f77b4")
fig.axis()
fig.plot("chr1:1,000,000-1,100,000", show=False)

```

Built-in themes include `"default"`, `"minimal"`, and `"publication"`.
4 changes: 1 addition & 3 deletions docs/best_practices.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ Call `autocolor()` once and reuse `color_group` for related tracks.

```{python}
from plotnado import GenomicFigure
from plotnado.examples import REGION, intervals, signal
# signal() → DataFrame(chrom, start, end, value) — replace with a BigWig path/URL or DataFrame
# intervals() → DataFrame(chrom, start, end, name) — replace with a BED/BigBed path, URL, or DataFrame
from docs._examples import REGION, intervals, signal

fig = GenomicFigure(track_height=1.05).autocolor("Set2")
fig.bigwig(signal(phase=0.0), title="A signal", color_group="A")
Expand Down
Loading
Loading