Locked History Actions

CyniAlgorithmTutorialSwingUI

How to create a Cyni Algorithm with own Java Swing UI

Introduction

In order to help app developers, we provide a Cyni Algorithm sample, which contains a "HelloWorld" implementation of a Cyni Algorithm. This sample will serve as a starting point or template for new app developers. Cyni sample code can be used by following these steps:

  1. Check out the cyni sample projects from our Github repository with this command:

git clone git://github.com/schwikowskilab/cyni-samples.git
  1. Go the cyni-gui-algo-sample directory and compile it with mvn clean install

This tutorial is focused on showing the main steps to create a Cyni Algorithm that does not use Cytoscape Tunables to generate the User Interface for input parameter handling. All the User Interface methods are centralized in the new class extending CyniAlgorithmContext. Next sections describe each file that needs to be created to produce a Cyni Algorithm App that provides your own swing UI.

Pom File

Here are the main lines to modify in the pom.xml file. The fields bundle.symbolicName and bundle.namespace properties should be modified according to new app directory configuration. Tags groupId and artifactId also have to be modified. Finally, version tab should set to developer requirements.

<properties>
        <bundle.symbolicName>cyni-gui-algo-sample</bundle.symbolicName>
        <bundle.namespace>fr.systemsbiology.cyniSampleGuiAlgorithm.internal</bundle.namespace>
        <cytoscape.api.version>3.1.0</cytoscape.api.version>
        <cyni.api.version>1.0.0</cyni.api.version>
        <maven-bundle-plugin.version>2.3.4</maven-bundle-plugin.version>
        <osgi.api.version>4.2.0</osgi.api.version>
</properties>

<groupId>fr.systemsbiology.cyniSampleGuiAlgorithm</groupId>
<artifactId>cyniSampleGuiAlgorithm</artifactId>
<packaging>bundle</packaging>
<name>${bundle.symbolicName}</name>

<version>3.0.0-alpha1-SNAPSHOT</version>

CyActivator

In this file, any Cyni Algorithm implemented needs to be registered. These two lines do the work. First, we create the object for the new Cyni Algorithm and then we register it to make it available by the Cyni Algorithm Manager.

   1     //Define new Cyni Algorithm
   2     CyniSampleGuiAlgorithm test = new CyniSampleGuiAlgorithm();
   3     //Register new Cyni Algorithm
   4     registerService(bc,test,CyCyniAlgorithm.class, new Properties());

CyniSampleAlgorithm

In the constructor of this class, there are three parameters that need to be set. The computer name of the algorithm, the human name of the algorithm (the one used to be displayed) and the category of the algorithm. This parameters are passed to the parent class.

   1 public CyniSampleAlgorithm() {
   2     super("sampleGuiAlgo.cyni","Cyni Sample Gui Algorithm",true,CyniCategory.INDUCTION);
   3 }

The other two main functions serve to generate the task object and the context object. The context method contains a tunableSetter argument, which allows users to set the context without using a User Interface. The content of context method should be unmodified regarding the lines involving the tunableSetter.

   1 public TaskIterator createTaskIterator(Object context,CyTable table, CyNetworkFactory networkFactory, CyNetworkViewFactory networkViewFactory,CyNetworkManager networkManager,CyNetworkTableManager netTableMgr, CyRootNetworkManager rootNetMgr,CyNetworkViewManager networkViewManager, CyLayoutAlgorithmManager layoutManager, CyCyniMetricsManager metricsManager) {
   2     selectedTable = table;
   3     return new TaskIterator(new CyniSampleGuiAlgorithmTask(getName(),(CyniSampleAlgorithmContext)context,networkFactory,networkViewFactory,networkManager,netTableMgr,rootNetMgr,networkViewManager,layoutManager,metricsManager, selectedTable));
   4         }
   5 
   6 public Object createCyniContext(CyTable table, CyCyniMetricsManager metricsManager, TunableSetter tunableSetter,Map<String, Object> mparams) {
   7     Object context;
   8     selectedTable = table;
   9     context = new CyniSampleGuiAlgorithmContext();
  10     if(mparams != null && !mparams.isEmpty())
  11         tunableSetter.applyTunables(context, mparams);
  12     return context;
  13 }

CyniSampleAlgorithmContext

This file must extend the CyniAlgorithmContext class. If we don't want Cytoscape to use Cytoscape Tunables to display the User Interface that will allow selecting the parameters for this algorithm. This class should modify the following methods to provide to Cytoscape your own java swing panel for parameter handling.

   1 public boolean contextHasOwnSwingPanel()
   2 {
   3         return true;
   4 }
   5 
   6 public JPanel getContextSwingPanel()
   7 {
   8         return mainPanel;
   9 }
  10         
  11 public boolean contextContentValid()
  12 {
  13         if(getParam2() > 0)
  14                 return true;
  15         else
  16                 return false;
  17 }

