diff --git a/AutoAnnotate/pom.xml b/AutoAnnotate/pom.xml index 2dbab89..24ae650 100644 --- a/AutoAnnotate/pom.xml +++ b/AutoAnnotate/pom.xml @@ -5,7 +5,7 @@ AutoAnnotate org.baderlab.autoannotate org.baderlab.autoannotate - 3.3.0 + 3.4.0 AutoAnnotate diff --git a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/ApplicationModule.java b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/ApplicationModule.java index ca0b50f..6de3ff8 100644 --- a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/ApplicationModule.java +++ b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/ApplicationModule.java @@ -9,6 +9,7 @@ import org.baderlab.autoannotate.internal.task.CollapseAllTaskFactory; import org.baderlab.autoannotate.internal.task.CollapseTask; import org.baderlab.autoannotate.internal.task.CreateAnnotationSetTask; +import org.baderlab.autoannotate.internal.task.CreateSubnetworkTask; import org.baderlab.autoannotate.internal.task.LayoutAnnotationSetTaskFactory; import org.baderlab.autoannotate.internal.task.LayoutClustersTaskFactory; import org.baderlab.autoannotate.internal.task.RunClusterMakerTaskFactory; @@ -87,6 +88,7 @@ protected void configure() { installFactory(RemoveAllAnnotationsTask.Factory.class); installFactory(CreateAnnotationSetTask.Factory.class); installFactory(CreateClusterTask.Factory.class); + installFactory(CreateSubnetworkTask.Factory.class); } private void installFactory(Class factoryInterface) { diff --git a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/CytoscapeServiceModule.java b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/CytoscapeServiceModule.java index f81db41..2f3bbd0 100644 --- a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/CytoscapeServiceModule.java +++ b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/CytoscapeServiceModule.java @@ -19,6 +19,7 @@ import org.cytoscape.model.CyNetworkTableManager; import org.cytoscape.model.CyTableFactory; import org.cytoscape.model.CyTableManager; +import org.cytoscape.model.subnetwork.CyRootNetworkManager; import org.cytoscape.service.util.CyServiceRegistrar; import org.cytoscape.session.CySessionManager; import org.cytoscape.util.swing.FileUtil; @@ -75,6 +76,7 @@ protected void configure() { bindService(CyTableManager.class); bindService(CyTableFactory.class); bindService(FileUtil.class); + bindService(CyRootNetworkManager.class); bindService(DialogTaskManager.class); TypeLiteral> synchronousManager = new TypeLiteral>(){}; diff --git a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/CreateAnnotationSetTask.java b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/CreateAnnotationSetTask.java index 54c91a3..3298710 100644 --- a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/CreateAnnotationSetTask.java +++ b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/CreateAnnotationSetTask.java @@ -26,8 +26,11 @@ import org.baderlab.autoannotate.internal.model.io.CreationParameter; import org.baderlab.autoannotate.internal.util.ResultObserver; import org.cytoscape.model.CyNetwork; +import org.cytoscape.model.CyNetworkManager; import org.cytoscape.model.CyNode; import org.cytoscape.view.model.CyNetworkView; +import org.cytoscape.view.model.View; +import org.cytoscape.view.presentation.property.BasicVisualLexicon; import org.cytoscape.work.AbstractTask; import org.cytoscape.work.TaskIterator; import org.cytoscape.work.TaskManager; @@ -41,8 +44,10 @@ public class CreateAnnotationSetTask extends AbstractTask { @Inject private RunClusterMakerTaskFactory.Factory clusterMakerFactoryFactory; + @Inject private CreateSubnetworkTask.Factory subnetworkTaskFactory; @Inject private Provider labelManagerProvider; @Inject private LayoutClustersTaskFactory.Factory layoutTaskFactoryFactory; + @Inject private CyNetworkManager networkManager; @Inject private @Named("sync") TaskManager syncTaskManager; @Inject private ModelManager modelManager; @@ -170,11 +175,30 @@ private boolean needClusterEdgeAttribute() { private Map> runClusterMaker(Optional cutoff) { - RunClusterMakerTaskFactory clusterMakerTaskFactory = clusterMakerFactoryFactory.create(params, cutoff.orElse(null)); + CyNetworkView networkView = params.getNetworkView(); + CyNetwork network = networkView.getModel(); + boolean hasHidden = hasHiddenNodes(networkView); + if(hasHidden) { + Collection visibleNodes = getVisibleNodes(networkView); + CreateSubnetworkTask subnetworkTask = subnetworkTaskFactory.create(network, visibleNodes); + ResultObserver observer = new ResultObserver<>(subnetworkTask, CyNetwork.class); + syncTaskManager.execute(new TaskIterator(subnetworkTask), observer); + network = observer.getResults().get(); + networkManager.addNetwork(network, false); + } + + RunClusterMakerTaskFactory clusterMakerTaskFactory = + clusterMakerFactoryFactory.create(network, params.getClusterAlgorithm(), params.getClusterMakerEdgeAttribute(), cutoff.orElse(null)); RunClusterMakerResultObserver clusterResultObserver = new RunClusterMakerResultObserver(); TaskIterator tasks = clusterMakerTaskFactory.createTaskIterator(clusterResultObserver); syncTaskManager.execute(tasks); - return clusterResultObserver.getResult(); + Map> result = clusterResultObserver.getResult(); + + if(hasHidden) { + networkManager.destroyNetwork(network); + } + + return result; } @@ -215,7 +239,8 @@ private String createName(NetworkViewSet networkViewSet) { private Map> computeClustersFromColumn() { String attribute = params.getClusterDataColumn(); - CyNetwork network = params.getNetworkView().getModel(); + CyNetworkView networkView = params.getNetworkView(); + CyNetwork network = networkView.getModel(); Map> clusters = new HashMap<>(); @@ -227,6 +252,9 @@ private Map> computeClustersFromColumn() { } for(CyNode node : network.getNodeList()) { + if(isHidden(node, networkView)) + continue; + List list; if(isList) list = network.getRow(node).getList(attribute, type); @@ -234,18 +262,12 @@ private Map> computeClustersFromColumn() { list = Collections.singletonList(network.getRow(node).get(attribute, type)); for(Object o : list) { - if(o == null) - continue; - String key = String.valueOf(o).trim(); - if(key.isEmpty()) - continue; - - Collection cluster = clusters.get(key); - if(cluster == null) { - cluster = new HashSet<>(); - clusters.put(key, cluster); + if(o != null) { + String key = String.valueOf(o).trim(); + if(!key.isEmpty()) { + clusters.computeIfAbsent(key, k -> new HashSet<>()).add(node); + } } - cluster.add(node); } } return clusters; @@ -274,12 +296,38 @@ private void limitClusters(Map> clusters, int maxClust } private Collection getUnclusteredNodes(Map> clusters) { - CyNetwork network = params.getNetworkView().getModel(); + CyNetworkView networkView = params.getNetworkView(); + CyNetwork network = networkView.getModel(); Set nodes = new HashSet<>(network.getNodeList()); for(Collection cluster : clusters.values()) { nodes.removeAll(cluster); } + + // filter out hidden nodes + nodes.removeIf(node -> isHidden(node, networkView)); return nodes; } + + + private static boolean isHidden(View nodeView) { + if(nodeView == null) + return false; + return nodeView.getVisualProperty(BasicVisualLexicon.NODE_VISIBLE) == Boolean.FALSE; + } + + private static boolean isHidden(CyNode node, CyNetworkView networkView) { + View nodeView = networkView.getNodeView(node); + return isHidden(nodeView); + } + private static boolean hasHiddenNodes(CyNetworkView view) { + return view.getNodeViews().stream().anyMatch(CreateAnnotationSetTask::isHidden); + } + + private static Collection getVisibleNodes(CyNetworkView view) { + return view.getNodeViews().stream() + .filter(nv -> !isHidden(nv)) + .map(nv -> nv.getModel()) + .collect(Collectors.toList()); + } } diff --git a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/CreateSubnetworkTask.java b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/CreateSubnetworkTask.java new file mode 100644 index 0000000..4da51e0 --- /dev/null +++ b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/CreateSubnetworkTask.java @@ -0,0 +1,159 @@ +package org.baderlab.autoannotate.internal.task; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.cytoscape.model.CyColumn; +import org.cytoscape.model.CyEdge; +import org.cytoscape.model.CyNetwork; +import org.cytoscape.model.CyNode; +import org.cytoscape.model.CyRow; +import org.cytoscape.model.CyTable; +import org.cytoscape.model.VirtualColumnInfo; +import org.cytoscape.model.subnetwork.CyRootNetworkManager; +import org.cytoscape.model.subnetwork.CySubNetwork; +import org.cytoscape.work.AbstractTask; +import org.cytoscape.work.ObservableTask; +import org.cytoscape.work.TaskMonitor; + +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +public class CreateSubnetworkTask extends AbstractTask implements ObservableTask { + + @Inject private CyRootNetworkManager rootNetMgr; + + private final CyNetwork parentNetwork; + private final Collection nodes; + private CySubNetwork resultNetwork; + + + public interface Factory { + CreateSubnetworkTask create(CyNetwork parentNetwork, Collection nodes); + } + + @Inject + public CreateSubnetworkTask(@Assisted CyNetwork parentNetwork, @Assisted Collection nodes) { + this.parentNetwork = parentNetwork; + this.nodes = nodes; + } + + @Override + public void run(TaskMonitor tm) { + if (parentNetwork == null) { + tm.showMessage(TaskMonitor.Level.ERROR, "Source network must be specified."); + return; + } + + tm.setProgress(0.2); + + // create subnetwork and add selected nodes and appropriate edges + final CySubNetwork newNet = rootNetMgr.getRootNetwork(parentNetwork).addSubNetwork(); + + //We need to cpy the columns to local tables, since copying them to default table will duplicate the virtual columns. + addColumns(parentNetwork.getTable(CyNode.class, CyNetwork.LOCAL_ATTRS), newNet.getTable(CyNode.class, CyNetwork.LOCAL_ATTRS)); + addColumns(parentNetwork.getTable(CyEdge.class, CyNetwork.LOCAL_ATTRS), newNet.getTable(CyEdge.class, CyNetwork.LOCAL_ATTRS) ); + addColumns(parentNetwork.getTable(CyNetwork.class, CyNetwork.LOCAL_ATTRS), newNet.getTable(CyNetwork.class, CyNetwork.LOCAL_ATTRS)); + + tm.setProgress(0.3); + + for(CyNode node : nodes) { + newNet.addNode(node); + cloneRow(parentNetwork.getRow(node), newNet.getRow(node)); + //Set rows and edges to not selected state to avoid conflicts with table browser + newNet.getRow(node).set(CyNetwork.SELECTED, false); + } + + tm.setProgress(0.4); + + for (final CyEdge edge : getEdges(parentNetwork, nodes)) { + newNet.addEdge(edge); + cloneRow(parentNetwork.getRow(edge), newNet.getRow(edge)); + //Set rows and edges to not selected state to avoid conflicts with table browser + newNet.getRow(edge).set(CyNetwork.SELECTED, false); + } + + tm.setProgress(0.5); + + newNet.getRow(newNet).set(CyNetwork.NAME, getNetworkName()); + + resultNetwork = newNet; + tm.setProgress(1.0); + } + + private void addColumns(CyTable parentTable, CyTable subTable) { + List colsToAdd = new ArrayList(); + + for (CyColumn col: parentTable.getColumns()) + if (subTable.getColumn(col.getName()) == null) + colsToAdd.add( col ); + + for (CyColumn col: colsToAdd) { + VirtualColumnInfo colInfo = col.getVirtualColumnInfo(); + if (colInfo.isVirtual()) + addVirtualColumn(col, subTable); + else + copyColumn(col, subTable); + } + } + + private void addVirtualColumn (CyColumn col, CyTable subTable){ + VirtualColumnInfo colInfo = col.getVirtualColumnInfo(); + CyColumn checkCol= subTable.getColumn(col.getName()); + + if (checkCol == null) + subTable.addVirtualColumn(col.getName(), colInfo.getSourceColumn(), colInfo.getSourceTable(), + colInfo.getTargetJoinKey(), col.isImmutable()); + + else + if (!checkCol.getVirtualColumnInfo().isVirtual() || + !checkCol.getVirtualColumnInfo().getSourceTable().equals(colInfo.getSourceTable()) || + !checkCol.getVirtualColumnInfo().getSourceColumn().equals(colInfo.getSourceColumn())) + subTable.addVirtualColumn(col.getName(), colInfo.getSourceColumn(), colInfo.getSourceTable(), + colInfo.getTargetJoinKey(), col.isImmutable()); + } + + private void copyColumn(CyColumn col, CyTable subTable) { + if (List.class.isAssignableFrom(col.getType())) + subTable.createListColumn(col.getName(), col.getListElementType(), false); + else + subTable.createColumn(col.getName(), col.getType(), false); + } + + private void cloneRow(final CyRow from, final CyRow to) { + for (final CyColumn column : from.getTable().getColumns()){ + if (!column.getVirtualColumnInfo().isVirtual()) + to.set(column.getName(), from.getRaw(column.getName())); + } + } + + private String getNetworkName() { + return "AutoAnnotate_Temp"; + } + + /** + * Returns all edges that connect the selected nodes. + */ + private static Set getEdges(CyNetwork net, Collection nodes) { + Set edges = new HashSet(); + + for (final CyNode n1 : nodes) { + for (final CyNode n2 : nodes) + edges.addAll(net.getConnectingEdgeList(n1, n2, CyEdge.Type.ANY)); + } + + return edges; + } + + @Override + public R getResults(Class type) { + if(CyNetwork.class.equals(type)) { + return type.cast(resultNetwork); + } + return null; + } + +} diff --git a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/RunClusterMakerTaskFactory.java b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/RunClusterMakerTaskFactory.java index 0e8d4d5..fc00e13 100644 --- a/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/RunClusterMakerTaskFactory.java +++ b/AutoAnnotate/src/main/java/org/baderlab/autoannotate/internal/task/RunClusterMakerTaskFactory.java @@ -1,11 +1,10 @@ package org.baderlab.autoannotate.internal.task; -import java.util.Objects; - import javax.annotation.Nullable; import org.baderlab.autoannotate.internal.model.ClusterAlgorithm; import org.cytoscape.command.CommandExecutorTaskFactory; +import org.cytoscape.model.CyNetwork; import org.cytoscape.model.CyTable; import org.cytoscape.work.TaskFactory; import org.cytoscape.work.TaskIterator; @@ -19,16 +18,21 @@ public class RunClusterMakerTaskFactory implements TaskFactory { @Inject private CommandExecutorTaskFactory commandTaskFactory; - private final AnnotationSetTaskParamters params; + private final ClusterAlgorithm algorithm; + private final CyNetwork network; + private final String edgeAttribute; private final Double cutoff; public static interface Factory { - RunClusterMakerTaskFactory create(AnnotationSetTaskParamters params, @Nullable Double cutoff); + RunClusterMakerTaskFactory create(CyNetwork network, ClusterAlgorithm algorithm, @Nullable String edgeAttribute, @Nullable Double cutoff); } @AssistedInject - public RunClusterMakerTaskFactory(@Assisted AnnotationSetTaskParamters params, @Assisted @Nullable Double cutoff) { - this.params = Objects.requireNonNull(params); + public RunClusterMakerTaskFactory(@Assisted CyNetwork network, @Assisted ClusterAlgorithm algorithm, + @Assisted @Nullable String edgeAttribute, @Assisted @Nullable Double cutoff) { + this.network = network; + this.algorithm = algorithm; + this.edgeAttribute = edgeAttribute; this.cutoff = cutoff; } @@ -43,26 +47,24 @@ public TaskIterator createTaskIterator(TaskObserver taskObserver) { * MKTODO if the command gets any more complex then create a ClusterMakerCommandBuilder */ public String getClusterCommand() { - ClusterAlgorithm alg = params.getClusterAlgorithm(); String columnName = getColumnName(); + String command = algorithm.getCommandName(); + Long suid = network.getSUID(); - String command = alg.getCommandName(); - Long suid = params.getNetworkView().getModel().getSUID(); + StringBuilder sb = new StringBuilder("cluster ").append(command) + .append(" network=\"SUID:").append(suid).append('"') + .append(" clusterAttribute=\"").append(columnName).append('"'); + if(algorithm.isEdgeAttributeRequired()) + sb.append(" attribute=\"").append(edgeAttribute).append('"'); + if(algorithm.isEdgeAttributeRequired() && cutoff != null) + sb.append(" edgeCutOff=\"").append(cutoff).append('"'); - if(alg.isEdgeAttributeRequired() && cutoff != null) { - return String.format("cluster %s network=\"SUID:%d\" clusterAttribute=\"%s\" attribute=\"%s\" edgeCutOff=\"%s\"", command, suid, columnName, params.getClusterMakerEdgeAttribute(), cutoff); - } - else if(alg.isEdgeAttributeRequired()) { - return String.format("cluster %s network=\"SUID:%d\" clusterAttribute=\"%s\" attribute=\"%s\"", command, suid, columnName, params.getClusterMakerEdgeAttribute()); - } - else { - return String.format("cluster %s network=\"SUID:%d\" clusterAttribute=\"%s\"", command, suid, columnName); - } + return sb.toString(); } private String getColumnName() { - CyTable table = params.getNetworkView().getModel().getDefaultNodeTable(); - final String originalName = params.getClusterAlgorithm().getColumnName(); + CyTable table = network.getDefaultNodeTable(); + final String originalName = algorithm.getColumnName(); String name = originalName; int suffix = 2; @@ -74,7 +76,10 @@ private String getColumnName() { public String getNetworkCommand() { - return "cluster getnetworkcluster algorithm=" + params.getClusterAlgorithm().getCommandName(); + return new StringBuilder("cluster getnetworkcluster") + .append(" network=\"SUID:").append(network.getSUID()).append('"') + .append(" algorithm=").append(algorithm.getCommandName()) + .toString(); }