Differences between revisions 67 and 82 (spanning 15 versions)
Revision 67 as of 2012-06-26 22:55:43
Size: 37219
Editor: server2
Comment:
Revision 82 as of 2013-04-29 20:16:46
Size: 36583
Editor: server2
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Do you want to share your own code snippet? =

Let us know! Send a message to [[https://groups.google.com/forum/?fromgroups#!forum/cytoscape-discuss|Cytoscape Discuss]] to have your snippet included in this cookbook.
Line 2: Line 6:
= About the cookbook =


To help app developers to develop their own app, the Cytoscape developer team developed the cookbook, a collection of small apps. The cookbook could be used to

 1. get your feet wet
 1. find a template project to extend
 1. find out how to do something in Cytoscape.

= How to use the cookbook? =
SVN repository: {{{http://chianti.ucsd.edu/svn/core3/samples/trunk/}}}

Steps:

 1. Check out sample project from SVN repository with the above URL
 1. Compile with {{{mvn clean install}}}
 1. Copy the jar in the project target directory to Cytoscape installation: deploy directory
 1. Start Cytoscape 3.0


= The list of app examples in the cookbook =

The list of sample apps is basically the same as in [[http://cytoscape.wodaklab.org/wiki/plugin_developer_tutorial|the cookbook for Cytoscape 2.X]]. They are mostly Cytoscape Bundle apps, but also include a few Simple apps. Some of them are,

== Introduction ==
This tutorial will show some code snippets about how to use Cytoscape APIs on app development. Each feature is included in a sample app, which can serve as a starting point or template for new app developers. The code snippets can also be used as reference for experienced developers.

Cytoscape app is usually packaged in a jar file and deployed to the deploy directory of Cytoscape. When Cytoscape starts up and initializes, its app manager will look up all the apps in deploy directory.

There are two types of Cytoscape App, Bundle app and Simplified App. In this cook book, we provide sample for both types.

If app developer will share and publish their Apps, they are encouraged to submit their Apps to Cytoscape app store website at http://apps.cytoscape.org/ .

= Swing Application =
Line 36: Line 10:
Here's how to add a tabbed panel to the control panel.
'''Step 1'''
Line 51: Line 26:
'''Step 2'''
Line 59: Line 35:

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].
Line 64: Line 38:
'''Step 1'''
Line 85: Line 59:
'''Step 2'''
Line 94: Line 69:
The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].
Line 98: Line 71:
'''Step 1'''
Line 113: Line 87:
'''Step 2'''
Line 122: Line 97:
The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].


= Model =
Line 126: Line 102:
To create a network, get a reference to the `CyNetworkFactory` service, and tell it to create a network. With the new network, nodes and edges can be created through the CyNetwork interface. To create a network, get a reference to the `CyNetworkFactory` service, and tell it to create a network. With the new network, nodes and edges can be created through the    `CyNetwork` interface.
Line 130: Line 106:
  CyNetworkFactory cyNetworkFactoryServiceRef = getService(bc,CyNetworkFactory.class);
  CyNetworkFactory networkFactory = getService(bc, CyNetworkFactory.class);
Line 134: Line 109:
  // To create a new network
  CyNetwork myNet = cnf.createNetwork();
  // Create a new network
  CyNetwork myNet = networkFactory.createNetwork();
     // Set name for network
  myNet.getRow(net).set(CyNetwork.NAME, "My network");
Line 143: Line 120:
  // set name for new nodes
  myNet.getDefaultNodeTable().getRow(node1.getSUID()).set("name", "Node1");
  myNet.getDefaultNodeTable().getRow(node2.getSUID()).set("name", "Node2");
  // Set name for new nodes
  myNet.getRow(node1).set(CyNetwork.NAME, "Node1");
  myNet.getRow(node2).set(CyNetwork.NAME, "Node2");
Line 150: Line 127:
  // Add the network to Cytoscape
  CyNetworkManager networkManager = getService(bc, CyNetworkManager.class);
  networkManager.addNetwork(myNet);
Line 168: Line 148:
The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to create, modify, and destroy a network view? ==
To create a network, get a reference to the `CyNetworkViewFactory` service, and tell it to create a network view.

First, in the `start` method of your `CyActivator` class:
{{{
#!java
  // Get a CyNetworkViewFactory
  CyNetworkViewFactory cyNetworkViewFactoryServiceRef = getService(bc,CyNetworkViewFactory.class);
}}}

Now you can use `CyNetworkViewFactory` in your code:
{{{
#!java
  // Create a new network view
  CyNetworkView myView = cnvf.createNetworkView(myNet);
}}}

Destroying networks is done through the `CyNetworkViewManager` service.

First, in the `start` method of your `CyActivator` class:
{{{
#!java
  // get a CyNetworkViewManager
  CyNetworkViewManager cyNetworkViewManagerServiceRef = getService(bc,CyNetworkViewManager.class);
}}}

Now you can use `CyNetworkViewManager` in your code:
{{{
#!java
  // destroy a network view through NetworkViewManager
  networkViewManager.destroyNetworkView(myView);
}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].
Line 213: Line 156:
== How to handle events from a network (and discuss each event type)? ==
To handle Cytoscape events, implement the listener interface and register it.
{{{
#!java
  // Define a class, which implements a listener interface
  public class MyListenerClass implements NetworkAddedListener {
    ....
    public void handleEvent(NetworkAddedEvent e){
        // do something here
    }
  }
}}}

In the `start` method of your `CyActivator` class:
{{{
#!java
  // Register the listener in the CyActivator class
  registerService(bc,myListenerClass, NetworkAddedListener.class, new Properties());
}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to change the background color of a view? ==
Network background color is changed as a _visual property_.
{{{
#!java
  // Set the background of current view to RED
  view.setVisualProperty(BasicVisualLexicon.NETWORK_BACKGROUND_PAINT, Color.red);
  view.updateView();
}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to zoom a network view? ==


{{{
#!java
// Get the scale and adjust
double newScale = view.getVisualProperty(NETWORK_SCALE_FACTOR).doubleValue() * scale;
view.setVisualProperty(NETWORK_SCALE_FACTOR, newScale);
...
view.updateView();
}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].
== How to set the name of a network? ==

{{{
#!java
  CyNetwork net = ...;
  String name = ...;
  net.getRow(net).set(CyNetwork.NAME, name);
}}}

== How to get the name of a network? ==

{{{
#!java
  CyNetwork net = ...;
  String name = net.getRow(net).get(CyNetwork.NAME, String.class);
}}}

== How to set the name of a node? ==

{{{
#!java
  CyNode node = ...;
  String myNodeName = ...;
  net.getRow(node).set(CyNetwork.NAME, myNodeName);
}}}

== How to get the name of a node? ==

{{{
#!java
  CyNode node = ...;
  String myNodeName = net.getRow(node).get(CyNetwork.NAME, String.class);
}}}
Line 262: Line 192:
There are two step to load attribute to a table. (1) Create a global table and populate it. (2) Map the global table to specific table based on a key attribute, i.e. create virtual column for the table.
Line 275: Line 204:
 String attributeNmae = "MyAttributeName";
 table.createColumn(attributeNmae, Integer.class, false);
 String attributeName = "MyAttributeName";
 table.createColumn(attributeName, Integer.class, false);
Line 281: Line 210:
 row.set(attributeNmae, new Integer(2));  row.set(attributeName, new Integer(2));
Line 284: Line 213:
 row.set(attributeNmae, new Integer(3));  row.set(attributeName, new Integer(3));
Line 287: Line 216:
 row.set(attributeNmae, new Integer(4));  row.set(attributeName, new Integer(4));
Line 297: Line 226:




}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].
}}}
Line 307: Line 229:
1. get the CyTable through the network '''Step 1''': get the CyTable through the network
Line 314: Line 236:
2. Find the column and delete it '''Step 2''': Find the column and delete it
Line 322: Line 244:
The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]]. == How to get all the nodes with a specific attribute value? ==

Copy this method in your code:

{{{
#!java
    /**
     * Get all the nodes with a given attribute value.
     *
     * This method is effectively a wrapper around {@link CyTable#getMatchingRows}.
     * It converts the table's primary keys (assuming they are node SUIDs) back to
     * nodes in the network.
     *
     * Here is an example of using this method to find all nodes with a given name:
     *
     * {@code
     * CyNetwork net = ...;
     * String nodeNameToSearchFor = ...;
     * Set<CyNode> nodes = getNodesWithValue(net, net.getDefaultNodeTable(), "name", nodeNameToSearchFor);
     * // nodes now contains all CyNodes with the name specified by nodeNameToSearchFor
     * }
     * @param net The network that contains the nodes you are looking for.
     * @param table The node table that has the attribute value you are looking for;
     * the primary keys of this table <i>must</i> be SUIDs of nodes in {@code net}.
     * @param colname The name of the column with the attribute value
     * @param value The attribute value
     * @return A set of {@code CyNode}s with a matching value, or an empty set if no nodes match.
     */
    private static Set<CyNode> getNodesWithValue(
            final CyNetwork net, final CyTable table,
            final String colname, final Object value)
    {
        final Collection<CyRow> matchingRows = table.getMatchingRows(colname, value);
        final Set<CyNode> nodes = new HashSet<CyNode>();
        final String primaryKeyColname = table.getPrimaryKey().getName();
        for (final CyRow row : matchingRows)
        {
            final Long nodeId = row.get(primaryKeyColname, Long.class);
            if (nodeId == null)
                continue;
            final CyNode node = net.getNode(nodeId);
            if (node == null)
                continue;
            nodes.add(node);
        }
        return nodes;
    }
}}}

== How to use model objects (CyNetwork, CyNode, etc.) when writing tests? ==

'''Step 1'''. Include the JUnit framework as a dependency in your {{{pom.xml}}}:
{{{#!xml
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
}}}

''Step 2''. Include the {{{model-impl}}} package as a dependency in your {{{pom.xml}}}:
{{{#!xml
<dependency>
    <groupId>org.cytoscape</groupId>
    <artifactId>model-impl</artifactId>
    <version>${cytoscape.api.version}</version>
    <scope>test</scope>
</dependency>
}}}

''Step 3''. In your testing code, use {{{NetworkTestSupport}}} to get a {{{CyNetwork}}} instance:

{{{#!java
import org.cytoscape.model.NetworkTestSupport;

...

final NetworkTestSupport nts = new NetworkTestSupport();
final CyNetwork network = nts.getNetwork();

// Now you have a CyNetwork!
}}}

= View Model =

== Getting node views for newly created nodes? ==

After creating a node and edge, this is how to get its view:

{{{
#!java
  CyNetworkView networkView = ...;
  CyNetwork network = networkView.getModel();
  CyEventHelper eventHelper = ...;
  CyNode newNode = network.addNode();
  network.getRow(newNode).set(CyNetwork.NAME, "New Node");
  eventHelper.flushPayloadEvents();
  View<CyNode> newNodeView = networkView.getNodeView(newNode);
}}}

After creating the node in {{{CyNetwork}}}, you have to call {{{CyEventHelper}}}'s
{{{flushPayloadEvents}}} so that the new node gets a node view. If {{{flushPayloadEvents}}}
is not called, {{{getNodeView}}} may return null.

If you are creating a bunch of nodes at once, call {{{flushPayloadEvents}}} after you have finished creating all the nodes, ''not'' after each node is created. Example:

{{{
#!java
  CyNetworkView networkView = ...;
  CyNetwork network = networkView.getModel();
  CyEventHelper eventHelper = ...;
  
  for (int i = 1; i <= 100; i++) {
    CyNode node = network.addNode();
    network.getRow(newNode).set(CyNetwork.NAME, "Node " + i);
  }
  eventHelper.flushPayloadEvents();
}}}

== How to create, modify, and destroy a network view? ==
To create a network, get a reference to the `CyNetworkViewFactory` service, and tell it to create a network view.

First, in the `start` method of your `CyActivator` class:
{{{
#!java
  // Get a CyNetworkViewFactory
  CyNetworkViewFactory networkViewFactory = getService(bc, CyNetworkViewFactory.class);
}}}

Now you can use `CyNetworkViewFactory` in your code:
{{{
#!java
  // Create a new network view
  CyNetworkView myView = networkViewFactory.createNetworkView(myNet);

  // Add view to Cytoscape
  CyNetworkViewManager networkViewManager = getService(bc, CyNetworkViewManager.class);
  networkViewManager.addNetworkView(myView);
}}}

Destroying network views is done through the `CyNetworkViewManager` service.

First, in the `start` method of your `CyActivator` class:
{{{
#!java
  // get a CyNetworkViewManager
  CyNetworkViewManager networkViewManager = getService(bc, CyNetworkViewManager.class);
}}}

Now you can use `CyNetworkViewManager` in your code:
{{{
#!java
  // destroy a network view through NetworkViewManager
  networkViewManager.destroyNetworkView(myView);
}}}

== How to change the background color of a view? ==

Network background color is changed as a _visual property_.
{{{
#!java
  // Set the background of current view to RED
  view.setVisualProperty(BasicVisualLexicon.NETWORK_BACKGROUND_PAINT, Color.red);
  view.updateView();
}}}


== How to zoom a network view? ==


{{{
#!java
// Get the scale and adjust
double newScale = view.getVisualProperty(NETWORK_SCALE_FACTOR).doubleValue() * scale;
view.setVisualProperty(NETWORK_SCALE_FACTOR, newScale);
...
view.updateView();
}}}

== How to get and set node coordinate positions? ==

Given a {{{View<CyNode>}}}, here's how to get its x and y coordinate positions:
{{{
#!java
View<CyNode> nodeView = ...;
Double x = nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION);
Double y = nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION);}}}

Here's how to set the x and y coordinate positions:
{{{
#!java
View<CyNode> nodeView = ...;
double x = ...;
double y = ...;
nodeView.setVisualProperty(BasicVisualLexicon.NODE_X_LOCATION, x);
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION, y);}}}

