PPI Networks: From the STRING Database to Cytoscape Visualization
Query STRING v12.5 with a gene list, understand confidence scores and evidence channels, then import the network into Cytoscape for clustering.
You finished a differential expression analysis and you are staring at a list of 200 upregulated genes. Ranking them by fold change tells you which genes changed, but not how they work together. The biological story almost always lives in the connections: which proteins bind each other, sit in the same complex, or share the same regulatory pathway. A protein-protein interaction (PPI) network is how you turn a flat gene list into a graph you can actually reason about, and the fastest route from list to graph runs through the STRING database and into Cytoscape.
Why a PPI network beats a ranked list
A gene list treats every hit as an independent event. Biology does not work that way. Proteins operate in modules: a ribosome, a proteasome, a signaling cascade. When 30 of your 200 hits turn out to be physically or functionally linked, that cluster is a far stronger signal than any single gene's p-value. Network analysis surfaces those modules, highlights the hub proteins that connect them, and gives you testable hypotheses about mechanism rather than a spreadsheet to squint at.
STRING (Search Tool for the Retrieval of Interacting Genes/proteins) is the standard starting point because it aggregates interactions from many sources into one scored graph covering thousands of organisms. Crucially, STRING interactions are functional associations, not only direct physical binding: two linked proteins may bind directly, or simply act in the same pathway. Telling the two apart comes down to the evidence channels, so that is where the analysis really begins.
Understanding STRING evidence channels
Every STRING edge carries a combined score, but that number is built from separate channels, each capturing a different kind of evidence. Understanding them separates a network you trust from a hairball you overinterpret.
| Channel | What it measures | Direct binding? |
|---|---|---|
experiments | Physical interaction assays (Y2H, affinity purification, mass spec) | Often |
database | Curated pathways from KEGG, Reactome, BioCyc | Functional |
textmining | Co-mention in PubMed abstracts and full text | Weak/indirect |
coexpression | Correlated expression across conditions | No |
neighborhood | Conserved gene proximity on prokaryotic genomes | No |
fusion | Genes fused into one ORF in another species | No |
cooccurrence | Correlated presence/absence across genomes | No |
The single most common beginner mistake is treating a high combined score as proof of physical interaction. A pair of proteins can score 0.9 almost entirely from textmining because they appear together in hundreds of abstracts, without a single co-purification experiment. If your downstream claim is "these proteins form a complex," filter to the experiments and database channels and ignore the rest. If your claim is the softer "these proteins are functionally related," the combined score is fine.
STRING scores are probabilities of a functional link, not correlation coefficients. A combined score of 0.7 means STRING estimates roughly a 70 percent chance the association is real given all evidence, benchmarked against KEGG pathways. It does not mean the interaction is 70 percent strong.
Choosing a confidence threshold
STRING exposes four preset confidence cutoffs on the combined score, and picking one is the most consequential decision you will make. The presets are low = 0.15, medium = 0.40, high = 0.70, and highest = 0.90.
Set it too low and weak textmining edges connect nearly every gene, producing the dreaded hairball with no visible structure. Set it too high and you lose real interactions, fragmenting the network into disconnected singletons. For most exploratory analyses, start at high (0.70). It keeps well-supported edges, drops most textmining noise, and usually leaves visible modules. Drop to medium (0.40) only if high leaves your genes too disconnected to interpret, and say so explicitly when you report results. Never mix thresholds within one figure.
Querying STRING from the web interface
For a one-off analysis, the STRING web interface (currently v12.5) is the quickest path. Paste your gene list into the Multiple proteins search, pick the organism (for example Homo sapiens), and STRING resolves ambiguous symbols before drawing the network. On the results page, open Settings to set the minimum interaction score and choose which active interaction sources (channels) to include. STRING also runs functional enrichment automatically, reporting enriched GO terms, KEGG pathways, and protein domains below the network, which pairs naturally with a dedicated GO, KEGG, and GSEA enrichment workflow.
The web view is great for a look, but it is not where you do serious analysis. For that you export. Use Exports to download the network as TSV, or better, send it straight to Cytoscape.
Reproducible queries with the STRINGdb R package
When you want the query scripted, versioned, and reproducible, the STRINGdb Bioconductor package is the tool. It runs the same API programmatically, so the exact network in your paper can be regenerated from code rather than a remembered sequence of clicks. Install it inside a dedicated environment, following the same pattern as our note on conda environments and Bioconda channels, then work in R:
BiocManager::install("STRINGdb")
library(STRINGdb)
# version and species: 9606 is Homo sapiens, score_threshold is x1000
string_db <- STRINGdb$new(
version = "12.0",
species = 9606,
score_threshold = 700,
input_directory = ""
)
genes <- data.frame(gene = c("TP53", "MDM2", "CDKN1A", "BAX", "ATM"))
mapped <- string_db$map(genes, "gene", removeUnmappedRows = TRUE)
hits <- mapped$STRING_id
string_db$plot_network(hits)Two things trip people up here. First, score_threshold in STRINGdb is the combined score multiplied by 1000, so high confidence is 700, not 0.70. Second, map() silently drops symbols it cannot resolve unless removeUnmappedRows = TRUE is set; a typo or outdated alias quietly shrinks your network, so always print nrow(mapped) against your input length.
Pin the version argument explicitly. STRING re-scores interactions with each release, so a network built on 12.0 will not exactly reproduce on a later version. Recording the version string is the single cheapest thing you can do for reproducibility.
Getting the network into Cytoscape
Cytoscape is the open-source desktop application that turns the STRING edge table into an interactive, publication-ready figure. The cleanest bridge is the stringApp, installed once from the Cytoscape App Manager. With it, you query STRING from inside Cytoscape via File then Import then Network from Public Databases, choosing STRING protein query. The stringApp pulls the network and every per-channel score as edge attributes, plus node attributes like protein description and structure thumbnails, so the metadata you need for filtering rides along automatically.
If you queried STRING elsewhere, import the exported TSV directly: map the two protein columns to source and target, and every remaining column (combined_score, experiments, textmining) becomes an edge attribute you can style or filter on.
Analyzing and styling the network in Cytoscape
A raw imported network is a tangle. The value comes from what you do next.
Compute topology. Run Tools then Analyze Network to calculate degree, betweenness centrality, and clustering coefficient per node. Degree (edge count) flags hubs, the highly connected proteins that tend to be functionally central. Map node size to degree so hubs pop visually.
Find modules with clustering. Install the clusterMaker2 app and run MCL (Markov clustering) on the combined score column. MCL partitions the network into densely connected clusters that frequently correspond to protein complexes or pathway modules. Color nodes by cluster and the biological structure of your gene list becomes legible at a glance.
Filter to strong evidence. Use the Cytoscape filter panel to hide edges below a channel-specific cutoff, for example show only edges where experiments > 0.4. This moves you from a functional-association network to a physical-interaction network without re-querying, and your figure can now honestly claim direct interactions.
Style for the reader. Use a Visual Style to encode information: node fill by fold change from your expression data (import it as a node table column keyed on gene name), node size by degree, edge thickness by combined score. A good PPI figure lets a reviewer read the biology from color and size alone. If your node attributes came from an RNA-seq differential expression run, the two analyses converge into one figure.
Common pitfalls that inflate networks
The seductive failure mode is a dense, impressive-looking hairball that means nothing, usually from a low threshold with all channels enabled, letting textmining edges connect everything. Another is the whole-proteome background trap: STRING enrichment tests your gene set against the entire genome by default, so if your input list was itself derived from expressed genes, the correct background is expressed genes, not the whole proteome, or your p-values will be optimistic. Finally, STRING is only as current as its source databases; a very recent interaction may not appear until the next release and textmining pass.
Practical Takeaways
- Treat the STRING combined score as a probability of functional association, not proof of physical binding; check the per-channel evidence before claiming a complex.
- Start at
highconfidence (0.70, or700inSTRINGdb) and only relax it if the network fragments, never mixing thresholds in one figure. - Filter to the
experimentsanddatabasechannels when you need physical interactions; use the combined score when functional relatedness is enough. - Use the stringApp to query STRING from inside Cytoscape so per-channel scores import as edge attributes automatically.
- Run Analyze Network for hubs and
clusterMaker2MCL for modules; map node color to fold change and size to degree so the figure reads at a glance. - Pin the STRING
versionand record your threshold and channels; a PPI network is only reproducible if those three facts travel with it.
A PPI network is not the end of an analysis, it is a hypothesis generator: the clusters point at complexes to validate, the hubs suggest targets, and the enriched pathways connect back to the broader question. If your hits came from expression data rather than a fixed gene list, building a co-expression network with WGCNA is a complementary route to the same kind of modules, and pairing either with functional enrichment turns clusters into a mechanistic story worth testing at the bench.