package uk.ac.rhul.cs.cl1.ui.procope;
import java.util.ArrayList;
import procope.data.complexes.Complex;
import procope.data.complexes.ComplexSet;
import procope.data.networks.ProteinNetwork;
import procope.methods.clustering.Clusterer;
import procope.tools.ProCopeException;
import uk.ac.rhul.cs.cl1.ClusterONE;
import uk.ac.rhul.cs.cl1.ClusterONEAlgorithmParameters;
import uk.ac.rhul.cs.cl1.ClusterONEException;
import uk.ac.rhul.cs.cl1.NodeSet;
import uk.ac.rhul.cs.cl1.ui.ClusterONEAlgorithmParametersDialog;
import uk.ac.rhul.cs.cl1.ui.SwingTaskMonitor;
import uk.ac.rhul.cs.graph.Graph;
import uk.ac.rhul.cs.utils.UniqueIDGenerator;
/**
* ProCope plugin version of ClusterONE.
*
* @author tamas
*/
public class ProcopePlugin implements Clusterer {
public ComplexSet cluster(ProteinNetwork net) {
ComplexSet result = new ComplexSet();
Graph graph = this.convertProteinNetworkToGraph(net);
ClusterONEAlgorithmParameters parameters = getAlgorithmParameters();
if (parameters == null)
return result;
ClusterONE algorithm = new ClusterONE(parameters);
algorithm.setTaskMonitor(new SwingTaskMonitor());
try {
algorithm.runOnGraph(graph);
} catch (ClusterONEException ex) {
/* Convert the exception to a ProCopeException */
ProCopeException newEx = new ProCopeException(ex.getMessage());
newEx.initCause(ex);
throw newEx;
}
for (NodeSet nodeSet: algorithm.getResults()) {
result.addComplex(this.convertNodeSetToComplex(nodeSet));
}
return result;
}
/**
* Obtains the algorithm parameters from the user using a standard ProCope dialog box
* @return the parameters
*/
protected ClusterONEAlgorithmParameters getAlgorithmParameters() {
ClusterONEAlgorithmParametersDialog dialog = new ClusterONEAlgorithmParametersDialog();
dialog.getParametersPanel().expandAll();
dialog.pack();
dialog.setLocationRelativeTo(null);
if (!dialog.execute())
return null;
return dialog.getParameters();
}
/**
* Converts a NodeSet object back to a ProCope Complex object
* @param nodeSet the nodeset to be converted
* @return the converted ProCope complex
*/
private Complex convertNodeSetToComplex(NodeSet nodeSet) {
ArrayList<Integer> ids = new ArrayList<Integer>(nodeSet.size());
Graph graph = nodeSet.getGraph();
for (int node: nodeSet) {
ids.add(Integer.parseInt(graph.getNodeName(node)));
}
return new Complex(ids);
}
/**
* Converts a ProteinNetwork object to a Graph object
* @param net the ProteinNetwork to be converted
* @return a Graph object where every node is a protein and every edge is a weighted interaction
*/
protected Graph convertProteinNetworkToGraph(ProteinNetwork net) {
Graph result = new Graph();
UniqueIDGenerator<Integer> idGen = new UniqueIDGenerator<Integer>(result);
if (net.isDirected())
throw new ProCopeException("ClusterONE supports undirected graphs only");
int[] edges = net.getEdgesArray();
for (int i = 0; i < edges.length; i += 2) {
int protein1 = idGen.get(edges[i]);
int protein2 = idGen.get(edges[i+1]);
float weight = net.getEdge(edges[i], edges[i+1]);
if (weight == Float.NaN)
continue;
if (weight < 0.0)
throw new ProCopeException("negative weights are not supported by ClusterONE");
if (weight > 1.0)
throw new ProCopeException("scores larger than 1.0 are not supported by ClusterONE");
result.createEdge(protein1, protein2, weight);
}
return result;
}
}