== How to write a layout algorithm? ==

First define a layout class, which implements CyLayoutAlgorithm interface or extends AbstractLayoutAlgorithm class. Then register the layout class as a service.

{{{
#!java
  // Define a layout class
  public class MyLayout extends AbstractLayoutAlgorithm {
    ...
  }


  // Define a layout task class
  public class MyLayoutTask extends AbstractLayoutTask {
    ...

    //Perform actual layout task
    final protected void doLayout(final TaskMonitor taskMonitor) {
      ...
    }
    ...
  }


  // Register the layout class as a service in CyActivator class
  Properties myLayoutProps = new Properties();
  myLayoutProps.setProperty("preferredMenu","My Layouts");
  registerService(bc,myLayout,CyLayoutAlgorithm.class, myLayoutProps);

}}}




== How to add components to the node view, edge view, and attribute browser context menus? ==
To add a context menu to a NodeView, define a class, which extends AbstractNodeViewTaskFactory, and register the NodeViewTaskFactory as service. We can add the title of menu item by setting the service property when we register the nodeViewTaskFactory.

To add context menu to the table browser, define a class, which extends AbstractTableCellTaskFactory. Create an instance and register it as service (Note register as TableCellTaskFactory).
 
{{{
#!java
  // Define a class MyNodeViewTaskFactory
  public class MyNodeViewTaskFactory extends AbstractNodeViewTaskFactory {
    ...
  }


  // Register myNodeViewTaskFactory as a service in CyActivator
  Properties myNodeViewTaskFactoryProps = new Properties();
  myNodeViewTaskFactoryProps.setProperty("title","My context menu title");
  registerService(bc,myNodeViewTaskFactory,NodeViewTaskFactory.class, myNodeViewTaskFactoryProps);

}}}

= VizMapper =

== How to use the VizMapper programmatically? ==

Cytosape provides services for using visual mapping programming. There services are VisualMappingManager, VisualStyleFactory and VisualMappingFunctionFactory. App should get references to these services in CyActivator class, the entry point of the app. We can create new visualStyle with VisualStyleFactory and create mapping function with VisualMappingFunctionFactory very easily. After a new visual style is created, it should register with the VisualMappingManger, in this way the new visual style will be available throughout Cytoscape.

{{{
#!java
  // To get references to services in CyActivator class
  VisualMappingManager vmmServiceRef = getService(bc,VisualMappingManager.class);
  
  VisualStyleFactory visualStyleFactoryServiceRef = getService(bc,VisualStyleFactory.class);
  
  VisualMappingFunctionFactory vmfFactoryC = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=continuous)");
  VisualMappingFunctionFactory vmfFactoryD = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=discrete)");
  VisualMappingFunctionFactory vmfFactoryP = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=passthrough)");


  // To create a new VisualStyle object and set the mapping function
  VisualStyle vs= this.visualStyleFactoryServiceRef.createVisualStyle("My visual style");


  //Use pass-through mapping
  String ctrAttrName1 = "SUID";
  PassthroughMapping pMapping = (PassthroughMapping) vmfFactoryP.createVisualMappingFunction(ctrAttrName1, String.class, attrForTest, BasicVisualLexicon.NODE_LABEL);

  vs.addVisualMappingFunction(pMapping);


  // Add the new style to the VisualMappingManager
  vmmServiceRef.addVisualStyle(vs);


  // Apply the visual style to a NetwokView
  vs.apply(myNetworkView);
  myNetworkView.updateView();
}}}

== How to apply a continuous color gradient to nodes according to their degree? ==
{{{
#!java
  
  // Set node color map to attribute "Degree"
  ContinuousMapping mapping = (ContinuousMapping)
  this.continuousMappingFactoryServiceRef.createVisualMappingFunction("Degree", Integer.class, BasicVisualLexicon.NODE_FILL_COLOR);

  // Define the points
  Double val1 = 2d;
  BoundaryRangeValues<Paint> brv1 = new BoundaryRangeValues<Paint>(Color.RED, Color.GREEN, Color.PINK);

  Double val2 = 12d;
  BoundaryRangeValues<Paint> brv2 = new BoundaryRangeValues<Paint>(Color.WHITE, Color.YELLOW, Color.BLACK);
  
  // Set the points
  mapping.addPoint(val1, brv1);
  mapping.addPoint(val2, brv2);

  // add the mapping to visual style
  vs.addVisualMappingFunction(mapping);

}}}

== How to load a visual properties file? ==
Cytoscape provide a service 'LoadVizmapFileTaskFactory' for loading visual styles definded in a property file.

{{{
#!java
  // get a reference to Cytoscape service -- LoadVizmapFileTaskFactory
  LoadVizmapFileTaskFactory loadVizmapFileTaskFactory = getService(bc,LoadVizmapFileTaskFactory.class);
}}}

{{{
#!java
  // Use the service to load visual style, 'f' is the File object to hold the visual properties
  Set<VisualStyle> vsSet = loadVizmapFileTaskFactory.loadStyles(f);
}}}

= I/O =

== How to build a network reader to support my own format? ==

First, we should define the format of my network file and its file extension. Let's say, each line in our network file has two columns, tab-delimited. And we define file extension '.tc', stands for 'two columns'.

{{{
#!java
  //1. define a file filter (BasicCyFileFilter), to support the reader to read the file with extension '.tc'
  HashSet<String> extensions = new HashSet<String>();
  extensions.add("tc");
  HashSet<String> contentTypes = new HashSet<String>();
  contentTypes.add("txt");
  String description = "My test filter";
  DataCategory category = DataCategory.NETWORK;
  BasicCyFileFilter filter = new BasicCyFileFilter(extensions,contentTypes, description, category, swingAdapter.getStreamUtil());


  //2. Create an instance of the ReaderFactory
  // Note that extends TCReaderFactory must implement the interface InputStreamTaskFactory or extends the class AbstractInputStreamTaskFactory.
  // And the defined task must implement CyNetworkReader
  TCReaderFactory factory = new TCReaderFactory(filter, swingAdapter.getCyNetworkFactory(), swingAdapter.getCyNetworkViewFactory());

  

  //3. register the ReaderFactory as an InputStreamTaskFactory.
  Properties props = new Properties();
  props.setProperty("readerDescription","TC file reader");
  props.setProperty("readerId","tcNetworkReader");
  swingAdapter.getCyServiceRegistrar().registerService(factory, InputStreamTaskFactory.class, props);
}}}