The method contextContentValid only needs to be implemented if the value of input parameters need to be validated before applying the algorithm. This method will be called before running the algorithm task and the task will only continue if this method returns true.
The values entered in the UI needs to be retrieved later on, so this class should provide methods to get the final values for these parameters. In Cyni sample, we provide (below) an example of these kind of methods.

   1 public double getParam1()
   2 {
   3         return param1Panel.getLimit();
   4 }
   5 
   6 public double getParam2()
   7 {
   8         return param2Panel.getLimit();
   9 }

There are three other files in this Cyni Sample that basically contain all implementation to generate the desired Swing Panel. This is just a possibility but any kind of implementation could be correct provided a Java Swing panel is finally generated.

CyniSampleAlgorithmTask

This file contains the actual implementation of the Cyni Algorithm. In the constructor, the context and the selected table are passed. In the context, there is the information of each input parameter for the algorithm.
Any implementation related to the Cyni Algorithm needs to be developed in the doCyniTask method.

   1 public CyniSampleGuiAlgorithmTask(final String name, final CyniSampleAlgorithmContext context, CyNetworkFactory networkFactory, CyNetworkViewFactory networkViewFactory,CyNetworkManager networkManager,CyNetworkTableManager netTableMgr, CyRootNetworkManager rootNetMgr,CyNetworkViewManager networkViewManager,CyLayoutAlgorithmManager layoutManager, CyCyniMetricsManager metricsManager, CyTable selectedTable)
   2 {
   3     super(name, context, networkFactory, networkViewFactory, networkManager, networkViewManager, netTableMgr, rootNetMgr);
   4     this.param1 = context.getParam1();
   5     this.param2 = context.getParam2();
   6     this.mytable = selectedTable;
   7 
   8 }
   9 
  10 /**
  11  *  Perform actualtask.
  12 */
  13 @Override
  14 final protected void doCyniTask(final TaskMonitor taskMonitor) {
  15 
  16     Double progress = 0.0d;
  17     CyNetwork networkSelected = null;
  18     String networkName;
  19     CyLayoutAlgorithm layout;
  20     CyNetworkView newNetworkView ;
  21 
  22     taskMonitor.setStatusMessage("Algorithm running ...");
  23     taskMonitor.setProgress(progress);
  24 
  25     .......................
  26 
  27     taskMonitor.setProgress(1.0d);
  28 }

The core of the method doCyniTask contains the main steps to create the new network. As shown in the code below, first a new network is created and then the selected table is checked to see if it is associated to a Cytoscape network. After that, if needed, a Cyni Table can be created to help better working with Cytoscape Table Data.
Finally, the new created network needs to be displayed and a layout is applied to the network. Several functions have been developed to help to perform all these tasks.

   1 //Create new network
   2 CyNetwork newNetwork = netFactory.createNetwork();
   3                 
   4                 
   5 //Check if a network is associated to the selected table
   6 networkSelected = getNetworkAssociatedToTable(mytable);
   7                 
   8 // Create the CyniTable
   9 CyniTable data = new CyniTable(mytable,attributeArray.toArray(new String[0]), false, false, selectedOnly);
  10                 
  11                 
  12 //Set the name of the network, another name could be chosen
  13 networkName = "Induction " + newNetwork.getSUID();
  14 if (newNetwork != null && networkName != null) {
  15     CyRow netRow = newNetwork.getRow(newNetwork);
  16     netRow.set(CyNetwork.NAME, networkName);
  17 }
  18                 
  19                 
  20 /*****************************************************/
  21 //
  22 // Add the different nodes and edges according to the table data
  23 //
  24 //
  25 /*****************************************************/
  26                 
  27 //Display the new network
  28 if (!cancelled)
  29 {
  30     newNetworkView = displayNewNetwork(newNetwork, false);
  31     taskMonitor.setProgress(1.0d);
  32     layout = layoutManager.getDefaultLayout();
  33     Object context = layout.getDefaultLayoutContext();
  34     insertTasksAfterCurrentTask(layout.createTaskIterator(newNetworkView, context,     CyLayoutAlgorithm.ALL_NODE_VIEWS,"");
  35 }

Finally, there are two actions that will be performed very often when working with tables and networks and it is important to know how to do it.

How to get data associated to a node or edge

There are two possibilities to perform this action.

1. First, get the table and then use getRow method.

   1 CyTable table = network.getTable(CyNode.class,CyNetwork.DEFAULT_ATTRS);
   2 CyRow nodeRow = table.getRow(node.getSUID());

2. You can also go straight into getting the row without having to get the table by using the getRow method in the CyNetwork class.

   1 CyRow nodeRow = cyNetwork.getRow(node,CyNetwork.DEFAULT_ATTRS);

How to get a node or an edge associated to a row in a table data

You need to get the SUID value for that row and then use it as input paramter in the getNode method.

   1 CyNode node = network.getNode(row.get(CyIdentifiable.SUID, Long.class));