Metadata-Version: 2.4
Name: modernsn
Version: 0.1.2
Summary: MODERN (MOdule DEtection and Refinement in signed Networks): community detection of a signed network.
Home-page: https://github.com/rnakato/MODERN
Author: Ryuichiro Nakato
Author-email: rnakato@iqb.u-tokyo.ac.jp
License: GPL3.0
Keywords: MODERN modernsn signed network community detection
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.14.2
Requires-Dist: pandas>=0.22.0
Requires-Dist: leidenalg>=0.8.3
Requires-Dist: eeisp>=0.5.0
Requires-Dist: matplotlib
Requires-Dist: seaborn
Requires-Dist: networkx
Requires-Dist: igraph
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# <img src="img/MODERN_logo.png" width="120"> MODERN: Community analysis for signed networks

**MODERN (MOdule DEtection and Refinement in signed Networks)** detects and
refines modules in networks containing positive and negative edges. The Python
package is named `modernsn`, and the command-line program is `modern`.

MODERN provides:

- signed modularity with Leiden or Louvain optimization;
- signed Constant Potts Model (CPM) clustering;
- metanode analysis of positive and negative relationships between modules;
- mapping of gene modules to cell clusters in single-cell RNA-seq data;
- negative-edge-guided reintegration of a fine starting partition;
- hard cannot-link refinement using negative edges as constraints;
- a multi-seed negative-edge leverage screen;
- a signed-network diagnostic with practical analysis recommendations; and
- parallel parameter sweeps for signed modularity and signed CPM.

<img src = "docs/_static/img/Workflow.png" width = 700ptx>

## Installation

```bash
pip install modernsn==0.1.2
```

The core dependencies are NumPy, pandas, python-igraph, leidenalg, NetworkX,
Matplotlib, seaborn, and EEISP. SciPy is also required when reading MATLAB
`.mat` input.

```bash
modern --version
modern --help
```

## Community-detection methods

| CLI method | Implementation | Objective |
|---|---|---|
| `leiden-mod-alpha` | Signed Leiden modularity | `alpha * Q_pos - (1 - alpha) * Q_neg` |
| `leiden-cpm-single` | Leiden CPM on one signed weighted graph | Positive and negative weights enter the CPM objective directly |
| `louvain` | LouvainSigned | `alpha * Q_pos - (1 - alpha) * Q_neg` |

Signed modularity and signed CPM have different resolution responses. Their
parameters should therefore be examined for the network being analyzed rather
than treated as interchangeable.

## Input formats

### Separate positive and negative TSV files

The default input is a pair of tab-separated files with five columns and no
header:

```text
gene_id1    gene_id2    gene_name1    gene_name2    weight
ENSG00001   ENSG00002   GeneA         GeneB         15.3
ENSG00001   ENSG00003   GeneA         GeneC         12.1
```

Edges can be selected by score threshold or by global rank:

```bash
# Score thresholds
modern --pos positive.tsv --neg negative.tsv \
  --thre-pos 10 --thre-neg 1 \
  --method leiden-mod-alpha --alpha 0.7 --resolution 1 \
  --seed 12345 --out-prefix results/run1

# Top-N edges
modern --pos positive.tsv --neg negative.tsv \
  --edge-select top-n --top-n-pos 500000 --top-n-neg 50000 \
  --method leiden-mod-alpha --alpha 0.7 --resolution 1 \
  --seed 12345 --out-prefix results/run1_topn
```

### One signed SNAP edge list

```bash
modern --format snap --snap signed_edges.txt.gz \
  --method leiden-mod-alpha --alpha 0.7 --resolution 1 \
  --seed 12345 --out-prefix results/snap_run
```

Use `--conflict` to control how opposite signs observed for the same
undirected node pair are handled. `--min-degree` optionally filters nodes using
the positive, negative, or union degree selected by `--degree-mode`.

### MATLAB sparse matrices

```bash
modern --format mat --mat signed_network.mat \
  --pos-key pos --neg-key neg \
  --method leiden-mod-alpha --alpha 0.7 --resolution 1 \
  --out-prefix results/mat_run
```

## Basic command-line use

### Signed modularity

```bash
modern --pos positive.tsv --neg negative.tsv \
  --method leiden-mod-alpha --alpha 0.7 --resolution 1 \
  --seed 12345 --out-prefix results/modularity
```

`alpha=1` gives a positive-only partition. Lower values increase the relative
contribution of the negative layer.