Compile [http://chianti.ucsd.edu/svn/core3/samples/trunk/sample27a|this sample code], and install the app in Cytoscape. When we try to import a network from a file (File-->Import-->Network-->File..), we will find file type '.tc' is listed as one of the file types supported by Cytoscape.

= Work =

== How to use the Cytoscape task monitor to show the progress of my job? ==

Get a Cytoscape service DialogTaskManager and execute the task through the taskManager.

{{{
#!java
  // Get a Cytoscape service 'DialogTaskManager' in CyActivator class
  DialogTaskManager dialogTaskManager = getService(bc, DialogTaskManager.class);


  // Define a task and set the progress in the run() method
  public class MyTask extends AbstractTask {
    ...
    public void run(final TaskMonitor taskMonitor) {
        // Give the task a title.
 taskMonitor.setTitle("My task");
        ...
 taskMonitor.setProgress(0.1);

        // do something here

        ...
 taskMonitor.setProgress(1.0);
  }


  // Execute the task through the TaskManager
  DialogTaskManager.execute(myTaskFactory);

}}}

== How to issue non-blocking, informational messages to users? ==

Cytoscape 3.0 has a status bar at the bottom of the Cytoscape desktop window. Tasks can put messages into the status bar. These messages wouldn't require immediate user attention but are informational. Debug messages useful for developers do not belong in the status bar.

To issue user messages to the status bar:

'''Step 1'''. Include the SLF4J library as a dependency in your {{{pom.xml}}} file.

{{{
#!xml
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.6.6</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
</dependency>
}}}

'''Step 2'''. Obtain an instance of the {{{CyUserMessages}}} log.

{{{
#!java
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
...
Logger userMessagesLogger = LoggerFactory.getLogger("CyUserMessages");
}}}

'''Step 3'''. Issue log messages to the {{{CyUserMessages}}} log.

{{{
#!java
int lineError = 12;
userMessagesLogger.warn("Parse error on line {}", lineError);
}}}

The message will appear in the status bar.

= Session =

== How to save/restore app states? ==
There are two events, which are important for saving/restoring App state. The two evetns are SessionAboutToBeSavedEvent and SessionLoadedEvent. App should implement the two listeners and register them.

{{{
#!java

  // Implements the session event listeners
  public class MyClass implements SessionAboutToBeSavedListener, SessionLoadedListener {

      // Save app state in a file
      public void handleEvent(SessionAboutToBeSavedEvent e){
          // save app state file "myAppStateFile"
          ...
      }

      // restore app state from a file
      public void handleEvent(SessionLoadedEvent e){

        if (e.getLoadedSession().getAppFileListMap() == null || e.getLoadedSession().getAppFileListMap().size() ==0){
            return;
        }
 List<File> files = e.getLoadedSession().getAppFileListMap().get("myAppStateFile");
        ...
       }
  }
 

  // Register the two listeners in the CyActivator class
  registerService(bc,myClass,SessionAboutToBeSavedListener.class, new Properties());
  registerService(bc,myClass,SessionLoadedListener.class, new Properties());

}}}

== How to add CyProperty to save values across sessions? ==

CyProperty acts as a container to save properties of the type (key, value) across sessions. They are available for the user to manually change in the preference menu option.

{{{
#!java
 //1. Adding a property which saves the node border width selected by the user.
 public static String NodeBorderWidthInPaths = "NODE_BORDER_WIDTH_IN_PATHS";
 public static Double NodeBorderWidthInPathsValue = 20.0;
 public static Properties nodeBorderWidthProps = new Properties();

 //2. Find if the CyProperty already exists, if not create one with default value.
 CyProperty<Properties> nodeBorderWidthProperty = null;
 CySessionManager mySessionManager;
 mySessionManager = adapter.getCySessionManager();
 CySession session;
 session = mySessionManager.getCurrentSession();
 if(session.equals(null))
  System.out.println("session null");
  
 //3. Get all properties and loop through to find your own.
 Set<CyProperty<?>> props = new HashSet<CyProperty<?>>();
 props = session.getProperties();
 if(props.equals(null))
  System.out.println("props null");
 boolean flag = false;
 
 for (CyProperty<?> prop : props) {
     if (prop.getName() != null){
      if (prop.getName().equals(NodeBorderWidthInPaths)) {
         nodeBorderWidthProperty = (CyProperty<Properties>) prop;
         flag = true;
         break;
      }
     }
 }
 
 //4. If the property does not exists, create nodeBorderWidthProperty
 if (!flag)
 {
  nodeBorderWidthProps.setProperty(NodeBorderWidthInPaths, NodeBorderWidthInPathsValue.toString());
  nodeBorderWidthProperty = new
    SimpleCyProperty(NodeBorderWidthInPaths,
      nodeBorderWidthProps, Float.TYPE, CyProperty.SavePolicy.SESSION_FILE_AND_CONFIG_DIR );
 }
 //5. If not null, property exists, get value from it and set NodeBorderWidthInPathsValue
 else
 {
  nodeBorderWidthProps = nodeBorderWidthProperty.getProperties();
  NodeBorderWidthInPathsValue = Double.valueOf((String)nodeBorderWidthProps.get(NodeBorderWidthInPaths));
 }
}}}

= Events =

== How to handle events from a network ==
'''Step 1'''
{{{
#!java
  // Define a class, which implements a listener interface
  public class MyListenerClass implements NetworkAddedListener {
    ....
    public void handleEvent(NetworkAddedEvent e){
        // do something here
    }
  }
}}}

'''Step 2'''
{{{
#!java
  // In the `start` method of your `CyActivator` class,
  // register the listener in the CyActivator class
  registerService(bc,myListenerClass, NetworkAddedListener.class, new Properties());
}}}


= Equations =

== How to add new attribute functions via a Cytoscape App? ==
Here we will go through all the steps necessary to create a new built-in function IXOR(). The complete example code and can be downloaded from here.
The easiest part is writing the actual plug-in class, which look similar to this:
{{{
#!java
  import org.cytoscape.equations.EquationCompiler;
  import org.cytoscape.equations.Interpreter;
  import org.cytoscape.equations.EquationParser;

  public class Sample23 {

 public Sample23(EquationCompiler eqCompilerRef, Interpreter interpreterRef){
  final EquationParser theParser = eqCompilerRef.getParser();
  theParser.registerFunction(new IXor());
 }
  }
}}}

Here we register a new built-in function called IXor. You can also register multiple built-in functions if you prefer.

The next part is creating one class each for every new built-in. Each such class has to implement the org.cytoscape.equations.Function interface usually via org.cytoscape.equations.AbstractFunction. The easiest way to get started is to peruse the existing built-ins in equations Cytoscape core library and look for a function with a similar or identical argument list. If you can't find one it may still be instructive to read through the implementation of a couple of existing functions.

First you have to create the constructor where you describe the arguments that your function will take:

{{{
#!java
public IXor() {
        super(new ArgDescriptor[] {
                        new ArgDescriptor(ArgType.INT, "arg1", "A quantity that can be converted to an integer."),
                        new ArgDescriptor(ArgType.INT, "arg2", "A quantity that can be converted to an integer."),
                });
}}}


The most trivial to implement methods are getName(), and getFunctionSummary().
{{{
#!java
/**
 * Used to parse the function string. This name is treated in a case-insensitive manner!
 * @return the name by which you must call the function when used in an attribute equation.
 */
public String getName() { return "IXOR"; }

/**
  * Used to provide help for users.
  * @return a description of what this function does
  */
public String getFunctionSummary() { return "Returns an integer value that is the exclusive-or of 2 other integer values."; }
}}}

The next method is still simple but already touches on the one area that is somewhat complicated in attribute functions: data types and data type conversions!

{{{
#!java
public Class getReturnType() { return Long.class; }
}}}

Our example function is supposed to return an integer value. Integers in equation functions are represented as instances of class java.lang.Long. Therefore it is imperative not to return Integer.class! The user of the function can be blissfully unaware of this distinction. Just remember to always substitute Long for Integer and you should be fine.

The next method evaluateFunction() is the one that gets called when an expression is being evaluated. No argument type-checking is needed here because the compiler already took care of that for us. But, we need to handle all possible valid argument types and counts. (N.B., functions may be overloaded and/or variadic.) In this example the arguments can be any combination of Long and Double.

{{{
#!java
public Object evaluateFunction(final Object[] args) {
        long arg1;
        try {
                arg1 = FunctionUtil.getArgAsLong(args[0]);
        } catch (final Exception e) {
                throw new IllegalArgumentException("IXOR: can't convert the 1st argument to an integer!");
        }

        long arg2;
        try {
                arg2 = FunctionUtil.getArgAsLong(args[0]);
        } catch (final Exception e) {
                throw new IllegalArgumentException("IXOR: can't convert the 2nd argument to an integer!");
        }

        final long result = arg1 ^ arg2;
        return (Long)result;
}
}}}

[[http://wiki.cytoscape.org/Implementing_Attribute_Equations_Functions|This tutorial]] on how to write attribute functions may also be helpful.


= Web Services =
Line 363: Line 921:
 
Line 366: Line 923:
Step 1. Define a UI class for the setting of the client. This UI may listen to Cytoscape events '''Step 1''': Define a UI class for the setting of the client. This UI may listen to Cytoscape events
Line 376: Line 933:
Step 2. Define a client class, which must implement WebServiceClient and pass the UI class defined at previous step to the client. If UI is not defined, the default UI will be used. '''Step 2''': Define a client class, which must implement WebServiceClient and pass the UI class defined at previous step to the client. If UI is not defined, the default UI will be used.
Line 384: Line 941:
Step 3. After the client is registered as service, the client can be find under File-->Import->Table-->Public databases...


== How to use the VizMapper programmatically? ==

Cytosape provides services for using visual mapping programming. There services are VisualMappingManager, VisualStyleFactory and VisualMappingFunctionFactory. App should get references to these services in CyActivator class, the entry point of the app. We can create new visualStyle with VisualStyleFactory and create mapping function with VisualMappingFunctionFactory very easily. After a new visual style is created, it should register with the VisualMappingManger, in this way the new visual style will be available throughout Cytoscape.

{{{
#!java
  // To get references to services in CyActivator class
  VisualMappingManager vmmServiceRef = getService(bc,VisualMappingManager.class);
  
  VisualStyleFactory visualStyleFactoryServiceRef = getService(bc,VisualStyleFactory.class);
  
  VisualMappingFunctionFactory vmfFactoryC = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=continuous)");
  VisualMappingFunctionFactory vmfFactoryD = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=discrete)");
  VisualMappingFunctionFactory vmfFactoryP = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=passthrough)");


  // To create a new VisualStyle object and set the mapping function
  VisualStyle vs= this.visualStyleFactoryServiceRef.createVisualStyle("My visual style");


  //Use pass-through mapping
  String ctrAttrName1 = "SUID";
  PassthroughMapping pMapping = (PassthroughMapping) vmfFactoryP.createVisualMappingFunction(ctrAttrName1, String.class, attrForTest, BasicVisualLexicon.NODE_LABEL);

  vs.addVisualMappingFunction(pMapping);


  // Add the new style to the VisualMappingManager
  vmmServiceRef.addVisualStyle(vs);


  // Apply the visual style to a NetwokView
  vs.apply(myNetworkView);
  myNetworkView.updateView();
}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to apply a continuous color gradient to nodes according to their degree? ==
{{{
#!java
  
  // Set node color map to attribute "Degree"
  ContinuousMapping mapping = (ContinuousMapping)
  this.continuousMappingFactoryServiceRef.createVisualMappingFunction("Degree", Integer.class, BasicVisualLexicon.NODE_FILL_COLOR);

  // Define the points
  Double val1 = 2d;
  BoundaryRangeValues<Paint> brv1 = new BoundaryRangeValues<Paint>(Color.RED, Color.GREEN, Color.PINK);

  Double val2 = 12d;
  BoundaryRangeValues<Paint> brv2 = new BoundaryRangeValues<Paint>(Color.WHITE, Color.YELLOW, Color.BLACK);
  
  // Set the points
  mapping.addPoint(val1, brv1);
  mapping.addPoint(val2, brv2);

  // add the mapping to visual style
  vs.addVisualMappingFunction(mapping);

}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to load a visual properties file? ==
Cytoscape provide a service 'LoadVizmapFileTaskFactory' for loading visual styles definded in a property file.

{{{
#!java
  // get a reference to Cytoscape service -- LoadVizmapFileTaskFactory
  LoadVizmapFileTaskFactory loadVizmapFileTaskFactory = getService(bc,LoadVizmapFileTaskFactory.class);
}}}

{{{
#!java
  // Use the service to load visual style, 'f' is the File object to hold the visual properties
  Set<VisualStyle> vsSet = loadVizmapFileTaskFactory.loadStyles(f);
}}}

== How to write a layout algorithm? ==

First define a layout class, which implements CyLayoutAlgorithm interface or extends AbstractLayoutAlgorithm class. Then register the layout class as a service.

{{{
#!java
  // Define a layout class
  public class MyLayout extends AbstractLayoutAlgorithm {
    ...
  }


  // Define a layout task class
  public class MyLayoutTask extends AbstractLayoutTask {
    ...

    //Perform actual layout task
    final protected void doLayout(final TaskMonitor taskMonitor) {
      ...
    }
    ...
  }


  // Register the layout class as a service in CyActivator class
  Properties myLayoutProps = new Properties();
  myLayoutProps.setProperty("preferredMenu","My Layouts");
  registerService(bc,myLayout,CyLayoutAlgorithm.class, myLayoutProps);

}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to write a Group Viewer? ==
{{{
#!java

}}}


== How to add components to the node view, edge view, and attribute browser context menus? ==
To add a context menu to a NodeView, define a class, which extends AbstractNodeViewTaskFactory, and register the NodeViewTaskFactory as service. We can add the title of menu item by setting the service property when we register the nodeViewTaskFactory.

To add context menu to the table browser, define a class, which extends AbstractTableCellTaskFactory. Create an instance and register it as service (Note register as TableCellTaskFactory).
 
{{{
#!java
  // Define a class MyNodeViewTaskFactory
  public class MyNodeViewTaskFactory extends AbstractNodeViewTaskFactory {
    ...
  }


  // Register myNodeViewTaskFactory as a service in CyActivator
  Properties myNodeViewTaskFactoryProps = new Properties();
  myNodeViewTaskFactoryProps.setProperty("title","My context menu title");
  registerService(bc,myNodeViewTaskFactory,NodeViewTaskFactory.class, myNodeViewTaskFactoryProps);

}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to save/restore app states? ==
There are two events, which are important for saving/restoring App state. The two evetns are SessionAboutToBeSavedEvent and SessionLoadedEvent. App should implement the two listeners and register them.

{{{
#!java

  // Implements the session event listeners
  public class MyClass implements SessionAboutToBeSavedListener, SessionLoadedListener {

      // Save app state in a file
      public void handleEvent(SessionAboutToBeSavedEvent e){
          // save app state file "myAppStateFile"
          ...
      }

      // restore app state from a file
      public void handleEvent(SessionLoadedEvent e){

        if (e.getLoadedSession().getAppFileListMap() == null || e.getLoadedSession().getAppFileListMap().size() ==0){
            return;
        }
 List<File> files = e.getLoadedSession().getAppFileListMap().get("myAppStateFile");
        ...
       }
  }
 

  // Register the two listeners in the CyActivator class
  registerService(bc,myClass,SessionAboutToBeSavedListener.class, new Properties());
  registerService(bc,myClass,SessionLoadedListener.class, new Properties());

}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to use the Cytoscape task monitor to show the progress of my job? ==

Get a Cytoscape service DialogTaskManager and execute the task through the taskManager.

{{{
#!java
  // Get a Cytoscape service 'DialogTaskManager' in CyActivator class
  DialogTaskManager dialogTaskManager = getService(bc, DialogTaskManager.class);


  // Define a task and set the progress in the run() method
  public class MyTask extends AbstractTask {
    ...
    public void run(final TaskMonitor taskMonitor) {
        // Give the task a title.
 taskMonitor.setTitle("My task");
        ...
 taskMonitor.setProgress(0.1);

        // do something here

        ...
 taskMonitor.setProgress(1.0);
  }


  // Execute the task through the TaskManager
  DialogTaskManager.execute(myTaskFactory);

}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].


== How to add new attribute functions via a Cytoscape App? ==
Here we will go through all the steps necessary to create a new built-in function IXOR(). The complete example code and can be downloaded from here.
The easiest part is writing the actual plug-in class, which look similar to this:
{{{
#!java
  import org.cytoscape.equations.EquationCompiler;
  import org.cytoscape.equations.Interpreter;
  import org.cytoscape.equations.EquationParser;

  public class Sample23 {

 public Sample23(EquationCompiler eqCompilerRef, Interpreter interpreterRef){
  final EquationParser theParser = eqCompilerRef.getParser();
  theParser.registerFunction(new IXor());
 }
  }
}}}

Here we register a new built-in function called IXor. You can also register multiple built-in functions if you prefer.

The next part is creating one class each for every new built-in. Each such class has to implement the org.cytoscape.equations.Function interface usually via org.cytoscape.equations.AbstractFunction. The easiest way to get started is to peruse the existing built-ins in equations Cytoscape core library and look for a function with a similar or identical argument list. If you can't find one it may still be instructive to read through the implementation of a couple of existing functions.

First you have to create the constructor where you describe the arguments that your function will take:

{{{
#!java
public IXor() {
        super(new ArgDescriptor[] {
                        new ArgDescriptor(ArgType.INT, "arg1", "A quantity that can be converted to an integer."),
                        new ArgDescriptor(ArgType.INT, "arg2", "A quantity that can be converted to an integer."),
                });
}}}


The most trivial to implement methods are getName(), and getFunctionSummary().
{{{
#!java
/**
 * Used to parse the function string. This name is treated in a case-insensitive manner!
 * @return the name by which you must call the function when used in an attribute equation.
 */
public String getName() { return "IXOR"; }

/**
  * Used to provide help for users.
  * @return a description of what this function does
  */
public String getFunctionSummary() { return "Returns an integer value that is the exclusive-or of 2 other integer values."; }
}}}

The next method is still simple but already touches on the one area that is somewhat complicated in attribute functions: data types and data type conversions!

{{{
#!java
public Class getReturnType() { return Long.class; }
}}}

Our example function is supposed to return an integer value. Integers in equation functions are represented as instances of class java.lang.Long. Therefore it is imperative not to return Integer.class! The user of the function can be blissfully unaware of this distinction. Just remember to always substitute Long for Integer and you should be fine.

The next method evaluateFunction() is the one that gets called when an expression is being evaluated. No argument type-checking is needed here because the compiler already took care of that for us. But, we need to handle all possible valid argument types and counts. (N.B., functions may be overloaded and/or variadic.) In this example the arguments can be any combination of Long and Double.

{{{
#!java
public Object evaluateFunction(final Object[] args) {
        long arg1;
        try {
                arg1 = FunctionUtil.getArgAsLong(args[0]);
        } catch (final Exception e) {
                throw new IllegalArgumentException("IXOR: can't convert the 1st argument to an integer!");
        }

        long arg2;
        try {
                arg2 = FunctionUtil.getArgAsLong(args[0]);
        } catch (final Exception e) {
                throw new IllegalArgumentException("IXOR: can't convert the 2nd argument to an integer!");
        }

        final long result = arg1 ^ arg2;
        return (Long)result;
}
}}}

See Also

[[http://wiki.cytoscape.org/Implementing_Attribute_Equations_Functions|This tutorial]] on how to write attribute functions may also be helpful.

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].
'''Step 3''': After the client is registered as service, the client can be find under File-->Import->Table-->Public databases...

= Help =
Line 755: Line 1014:
== How to add NetworkViewTaskFactories to the right click or double click menus on network view? ==

First the customized TaskFactory must implement NetworkViewTaskFactory interface or extend AbstractNetworkViewTaskFactory. Secondly, the service property "preferredAction" should be set to be "OPEN" for double click, or "NEW" for right click menu.

{{{
#!java

 MyNetworkViewTaskFactory myNetworkViewTaskFactory = new MyNetworkViewTaskFactory(applicationManagerManagerServiceRef);

 // Add double click menu to the network view
 Properties myNetworkViewTaskFactoryProps = new Properties();
 myNetworkViewTaskFactoryProps.setProperty("preferredAction","OPEN");
 myNetworkViewTaskFactoryProps.setProperty("title","my title");

 // Register the service
 registerService(bc,myNetworkViewTaskFactory,NetworkViewTaskFactory.class, myNetworkViewTaskFactoryProps);
}}}

This also applies to add menu item to the double click / right click of nodeView or edgeView.

{{{
#!java
 // To add a right click menu item on node view, set "preferredAction" to "NEW"
 MyNodeViewTaskFactory myNodeViewTaskFactory = new MyNodeViewTaskFactory();

 // Add double click menu item to the node view
 Properties myNodeViewTaskFactoryProps = new Properties();
 myNodeViewTaskFactoryProps.setProperty("preferredAction","NEW");
 myNodeViewTaskFactoryProps.setProperty("title","my node action");

 // Register the service
 registerService(bc,myNodeViewTaskFactory,NodeViewTaskFactory.class, myNodeViewTaskFactoryProps);
}}}

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to add a context menu to edge view or node view in your app? ==

[[http://chianti.ucsd.edu/svn/core3/samples/trunk/sample26/|Sample 26]] is an example of using {{{CyNodeViewContextMenuFactory}}} and {{{CyEdgeViewContextMenuFactory}}} for adding a menu item to the popup menu of node and edge views in the network view panel. these context menu factories are mainly different from using {{{NodeViewTaskFactory}}} in that the manu item is directly accessible and can be modified. Below, two example codes for adding a menu item to right click menu on node and edge, respectively, is shown:

{{{
#!java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import org.cytoscape.application.swing.CyMenuItem;
import org.cytoscape.application.swing.CyNodeViewContextMenuFactory;
import org.cytoscape.model.CyNode;
import org.cytoscape.view.model.CyNetworkView;
import org.cytoscape.view.model.View;

public class CyNodeVCMFSample implements CyNodeViewContextMenuFactory, ActionListener{

 @Override
 public CyMenuItem createMenuItem(CyNetworkView netView,
   View<CyNode> nodeView) {
  
  JMenuItem jMenu = new JMenuItem("sample CyNodeVCMF");
  jMenu.addActionListener(this);
  CyMenuItem newMenu = new CyMenuItem(jMenu, 1);
  return newMenu;
  
 }

 public void actionPerformed(ActionEvent e) {

  // Write your own function here.
  JOptionPane.showMessageDialog(null, "CyNodeViewContextMenuFactory worked!");
  
 }
= OSGi =

== An easier way to construct service properties ==

Writing code to put in service properties requires a lot of boilerplate. Here's an example:

{{{
#!java
public void start(BundleContext bc) {
  Properties props = new Properties();
  props.put(TITLE, "My app");
  props.put(PREFERRED_MENU, "Apps");
  TaskFactory myTaskFactory = ...;
  registerService(bc, myTaskFactory, props);
Line 831: Line 1031:

{{{
#!java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import org.cytoscape.application.swing.CyEdgeViewContextMenuFactory;
import org.cytoscape.application.swing.CyMenuItem;
import org.cytoscape.model.CyEdge;
import org.cytoscape.view.model.CyNetworkView;
import org.cytoscape.view.model.View;

public class CyEdgeVCNMFSample implements CyEdgeViewContextMenuFactory, ActionListener {

 @Override
 public CyMenuItem createMenuItem(CyNetworkView netView,
   View<CyEdge> edgeView) {
  JMenuItem newMenuItem = new JMenuItem("Sample cyEdgeVNMF");
  newMenuItem.addActionListener(this);
  CyMenuItem edgeMenu = new CyMenuItem(newMenuItem, 1);
  return edgeMenu;
 }

 @Override
 public void actionPerformed(ActionEvent e) {
  
  // Write your own function here.
  JOptionPane.showMessageDialog(null, "CyEdgeViewContextMenuFactory action worked!");
  
 }
 
To avoid having to construct a {{{Properties}}} object manually for each service, you can use the {{{ezProps}}} method:

{{{
#!java
private static Properties ezProps(String... vals) {
    final Properties props = new Properties();
    for (int i = 0; i < vals.length; i += 2)
       props.put(vals[i], vals[i + 1]);
    return props;
Line 868: Line 1043:
As you can see, the requested menu item is defined and modified (the text is set) in these code, whereas in [[http://wiki.cytoscape.org/Cytoscape_3/AppDeveloper/Cytoscape_3_App_Cookbook#How_to_add_NetworkViewTaskFactories_to_the_right_click_or_double_click_menus_on_network_view.3F|NetworkViewTaskFactory]] the menu items are generated automatically. In addition to {{{CyNodeViewContextMenuFactory}}} interface, {{{ActionListener}}} interface is also required to be implemented in order to perform the required action when menu item is selected (click).

It is also important to note that, any classes implementing these context meny factory interfaces, requires to be registered in the CyActiavtor:

{{{
#!java
import java.util.Properties;

import org.cytoscape.application.swing.CyEdgeViewContextMenuFactory;
import org.cytoscape.application.swing.CyNodeViewContextMenuFactory;
import org.cytoscape.service.util.AbstractCyActivator;
import org.osgi.framework.BundleContext;

public class CyActivator extends AbstractCyActivator {

 @Override
 public void start(BundleContext context) throws Exception {
  CyNodeViewContextMenuFactory cyNodeVCMF = new CyNodeVCMFSample();
  CyEdgeViewContextMenuFactory cyEdgeVCMF = new CyEdgeVCNMFSample();
  
  Properties properties = new Properties();
  registerAllServices(context, cyNodeVCMF, properties);
  registerAllServices(context, cyEdgeVCMF, properties);
  
 }
The example above can be reworked using {{{ezProps}}}:

{{{
#!java
public void start(BundleContext bc) {
  TaskFactory myTaskFactory = ...;
  registerService(bc, myTaskFactory, ezProps(
    TITLE, "My app",
    PREFERRED_MENU, "Apps"));
Line 895: Line 1053:

}}}

== How to build a network reader to support my own format? ==

First, we should define the format of my network file and its file extension. Let's say, each line in our network file has two columns, tab-delimited. And we define file extension '.tc', stands for 'two columns'.

{{{
#!java
  //1. define a file filter (BasicCyFileFilter), to support the reader to read the file with extension '.tc'
  HashSet<String> extensions = new HashSet<String>();
  extensions.add("tc");
  HashSet<String> contentTypes = new HashSet<String>();
  contentTypes.add("txt");
  String description = "My test filter";
  DataCategory category = DataCategory.NETWORK;
  BasicCyFileFilter filter = new BasicCyFileFilter(extensions,contentTypes, description, category, swingAdapter.getStreamUtil());


  //2. Create an instance of the ReaderFactory
  // Note that extends TCReaderFactory must implement the interface InputStreamTaskFactory or extends the class AbstractInputStreamTaskFactory.
  // And the defined task must implement CyNetworkReader
  TCReaderFactory factory = new TCReaderFactory(filter, swingAdapter.getCyNetworkFactory(), swingAdapter.getCyNetworkViewFactory());

  

  //3. register the ReaderFactory as an InputStreamTaskFactory.
  Properties props = new Properties();
  props.setProperty("readerDescription","TC file reader");
  props.setProperty("readerId","tcNetworkReader");
  swingAdapter.getCyServiceRegistrar().registerService(factory, InputStreamTaskFactory.class, props);
}}}

Compile [http://chianti.ucsd.edu/svn/core3/samples/trunk/sample27a|this sample code], and install the app in Cytoscape. When we try to import a network from a file (File-->Import-->Network-->File..), we will find file type '.tc' is listed as one of the file types supported by Cytoscape.

The source code of sample Apps can be find [[http://chianti.ucsd.edu/svn/core3/samples/trunk/|here]].

== How to build a plugin with dependency on 3rd party library? ==
{{{
#!java

}}}



= Trouble shooting =

If you get compile error,

 1. Check the version number of parent POM, the latest is at [[http://chianti.ucsd.edu/svn/core3/parent/trunk|Cytoscape repository]]
 1. If this is a dependency problem, check the version number of depended bundle at [[http://cytoscape.wodaklab.org/nexus/index.html|Cytoscape repository]]


= Recommendations =
 1. If you’re a beginner you probably want to use the Simple app type. see example02a, example03a
 1. If you want to port as quickly as possible, again, go with the Simple app type.
 1. If you want to publish an API you must use the Bundle app type
 1. If you experience version conflicts or anticipate future version conflicts, again you must use the Bundle app type.
 1. If you are in doubt, you should probably use the Simple app type. You can always port it to the Bundle app type later should that become necessary. Both styles are supported and will be until (at least) version 4.0.


= App Porting Hints =
How to

 1. get current network --- see sample app 5
 1. get attributes --- see sample app 11
 1. add a menu item --- see sample app 3

= Questions, suggestions =

Please send e-mail to [[http://groups.google.com/group/cytoscape-helpdesk?pli=1|cytoscape help desk]] or [[http://groups.google.com/group/cytoscape-discuss|discussion group]]
}}}

Do you want to share your own code snippet?

Let us know! Send a message to Cytoscape Discuss to have your snippet included in this cookbook.

Contents

  1. Do you want to share your own code snippet?
  2. Swing Application
    1. How to add a tabbed Panel to Control panel?
    2. How to add an image icon (menu item) to the toolbar?
    3. How to create a submenu?
  3. Model
    1. How to create, modify, and destroy a network, nodes, and edges?
    2. How to determine which nodes are currently selected on a network?
    3. How to set the name of a network?
    4. How to get the name of a network?
    5. How to set the name of a node?
    6. How to get the name of a node?
    7. How to load attribute data?
    8. How to remove attributes?
    9. How to get all the nodes with a specific attribute value?
    10. How to use model objects (CyNetwork, CyNode, etc.) when writing tests?
  4. View Model
    1. Getting node views for newly created nodes?
    2. How to create, modify, and destroy a network view?
    3. How to change the background color of a view?
    4. How to zoom a network view?
    5. How to get and set node coordinate positions?
    6. How to write a layout algorithm?
    7. How to add components to the node view, edge view, and attribute browser context menus?
  5. VizMapper
    1. How to use the VizMapper programmatically?
    2. How to apply a continuous color gradient to nodes according to their degree?
    3. How to load a visual properties file?
  6. I/O
    1. How to build a network reader to support my own format?
  7. Work
    1. How to use the Cytoscape task monitor to show the progress of my job?
    2. How to issue non-blocking, informational messages to users?
  8. Session
    1. How to save/restore app states?
    2. How to add CyProperty to save values across sessions?
  9. Events
    1. How to handle events from a network
  10. Equations
    1. How to add new attribute functions via a Cytoscape App?
  11. Web Services
    1. How to use a web service client?
    2. How to write a web service client?
  12. Help
    1. How to add plug-in specific help to the Cytoscape main help system?
  13. OSGi
    1. An easier way to construct service properties

Swing Application

How to add a tabbed Panel to Control panel?

Step 1

   1 // Define a CytoPanel class
   2 public class MyCytoPanel extends JPanel implements CytoPanelComponent {
   3 
   4     ...
   5     @Override
   6     public CytoPanelName getCytoPanelName() {
   7         return CytoPanelName.WEST;
   8     }
   9      ...
  10 }
  11 

Step 2

   1 // In the start method of your CyActivator class:
   2 //   Create an instance:
   3 MyCytoPanel myPanel = new MyPanel();
   4 //   Register it as a service:
   5 registerService(bc,myCytoPanel,CytoPanelComponent.class, new Properties());
   6 

How to add an image icon (menu item) to the toolbar?

Step 1

   1 // Define a CyAction class
   2 public class AddImageIconAction extends AbstractCyAction {
   3         
   4     public AddImageIconAction(CySwingApplication desktopApp){
   5         ...
   6         ImageIcon icon = new ImageIcon(getClass().getResource("/images/tiger.jpg"));
   7 
   8         putValue(LARGE_ICON_KEY, icon);
   9        ...
  10     }
  11 
  12     public boolean isInToolBar() {
  13         return true;
  14     }
  15     ...
  16 }
  17 

Step 2

   1 // In the start method of your CyActivator class:
   2 //   Create an instance:
   3 AddImageIconAction addImageIconAction = new AddImageIconAction(cytoscapeDesktopService);
   4 //   Register it as a service:
   5 registerService(bc,addImageIconAction,CyAction.class, new Properties());
   6 

How to create a submenu?

Step 1

   1 // Define a CyAction class
   2 public class Sample04 extends AbstractCyAction {
   3     ...
   4     public Sample04(CySwingApplication desktopApp){
   5         // Add a sub-menu item -- Apps->Sample04->sample04
   6         super("sample04...");
   7         setPreferredMenu("Apps.Sample04");
   8         //Specify the menuGravity value to put the menuItem in the desired place
   9         setMenuGravity(2.0f);
  10         ...
  11     }
  12 

Step 2

   1 // In the start method of your CyActivator class:
   2 //   Create an instance:
   3 Sample04 Sample04Action = new Sample04(cytoscapeDesktopService);
   4 //   Register it as a service:
   5 registerService(bc,Sample04Action,CyAction.class, new Properties());
   6 

Model

How to create, modify, and destroy a network, nodes, and edges?

To create a network, get a reference to the CyNetworkFactory service, and tell it to create a network. With the new network, nodes and edges can be created through the CyNetwork interface.

   1   // To get a reference of CyNetworkFactory at CyActivator class of the App
   2   CyNetworkFactory networkFactory = getService(bc, CyNetworkFactory.class);
   3 ...
   4 
   5   // Create a new network
   6   CyNetwork myNet = networkFactory.createNetwork();
   7   
   8   // Set name for network
   9   myNet.getRow(net).set(CyNetwork.NAME, "My network");
  10 ...
  11 
  12   // Add two nodes to the network
  13   CyNode node1 = myNet.addNode();
  14   CyNode node2 = myNet.addNode();
  15                 
  16   // Set name for new nodes
  17   myNet.getRow(node1).set(CyNetwork.NAME, "Node1");
  18   myNet.getRow(node2).set(CyNetwork.NAME, "Node2");
  19                 
  20   // Add an edge
  21   myNet.addEdge(node1, node2, true);
  22 
  23   // Add the network to Cytoscape
  24   CyNetworkManager networkManager = getService(bc, CyNetworkManager.class);
  25   networkManager.addNetwork(myNet);
  26 

Destroying networks is done through the CyNetworkManager service.

First, in the start method of your CyActivator class:

   1   // Get a CyNetworkManager
   2   CyNetworkManager netMgr = getService(bc,CyNetworkManager.class);
   3 

Now you can use CyNetworkManager in your code:

   1   // Destroy a network with NetworkManager
   2   netMgr.destroyNetwork(myNet); 
   3 

How to determine which nodes are currently selected on a network?

We can use CyTableUtil to get the list of selected nodes in a network

   1 //Get the selected nodes
   2   List<CyNode> nodes = CyTableUtil.getNodesInState(myNetwork,"selected",true);
   3 

How to set the name of a network?

   1   CyNetwork net = ...;
   2   String name = ...;
   3   net.getRow(net).set(CyNetwork.NAME, name);
   4 

How to get the name of a network?

   1   CyNetwork net = ...;
   2   String name = net.getRow(net).get(CyNetwork.NAME, String.class);
   3 

How to set the name of a node?

   1   CyNode node = ...;
   2   String myNodeName = ...;
   3   net.getRow(node).set(CyNetwork.NAME, myNodeName);
   4 

How to get the name of a node?

   1   CyNode node = ...;
   2   String myNodeName = net.getRow(node).get(CyNetwork.NAME, String.class);
   3 

How to load attribute data?

   1 // Define a task
   2 public class CreateTableTask extends AbstractTask {
   3     ....
   4     @Override
   5     public void run(TaskMonitor tm) throws IOException {
   6         // Step 1: create a new table
   7         CyTable table = tableFactory.createTable("MyAttrTable " + Integer.toString(numImports++), 
   8                                    "name", String.class, true, true);
   9 
  10         // create a column for the table
  11         String attributeName = "MyAttributeName"; 
  12         table.createColumn(attributeName, Integer.class, false);
  13                 
  14         // Step 2: populate the table with some data
  15         String[] keys = {"YLL021W","YBR170C","YLR249W"}; //map to the the "name" column
  16         CyRow row = table.getRow(keys[0]);
  17         row.set(attributeName, new Integer(2));
  18 
  19         row = table.getRow(keys[1]);
  20         row.set(attributeName, new Integer(3));
  21 
  22         row = table.getRow(keys[2]);
  23         row.set(attributeName, new Integer(4));
  24 
  25         // We are loading node attribute
  26         Class<? extends CyTableEntry> type = CyNode.class;
  27 
  28         // Step 3: pass the new table to MapNetworkAttrTask
  29         super.insertTasksAfterCurrentTask( new MapNetworkAttrTask(type,table,netMgr,appMgr,rootNetworkManager) );
  30     }
  31     ....
  32 }
  33 

How to remove attributes?

Step 1: get the CyTable through the network

   1     // case for Node table
   2     CyTable nodeTable = network.getDefaultNodeTable();
   3 

Step 2: Find the column and delete it

   1     if(nodeTable.getColumn(columnName)!= null){
   2         nodeTable.deleteColumn(columnName);
   3     }   
   4 

How to get all the nodes with a specific attribute value?

Copy this method in your code:

   1     /**
   2      * Get all the nodes with a given attribute value.
   3      *
   4      * This method is effectively a wrapper around {@link CyTable#getMatchingRows}.
   5      * It converts the table's primary keys (assuming they are node SUIDs) back to
   6      * nodes in the network.
   7      *
   8      * Here is an example of using this method to find all nodes with a given name:
   9      *
  10      * {@code
  11      *   CyNetwork net = ...;
  12      *   String nodeNameToSearchFor = ...;
  13      *   Set<CyNode> nodes = getNodesWithValue(net, net.getDefaultNodeTable(), "name", nodeNameToSearchFor);
  14      *   // nodes now contains all CyNodes with the name specified by nodeNameToSearchFor
  15      * }
  16      * @param net The network that contains the nodes you are looking for.
  17      * @param table The node table that has the attribute value you are looking for;
  18      * the primary keys of this table <i>must</i> be SUIDs of nodes in {@code net}.
  19      * @param colname The name of the column with the attribute value
  20      * @param value The attribute value
  21      * @return A set of {@code CyNode}s with a matching value, or an empty set if no nodes match.
  22      */
  23     private static Set<CyNode> getNodesWithValue(
  24             final CyNetwork net, final CyTable table,
  25             final String colname, final Object value)
  26     {
  27         final Collection<CyRow> matchingRows = table.getMatchingRows(colname, value);
  28         final Set<CyNode> nodes = new HashSet<CyNode>();
  29         final String primaryKeyColname = table.getPrimaryKey().getName();
  30         for (final CyRow row : matchingRows)
  31         {
  32             final Long nodeId = row.get(primaryKeyColname, Long.class);
  33             if (nodeId == null)
  34                 continue;
  35             final CyNode node = net.getNode(nodeId);
  36             if (node == null)
  37                 continue;
  38             nodes.add(node);
  39         }
  40         return nodes;
  41     }
  42 

How to use model objects (CyNetwork, CyNode, etc.) when writing tests?

Step 1. Include the JUnit framework as a dependency in your pom.xml:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>

Step 2. Include the model-impl package as a dependency in your pom.xml:

<dependency>
    <groupId>org.cytoscape</groupId>
    <artifactId>model-impl</artifactId>
    <version>${cytoscape.api.version}</version>
    <scope>test</scope>
</dependency>

Step 3. In your testing code, use NetworkTestSupport to get a CyNetwork instance:

   1 import org.cytoscape.model.NetworkTestSupport;
   2 
   3 ...
   4 
   5 final NetworkTestSupport nts = new NetworkTestSupport();
   6 final CyNetwork network = nts.getNetwork();
   7 
   8 // Now you have a CyNetwork!
   9 

View Model

Getting node views for newly created nodes?

After creating a node and edge, this is how to get its view:

   1   CyNetworkView networkView = ...;
   2   CyNetwork network = networkView.getModel();
   3   CyEventHelper eventHelper = ...;
   4   CyNode newNode = network.addNode();
   5   network.getRow(newNode).set(CyNetwork.NAME, "New Node");
   6   eventHelper.flushPayloadEvents();
   7   View<CyNode> newNodeView = networkView.getNodeView(newNode);
   8 

After creating the node in CyNetwork, you have to call CyEventHelper's flushPayloadEvents so that the new node gets a node view. If flushPayloadEvents is not called, getNodeView may return null.

If you are creating a bunch of nodes at once, call flushPayloadEvents after you have finished creating all the nodes, not after each node is created. Example:

   1   CyNetworkView networkView = ...;
   2   CyNetwork network = networkView.getModel();
   3   CyEventHelper eventHelper = ...;
   4   
   5   for (int i = 1; i <= 100; i++) {
   6     CyNode node = network.addNode();
   7     network.getRow(newNode).set(CyNetwork.NAME, "Node " + i);
   8   }
   9   eventHelper.flushPayloadEvents();
  10 

How to create, modify, and destroy a network view?

To create a network, get a reference to the CyNetworkViewFactory service, and tell it to create a network view.

First, in the start method of your CyActivator class:

   1   // Get a CyNetworkViewFactory
   2   CyNetworkViewFactory networkViewFactory = getService(bc, CyNetworkViewFactory.class);
   3 

Now you can use CyNetworkViewFactory in your code:

   1   // Create a new network view
   2   CyNetworkView myView = networkViewFactory.createNetworkView(myNet);
   3 
   4   // Add view to Cytoscape
   5   CyNetworkViewManager networkViewManager = getService(bc, CyNetworkViewManager.class);
   6   networkViewManager.addNetworkView(myView);
   7 

Destroying network views is done through the CyNetworkViewManager service.

First, in the start method of your CyActivator class:

   1   // get a CyNetworkViewManager
   2   CyNetworkViewManager networkViewManager = getService(bc, CyNetworkViewManager.class);
   3 

Now you can use CyNetworkViewManager in your code:

   1   // destroy a network view through NetworkViewManager
   2   networkViewManager.destroyNetworkView(myView);
   3 

How to change the background color of a view?

Network background color is changed as a _visual property_.

   1   // Set the background of current view to RED  
   2   view.setVisualProperty(BasicVisualLexicon.NETWORK_BACKGROUND_PAINT, Color.red);
   3   view.updateView(); 
   4 

How to zoom a network view?

   1 // Get the scale and adjust
   2 double newScale = view.getVisualProperty(NETWORK_SCALE_FACTOR).doubleValue() * scale;
   3 view.setVisualProperty(NETWORK_SCALE_FACTOR, newScale);
   4 ...     
   5 view.updateView();
   6 

How to get and set node coordinate positions?

Given a View<CyNode>, here's how to get its x and y coordinate positions:

   1 View<CyNode> nodeView = ...;
   2 Double x = nodeView.getVisualProperty(BasicVisualLexicon.NODE_X_LOCATION);
   3 Double y = nodeView.getVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION);
   4 

Here's how to set the x and y coordinate positions:

   1 View<CyNode> nodeView = ...;
   2 double x = ...;
   3 double y = ...;
   4 nodeView.setVisualProperty(BasicVisualLexicon.NODE_X_LOCATION, x);
   5 nodeView.setVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION, y);
   6 

How to write a layout algorithm?

First define a layout class, which implements CyLayoutAlgorithm interface or extends AbstractLayoutAlgorithm class. Then register the layout class as a service.

   1   // Define a layout class
   2   public class MyLayout extends AbstractLayoutAlgorithm {
   3     ...
   4   }
   5 
   6 
   7   // Define a layout task class
   8   public class MyLayoutTask extends AbstractLayoutTask {
   9     ...
  10 
  11     //Perform actual layout task
  12     final protected void doLayout(final TaskMonitor taskMonitor) {
  13       ...   
  14     }
  15     ...
  16   }
  17 
  18 
  19   // Register the layout class as a service in CyActivator class
  20   Properties myLayoutProps = new Properties();
  21   myLayoutProps.setProperty("preferredMenu","My Layouts");
  22   registerService(bc,myLayout,CyLayoutAlgorithm.class, myLayoutProps);
  23 

How to add components to the node view, edge view, and attribute browser context menus?

To add a context menu to a NodeView, define a class, which extends AbstractNodeViewTaskFactory, and register the NodeViewTaskFactory as service. We can add the title of menu item by setting the service property when we register the nodeViewTaskFactory.

To add context menu to the table browser, define a class, which extends AbstractTableCellTaskFactory. Create an instance and register it as service (Note register as TableCellTaskFactory).

   1   // Define a class MyNodeViewTaskFactory 
   2   public class MyNodeViewTaskFactory extends AbstractNodeViewTaskFactory {
   3     ...
   4   }
   5 
   6 
   7   // Register myNodeViewTaskFactory as a service in CyActivator
   8   Properties myNodeViewTaskFactoryProps = new Properties();
   9   myNodeViewTaskFactoryProps.setProperty("title","My context menu title");
  10   registerService(bc,myNodeViewTaskFactory,NodeViewTaskFactory.class, myNodeViewTaskFactoryProps);
  11 

VizMapper

How to use the VizMapper programmatically?

Cytosape provides services for using visual mapping programming. There services are VisualMappingManager, VisualStyleFactory and VisualMappingFunctionFactory. App should get references to these services in CyActivator class, the entry point of the app. We can create new visualStyle with VisualStyleFactory and create mapping function with VisualMappingFunctionFactory very easily. After a new visual style is created, it should register with the VisualMappingManger, in this way the new visual style will be available throughout Cytoscape.

   1   // To get references to services in CyActivator class
   2   VisualMappingManager vmmServiceRef = getService(bc,VisualMappingManager.class);
   3                 
   4   VisualStyleFactory visualStyleFactoryServiceRef = getService(bc,VisualStyleFactory.class);
   5                 
   6   VisualMappingFunctionFactory vmfFactoryC = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=continuous)");
   7   VisualMappingFunctionFactory vmfFactoryD = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=discrete)");
   8   VisualMappingFunctionFactory vmfFactoryP = getService(bc,VisualMappingFunctionFactory.class, "(mapping.type=passthrough)");
   9 
  10 
  11   // To create a new VisualStyle object and set the mapping function
  12   VisualStyle vs= this.visualStyleFactoryServiceRef.createVisualStyle("My visual style");
  13 
  14 
  15   //Use pass-through mapping
  16   String ctrAttrName1 = "SUID";
  17   PassthroughMapping pMapping = (PassthroughMapping) vmfFactoryP.createVisualMappingFunction(ctrAttrName1, String.class, attrForTest, BasicVisualLexicon.NODE_LABEL);
  18 
  19   vs.addVisualMappingFunction(pMapping);                        
  20 
  21 
  22   // Add the new style to the VisualMappingManager
  23   vmmServiceRef.addVisualStyle(vs);
  24 
  25 
  26   // Apply the visual style to a NetwokView
  27   vs.apply(myNetworkView);
  28   myNetworkView.updateView();
  29 

How to apply a continuous color gradient to nodes according to their degree?

   1   
   2   // Set node color map to attribute "Degree"
   3   ContinuousMapping mapping = (ContinuousMapping)
   4                 this.continuousMappingFactoryServiceRef.createVisualMappingFunction("Degree", Integer.class, BasicVisualLexicon.NODE_FILL_COLOR);
   5 
   6   // Define the points
   7   Double val1 = 2d;
   8   BoundaryRangeValues<Paint> brv1 = new BoundaryRangeValues<Paint>(Color.RED, Color.GREEN, Color.PINK);
   9 
  10   Double val2 = 12d;
  11   BoundaryRangeValues<Paint> brv2 = new BoundaryRangeValues<Paint>(Color.WHITE, Color.YELLOW, Color.BLACK);
  12                 
  13   // Set the points
  14   mapping.addPoint(val1, brv1);
  15   mapping.addPoint(val2, brv2);
  16 
  17   // add the mapping to visual style            
  18   vs.addVisualMappingFunction(mapping); 
  19 

How to load a visual properties file?

Cytoscape provide a service 'LoadVizmapFileTaskFactory' for loading visual styles definded in a property file.

   1   // get a reference to Cytoscape service -- LoadVizmapFileTaskFactory 
   2   LoadVizmapFileTaskFactory loadVizmapFileTaskFactory =  getService(bc,LoadVizmapFileTaskFactory.class);
   3 

   1   // Use the service to load visual style, 'f' is the File object to hold the visual properties 
   2   Set<VisualStyle> vsSet = loadVizmapFileTaskFactory.loadStyles(f);
   3 

I/O

How to build a network reader to support my own format?

First, we should define the format of my network file and its file extension. Let's say, each line in our network file has two columns, tab-delimited. And we define file extension '.tc', stands for 'two columns'.

   1   //1. define a file filter (BasicCyFileFilter), to support the reader to read the file with extension '.tc'
   2   HashSet<String> extensions = new HashSet<String>();
   3   extensions.add("tc");
   4   HashSet<String> contentTypes = new HashSet<String>();
   5   contentTypes.add("txt");
   6   String description = "My test filter";
   7   DataCategory category = DataCategory.NETWORK;
   8   BasicCyFileFilter filter = new BasicCyFileFilter(extensions,contentTypes, description, category, swingAdapter.getStreamUtil());
   9 
  10 
  11   //2. Create an instance of the ReaderFactory
  12   // Note that extends TCReaderFactory  must implement the interface InputStreamTaskFactory or extends the class  AbstractInputStreamTaskFactory.
  13   // And the defined task must implement CyNetworkReader
  14   TCReaderFactory factory = new TCReaderFactory(filter, swingAdapter.getCyNetworkFactory(), swingAdapter.getCyNetworkViewFactory());
  15 
  16   
  17 
  18   //3. register the ReaderFactory as an InputStreamTaskFactory.
  19   Properties props = new Properties();
  20   props.setProperty("readerDescription","TC file reader");
  21   props.setProperty("readerId","tcNetworkReader");
  22   swingAdapter.getCyServiceRegistrar().registerService(factory, InputStreamTaskFactory.class, props);
  23 

Compile [http://chianti.ucsd.edu/svn/core3/samples/trunk/sample27a|this sample code], and install the app in Cytoscape. When we try to import a network from a file (File-->Import-->Network-->File..), we will find file type '.tc' is listed as one of the file types supported by Cytoscape.

Work

How to use the Cytoscape task monitor to show the progress of my job?

Get a Cytoscape service DialogTaskManager and execute the task through the taskManager.

   1   // Get a Cytoscape service 'DialogTaskManager' in CyActivator class
   2   DialogTaskManager dialogTaskManager = getService(bc, DialogTaskManager.class);
   3 
   4 
   5   // Define a task and set the progress in the run() method
   6   public class MyTask extends AbstractTask {
   7     ...
   8     public void run(final TaskMonitor taskMonitor) {
   9         // Give the task a title.
  10         taskMonitor.setTitle("My task");
  11         ...
  12         taskMonitor.setProgress(0.1);
  13 
  14         // do something here
  15 
  16         ...
  17         taskMonitor.setProgress(1.0);
  18   }
  19 
  20 
  21   // Execute the task through the TaskManager
  22   DialogTaskManager.execute(myTaskFactory);
  23 

How to issue non-blocking, informational messages to users?

Cytoscape 3.0 has a status bar at the bottom of the Cytoscape desktop window. Tasks can put messages into the status bar. These messages wouldn't require immediate user attention but are informational. Debug messages useful for developers do not belong in the status bar.

To issue user messages to the status bar:

Step 1. Include the SLF4J library as a dependency in your pom.xml file.

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.6.6</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-simple</artifactId>
</dependency>

Step 2. Obtain an instance of the CyUserMessages log.

   1 import org.slf4j.LoggerFactory;
   2 import org.slf4j.Logger;
   3 ...
   4 Logger userMessagesLogger = LoggerFactory.getLogger("CyUserMessages");
   5 

Step 3. Issue log messages to the CyUserMessages log.

   1 int lineError = 12;
   2 userMessagesLogger.warn("Parse error on line {}", lineError);
   3 

The message will appear in the status bar.

Session

How to save/restore app states?

There are two events, which are important for saving/restoring App state. The two evetns are SessionAboutToBeSavedEvent and SessionLoadedEvent. App should implement the two listeners and register them.

   1   // Implements the session event listeners
   2   public class MyClass implements SessionAboutToBeSavedListener, SessionLoadedListener {
   3 
   4       // Save app state in a file
   5       public void handleEvent(SessionAboutToBeSavedEvent e){
   6           // save app state file "myAppStateFile"
   7           ...
   8       }
   9 
  10       // restore app state from a file
  11       public void handleEvent(SessionLoadedEvent e){
  12 
  13         if (e.getLoadedSession().getAppFileListMap() == null || e.getLoadedSession().getAppFileListMap().size() ==0){
  14             return;
  15         }       
  16         List<File> files = e.getLoadedSession().getAppFileListMap().get("myAppStateFile");
  17         ...
  18        }
  19   }
  20  
  21 
  22   // Register the two listeners in the CyActivator class
  23   registerService(bc,myClass,SessionAboutToBeSavedListener.class, new Properties());
  24   registerService(bc,myClass,SessionLoadedListener.class, new Properties());
  25 

How to add CyProperty to save values across sessions?

CyProperty acts as a container to save properties of the type (key, value) across sessions. They are available for the user to manually change in the preference menu option.

   1         //1. Adding a property which saves the node border width selected by the user.
   2         public static String NodeBorderWidthInPaths = "NODE_BORDER_WIDTH_IN_PATHS";
   3         public static Double NodeBorderWidthInPathsValue = 20.0;
   4         public static Properties nodeBorderWidthProps = new Properties();
   5 
   6         //2. Find if the CyProperty already exists, if not create one with default value.
   7         CyProperty<Properties> nodeBorderWidthProperty = null;
   8         CySessionManager mySessionManager;
   9         mySessionManager = adapter.getCySessionManager();
  10         CySession session;
  11         session = mySessionManager.getCurrentSession();
  12         if(session.equals(null))
  13                 System.out.println("session null");
  14                 
  15         //3. Get all properties and loop through to find your own.
  16         Set<CyProperty<?>> props = new HashSet<CyProperty<?>>();
  17         props = session.getProperties();
  18         if(props.equals(null))
  19                 System.out.println("props null");
  20         boolean flag = false;
  21         
  22         for (CyProperty<?> prop : props) {
  23             if (prop.getName() != null){
  24                 if (prop.getName().equals(NodeBorderWidthInPaths)) {
  25                 nodeBorderWidthProperty = (CyProperty<Properties>) prop;
  26                 flag = true;
  27                 break;
  28                 }
  29             }
  30         }
  31         
  32         //4. If the property does not exists, create nodeBorderWidthProperty
  33         if (!flag)
  34         {
  35                 nodeBorderWidthProps.setProperty(NodeBorderWidthInPaths, NodeBorderWidthInPathsValue.toString());
  36                 nodeBorderWidthProperty = new 
  37                                 SimpleCyProperty(NodeBorderWidthInPaths, 
  38                                                 nodeBorderWidthProps, Float.TYPE, CyProperty.SavePolicy.SESSION_FILE_AND_CONFIG_DIR );
  39         }
  40         //5. If not null, property exists, get value from it and set NodeBorderWidthInPathsValue
  41         else
  42         {
  43                 nodeBorderWidthProps = nodeBorderWidthProperty.getProperties();
  44                 NodeBorderWidthInPathsValue = Double.valueOf((String)nodeBorderWidthProps.get(NodeBorderWidthInPaths));
  45         }
  46 

Events

How to handle events from a network

Step 1

   1   // Define a class, which implements a listener interface
   2   public class MyListenerClass implements NetworkAddedListener {
   3     ....
   4     public void handleEvent(NetworkAddedEvent e){
   5         // do something here
   6     }
   7   }
   8 

Step 2

   1   // In the `start` method of your `CyActivator` class,
   2   // register the listener in the CyActivator class
   3   registerService(bc,myListenerClass, NetworkAddedListener.class, new Properties());
   4 

Equations

How to add new attribute functions via a Cytoscape App?

Here we will go through all the steps necessary to create a new built-in function IXOR(). The complete example code and can be downloaded from here. The easiest part is writing the actual plug-in class, which look similar to this:

   1   import org.cytoscape.equations.EquationCompiler;
   2   import org.cytoscape.equations.Interpreter;
   3   import org.cytoscape.equations.EquationParser;
   4 
   5   public class Sample23 {
   6 
   7         public Sample23(EquationCompiler eqCompilerRef, Interpreter interpreterRef){
   8                 final EquationParser theParser = eqCompilerRef.getParser();
   9                 theParser.registerFunction(new IXor());
  10         }
  11   }
  12 

Here we register a new built-in function called IXor. You can also register multiple built-in functions if you prefer.

The next part is creating one class each for every new built-in. Each such class has to implement the org.cytoscape.equations.Function interface usually via org.cytoscape.equations.AbstractFunction. The easiest way to get started is to peruse the existing built-ins in equations Cytoscape core library and look for a function with a similar or identical argument list. If you can't find one it may still be instructive to read through the implementation of a couple of existing functions.

First you have to create the constructor where you describe the arguments that your function will take:

   1 public IXor() {
   2         super(new ArgDescriptor[] {
   3                         new ArgDescriptor(ArgType.INT, "arg1", "A quantity that can be converted to an integer."),
   4                         new ArgDescriptor(ArgType.INT, "arg2", "A quantity that can be converted to an integer."),
   5                 });
   6 

The most trivial to implement methods are getName(), and getFunctionSummary().

   1 /**                                                                                                                                                                                                                                                  
   2  *  Used to parse the function string.  This name is treated in a case-insensitive manner!                                                                                                                                                           
   3  *  @return the name by which you must call the function when used in an attribute equation.                                                                                                                                                        
   4  */
   5 public String getName() { return "IXOR"; }
   6 
   7 /**                                                                                                                                                                                                                                                  
   8   *  Used to provide help for users.                                                                                                                                                                                                                  
   9   *  @return a description of what this function does                                                                                                                                                                                                
  10   */
  11 public String getFunctionSummary() { return "Returns an integer value that is the exclusive-or of 2 other integer values."; }
  12 

The next method is still simple but already touches on the one area that is somewhat complicated in attribute functions: data types and data type conversions!

   1 public Class getReturnType() { return Long.class; }
   2 

Our example function is supposed to return an integer value. Integers in equation functions are represented as instances of class java.lang.Long. Therefore it is imperative not to return Integer.class! The user of the function can be blissfully unaware of this distinction. Just remember to always substitute Long for Integer and you should be fine.

The next method evaluateFunction() is the one that gets called when an expression is being evaluated. No argument type-checking is needed here because the compiler already took care of that for us. But, we need to handle all possible valid argument types and counts. (N.B., functions may be overloaded and/or variadic.) In this example the arguments can be any combination of Long and Double.

   1 public Object evaluateFunction(final Object[] args) {
   2         long arg1;
   3         try {
   4                 arg1 = FunctionUtil.getArgAsLong(args[0]);
   5         } catch (final Exception e) {
   6                 throw new IllegalArgumentException("IXOR: can't convert the 1st argument to an integer!");
   7         }
   8 
   9         long arg2;
  10         try {
  11                 arg2 = FunctionUtil.getArgAsLong(args[0]);
  12         } catch (final Exception e) {
  13                 throw new IllegalArgumentException("IXOR: can't convert the 2nd argument to an integer!");
  14         }
  15 
  16         final long result = arg1 ^ arg2;
  17         return (Long)result;
  18 }
  19 

This tutorial on how to write attribute functions may also be helpful.

Web Services

How to use a web service client?

First define a listener of web service client and register it as service -- WebServiceHelper. This class will keep tracker of web service clients available using a Map.

   1   public class WebServiceHelper {
   2   ...
   3         public void addWebServiceClient(final WebServiceClient newFactory,
   4                         final Map properties)
   5         {
   6                 webserviceMap.put(newFactory, properties);
   7         }
   8 
   9         public void removeWebServiceClient(final WebServiceClient factory,
  10                         final Map properties)
  11         {
  12                 webserviceMap.remove(factory);
  13         }
  14   ...
  15   }  
  16 

At running time, check if the needed service is available by looking at the map.

   1   Iterator<WebServiceClient> it = webserviceMap.keySet().iterator();
   2                 
   3   while (it.hasNext()){
   4     WebServiceClient client = it.next();
   5     // Based on the serviceLocation, we can find if the client we are looking for is available
   6     System.out.println("WebService CLient client: DisplayName() is "+client.getDisplayName());
   7     System.out.println("WebService CLient client: ServiceLocation() is "+client.getServiceLocation());
   8     ....  
   9   }
  10 

If the needed client is found, then we can construct the query and execute the query through the API of the client.

How to write a web service client?

Step 1: Define a UI class for the setting of the client. This UI may listen to Cytoscape events

   1   public class MyWebserviceClientPanel extends JPanel implements ColumnCreatedListener, ColumnDeletedListener,
   2     SetCurrentNetworkListener {
   3   ...
   4 }
   5 

Step 2: Define a client class, which must implement WebServiceClient and pass the UI class defined at previous step to the client. If UI is not defined, the default UI will be used.

   1   public class MyWebserviceClient extends AbstractWebServiceGUIClient implements TableImportWebServiceClient {
   2   ...
   3   }
   4 

Step 3: After the client is registered as service, the client can be find under File-->Import->Table-->Public databases...

Help

How to add plug-in specific help to the Cytoscape main help system?

If you download Sample 24 and instal and copy the jar to the deploy directory fo your running Cytoscape, you will see topic Sample 24 help is added to your help panel (Help --> Contents...). In order to make it simpler, you can download the help directory in the sampel 24 trunk and copy this folder to your project's resources folder. Next you need to get the CyHelpBroker service in your CyActivator class. The code in sample 24:

   1 import java.util.Properties;
   2 
   3 import org.cytoscape.application.swing.CyHelpBroker;
   4 import org.cytoscape.service.util.AbstractCyActivator;
   5 import org.osgi.framework.BundleContext;
   6 
   7 public class CyActivator extends AbstractCyActivator {
   8 
   9         @Override
  10         public void start(BundleContext context) throws Exception {
  11                 
  12                 CyHelpBroker cyHelpBroker = getService(context, CyHelpBroker.class);
  13 
  14                 AppHelp action = new AppHelp(cyHelpBroker);
  15                 registerAllServices(context, action, new Properties());
  16         }
  17 
  18 }
  19 

In the main entry point of your plug-in, add the following function:

   1 ...
   2 import java.net.URL;
   3 import org.cytoscape.application.swing.CyHelpBroker;
   4 import javax.help.HelpSet;
   5 ...
   6         /**
   7          *  Hook plugin help into the Cytoscape main help system:
   8          */
   9         private void addHelp() {
  10                 final String HELP_SET_NAME = "/help/jhelpset";
  11                 final ClassLoader classLoader = AppHelp.class.getClassLoader();
  12                 URL helpSetURL;
  13                 try {
  14                         helpSetURL = HelpSet.findHelpSet(classLoader, HELP_SET_NAME);
  15                         final HelpSet newHelpSet = new HelpSet(classLoader, helpSetURL);
  16                         cyHelpBroker.getHelpSet().add(newHelpSet);
  17                 } catch (final Exception e) {
  18                         System.err.println("Sample24: Could not find help set: \"" + HELP_SET_NAME + "!");
  19                 }
  20         }
  21 

Invoke this function somewhere in the constructor for the class. Finally, edit the files in the help directory. Most likely you would want to edit the files named jhelpmap.jhm and Topic.html. You may consider removing both, SubTopic.html and the reference to it in jhelpmap.jhm. You can also add additional topics, if you want. The effect this will have is to add a new topic at the very bottom of the Cytoscape help index. You may have a help button in your plug-in, in which case you would probably want to add code similar to the following:

   1        ...
   2 import cytoscape.view.CyHelpBroker;
   3        ...
   4        CyHelpBroker.getHelpBroker().enableHelpOnButton(helpButton, "Topic", null);
   5        ...
   6 

That should be all that is needed to dynamically add your own help topic(s)!

OSGi

An easier way to construct service properties

Writing code to put in service properties requires a lot of boilerplate. Here's an example:

   1 public void start(BundleContext bc) {
   2   Properties props = new Properties();
   3   props.put(TITLE, "My app");
   4   props.put(PREFERRED_MENU, "Apps");
   5   TaskFactory myTaskFactory = ...;
   6   registerService(bc, myTaskFactory, props);
   7 }
   8 

To avoid having to construct a Properties object manually for each service, you can use the ezProps method:

   1 private static Properties ezProps(String... vals) {
   2     final Properties props = new Properties();
   3     for (int i = 0; i < vals.length; i += 2)
   4        props.put(vals[i], vals[i + 1]);
   5     return props;
   6 }
   7 

The example above can be reworked using ezProps:

   1 public void start(BundleContext bc) {
   2   TaskFactory myTaskFactory = ...;
   3   registerService(bc, myTaskFactory, ezProps(
   4     TITLE, "My app",
   5     PREFERRED_MENU, "Apps"));
   6 }
   7 

Cytoscape_3/AppDeveloper/Cytoscape_3_App_Cookbook (last edited 2020-02-05 19:54:29 by KristinaHanspers)

Funding for Cytoscape is provided by a federal grant from the U.S. National Institute of General Medical Sciences (NIGMS) of the Na tional Institutes of Health (NIH) under award number GM070743-01. Corporate funding is provided through a contract from Unilever PLC.

MoinMoin Appliance - Powered by TurnKey Linux