modernsn 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
modernsn-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ryuichiro Nakato
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,353 @@
1
+ Metadata-Version: 2.4
2
+ Name: modernsn
3
+ Version: 0.1.0
4
+ Summary: MODERN (MOdule DEtection and Refinement in signed Networks): community detection of a signed network.
5
+ Home-page: https://github.com/rnakato/MODERN
6
+ Author: Ryuichiro Nakato
7
+ Author-email: rnakato@iqb.u-tokyo.ac.jp
8
+ License: GPL3.0
9
+ Keywords: MODERN modernsn signed network community detection
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: numpy>=1.14.2
16
+ Requires-Dist: pandas>=0.22.0
17
+ Requires-Dist: leidenalg>=0.8.3
18
+ Requires-Dist: eeisp>=0.5.0
19
+ Requires-Dist: matplotlib
20
+ Requires-Dist: seaborn
21
+ Requires-Dist: networkx
22
+ Requires-Dist: igraph
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: keywords
30
+ Dynamic: license
31
+ Dynamic: license-file
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ # MODERN
37
+
38
+ **MO**dule **DE**tection and **R**efinement in signed **N**etworks (MODERN) detects community structure in signed networks — networks with both positive (attractive) and negative (repulsive) edges. It extends classical community detection algorithms (Louvain, Leiden) to leverage negative edge information, which is critical for accurate module detection in biological networks such as gene co-expression networks.
39
+
40
+ ## Why signed networks?
41
+
42
+ Standard community detection methods use only positive edges and ignore negative correlations between genes. When inter-community positive edges are abundant (e.g., in correlation-based networks), unsigned methods fail to identify the correct community structure because they cannot distinguish "noise" positive edges from true intra-community edges.
43
+
44
+ Signed methods use negative edges as repulsive forces to push nodes apart, recovering the correct community structure even when the positive graph alone is ambiguous.
45
+
46
+ <p align="center">
47
+ <img src="docs/fig1_signed_vs_unsigned_matrix.png" width="90%">
48
+ </p>
49
+
50
+ *Signed adjacency matrix sorted by detected communities. As inter-community positive edges increase (top to bottom), unsigned modularity collapses (ARI=0.07) while signed methods maintain near-perfect recovery (ARI>0.93).*
51
+
52
+ ## Methods
53
+
54
+ MODERN provides three community detection methods for signed networks:
55
+
56
+ | Method | Algorithm | Objective | Best for |
57
+ |--------|-----------|-----------|----------|
58
+ | `louvain` | LouvainSigned | α·Q⁺ − (1−α)·Q⁻ | Compatibility with existing Louvain workflows |
59
+ | `leiden-mod-alpha` | LeidenSigned (modularity) | α·Q⁺ − (1−α)·Q⁻ | General signed networks |
60
+ | `leiden-cpm-single` | LeidenSigned (CPM) | Σ(w_ij − γ) on signed graph | Correlation-based networks (co-expression) |
61
+
62
+ **When to use CPM over modularity:** Modularity's null model assumes a configuration-model random graph. In correlation-based networks (e.g., gene co-expression), the positive graph is inherently dense, distorting the null model. CPM uses an absolute density threshold (γ) instead and is not affected by this issue.
63
+
64
+ ## Installation
65
+
66
+ ```bash
67
+ pip install modernsn
68
+ ```
69
+
70
+ ### Dependencies
71
+
72
+ - Python ≥ 3.9
73
+ - numpy
74
+ - igraph (python-igraph)
75
+ - leidenalg
76
+ - networkx
77
+ - matplotlib (for plotting outputs)
78
+ - scipy (for MAT format support)
79
+
80
+ ## Quick start
81
+
82
+ ```bash
83
+ # Basic run with Leiden signed modularity
84
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
85
+ --method leiden-mod-alpha --alpha 0.6 --resolution 1.0 \
86
+ --out-prefix results/my_analysis
87
+
88
+ # Leiden signed CPM (recommended for co-expression networks)
89
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
90
+ --method leiden-cpm-single --gamma 0.05 --lambda-neg 1.0 \
91
+ --out-prefix results/my_analysis
92
+
93
+ # Louvain signed
94
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
95
+ --method louvain --alpha 0.6 --resolution 1.0 \
96
+ --out-prefix results/my_analysis
97
+
98
+ # Multi-seed negative-edge leverage screen
99
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
100
+ --method leiden-mod-alpha --negative-edge-leverage \
101
+ --leverage-seeds 1 2 3 10 42 \
102
+ --out-prefix results/my_analysis
103
+
104
+ # Signed-network diagnostic and analysis recommendations
105
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
106
+ --method leiden-mod-alpha --check-signed-network \
107
+ --leverage-seeds 1 2 3 10 42 \
108
+ --out-prefix results/my_analysis
109
+ ```
110
+
111
+ ## Input formats
112
+
113
+ ### TSV (default)
114
+
115
+ Tab-separated file with five columns (no header):
116
+
117
+ ```
118
+ gene_id1 gene_id2 gene_name1 gene_name2 weight
119
+ ENSG00001 ENSG00002 GeneA GeneB 15.3
120
+ ENSG00001 ENSG00003 GeneA GeneC 12.1
121
+ ```
122
+
123
+ Provide separate files for positive and negative edges via `--pos` and `--neg`. Use `--thre-pos` and `--thre-neg` to filter edges by weight.
124
+
125
+ ### MAT (MATLAB sparse matrix)
126
+
127
+ ```bash
128
+ modern --format mat --mat data/network.mat \
129
+ --pos-key pos --neg-key neg \
130
+ --method leiden-mod-alpha --out-prefix results/mat_run
131
+ ```
132
+
133
+ The MAT file should contain two sparse matrices (positive and negative adjacency).
134
+
135
+ ## Output files
136
+
137
+ When `--out-prefix` is specified, MODERN generates the following outputs:
138
+
139
+ | File | Description |
140
+ |------|-------------|
141
+ | `<prefix>_partition.tsv` | Community assignment for each gene (gene_id, gene_name, community) |
142
+ | `<prefix>_summary.txt` | Parameters, graph statistics, community size distribution, entropy |
143
+ | `<prefix>_communities.gmt` | GMT format for direct use with GSEA, Enrichr, clusterProfiler |
144
+ | `<prefix>_community_sizes.pdf` | Rank-size plot and histogram of community sizes |
145
+ | `<prefix>_inter_community.pdf` | Heatmap of inter-community edge density (positive / negative / signed) |
146
+ | `<prefix>_module_<id>.pdf` | Subnetwork visualization for top modules (positive=red, negative=blue) |
147
+
148
+ With `--negative-edge-leverage`, MODERN instead writes one row per seed to
149
+ `<prefix>_negative_edge_leverage.tsv` and a multi-seed summary to
150
+ `<prefix>_negative_edge_leverage_summary.txt`.
151
+
152
+ With `--check-signed-network`, MODERN reports network size, low- and
153
+ high-resolution partition summaries, metanode enrichment, multi-seed
154
+ negative-edge leverage, and analysis recommendations. The full result is saved
155
+ to `<prefix>_signed_network_check.json`.
156
+
157
+ ## Negative-edge leverage
158
+
159
+ Negative-edge leverage asks whether positive-only reintegration would merge
160
+ module boundaries supported by negative edges. MODERN first generates a
161
+ high-resolution positive-only Leiden partition, then performs reintegration
162
+ without applying the negative-edge veto. The score is
163
+
164
+ ```
165
+ (negative edges newly placed within modules) / (negative edges evaluated)
166
+ ```
167
+
168
+ The defaults reproduce the manuscript screen: resolution 4, positive-coupling
169
+ robust-z threshold 1, minimum module size 10, and seeds 1, 2, 3, 10, and 42.
170
+ The empirical candidate threshold of 0.02 is reported as a screen rather than a
171
+ general significance cutoff.
172
+
173
+ ### Disabling outputs
174
+
175
+ ```bash
176
+ --no-plot # Skip all PDF plots
177
+ --no-gmt # Skip GMT output
178
+ --quiet # Suppress progress messages
179
+ ```
180
+
181
+ ### Controlling module plots
182
+
183
+ ```bash
184
+ --top-modules 10 # Number of top modules to plot (default: 10)
185
+ --max-nodes-per-module 200 # Max nodes per module plot (default: 200)
186
+ ```
187
+
188
+ ## Parameters
189
+
190
+ ### Method-specific parameters
191
+
192
+ **Modularity-based methods** (`louvain`, `leiden-mod-alpha`):
193
+
194
+ | Parameter | Description | Default |
195
+ |-----------|-------------|---------|
196
+ | `--alpha` | Balance between positive and negative modularity (0–1). Higher α emphasizes positive edges. | 0.5 |
197
+ | `--resolution` | Resolution parameter. Higher values produce more, smaller communities. | 1.0 |
198
+
199
+ **CPM method** (`leiden-cpm-single`):
200
+
201
+ | Parameter | Description | Default |
202
+ |-----------|-------------|---------|
203
+ | `--gamma` | CPM resolution. Minimum edge density within communities. | 0.5 |
204
+ | `--lambda-neg` | Weight multiplier for negative edges. Controls how strongly negative edges repel. | 0.0 |
205
+ | `--neg-weight-mode` | How to transform negative weights: `absolute` (−λ·\|w\|) or `signed` (λ·w). | absolute |
206
+
207
+ ### Common parameters
208
+
209
+ | Parameter | Description | Default |
210
+ |-----------|-------------|---------|
211
+ | `--seed` | Random seed for reproducibility. | None |
212
+ | `--out-prefix` | Output file prefix. If omitted, only prints summary to stdout. | None |
213
+
214
+ ## Python API
215
+
216
+ MODERN can also be used as a Python library:
217
+
218
+ ```python
219
+ import modernsn.network_module as nr
220
+ import modernsn.LeidenSigned as les
221
+
222
+ # Load graphs
223
+ G_pos = nr.load_graph_from_TSV_igraph("positive.tsv", threshold=10)
224
+ G_neg = nr.load_graph_from_TSV_igraph("negative.tsv", threshold=5)
225
+
226
+ # Leiden signed modularity
227
+ partition = les.find_partition_signed_modularity_alpha(
228
+ G_pos, G_neg, alpha=0.6, resolution=1.0, seed=42
229
+ )
230
+
231
+ # Leiden signed CPM (single signed graph)
232
+ G_signed = nr.load_signed_graph_from_two_TSV_igraph(
233
+ "positive.tsv", "negative.tsv",
234
+ pos_threshold=10, neg_threshold=5, lambda_neg=1.0
235
+ )
236
+ partition = les.find_partition_signed_CPM_single_graph(
237
+ G_signed, gamma=0.05, seed=42
238
+ )
239
+
240
+ # Inspect results
241
+ print(partition.membership)
242
+ nr.display_communities_by_name(G_pos, partition)
243
+ nr.count_nodes_in_communities(partition)
244
+
245
+ # Multi-seed negative-edge leverage
246
+ leverage = nr.calculate_negative_edge_leverage_multiseed(
247
+ G_pos, G_neg, seeds=[1, 2, 3, 10, 42]
248
+ )
249
+ print(leverage["negative_edge_leverage_median"])
250
+ print(leverage["classification"])
251
+
252
+ # Combined signed-network diagnostic
253
+ diagnostic = nr.check_signed_network(G_pos, G_neg)
254
+ print(diagnostic["network"])
255
+ print(diagnostic["recommendations"])
256
+ ```
257
+
258
+ ### Visualization
259
+
260
+ ```python
261
+ # Visualize a specific module (positive=red, negative=blue)
262
+ nr.visualize_module_signed(G_pos, G_neg, partition, community_id=0)
263
+
264
+ # Visualize the module containing a specific gene
265
+ nr.visualize_module_of_gene_signed(G_pos, G_neg, partition, "TP53")
266
+
267
+ # Top-degree nodes within a module
268
+ nr.visualize_module_of_gene_top_degree_nodes_signed(
269
+ G_pos, G_neg, partition, "TP53", top_n=30
270
+ )
271
+ ```
272
+
273
+ ## Benchmarking
274
+
275
+ MODERN includes a simulation framework for evaluating community detection methods on signed networks.
276
+
277
+ ```bash
278
+ # Quick test (no modernsn package required)
279
+ python sim3_benchmark.py test
280
+
281
+ # Full benchmark with all methods and parameter grids
282
+ python sim3_benchmark.py run sim3_results/
283
+
284
+ # Generate example correlation matrix visualizations
285
+ python sim3_benchmark.py plot sim3_results/
286
+ ```
287
+
288
+ ### Simulation types
289
+
290
+ | Type | Model | Tests |
291
+ |------|-------|-------|
292
+ | **Type A** | Correlation-based co-expression | Modularity null model distortion on dense positive graphs |
293
+ | **Type B** | Planted partition (stochastic block model) | Control — balanced positive/negative structure |
294
+ | **Type C** | scRNA-seq exclusive expression | Multipartite negative graph where "enemy of enemy ≠ friend" |
295
+
296
+ ### Example visualizations
297
+
298
+ ```bash
299
+ # Generate concrete examples showing signed vs unsigned differences
300
+ python sim3_examples.py sim3_examples/
301
+ ```
302
+
303
+ This produces network graphs and adjacency matrix heatmaps at three difficulty levels, clearly demonstrating when signed methods outperform unsigned methods.
304
+
305
+ ## How it works
306
+
307
+ ### Signed modularity (multiplex optimization)
308
+
309
+ The positive and negative graphs are treated as two layers of a multiplex network. The objective function is:
310
+
311
+ ```
312
+ Q_signed = α · Q_modularity(G⁺) − (1 − α) · Q_modularity(G⁻)
313
+ ```
314
+
315
+ This is optimized using `leidenalg.optimise_partition_multiplex`, which simultaneously considers both layers with different weights.
316
+
317
+ ### Signed CPM (single graph)
318
+
319
+ Positive and negative edges are combined into a single graph with signed weights:
320
+
321
+ ```
322
+ w_signed(i,j) = w_pos(i,j) − λ_neg · w_neg(i,j)
323
+ ```
324
+
325
+ Standard CPM is then applied, where the objective function naturally penalizes negative edges within the same community:
326
+
327
+ ```
328
+ H_CPM = Σ_{i,j in same community} (w_signed(i,j) − γ)
329
+ ```
330
+
331
+ ## Choosing a method
332
+
333
+ ```
334
+ Is your network correlation-based (co-expression, etc.)?
335
+ ├── Yes → Use leiden-cpm-single
336
+ │ Start with --gamma 0.05 --lambda-neg 1.0
337
+ │ Increase gamma for smaller communities
338
+
339
+ └── No (e.g., social network, citation network)
340
+ ├── Need reproducibility/stability? → Use leiden-mod-alpha
341
+ │ Start with --alpha 0.6 --resolution 1.0
342
+
343
+ └── Compatibility with existing Louvain pipeline? → Use louvain
344
+ Start with --alpha 0.6 --resolution 1.0
345
+ ```
346
+
347
+ ## Citation
348
+
349
+ If you use MODERN in your research, please cite:
350
+
351
+ ```
352
+ [Citation information to be added]
353
+ ```
@@ -0,0 +1,318 @@
1
+ # MODERN
2
+
3
+ **MO**dule **DE**tection and **R**efinement in signed **N**etworks (MODERN) detects community structure in signed networks — networks with both positive (attractive) and negative (repulsive) edges. It extends classical community detection algorithms (Louvain, Leiden) to leverage negative edge information, which is critical for accurate module detection in biological networks such as gene co-expression networks.
4
+
5
+ ## Why signed networks?
6
+
7
+ Standard community detection methods use only positive edges and ignore negative correlations between genes. When inter-community positive edges are abundant (e.g., in correlation-based networks), unsigned methods fail to identify the correct community structure because they cannot distinguish "noise" positive edges from true intra-community edges.
8
+
9
+ Signed methods use negative edges as repulsive forces to push nodes apart, recovering the correct community structure even when the positive graph alone is ambiguous.
10
+
11
+ <p align="center">
12
+ <img src="docs/fig1_signed_vs_unsigned_matrix.png" width="90%">
13
+ </p>
14
+
15
+ *Signed adjacency matrix sorted by detected communities. As inter-community positive edges increase (top to bottom), unsigned modularity collapses (ARI=0.07) while signed methods maintain near-perfect recovery (ARI>0.93).*
16
+
17
+ ## Methods
18
+
19
+ MODERN provides three community detection methods for signed networks:
20
+
21
+ | Method | Algorithm | Objective | Best for |
22
+ |--------|-----------|-----------|----------|
23
+ | `louvain` | LouvainSigned | α·Q⁺ − (1−α)·Q⁻ | Compatibility with existing Louvain workflows |
24
+ | `leiden-mod-alpha` | LeidenSigned (modularity) | α·Q⁺ − (1−α)·Q⁻ | General signed networks |
25
+ | `leiden-cpm-single` | LeidenSigned (CPM) | Σ(w_ij − γ) on signed graph | Correlation-based networks (co-expression) |
26
+
27
+ **When to use CPM over modularity:** Modularity's null model assumes a configuration-model random graph. In correlation-based networks (e.g., gene co-expression), the positive graph is inherently dense, distorting the null model. CPM uses an absolute density threshold (γ) instead and is not affected by this issue.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ pip install modernsn
33
+ ```
34
+
35
+ ### Dependencies
36
+
37
+ - Python ≥ 3.9
38
+ - numpy
39
+ - igraph (python-igraph)
40
+ - leidenalg
41
+ - networkx
42
+ - matplotlib (for plotting outputs)
43
+ - scipy (for MAT format support)
44
+
45
+ ## Quick start
46
+
47
+ ```bash
48
+ # Basic run with Leiden signed modularity
49
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
50
+ --method leiden-mod-alpha --alpha 0.6 --resolution 1.0 \
51
+ --out-prefix results/my_analysis
52
+
53
+ # Leiden signed CPM (recommended for co-expression networks)
54
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
55
+ --method leiden-cpm-single --gamma 0.05 --lambda-neg 1.0 \
56
+ --out-prefix results/my_analysis
57
+
58
+ # Louvain signed
59
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
60
+ --method louvain --alpha 0.6 --resolution 1.0 \
61
+ --out-prefix results/my_analysis
62
+
63
+ # Multi-seed negative-edge leverage screen
64
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
65
+ --method leiden-mod-alpha --negative-edge-leverage \
66
+ --leverage-seeds 1 2 3 10 42 \
67
+ --out-prefix results/my_analysis
68
+
69
+ # Signed-network diagnostic and analysis recommendations
70
+ modern --pos positive_edges.tsv --neg negative_edges.tsv \
71
+ --method leiden-mod-alpha --check-signed-network \
72
+ --leverage-seeds 1 2 3 10 42 \
73
+ --out-prefix results/my_analysis
74
+ ```
75
+
76
+ ## Input formats
77
+
78
+ ### TSV (default)
79
+
80
+ Tab-separated file with five columns (no header):
81
+
82
+ ```
83
+ gene_id1 gene_id2 gene_name1 gene_name2 weight
84
+ ENSG00001 ENSG00002 GeneA GeneB 15.3
85
+ ENSG00001 ENSG00003 GeneA GeneC 12.1
86
+ ```
87
+
88
+ Provide separate files for positive and negative edges via `--pos` and `--neg`. Use `--thre-pos` and `--thre-neg` to filter edges by weight.
89
+
90
+ ### MAT (MATLAB sparse matrix)
91
+
92
+ ```bash
93
+ modern --format mat --mat data/network.mat \
94
+ --pos-key pos --neg-key neg \
95
+ --method leiden-mod-alpha --out-prefix results/mat_run
96
+ ```
97
+
98
+ The MAT file should contain two sparse matrices (positive and negative adjacency).
99
+
100
+ ## Output files
101
+
102
+ When `--out-prefix` is specified, MODERN generates the following outputs:
103
+
104
+ | File | Description |
105
+ |------|-------------|
106
+ | `<prefix>_partition.tsv` | Community assignment for each gene (gene_id, gene_name, community) |
107
+ | `<prefix>_summary.txt` | Parameters, graph statistics, community size distribution, entropy |
108
+ | `<prefix>_communities.gmt` | GMT format for direct use with GSEA, Enrichr, clusterProfiler |
109
+ | `<prefix>_community_sizes.pdf` | Rank-size plot and histogram of community sizes |
110
+ | `<prefix>_inter_community.pdf` | Heatmap of inter-community edge density (positive / negative / signed) |
111
+ | `<prefix>_module_<id>.pdf` | Subnetwork visualization for top modules (positive=red, negative=blue) |
112
+
113
+ With `--negative-edge-leverage`, MODERN instead writes one row per seed to
114
+ `<prefix>_negative_edge_leverage.tsv` and a multi-seed summary to
115
+ `<prefix>_negative_edge_leverage_summary.txt`.
116
+
117
+ With `--check-signed-network`, MODERN reports network size, low- and
118
+ high-resolution partition summaries, metanode enrichment, multi-seed
119
+ negative-edge leverage, and analysis recommendations. The full result is saved
120
+ to `<prefix>_signed_network_check.json`.
121
+
122
+ ## Negative-edge leverage
123
+
124
+ Negative-edge leverage asks whether positive-only reintegration would merge
125
+ module boundaries supported by negative edges. MODERN first generates a
126
+ high-resolution positive-only Leiden partition, then performs reintegration
127
+ without applying the negative-edge veto. The score is
128
+
129
+ ```
130
+ (negative edges newly placed within modules) / (negative edges evaluated)
131
+ ```
132
+
133
+ The defaults reproduce the manuscript screen: resolution 4, positive-coupling
134
+ robust-z threshold 1, minimum module size 10, and seeds 1, 2, 3, 10, and 42.
135
+ The empirical candidate threshold of 0.02 is reported as a screen rather than a
136
+ general significance cutoff.
137
+
138
+ ### Disabling outputs
139
+
140
+ ```bash
141
+ --no-plot # Skip all PDF plots
142
+ --no-gmt # Skip GMT output
143
+ --quiet # Suppress progress messages
144
+ ```
145
+
146
+ ### Controlling module plots
147
+
148
+ ```bash
149
+ --top-modules 10 # Number of top modules to plot (default: 10)
150
+ --max-nodes-per-module 200 # Max nodes per module plot (default: 200)
151
+ ```
152
+
153
+ ## Parameters
154
+
155
+ ### Method-specific parameters
156
+
157
+ **Modularity-based methods** (`louvain`, `leiden-mod-alpha`):
158
+
159
+ | Parameter | Description | Default |
160
+ |-----------|-------------|---------|
161
+ | `--alpha` | Balance between positive and negative modularity (0–1). Higher α emphasizes positive edges. | 0.5 |
162
+ | `--resolution` | Resolution parameter. Higher values produce more, smaller communities. | 1.0 |
163
+
164
+ **CPM method** (`leiden-cpm-single`):
165
+
166
+ | Parameter | Description | Default |
167
+ |-----------|-------------|---------|
168
+ | `--gamma` | CPM resolution. Minimum edge density within communities. | 0.5 |
169
+ | `--lambda-neg` | Weight multiplier for negative edges. Controls how strongly negative edges repel. | 0.0 |
170
+ | `--neg-weight-mode` | How to transform negative weights: `absolute` (−λ·\|w\|) or `signed` (λ·w). | absolute |
171
+
172
+ ### Common parameters
173
+
174
+ | Parameter | Description | Default |
175
+ |-----------|-------------|---------|
176
+ | `--seed` | Random seed for reproducibility. | None |
177
+ | `--out-prefix` | Output file prefix. If omitted, only prints summary to stdout. | None |
178
+
179
+ ## Python API
180
+
181
+ MODERN can also be used as a Python library:
182
+
183
+ ```python
184
+ import modernsn.network_module as nr
185
+ import modernsn.LeidenSigned as les
186
+
187
+ # Load graphs
188
+ G_pos = nr.load_graph_from_TSV_igraph("positive.tsv", threshold=10)
189
+ G_neg = nr.load_graph_from_TSV_igraph("negative.tsv", threshold=5)
190
+
191
+ # Leiden signed modularity
192
+ partition = les.find_partition_signed_modularity_alpha(
193
+ G_pos, G_neg, alpha=0.6, resolution=1.0, seed=42
194
+ )
195
+
196
+ # Leiden signed CPM (single signed graph)
197
+ G_signed = nr.load_signed_graph_from_two_TSV_igraph(
198
+ "positive.tsv", "negative.tsv",
199
+ pos_threshold=10, neg_threshold=5, lambda_neg=1.0
200
+ )
201
+ partition = les.find_partition_signed_CPM_single_graph(
202
+ G_signed, gamma=0.05, seed=42
203
+ )
204
+
205
+ # Inspect results
206
+ print(partition.membership)
207
+ nr.display_communities_by_name(G_pos, partition)
208
+ nr.count_nodes_in_communities(partition)
209
+
210
+ # Multi-seed negative-edge leverage
211
+ leverage = nr.calculate_negative_edge_leverage_multiseed(
212
+ G_pos, G_neg, seeds=[1, 2, 3, 10, 42]
213
+ )
214
+ print(leverage["negative_edge_leverage_median"])
215
+ print(leverage["classification"])
216
+
217
+ # Combined signed-network diagnostic
218
+ diagnostic = nr.check_signed_network(G_pos, G_neg)
219
+ print(diagnostic["network"])
220
+ print(diagnostic["recommendations"])
221
+ ```
222
+
223
+ ### Visualization
224
+
225
+ ```python
226
+ # Visualize a specific module (positive=red, negative=blue)
227
+ nr.visualize_module_signed(G_pos, G_neg, partition, community_id=0)
228
+
229
+ # Visualize the module containing a specific gene
230
+ nr.visualize_module_of_gene_signed(G_pos, G_neg, partition, "TP53")
231
+
232
+ # Top-degree nodes within a module
233
+ nr.visualize_module_of_gene_top_degree_nodes_signed(
234
+ G_pos, G_neg, partition, "TP53", top_n=30
235
+ )
236
+ ```
237
+
238
+ ## Benchmarking
239
+
240
+ MODERN includes a simulation framework for evaluating community detection methods on signed networks.
241
+
242
+ ```bash
243
+ # Quick test (no modernsn package required)
244
+ python sim3_benchmark.py test
245
+
246
+ # Full benchmark with all methods and parameter grids
247
+ python sim3_benchmark.py run sim3_results/
248
+
249
+ # Generate example correlation matrix visualizations
250
+ python sim3_benchmark.py plot sim3_results/
251
+ ```
252
+
253
+ ### Simulation types
254
+
255
+ | Type | Model | Tests |
256
+ |------|-------|-------|
257
+ | **Type A** | Correlation-based co-expression | Modularity null model distortion on dense positive graphs |
258
+ | **Type B** | Planted partition (stochastic block model) | Control — balanced positive/negative structure |
259
+ | **Type C** | scRNA-seq exclusive expression | Multipartite negative graph where "enemy of enemy ≠ friend" |
260
+
261
+ ### Example visualizations
262
+
263
+ ```bash
264
+ # Generate concrete examples showing signed vs unsigned differences
265
+ python sim3_examples.py sim3_examples/
266
+ ```
267
+
268
+ This produces network graphs and adjacency matrix heatmaps at three difficulty levels, clearly demonstrating when signed methods outperform unsigned methods.
269
+
270
+ ## How it works
271
+
272
+ ### Signed modularity (multiplex optimization)
273
+
274
+ The positive and negative graphs are treated as two layers of a multiplex network. The objective function is:
275
+
276
+ ```
277
+ Q_signed = α · Q_modularity(G⁺) − (1 − α) · Q_modularity(G⁻)
278
+ ```
279
+
280
+ This is optimized using `leidenalg.optimise_partition_multiplex`, which simultaneously considers both layers with different weights.
281
+
282
+ ### Signed CPM (single graph)
283
+
284
+ Positive and negative edges are combined into a single graph with signed weights:
285
+
286
+ ```
287
+ w_signed(i,j) = w_pos(i,j) − λ_neg · w_neg(i,j)
288
+ ```
289
+
290
+ Standard CPM is then applied, where the objective function naturally penalizes negative edges within the same community:
291
+
292
+ ```
293
+ H_CPM = Σ_{i,j in same community} (w_signed(i,j) − γ)
294
+ ```
295
+
296
+ ## Choosing a method
297
+
298
+ ```
299
+ Is your network correlation-based (co-expression, etc.)?
300
+ ├── Yes → Use leiden-cpm-single
301
+ │ Start with --gamma 0.05 --lambda-neg 1.0
302
+ │ Increase gamma for smaller communities
303
+
304
+ └── No (e.g., social network, citation network)
305
+ ├── Need reproducibility/stability? → Use leiden-mod-alpha
306
+ │ Start with --alpha 0.6 --resolution 1.0
307
+
308
+ └── Compatibility with existing Louvain pipeline? → Use louvain
309
+ Start with --alpha 0.6 --resolution 1.0
310
+ ```
311
+
312
+ ## Citation
313
+
314
+ If you use MODERN in your research, please cite:
315
+
316
+ ```
317
+ [Citation information to be added]
318
+ ```