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.
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.
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.tsvandPREFIX_negative_edge_leverage_summary.txt; orPREFIX_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)
Signed CPM and cannot-link refinement
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"]
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:
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; andkarateclub_with_negtive_edges.ipynb: a signed Karate Club example.
Interpretation workflow
- Inspect node and positive/negative edge counts with
--check-signed-network. - Compare low- and high-resolution partitions and repeat stochastic analyses across seeds.
- Use signed modularity or signed CPM when negative edges contribute broadly to partitioning.
- Use reintegration when a fine positive partition contains strongly coupled module pairs and negative edges mark boundaries that should be retained.
- 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)
| File | Size | Uploaded | |
|---|---|---|---|
| modernsn-0.1.2.tar.gz | 68.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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
|