### Signed CPM

```bash
modern --pos positive.tsv --neg negative.tsv \
  --method leiden-cpm-single --lambda-neg 1 --gamma 0.05 \
  --seed 12345 --out-prefix results/cpm
```

`lambda-neg` scales negative edge weights. `gamma` controls CPM resolution and
can produce large changes in module number, so it should be swept explicitly.

## Refinement and diagnostic modes

### Negative-edge-guided reintegration

Reintegration starts from a relatively fine Leiden partition. Positive
coupling proposes module mergers, while negative edges can preserve selected
boundaries.

```bash
modern --pos positive.tsv --neg negative.tsv \
  --method leiden-mod-alpha --alpha 1 --resolution 4 \
  --reintegrate --reintegrate-z 1 --reintegrate-max-neg 0 \
  --reintegrate-min-size 10 --seed 10 \
  --out-prefix results/reintegrated
```

The public Python function retains its original name
`reintegrate_communities_EEI_guided`, but it accepts any negative-edge graph;
it is not restricted to EEI networks.

### Hard cannot-link refinement

`--cannot-link` splits modules that still contain negative edges. This is useful
when negative pairs should be treated as hard constraints, including networks
with too few negative edges for a dataset-level leverage screen.

```bash
modern --pos positive.tsv --neg negative.tsv \
  --method leiden-mod-alpha --alpha 1 --resolution 1 \
  --cannot-link --seed 12345 --out-prefix results/cannot_link
```

### Negative-edge leverage

Negative-edge leverage measures how often positive-only reintegration absorbs
boundaries supported by negative edges:

```text
newly internal negative edges / evaluated negative edges
```

Because the starting high-resolution partition is stochastic, the screen is
run across multiple seeds and reports the full range and a classification.

```bash
modern --pos positive.tsv --neg negative.tsv \
  --method leiden-mod-alpha --negative-edge-leverage \
  --leverage-resolution 4 --leverage-z 1 \
  --leverage-seeds 1 2 3 10 42 \
  --out-prefix results/leverage
```

The default candidate threshold (`0.02`) is an empirical screening threshold,
not a statistical significance cutoff.

### Signed-network check

The combined diagnostic summarizes network size, positive and negative edge
counts, low- and high-resolution positive-only partitions, metanode
relationships, and multi-seed negative-edge leverage. It prints a readable
report to standard output and, when a prefix is supplied, saves the same report
as text.

```bash
modern --pos positive.tsv --neg negative.tsv \
  --method leiden-mod-alpha --check-signed-network \
  --resolution 1 --leverage-resolution 4 \
  --leverage-seeds 1 2 3 10 42 \
  --out-prefix results/network_check
```

The recommendations are empirical analysis guidance. They do not constitute a
formal test that a network has one correct partition.

## Output files

A standard partitioning run with `--out-prefix PREFIX` can generate:

| File | Content |
|---|---|
| `PREFIX_partition.tsv` | Node identifiers, names, and module assignments |
| `PREFIX_summary.txt` | Parameters and partition summary |
| `PREFIX_communities.gmt` | Module membership in GMT format |
| `PREFIX_community_sizes.pdf` | Module-size plots |
| `PREFIX_inter_community.pdf` | Intermodule positive/negative heatmaps |
| `PREFIX_module_<id>.pdf` | Signed subnetworks for the largest modules |

Use `--no-plot`, `--no-gmt`, and `--quiet` to disable plots, GMT output, and
progress messages, respectively.

Special modes instead write:

- `PREFIX_negative_edge_leverage.tsv` and
  `PREFIX_negative_edge_leverage_summary.txt`; or
- `PREFIX_signed_network_check.txt`.

## Python API

### Load graphs and run signed modularity

```python
import modernsn.LeidenSigned as les
import modernsn.network_load as nl
import modernsn.network_module as nm

G_pos = nl.load_graph_from_TSV_igraph_threshold("positive.tsv", threshold=10)
G_neg = nl.load_graph_from_TSV_igraph_threshold("negative.tsv", threshold=1)
G_pos, G_neg = les.align_graphs(G_pos, G_neg)

partition = les.find_partition_signed_modularity(
    G_pos,
    G_neg,
    alpha=0.7,
    resolution=1.0,
    seed=12345,
)

print(partition.sizes())
nm.display_communities_by_name(G_pos, partition)
```

### Signed CPM and cannot-link refinement

