Skip to content
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ docs/_generated/
docs/tutorials/generated/
docs/readme.md
docs/troubleshooting.md
docs/roadmap.md
docs/quickstart.png
docs/_static/logo.png
data/archive.tar.gz
Expand Down
18 changes: 18 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cff-version: 1.2.0
message: "If you use MethylSeg, please cite this software."
title: "MethylSeg"
type: software
version: "0.1.8"
abstract: >-
MethylSeg is a context-aware methylome segmentation method for identifying
partially methylated domains in whole-genome bisulfite sequencing and
methylation microarray data.
authors:
- family-names: "Tye"
given-names: "Jacob"
orcid: "https://orcid.org/0009-0000-6883-9572"
- family-names: "Clement"
given-names: "Kendell"
orcid: "https://orcid.org/0000-0003-3808-0811"
repository-code: "https://github.com/clementlab/MethylSeg"
url: "https://github.com/clementlab/MethylSeg"
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

![logo](https://raw.githubusercontent.com/clementlab/MethylSeg/main/logo.png)

[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22904886.svg)](https://doi.org/10.5281/zenodo.22904886)

MethylSeg is a Python toolkit for identifying methylation domains from
whole-genome bisulfite sequencing (WGBS) and microarray methylation data. It
supports data preparation, methylation-state model training, genome
Expand All @@ -25,17 +27,15 @@ values were observed during testing:

> [!NOTE]
> Numba has known compatibility issues on ARM-based systems. See the
> [Troubleshooting guide](TROUBLESHOOTING.md) for installation guidance.
> [Troubleshooting guide](https://github.com/clementlab/MethylSeg/blob/main/TROUBLESHOOTING.md)
> for installation guidance.

## Installation

Install from TestPyPI
Install from PyPI

```bash
python -m pip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
methylseg
python -m pip install methylseg
```

or install the current version from GitHub:
Expand All @@ -44,8 +44,6 @@ or install the current version from GitHub:
python -m pip install "git+https://github.com/clementlab/MethylSeg.git"
```



## Reference files

### Sample data
Expand Down Expand Up @@ -255,12 +253,17 @@ The BED files themselves are tab-delimited and do not contain a header.

## Citation

A manuscript describing MethylSeg is in preparation. Citation information will
be added when it becomes available.
If you use MethylSeg, please cite the software using the
[CITATION.cff](https://github.com/clementlab/MethylSeg/blob/main/CITATION.cff)
metadata. On GitHub, select **Cite this repository** to copy the citation in APA
or BibTeX format.

A manuscript describing MethylSeg is in preparation. Its citation will be added
when available.

## Planned support

- [ ] Add defaults for HM27 and EPIC microarray formats
See [ROADMAP.md](https://github.com/clementlab/MethylSeg/blob/main/ROADMAP.md)

## Reporting issues

Expand Down
17 changes: 17 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# MethylSeg Roadmap

## 1.1.0

- [ ] Develop and benchmark platform-specific defaults for HM27 and EPIC arrays
- [ ] Add optional confidence scores for MethylSeg region calls

## 1.2.0

- [ ] Add a scalable multi-sample workflow
- Support efficient processing of multiple samples
- Generate cohort-level consensus regions and recurrence statistics

## 2.0.0

- [ ] Replace the external ctHMM implementation with an in-house model
- This will change the underlying model specification and may produce results that differ from MethylSeg 1.x.
12 changes: 10 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
GENERATED_TUTORIALS = DOCS_ROOT / "tutorials" / "generated"
STAGED_README = DOCS_ROOT / "readme.md"
STAGED_TROUBLESHOOTING = DOCS_ROOT / "troubleshooting.md"
STAGED_ROADMAP = DOCS_ROOT / "roadmap.md"
README_IMAGE = "quickstart.png"
README_LOGO = "logo.png"
REPOSITORY_URL = "https://github.com/clementlab/MethylSeg"
Expand Down Expand Up @@ -107,15 +108,21 @@ def _manual_rst_pages() -> list[str]:
"tutorials",
"api",
"troubleshooting",
"roadmap",
]


def _stage_readme() -> None:
"""Copy the README while retargeting links that are relative to the repo."""
"""Copy the README while retargeting repository links for Sphinx."""
readme = (PACKAGE_ROOT / "README.md").read_text()
readme = _convert_github_alerts(readme)
readme = readme.replace(
"(TROUBLESHOOTING.md)", "(troubleshooting.md)"
f"({REPOSITORY_URL}/blob/main/TROUBLESHOOTING.md)",
"(troubleshooting.md)",
)
readme = readme.replace(
f"({REPOSITORY_URL}/blob/main/ROADMAP.md)",
"(roadmap.md)",
)
readme = readme.replace(
"(examples/run_full_pipeline.ipynb)",
Expand All @@ -130,6 +137,7 @@ def _stage_readme() -> None:
readme = readme.replace("(LICENSE.md)", f"({REPOSITORY_URL}/blob/main/LICENSE)")
_write(STAGED_README, readme)
_write(STAGED_TROUBLESHOOTING, (PACKAGE_ROOT / "TROUBLESHOOTING.md").read_text())
_write(STAGED_ROADMAP, (PACKAGE_ROOT / "ROADMAP.md").read_text())
STATIC_ROOT.mkdir(parents=True, exist_ok=True)
copy2(PACKAGE_ROOT / README_LOGO, STATIC_ROOT / README_LOGO)
copy2(PACKAGE_ROOT / README_IMAGE, DOCS_ROOT / README_IMAGE)
Expand Down
5 changes: 5 additions & 0 deletions methylseg/helper_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ def __init__(
resolution="auto",
min_coverage=10,
remove_low_coverage_like_cpgs=False,
low_coverage_like_beta_values=None,
chunk_size=1_000_000,
retain_removed_rows=True,
):
Expand All @@ -195,6 +196,8 @@ def __init__(
If ``True``, remove CpGs with beta values commonly produced by very
low coverage counts, such as 0.0, 0.25, 0.33, 0.5, 0.66/0.67,
0.75, and 1.0.
low_coverage_like_beta_values
A set of beta values that are indicative of low coverage.
chunk_size
Number of rows to read at a time when processing large files.
retain_removed_rows
Expand All @@ -207,6 +210,8 @@ def __init__(
self.resolution = resolution
self.min_coverage = min_coverage
self.remove_low_coverage_like_cpgs = remove_low_coverage_like_cpgs
if low_coverage_like_beta_values is not None:
self.LOW_COVERAGE_LIKE_BETA_VALUES = frozenset(low_coverage_like_beta_values)
self.chunk_size = chunk_size
self.retain_removed_rows = retain_removed_rows

Expand Down
17 changes: 15 additions & 2 deletions methylseg/methyl_state_assigner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Window-based emission feature engineering and KMeans state assignment."""

from enum import Enum
from pathlib import Path
import textwrap
import warnings

Expand Down Expand Up @@ -2556,11 +2557,18 @@ def plot_feature_distributions_by_kmeans_state(
show_plots: bool = True,
state_colors: dict | None = None,
state_cutoffs: dict | None = None,
save_plots: bool | None = None,
save_pdf: bool = False,
):
"""Plot training-emission histograms stratified by KMeans state.

``state_cutoffs`` optionally controls the biological-state display
labels; it does not change the KMeans assignments.

When ``save_plots`` is omitted, the legacy behavior is preserved:
plots are saved as PNG only when ``show_plots`` is false. Set
``save_plots=True`` to save while displaying and ``save_pdf=True`` to
add same-stem PDF companions.
"""
if not hasattr(self, "model"):
raise ValueError("No trained model found. Please train a model first.")
Expand Down Expand Up @@ -2623,8 +2631,13 @@ def plot_feature_distributions_by_kmeans_state(
ax.set_title(f"Distribution of {emission} by KMeans State")
ax.legend()
fig.tight_layout()
should_save = (not show_plots) if save_plots is None else save_plots
if should_save and self.out_dir is not None:
output_path = Path(self.out_dir) / f"feature_distribution_{emission}.png"
output_path.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(output_path)
if save_pdf:
fig.savefig(output_path.with_suffix(".pdf"))
if show_plots:
plt.show()
elif self.out_dir is not None:
fig.savefig(f"{self.out_dir}/feature_distribution_{emission}.png")
plt.close(fig)
2 changes: 2 additions & 0 deletions methylseg/methylseg_pathway.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def prepare_sample_info(
resolution: str = "auto",
min_coverage: int = 10,
remove_low_coverage_like_cpgs: bool = False,
low_coverage_like_beta_values: set[float] | None = None,
) -> tuple[SampleInfo, pd.DataFrame]:
"""
Prepare a methylation file into the package's canonical sample schema.
Expand Down Expand Up @@ -112,6 +113,7 @@ def prepare_sample_info(
resolution=resolution,
min_coverage=min_coverage,
remove_low_coverage_like_cpgs=remove_low_coverage_like_cpgs,
low_coverage_like_beta_values=low_coverage_like_beta_values,
).prepare()

@staticmethod
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "methylseg"
version = "0.1.8"
version = "1.0.0"
description = "Methylation segmentation utilities used in the TCGA methylation analysis repo."
readme = "README.md"
requires-python = ">=3.10"
Expand Down
Loading