package uk.ac.rhul.cs.cl1.ui.cytoscape3; import java.util.List; import org.cytoscape.model.CyColumn; import org.cytoscape.model.CyNetwork; import org.cytoscape.model.CyNode; import org.cytoscape.model.CyRow; import org.cytoscape.model.CyTable; import org.cytoscape.view.model.CyNetworkView; import org.cytoscape.work.Task; import org.cytoscape.work.TaskMonitor; import uk.ac.rhul.cs.cl1.ClusterONE; import uk.ac.rhul.cs.cl1.ClusterONEException; import uk.ac.rhul.cs.cl1.NodeSet; import uk.ac.rhul.cs.cl1.ValuedNodeSetList; import com.sosnoski.util.hashmap.ObjectIntHashMap; /** * Wrapper object for {@link ClusterONE} that makes it compatible with * Cytoscape's {@link Task} interface. * * @author ntamas */ public class ClusterONECytoscapeTask extends ClusterONE implements Task { /** * The network on which the algorithm is run. */ private CyNetwork network; /** * The network view that will show the results when the algorithm has * finished. May be null if the algorithm is run on a network without a * view. */ private CyNetworkView networkView; /** * The result listener to notify when the algorithm has finished and the * results are available. */ private ClusterONECytoscapeTask.ResultListener resultListener; // -------------------------------------------------------------------- // Constructors // -------------------------------------------------------------------- // -------------------------------------------------------------------- // Properties // -------------------------------------------------------------------- /** * Gets the network on which the algorithm is run. */ public CyNetwork getNetwork() { return this.network; } /** * Gets the network view that will show the results when the algorithm has * finished. */ public CyNetworkView getNetworkView() { return this.networkView; } /** * Sets the network on which the algorithm is run. It will clear the associated * network view unless it is associated to the same network. */ public void setNetwork(CyNetwork network) { this.network = network; if (this.networkView != null && this.networkView.getModel() != network) { this.networkView = null; } } /** * Sets the network view that will show the results when the algorithm has * finished. It will also call <code>setNetwork()</code> to set the associated * network to the network that is shown in the view. */ public void setNetworkView(CyNetworkView networkView) { this.networkView = networkView; this.setNetwork(networkView != null ? networkView.getModel() : null); } /** * Sets the result listener to notify when the algorithm has finished and the * results are available. */ public void setResultListener(ClusterONECytoscapeTask.ResultListener listener) { this.resultListener = listener; } // -------------------------------------------------------------------- // Query methods // -------------------------------------------------------------------- // -------------------------------------------------------------------- // Manipulation methods // -------------------------------------------------------------------- public void cancel() { halt(); } public void run(TaskMonitor taskMonitor) throws Exception { try { setTaskMonitor(taskMonitor != null ? new CytoscapeTaskMonitorWrapper(taskMonitor) : null); taskMonitor.setTitle(ClusterONE.applicationName); super.run(); // Construct the result and notify the listener if (resultListener != null) { Result result = new Result(); result.clusters = this.result; if (this.graph instanceof Graph) { result.nodeMapping = ((Graph)this.graph).getNodeMapping(); } resultListener.resultsCalculated(this, result); } } catch (ClusterONEException e) { throw e; } catch (Exception e) { throw new Exception("Unexpected error while running " + ClusterONE.applicationName + ". "+ "Please notify the plugin authors!", e); } } // -------------------------------------------------------------------- // Private methods // -------------------------------------------------------------------- // -------------------------------------------------------------------- // Result class // -------------------------------------------------------------------- /** * Class that contains the result of the task. * * The task result actually has two components: the detected clusters * and the mapping of the graph nodes back to CyNodes. */ public class Result { /** * The clusters detected by the algorithm. */ public ValuedNodeSetList clusters; /** * The mapping of graph node indices back to their corresponding CyNodes. */ public List<CyNode> nodeMapping; /** * Sets some ClusterONE specific node status attributes on a CyNetwork that * will be used by VizMapper later. */ public void setStatusAttributes() { if (networkView == null || networkView.getModel() == null) return; ObjectIntHashMap occurrences = new ObjectIntHashMap(); for (NodeSet nodeSet: clusters) { for (Integer nodeIdx: nodeSet) { int value = occurrences.get(nodeIdx); if (value == ObjectIntHashMap.DEFAULT_NOT_FOUND) value = 0; occurrences.add(nodeIdx, value+1); } } CyTable nodeTable = network.getDefaultNodeTable(); final String[] values = {"Outlier", "Cluster", "Overlap"}; CyColumn statusColumn = nodeTable.getColumn(ClusterONECytoscapeApp.ATTRIBUTE_STATUS); if (statusColumn != null && statusColumn.getType() != String.class) { // TODO /* int response = app.showConfirmDialog(Cytoscape.getDesktop(), "A node attribute named "+ATTRIBUTE_STATUS+" already exists and "+ "it is not a string attribute.\nDo you want to remove the existing "+ "attribute and re-register it as a string attribute?", "Attribute type mismatch", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (response == JOptionPane.NO_OPTION) return; */ nodeTable.deleteColumn(ClusterONECytoscapeApp.ATTRIBUTE_STATUS); statusColumn = null; } if (statusColumn == null) { nodeTable.createColumn(ClusterONECytoscapeApp.ATTRIBUTE_STATUS, String.class, false); } int i = 0; for (CyNode node: nodeMapping) { int index = occurrences.get(i); if (index == ObjectIntHashMap.DEFAULT_NOT_FOUND) index = 0; if (index > 2) index = 2; CyRow row = network.getRow(node); if (row != null) { row.set(ClusterONECytoscapeApp.ATTRIBUTE_STATUS, values[index]); } i++; } } } // -------------------------------------------------------------------- // ResultListener interface // -------------------------------------------------------------------- /** * Interface to be implemented by listeners interested in the result of a * ClusterONECytoscapeTask. */ public interface ResultListener { /** * Called when the results are ready. */ public void resultsCalculated(ClusterONECytoscapeTask task, Result result); } }