/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.tools.kamstore;
import static org.openbel.framework.common.BELUtilities.hasItems;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.openbel.framework.api.Kam;
import org.openbel.framework.api.Kam.KamEdge;
import org.openbel.framework.api.Kam.KamNode;
import org.openbel.framework.api.internal.KAMStoreConstants;
import org.openbel.framework.api.internal.KAMCatalogDao.KamFilter;
import org.openbel.framework.api.internal.KAMStoreDaoImpl.Annotation;
import org.openbel.framework.api.internal.KAMStoreDaoImpl.AnnotationDefinitionType;
import org.openbel.framework.api.internal.KAMStoreDaoImpl.AnnotationType;
import org.openbel.framework.api.internal.KAMStoreDaoImpl.BelDocumentInfo;
import org.openbel.framework.api.internal.KAMStoreDaoImpl.BelStatement;
import org.openbel.framework.api.AnnotationFilterCriteria;
import org.openbel.framework.api.KAMStore;
import org.openbel.framework.api.KAMStoreException;
import org.openbel.framework.common.InvalidArgument;
import org.openbel.framework.common.Reportable;
import org.openbel.framework.common.enums.FunctionEnum;
import org.openbel.framework.common.enums.RelationshipType;
import org.openbel.framework.common.model.CitationAuthorsAnnotationDefinition;
import org.openbel.framework.common.model.CitationCommentAnnotationDefinition;
import org.openbel.framework.common.model.CitationDateAnnotationDefinition;
import org.openbel.framework.common.model.CitationNameAnnotationDefinition;
import org.openbel.framework.common.model.CitationTypeAnnotationDefinition;
@SuppressWarnings("unused")
public final class KamSummarizer {
private static final String RANDOM_VALUE = RandomStringUtils
.randomAlphabetic(30);
private final Reportable reportable;
/**
* Constructs the KamSummarizer
*/
public KamSummarizer(final Reportable reportable) {
this.reportable = reportable;
}
public void printKamSummary(final KAMStore kAMStore,
final KamSummary summary)
throws InvalidArgument, KAMStoreException {
reportable.output(String.format("\n\nSummarizing KAM: %s", summary
.getKamInfo().getName()));
reportable.output(String.format("\tLast Compiled:\t%s", summary
.getKamInfo().getLastCompiled()));
reportable.output(String.format("\tDescription:\t%s", summary
.getKamInfo().getDescription()));
reportable.output();
reportable.output(String.format("\tNum BEL Documents:\t%d",
summary.getNumOfBELDocuments()));
reportable.output(String.format("\tNum Namespaces:\t\t%d",
summary.getNumOfNamespaces()));
reportable.output(String.format("\tNum Annotation Types:\t\t%d",
summary.getNumOfAnnotationTypes()));
if (hasItems(summary.getAnnotations())) {
reportable.output("\tAnnotation Types:");
for (AnnotationType annotation : summary.getAnnotations()) {
reportable
.output(String.format("\t\t%s", annotation.getName()));
switch (annotation.getAnnotationDefinitionType()) {
case ENUMERATION:
reportable.output("\t\t\tType: List");
break;
case REGULAR_EXPRESSION:
reportable.output("\t\t\tType: Pattern");
break;
case URL:
reportable.output("\t\t\tType: URL");
reportable.output("\t\t\tLocation: " + annotation.getUrl());
break;
}
if (annotation.getAnnotationDefinitionType() != AnnotationDefinitionType.URL) {
reportable.output(String.format("\t\t\tDescription: %s",
annotation.getDescription()));
reportable.output(String.format("\t\t\tUsage: %s",
annotation.getUsage()));
reportable.output(String
.format("\t\t\tDomain: %s",
buildAnnotationDomain(kAMStore, summary,
annotation)));
}
}
}
reportable.output();
reportable.output(String.format("\tNum Statements:\t%d",
summary.getNumOfBELStatements()));
printNetworkSummary(summary, reportable);
//print filtered kam summaries if they are available
if (summary.getFilteredKamSummaries() != null
&& !summary.getFilteredKamSummaries().isEmpty()) {
reportable.output("\nSummary by Annotation Type");
for (String filteredKam : summary.getFilteredKamSummaries()
.keySet()) {
reportable.output(filteredKam + ":");
KamSummary filteredSummary =
summary.getFilteredKamSummaries().get(filteredKam);
reportable.output(String.format("\tNum Statements:\t%d",
filteredSummary.getNumOfBELStatements()));
reportable.output(String.format("\tNum Edges:\t%d",
filteredSummary.getNumOfEdges()));
}
}
}
public static KamSummary
summarizeKam(final KAMStore kAMStore, final Kam kam)
throws InvalidArgument, KAMStoreException {
KamSummary summary;
summary = new KamSummary();
summary.setKamInfo(kam.getKamInfo());
Set<Integer> stmtIds = new HashSet<Integer>();
for (KamEdge edge : kam.getEdges()) {
for (BelStatement stmt : kAMStore.getSupportingEvidence(edge)) {
stmtIds.add(stmt.getId());
}
}
summary.setNumOfBELStatements(stmtIds.size());
summary.setNumOfNodes(kam.getNodes().size());
summary.setNumOfEdges(kam.getEdges().size());
summary.setNumOfBELDocuments(kAMStore.getBelDocumentInfos(
kam.getKamInfo()).size());
summary.setNumOfNamespaces(kAMStore.getNamespaces(kam.getKamInfo())
.size());
List<AnnotationType> annotationTypes =
kAMStore.getAnnotationTypes(kam.getKamInfo());
Collections.sort(annotationTypes, new Comparator<AnnotationType>() {
@Override
public int compare(AnnotationType at1, AnnotationType at2) {
if (at1 == null || at1.getName() == null) {
return -1;
} else if (at2 == null || at2.getName() == null) {
return 1;
}
return at1.getName().compareToIgnoreCase(at2.getName());
}
});
//filter out multiple citation annotation types
List<AnnotationType> filteredAnnotationTypes =
new ArrayList<AnnotationType>();
for (AnnotationType at : annotationTypes) {
if (!(CitationAuthorsAnnotationDefinition.ANNOTATION_DEFINITION_ID
.equals(at.getName())
||
CitationCommentAnnotationDefinition.ANNOTATION_DEFINITION_ID
.equals(at.getName())
||
CitationDateAnnotationDefinition.ANNOTATION_DEFINITION_ID
.equals(at.getName())
||
CitationNameAnnotationDefinition.ANNOTATION_DEFINITION_ID
.equals(at.getName()) || CitationTypeAnnotationDefinition.ANNOTATION_DEFINITION_ID
.equals(at.getName()))) {
//filter all citation annotation type but the reference to get a more accurate count of citations
//reference is required for a citation
filteredAnnotationTypes.add(at);
}
}
summary.setAnnotations(filteredAnnotationTypes);
summary.setNumOfAnnotationTypes(filteredAnnotationTypes.size());
//breakdown human, mouse, rat and summary sub-network
summary.setFilteredKamSummaries(summarizeAnnotationSpecificEdges(
kAMStore, kam, filteredAnnotationTypes));
return summary;
}
/**
* Summarize nodes and edges
* @param edges
* @param annotationStatements
* @return
*/
public static KamSummary summarizeKamNetwork(Collection<KamEdge> edges,
int statementCount) {
KamSummary summary = new KamSummary();
Set<KamNode> nodes = new HashSet<KamNode>(); //unique set of nodes
for (KamEdge edge : edges) {
nodes.add(edge.getSourceNode());
nodes.add(edge.getTargetNode());
}
summary.setNumOfBELStatements(statementCount);
summary.setNumOfNodes(nodes.size());
summary.setNumOfEdges(edges.size());
return summary;
}
/**
* returns the number of rnaAbundance nodes.
* @param nodes
* @return
*/
private int getNumRnaNodes(Collection<KamNode> nodes) {
int count = 0;
for (KamNode node : nodes) {
if (node.getFunctionType() == FunctionEnum.RNA_ABUNDANCE) {
count++;
}
}
return count;
}
/**
* return number of protein with phosphorylation modification
* @param nodes
* @return
*/
private int getPhosphoProteinNodes(Collection<KamNode> nodes) {
int count = 0;
for (KamNode node : nodes) {
if (node.getFunctionType() == FunctionEnum.PROTEIN_ABUNDANCE
&& node.getLabel().indexOf("proteinModification(P") > -1) {
count++;
}
}
return count;
}
/**
* returns number unique gene reference
* @param edges
* @return
*/
private int getUniqueGeneReference(Collection<KamNode> nodes) {
//count all protienAbundance reference
Set<String> uniqueLabels = new HashSet<String>();
for (KamNode node : nodes) {
if (node.getFunctionType() == FunctionEnum.PROTEIN_ABUNDANCE
&& StringUtils.countMatches(node.getLabel(), "(") == 1
&& StringUtils.countMatches(node.getLabel(), ")") == 1) {
uniqueLabels.add(node.getLabel());
}
}
return uniqueLabels.size();
}
/**
* returns number of inceases and directly_increases edges.
* @param edges
* @return
*/
private int getIncreasesEdges(Collection<KamEdge> edges) {
int count = 0;
for (KamEdge edge : edges) {
if (edge.getRelationshipType() == RelationshipType.INCREASES
|| edge.getRelationshipType() == RelationshipType.DIRECTLY_INCREASES) {
count++;
}
}
return count;
}
/**
* returns number of deceases and directly_decreases edges.
* @param edges
* @return
*/
private int getDecreasesEdges(Collection<KamEdge> edges) {
int count = 0;
for (KamEdge edge : edges) {
if (edge.getRelationshipType() == RelationshipType.DECREASES
|| edge.getRelationshipType() == RelationshipType.DIRECTLY_DECREASES) {
count++;
}
}
return count;
}
private int getUpstreamCount(String label, Collection<KamEdge> edges) {
int count = 0;
for (KamEdge edge : edges) {
if (edge.getSourceNode().getLabel().equals(label) && isCausal(edge)) {
count++;
}
}
return count;
}
/**
* returns nodes with causal downstream to rnaAbundance() nodes.
* @param edges
* @return
*/
private Map<String, Integer> getTranscriptionalControls(
Collection<KamEdge> edges) {
Map<String, Integer> controlCountMap = new HashMap<String, Integer>();
for (KamEdge edge : edges) {
if (edge.getTargetNode().getFunctionType() == FunctionEnum.RNA_ABUNDANCE
&& isCausal(edge)) {
if (controlCountMap
.containsKey(edge.getSourceNode().getLabel())) {
int count =
controlCountMap
.get(edge.getSourceNode().getLabel());
count = count + 1;
controlCountMap.put(edge.getSourceNode().getLabel(), count);
} else {
controlCountMap.put(edge.getSourceNode().getLabel(), 1);
}
}
}
return controlCountMap;
}
/**
* returns nodes with 4+ causal downstream to rnaAbundance() nodes.
* @param edges
* @return
*/
private Map<String, Integer> getHypotheses(Collection<KamEdge> edges) {
Map<String, Integer> controlCountMap =
getTranscriptionalControls(edges);
Map<String, Integer> hypCountMap = new HashMap<String, Integer>();
for (String hyp : controlCountMap.keySet()) {
if (controlCountMap.get(hyp) >= 4) {
hypCountMap.put(hyp, controlCountMap.get(hyp));
}
}
return hypCountMap;
}
/**
* returns true if the edge has one of the 4 causal relationship types.
* @param edge
* @return
*/
private boolean isCausal(KamEdge edge) {
return edge.getRelationshipType() == RelationshipType.INCREASES
|| edge.getRelationshipType() == RelationshipType.DIRECTLY_INCREASES
|| edge.getRelationshipType() == RelationshipType.DECREASES
|| edge.getRelationshipType() == RelationshipType.DIRECTLY_DECREASES;
}
private Collection<KamEdge> filterEdges(final KAMStore kAMStore,
final Kam kam, final String annotationName)
throws KAMStoreException {
KamFilter filter = kam.getKamInfo().createKamFilter();
AnnotationFilterCriteria criteria =
new AnnotationFilterCriteria(getAnnotationType(kAMStore, kam,
annotationName));
criteria.add(RANDOM_VALUE);
criteria.setInclude(false);
filter.add(criteria);
Kam filteredKam = kAMStore.getKam(kam.getKamInfo(), filter);
return filteredKam.getEdges();
}
/**
* Returns the first annotation type matching the specified name
* @param kam
* @param name
* @return AnnotationType, maybe null
*/
private AnnotationType getAnnotationType(final KAMStore kAMStore,
final Kam kam, final String name) throws KAMStoreException {
AnnotationType annoType = null;
List<BelDocumentInfo> belDocs =
kAMStore.getBelDocumentInfos(kam.getKamInfo());
//loop through all BEL documents used for this KAM
for (BelDocumentInfo doc : belDocs) {
//check annotation type on each document
List<AnnotationType> annoTypes = doc.getAnnotationTypes();
for (AnnotationType a : annoTypes) {
if (a.getName().equals(name)) {
annoType = a;
break;
}
}
if (annoType != null) {
break;
}
}
return annoType;
}
private static Map<String, KamSummary> summarizeAnnotationSpecificEdges(
final KAMStore kAMStore, final Kam kam,
final List<AnnotationType> annotations)
throws KAMStoreException {
Map<String, KamSummary> summaries =
new LinkedHashMap<String, KamSummary>();
for (AnnotationType annotation : annotations) {
if (ArrayUtils.contains(
KAMStoreConstants.CITATION_ANNOTATION_DEFINITION_IDS,
annotation.getName())) {
continue;
}
Set<KamEdge> annotationEdges = new HashSet<Kam.KamEdge>();
Set<Integer> annotationStatements = new HashSet<Integer>();
for (final KamEdge edge : kam.getEdges()) {
List<BelStatement> supportingEvidence =
kAMStore.getSupportingEvidence(edge);
if (hasItems(supportingEvidence)) {
for (BelStatement stmt : supportingEvidence) {
if (hasItems(stmt.getAnnotationList())) {
for (Annotation stmtAnnotation : stmt
.getAnnotationList()) {
if (annotation.getName().equals(
stmtAnnotation.getAnnotationType()
.getName())) {
annotationEdges.add(edge);
annotationStatements.add(stmt.getId());
}
}
}
}
}
}
KamSummary annotationNetworkSummary =
summarizeKamNetwork(annotationEdges,
annotationStatements.size());
summaries.put(annotation.getName(), annotationNetworkSummary);
}
return summaries;
}
private String buildAnnotationDomain(final KAMStore kAMStore,
final KamSummary summary,
final AnnotationType annotationType) throws KAMStoreException {
List<String> domainValues =
kAMStore.getAnnotationTypeDomainValues(summary.getKamInfo(),
annotationType);
summary.getAnnotationDomains().put(annotationType, domainValues);
StringBuilder sb = new StringBuilder();
for (String domainValue : domainValues) {
sb.append(domainValue).append("|");
}
return sb.substring(0, sb.length() - 1);
}
private void printNetworkSummary(final KamSummary summary,
final Reportable reportable) throws InvalidArgument,
KAMStoreException {
reportable.output(String.format("\tNum Nodes:\t%d",
summary.getNumOfNodes()));
reportable.output(String.format("\tNum Edges:\t%d",
summary.getNumOfEdges()));
reportable.output();
}
private String printEdge(final KamEdge kamEdge) {
return String.format("%s %s %s", kamEdge.getSourceNode().getLabel(),
kamEdge.getRelationshipType().getDisplayValue(), kamEdge
.getTargetNode().getLabel());
}
private void printBelStatement(final BelStatement belStatement) {
reportable.output(String.format("\tBEL Statement: %d\t%s",
belStatement.getId(), belStatement));
reportable.output(String.format("\t\tNum Annotations: %d", belStatement
.getAnnotationList().size()));
for (Annotation annotation : belStatement.getAnnotationList()) {
reportable.output(String.format("\t\t%s -> %s", annotation
.getAnnotationType().getName(), annotation.getValue()));
}
}
}