Skip to main content

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.

Installation

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.

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:

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:

# 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

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

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

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

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.

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.

--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.

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:

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.

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.

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

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)
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

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"]

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:

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

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

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.

Release files for modernsn 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for modernsn 0.1.2
File Size Uploaded
modernsn-0.1.2.tar.gz 68.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for modernsn 0.1.2
File Interpreter ABI Platform
modernsn-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 133.7 kB

Release files / modernsn-0.1.2.tar.gz

Download URL modernsn-0.1.2.tar.gz
Size 68.5 kB
Tags Source
SHA-256 checksum
How to use checksums
8916e490b8a102756c5d83ca7527ab58eaa13b4697456e5495590c51bfdc31ce
BLAKE2b-256 checksum
How to use checksums
4bb6b41244301843afa99acf59cec7f5d500f5c93eba3865362eeccb35980e6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.13

Release files / modernsn-0.1.2-py3-none-any.whl

Download URL modernsn-0.1.2-py3-none-any.whl
Size 65.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5f8a5ac73820e6beca22ee3d8fcdbe24ec7754f434d4b0b9986f3ef46f194bbd
BLAKE2b-256 checksum
How to use checksums
d816df27869df87b85c94b3658b3860955d8d28ce521e82a0f4ca59ede19acee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.13

Release history Release notifications | RSS feed

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page