```python
G_signed = nm.build_signed_graph_from_igraph(
    G_pos,
    G_neg,
    lambda_neg=1.0,
    neg_weight_mode="absolute",
)

cpm_partition = les.find_partition_signed_CPM_single_graph(
    G_signed,
    gamma=0.05,
    seed=12345,
)

constrained_partition, report = les.find_partition_signed_modularity_cannotlink(
    G_pos,
    G_neg,
    alpha=1.0,
    resolution=1.0,
    seed=12345,
    return_report=True,
)
print(report)
```

### Metanode relationships and reintegration

```python
high_resolution = les.find_partition_signed_modularity(
    G_pos, G_neg, alpha=1.0, resolution=4.0, seed=10
)

relationships = nm.label_community_relationships(
    G_pos,
    G_neg,
    high_resolution,
    min_size=10,
    connected_only=True,
)

reintegrated = nm.reintegrate_communities_EEI_guided(
    G_pos,
    G_neg,
    high_resolution,
    z_threshold=1.0,
    max_neg_count=0,
    min_size=10,
)
refined_partition = reintegrated["partition"]
```

### Link gene modules to single-cell clusters

With Scanpy installed, MODERN can score module genes in each cell, summarize
their expression scores by cell cluster, and display the result with a UMAP and
metanode network:

```python
mapping = nm.assign_communities_to_cell_clusters(
    partition,
    adata,
    min_size=20,
    cluster_key="cell_cluster",
    min_score=0.1,
)

nm.visualize_communities_with_umap(
    G_pos,
    G_neg,
    partition,
    adata,
    min_size=20,
    cluster_key="cell_cluster",
    show_heatmap=True,
)
```

Here, the per-cell score is the Scanpy `score_genes` score for the genes in a
module. The displayed cluster-level value is its mean within each cell cluster.

### Negative-edge leverage and network diagnostics

```python
leverage = nm.calculate_negative_edge_leverage_multiseed(
    G_pos,
    G_neg,
    seeds=[1, 2, 3, 10, 42],
)
print(leverage["negative_edge_leverage_median"])
print(leverage["classification"])

diagnostic = nm.check_signed_network(G_pos, G_neg)
print(nm.format_signed_network_check(diagnostic))
```

### Parallel parameter sweeps

```python
from modernsn.parameter_sweep import sweep_signed_cpm, sweep_signed_modularity

modularity_grid = sweep_signed_modularity(
    G_pos,
    G_neg,
    alphas=[0.5, 0.7, 1.0],
    resolutions=[0.5, 1.0, 2.0],
    seed=12345,
    n_jobs=4,
)

cpm_grid = sweep_signed_cpm(
    G_pos,
    G_neg,
    lambda_negs=[0.0, 0.5, 1.0],
    gammas=[0.0, 0.01, 0.05],
    seed=12345,
    n_jobs=3,
)
```

Both functions return pandas DataFrames containing the parameters and five
partition diagnostics: weighted positive edge fraction between modules,
weighted negative edge fraction within modules, module number, singleton-node
fraction, and largest-module fraction.

## Tutorials

Runnable notebooks are provided in `examples/`:

- `Tutorial_P10_12h_signed_network.ipynb`: construction and analysis of a
  CDI/EEI gene network from single-cell RNA-seq data;
- `Tutorial_Bunis_negative_edge_reintegration.ipynb`: interpretation of a
  module boundary retained by negative-edge-guided reintegration;
- `Tutorial_biological_network_parameter_response.ipynb`: parameter responses
  in different biological network types;
- `synthetic_2cluster_signed_demo.ipynb`: a small signed-network example; and
- `karateclub_with_negtive_edges.ipynb`: a signed Karate Club example.

## Interpretation workflow

1. Inspect node and positive/negative edge counts with
   `--check-signed-network`.
2. Compare low- and high-resolution partitions and repeat stochastic analyses
   across seeds.
3. Use signed modularity or signed CPM when negative edges contribute broadly
   to partitioning.
4. Use reintegration when a fine positive partition contains strongly coupled
   module pairs and negative edges mark boundaries that should be retained.
5. Use cannot-link refinement when particular negative pairs should be kept in
   different modules, even if the negative layer is sparse.

These steps are practical starting points; resolution and edge-selection
thresholds remain properties of the analyzed network.

## Citation

If you use MODERN, please cite:

* Nakato R., Nagai LAE, List M,  MODERN: community detection and exclusivity-aware module refinement in signed biological networks, in prep.

