Changelog
MSstatsBioNet (development version)
New features
-
A new API for building networks from MSstats results, which separates the steps that
annotateProteinInfoFromIndra()andgetSubnetworkFromIndra()combine, and works for proteins, PTM sites, and metabolites:-
prepare_entities()builds an entity table with one row per analyte, its entity type ("protein","ptm_site","metabolite", …), identifier system, organism, and statistics. It copieslog2FC,log10FC, orlogFCtologFC, parses PTM sites (with the parent protein fromGlobalProtein, except where MSstatsPTM wrote"missing"), and stops when the input has several comparisons inLabelunlesslabelnames one. -
indra_backend()creates the INDRA backend, andbackend_capabilities()lists what a backend supports. -
convert_ids()grounds the entity table (CoGEx for UniProt IDs and mnemonics, Gilda for gene symbols and chemical names), andget_entity_properties()addsis_transcription_factor,is_kinase, andis_phosphatase. UniProt IDs may be FASTA headers, as FragPipe writes them (sp|P32004|L1CAM_HUMAN, orsp|P32004|L1CAM_HUMAN_S1194for a site):idkeeps the header and the accession is converted. -
select_entities()flags the rows that pass the cutoffs, and drops none, so that nodes in the input are recognized even when they fail the cutoffs. -
get_network(backend, entities, query = subnetwork_query())queries the backend and returnsnodesandedgesthat meet the contract. It takesinteraction_types,min_evidence,min_confidence(new: drops edges below it, and edges with no score),evidence_sources, andinclude_entities. It prints the question it asks as a message, e.g. “INDRA subnetwork: how are 42 selected proteins connected to each other, with no other nodes added?”. -
get_network()also returnsprovenance, a one-row table recording when the network was retrieved (retrieved_at, UTC), from which backend, URL, and data version (NAfor INDRA, which has none), for which organism, with which arguments, and with which MSstatsBioNet version. INDRA’s data changes over time, so this is the only record of which data a network came from.merge_networks()combines the provenance of its networks. -
save_network(network, file)saves a network, with its provenance, to an.rdsfile (warning when the provenance was lost by rebuilding the list), andload_network(file)reads it back and checks it withvalidate_network(). -
?network_queriesdescribes the questions a query can ask, with a glossary.subnetwork_query()is the first; more are planned. -
get_evidence(backend, edges)returns the evidence sentences and PubMed IDs behind each edge, looked up bystatement_id. -
get_curations(backend, edges)counts, for each statement, the evidence curated as incorrect, andfilter_by_curation(network, min_evidence = 1)subtracts it fromevidence_count, drops the edges left belowmin_evidence(and edges left with no evidence), and drops the nodes left without edges. Likeget_evidence(), it uses the backend named in each edge’sbackend_databaseunlessbackendis given.indra_backend(curation_url = )sets the INDRA database URL. -
merge_networks(..., entities = NULL)combines networks from several queries or backends. An edge from two queries (samesource,target,backend_database, andstatement_id) becomes one row with thequery_typevalues joined by;, keeping the copy with the most evidence; the same relation from two backends stays two rows. Node roles are joined by;, andincluded_in_queryisTRUEif the node was in any query.has_measured_sitesis set on every row of a protein with sites in any network, so merging a protein network with a PTM network marks the protein-level rows too.measured,logFC, andadj.pvaluemust agree across the networks unlessentitiesis passed, in which case they (andhas_measured_sites) are recomputed from it. -
INDRA_DATABASE_SOURCESandINDRA_TEXT_MINED_SOURCESlist INDRA’s evidence sources (curated databases, and text-mining systems), soget_network(evidence_sources = INDRA_DATABASE_SOURCES)keeps only edges with curated-database evidence. They use INDRA’s internal names ("psp"for PhosphoSitePlus,"pc"for Pathway Commons, …), which are the names inedges$evidence_sources.backend_capabilities()$evidence_sourceslists both. A name in neither list, inget_network(evidence_sources =)orgetSubnetworkFromIndra(sources_filter =), gives a warning that suggests the internal name where there is one (e.g."psp"for"phosphosite"). -
filter_by_ptm_site(network)keeps the edges whosesiteis a PTM site of their target in the network, checking each edge on its own, and drops the nodes left without edges; it stops when no edges remain. UnlikegetSubnetworkFromIndra(filter_by_ptm_site = TRUE), which is unchanged, it doesn’t keep an edge for an unmeasured site because another statement between the same two nodes hits a measured one, splits node sites of protein groups on;, and keeps isolated nodes andprovenance. -
add_entity_values(network, entities, overwrite = FALSE)copies thelogFCandadj.pvalueof a grounded entity table onto the matching nodes of a network, without a query: for example, global profiling results (MSstatsPTM’sPROTEIN.Model) onto a network built from PTM results. Nodes match byidandsite, then by grounding, so a node named by the backend (e.g. a kinase added withinclude_entities) matches too. A protein with only PTM site rows gets a protein-level row, so its node is colored by the global result. Nodes that already have values stop the call unlessoverwrite = TRUE. - The S4 classes
NetworkBackend,IndraBackend,NetworkQuery, andSubnetworkQueryare exported, so other packages can add backends.
-
New function
validate_network()checks alist(nodes, edges)network against the edge and node contract (v1.0): required columns and types, the statement-type and entity-type vocabularies, value ranges,NAstatistics on nodes that are not in the input data, and that every edge’s source and target are nodes. It stops with an error listing every problem found.cytoscapeNetwork()draws the node status columns. Nodes not in the input data (measured = FALSE) have no fill and a dashed grey border, and the legend lists them as “not in input data”; nodes withincluded_in_query = FALSEare faded; nodes with anNAlogFChave no fill.entity_typesets the node shape: hexagon for metabolites and lipids, diamond for drugs, octagon for complexes, barrel for families. The legend shows only the node styles, shapes, and edge types present, and covers every statement type of the contract.filterSubnetworkByContext(),decomposeSubnetworkByTopic(),decomposeSubnetworkIntoHierarchicalTopics(),compareTopicModels(), andbootstrapTopicModels()take abackendargument. By default each edge’s evidence comes from the backend named in itsbackend_databasecolumn, so a network subset or rebuilt withlist(nodes =, edges =)still works. Passbackendto use one built with non-default settings, such asindra_backend(cogex_url = ).The PTM-Analysis vignette is rewritten for the new API, with a CPTAC clear cell renal cell carcinoma dataset that has both a phosphoproteomics and a global profiling experiment (
extdata/cptac-ccrcc-ptm-adjusted.csv,extdata/cptac-ccrcc-protein.csv).extdata/garrido-2024.csv, used only by the old vignette, is removed.
Breaking changes
cytoscapeNetwork()reads the edgedirectedcolumn: an undirected edge has no arrow and is drawn once for both directions, even when the reverse edge is missing. Edges without the column treatComplexandAssociationas undirected. Previously aComplexedge without its reverse was drawn as directed.cytoscapeNetwork()colours a protein with PTMsiterows from its row with nosite. A protein with only site rows is drawn as an uncoloured container, and its site nodes keep their own colours. Previously it took the colour of its first row, often a site’s fold change.cytoscapeNetwork()no longer draws anNAlogFCas the grey of a zero fold change.The edges returned by
getSubnetworkFromIndra()follow the edge contract. Columns are renamed, with no aliases:stmt_hashtostatement_id(now always character, taken from INDRA’s full-precisionmatches_hash),evidenceLinktoevidence_url,evidenceCounttoevidence_count(now integer), andsourceCountstoevidence_sources. New columns:directed(FALSEfor symmetric types such asComplex),confidence(INDRA belief score),backend_database("INDRA"), andquery_type("subnetwork").filterSubnetworkByContext(), the topic-model functions, andcytoscapeNetwork()read the new names, so edges built by hand for them must usestatement_idandevidence_url.evidence_urllinks to the INDRA page for that one statement. The oldevidenceLinklisted every statement between the two agents.The
cytoscapeNetwork()widget’s_edge_clickedShiny input reportsevidence_urlin place ofevidenceLink.The nodes returned by
getSubnetworkFromIndra()follow the node contract. Columns are renamed, with no aliases:entityNametoentity_name,entityIdtoentity_id, andSitetosite.logFCkeeps its name, whatever the log base of the input. New column:namespace, the grounding namespace(s) aligned withentity_id. The ID columns are always character, even when every grounded ID is numeric.getSubnetworkFromIndra()callsvalidate_network()on its result, so it stops with an error instead of returning a network that breaks the contract.cytoscapeNetwork(),exportNetworkToHTML(), andpreviewNetworkInBrowser()read the new node column names (entity_name,site). Nodes built by hand for them must use these names.cytoscapeNetwork()now errors whendisplayLabelTypeis not"id"or"entity_name". Other values used to fall back to"id"silently.The nodes returned by
getSubnetworkFromIndra()say whether each node is in the input data and why it is in the network. New columns:entity_type("protein","ptm_site","metabolite","family", …),measured(TRUEfor analytes ininput),included_in_query,node_role("passed_cutoffs", or"user_added"for nodes there only throughforce_include_other), andhas_measured_sites(TRUEfor proteins with PTM site rows).nodesis now always a data.frame, also wheninputis a data.table.Nodes added through
force_include_otherthat are not ininputhaveNAforlogFCandadj.pvalue, andmeasured = FALSE. They used to getlogFC = 0andadj.pvalue = 1, which looked like a protein in the input data with no change. They now also carry INDRA’s namespace and identifier, and anentity_typefrom the namespace (FamPlex families are"family").INDRA statements between identifiers that are equal but in different namespaces (
HGNC:1234andCHEBI:1234) are no longer merged into one edge. The order of the edge rows can differ from earlier versions.When several rows of
inputshare a grounding, e.g. two isoforms of one gene (P04637andP04637-2) or a protein and a protein group that contains it (P04637andP04637;P02342), each row is its own node, with its own statistics, and gets the INDRA edges of that grounding. One statement can therefore give several edges with the samestatement_id. A statement from a grounding to itself (a homodimer) gives each such node a self-loop, not edges between them. Before, the rows were merged into one node named after the INDRA gene (TP53) withlogFC = 0andadj.pvalue = 1.getSubnetworkFromIndra()stops wheninputhas more than one comparison in itsLabelcolumn, or repeats aProteinvalue. Filterinputto one comparison first.PTM sites are parsed from the end of each
;-separated member ofProtein:CLH1_HUMAN_S148gives siteS148(wasHUMAN_S148),P1_S148;P2_T5gives sitesS148;T5(wasS148;P2_T5), and an identifier whose last part is not a site (P1_S148_extra) has none. A PTM row without aGlobalProteincolumn is drawn on its parent protein’s node (P1), not on a node of its own (P1_S148).The message about rows with no grounding now counts only the rows that pass the cutoffs, since only those are sent to INDRA.
validate_network()requires the node columnsentity_type,entity_name,namespace,entity_id,measured,included_in_query, andnode_role.
Bug fixes
-
annotateProteinInfoFromIndra()grounds PTM sites whoseGlobalProteinis"missing", MSstatsPTM’s value inADJUSTED.Modelfor sites whose protein has no global profiling result. They were left ungrounded, and so were missing from the network ofgetSubnetworkFromIndra(). TheirGlobalProteinis now the protein without its site.
Deprecated
-
cytoscapeNetwork(displayLabelType = "entityName")(and the same argument ofexportNetworkToHTML()andpreviewNetworkInBrowser()) is deprecated. It gives a warning and is treated as"entity_name", the renamed nodes column. It will become defunct in the next Bioconductor release. - In
getSubnetworkFromIndra(), the argumentspaper_count_cutoff,correlation_cutoff, andprotein_level_dataare deprecated. Supplying any of them gives a warning. They will become defunct in the next Bioconductor release and be removed in the one after.-
paper_count_cutoffis now ignored. INDRA does not return paper counts (thepaperCountcolumn is always 1), so the default had no effect and values of 2 or more removed every edge and raised an error. -
correlation_cutoffandprotein_level_datastill work during the deprecation period. ThepaperCountandcorrelationcolumns of the returned edges will be removed when the arguments become defunct.
-
Internal changes
-
getSubnetworkFromIndra()now runs through an internal INDRA backend object and the S4 genericget_network(), the first step toward supporting network databases other than INDRA. - The error for a non-character
sources_filteringetSubnetworkFromIndra()now reads “evidence_sources must be a character vector”, the name of the argument in the new API. -
annotateProteinInfoFromIndra()now runs throughconvert_ids()andget_entity_properties(). Its output is unchanged. The INDRA backend now also holds the Gilda URL, and the organism of the entity table is passed to Gilda in place of a hard-coded human taxon ID. -
getSubnetworkFromIndra()builds an entity table frominput, flags the rows to query withselect_entities(), and passes all rows toget_network(), which matches the nodes INDRA returns against every row. Likeget_network(), it now prints the question it asks as a message. - The context and topic functions get edge evidence through
get_evidence(). The INDRA evidence lookup now uses the backend’scogex_urlin place of a hard-coded URL. Its output is unchanged. -
getSubnetworkFromIndra(filter_by_curation = TRUE)runsfilter_by_curation(). It looks up each statement hash once, where it used to look up every edge, uses the backend’scuration_url, prints how many edges it drops, and also drops edges left with no evidence whenevidence_count_cutoffis below 1. The curation lookup reads evidence hashes as character, so two hashes can no longer round to one number and be counted once.