Author: scooter
Date: 2011-02-25 18:20:31 -0800 (Fri, 25 Feb 2011)
New Revision: 24242

Added:
   csplugins/trunk/ucsf/scooter/nodeCharts/examples/heatstrip.com
   
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/HeatStrip.java
   
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/LinearGradientPaintFactory.java
Modified:
   csplugins/trunk/ucsf/scooter/nodeCharts/examples/bar2.com
   csplugins/trunk/ucsf/scooter/nodeCharts/pom.xml
   
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/NodeChartCommandHandler.java
   
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/ValueUtils.java
   
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/resources/nodeCharts/plugin.props
Log:
Added HeatStrips


Modified: csplugins/trunk/ucsf/scooter/nodeCharts/examples/bar2.com
===================================================================
--- csplugins/trunk/ucsf/scooter/nodeCharts/examples/bar2.com   2011-02-26 
00:28:15 UTC (rev 24241)
+++ csplugins/trunk/ucsf/scooter/nodeCharts/examples/bar2.com   2011-02-26 
02:20:31 UTC (rev 24242)
@@ -1,3 +1,2 @@
-nodecharts bar nodelist="all" attributelist="gal1RGexp,gal4RGexp,gal80Rexp" 
colorlist="up:cyan,down:yellow"
-
+nodecharts bar nodelist="all" attributelist="gal1RGexp,gal4RGexp,gal80Rexp" 
colorlist="up:red,down:green" showlabels="false"
 network view update

Added: csplugins/trunk/ucsf/scooter/nodeCharts/examples/heatstrip.com
===================================================================
--- csplugins/trunk/ucsf/scooter/nodeCharts/examples/heatstrip.com              
                (rev 0)
+++ csplugins/trunk/ucsf/scooter/nodeCharts/examples/heatstrip.com      
2011-02-26 02:20:31 UTC (rev 24242)
@@ -0,0 +1,3 @@
+nodecharts heatstrip nodelist="all" 
attributelist="gal1RGexp,gal4RGexp,gal80Rexp" colorlist="redgreen" 
normalize="true" showlabels="false"
+
+network view update

Modified: csplugins/trunk/ucsf/scooter/nodeCharts/pom.xml
===================================================================
--- csplugins/trunk/ucsf/scooter/nodeCharts/pom.xml     2011-02-26 00:28:15 UTC 
(rev 24241)
+++ csplugins/trunk/ucsf/scooter/nodeCharts/pom.xml     2011-02-26 02:20:31 UTC 
(rev 24242)
@@ -14,7 +14,7 @@
   <groupId>cytoscape.csplugins</groupId>
   <artifactId>nodeCharts</artifactId>
   <packaging>jar</packaging>
-  <version>0.93</version>
+  <version>0.94</version>
 
   <name>Node Charts Plugin</name>
 

Modified: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/NodeChartCommandHandler.java
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/NodeChartCommandHandler.java
       2011-02-26 00:28:15 UTC (rev 24241)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/NodeChartCommandHandler.java
       2011-02-26 02:20:31 UTC (rev 24242)
@@ -58,6 +58,7 @@
 // nodeChart imports
 import nodeCharts.view.NodeChartViewer;
 import nodeCharts.view.BarChart;
+import nodeCharts.view.HeatStrip;
 import nodeCharts.view.LineChart;
 import nodeCharts.view.PieChart;
 import nodeCharts.view.StripeChart;
@@ -80,9 +81,11 @@
        public static final String NETWORK = "network";
        public static final String NODE = "node";
        public static final String NODELIST = "nodelist";
+       public static final String NORMALIZE = "normalize";
        public static final String POSITION = "position";
        public static final String SCALE = "scale";
        public static final String SELECTED = "selected";
+       public static final String SHOWLABELS = "showlabels";
        public static final String VALUES = "valuelist";
 
        public NodeChartCommandHandler(String namespace, CyLogger logger) {
@@ -93,6 +96,7 @@
 
                // Register each command
                register(new BarChart());
+               register(new HeatStrip());
                register(new LineChart());
                register(new PieChart());
                register(new StripeChart());
@@ -185,6 +189,23 @@
                        labels = ValueUtils.getStringList(args.get(LABELS));
                }
 
+               boolean showLabels = true;
+               if (args.containsKey(SHOWLABELS)) {
+                       showLabels = 
ValueUtils.getBooleanValue(args.get(SHOWLABELS));
+               }
+
+               boolean normalize = false;
+               List<Double>maxValues = null;
+               if (args.containsKey(NORMALIZE)) {
+                       normalize = 
ValueUtils.getBooleanValue(args.get(NORMALIZE));
+                       if (normalize && args.containsKey(ATTRIBUTELIST)) {
+                               for (CyNode node: nodeList) {
+                                       values = 
ValueUtils.getDataFromAttributes (node, args.get(ATTRIBUTELIST), labels);
+                                       maxValues = 
ValueUtils.arrayMax(maxValues, values);
+                               }
+                       }
+               }
+
                double scale = 0.90;
                if (args.containsKey(SCALE)) {
                        try {
@@ -203,12 +224,18 @@
                                throw new CyCommandException("unknown position 
keyword or illegal position expression: "+position);
                }
 
+               if (!showLabels)
+                       labels = null;
+
                // OK, do it!
                for (CyNode node: nodeList) {
                        // If we've got an attributelist, we need to get our 
values now since they will change based on
                        // the node
-                       if (args.containsKey(ATTRIBUTELIST))
+                       if (args.containsKey(ATTRIBUTELIST)) {
                                values = ValueUtils.getDataFromAttributes 
(node, args.get(ATTRIBUTELIST), labels);
+                               if (normalize)
+                                       ValueUtils.normalize(values, maxValues);
+                       }
 
                        List<CustomGraphic> cgList = 
viewer.getCustomGraphics(args, values, labels, node, view, pos, scale);
                        ViewUtils.addCustomGraphics(cgList, node, view);
@@ -228,9 +255,11 @@
                addArgument(viewer.getName(), NETWORK, CURRENT);
                addArgument(viewer.getName(), NODE);
                addArgument(viewer.getName(), NODELIST);
+               addArgument(viewer.getName(), NORMALIZE, "false");
                addArgument(viewer.getName(), POSITION);
                addArgument(viewer.getName(), VALUES);
                addArgument(viewer.getName(), SCALE, "0.90");
+               addArgument(viewer.getName(), SHOWLABELS, "true");
 
                // Get the specific commands handled by the viewer
                Map<String,String> args = viewer.getOptions();

Modified: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/ValueUtils.java
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/ValueUtils.java
    2011-02-26 00:28:15 UTC (rev 24241)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/ValueUtils.java
    2011-02-26 02:20:31 UTC (rev 24242)
@@ -100,7 +100,7 @@
                }
                if (attributeArray.length == 1) {
                        // Handle the case where we were given a single, list 
attribute
-                       if (labels.size() == 0) {
+                       if (labels == null || labels.size() == 0) {
                                throw new CyCommandException("Labels must be 
specified if attribute is a list");
                        }
                        String attr = attributeArray[0].trim();
@@ -140,7 +140,7 @@
                                        }
                                }
                        }
-                       if (labels.size() == 0)
+                       if (labels != null && labels.size() == 0)
                                labels.addAll(Arrays.asList(attributeArray));
                        return result;
                }
@@ -190,6 +190,25 @@
                return new ArrayList<String>();
        }
 
+       /**
+        * Return the boolean equivalent of the input
+        *
+        * @param input an input value that is supposed to be Boolean
+        * @return the boolean value it represents
+        */
+       public static boolean getBooleanValue(Object input) {
+               if (input instanceof Boolean)
+                       return ((Boolean)input).booleanValue();
+               return Boolean.parseBoolean(input.toString());
+       }
+
+       /**
+        * Return the double equivalent of the input
+        *
+        * @param input an input value that is supposed to be a double
+        * @return the a double value it represents
+        * @throws NumberFormatException is the value is illegal
+        */
        public static double getDoubleValue(Object input) throws 
NumberFormatException {
                if (input instanceof Double)
                        return ((Double)input).doubleValue();
@@ -200,6 +219,28 @@
                throw new NumberFormatException("input can not be converted to 
double");
        }
 
+       public static List<Double> arrayMax(List<Double> maxValues, 
List<Double> values) {
+               // Initialize, if necessary
+               if (maxValues == null) {
+                       maxValues = new ArrayList<Double>(values.size());
+                       for (Double d: values)
+                               maxValues.add(Math.abs(d));
+                       return maxValues;
+               }
+
+               // OK, now we need to actually do the work...
+               for (int index = 0; index < values.size(); index++) {
+                       maxValues.set(index, Math.max(maxValues.get(index), 
Math.abs(values.get(index))));
+               }
+               return maxValues;
+       }
+
+       public static void normalize(List<Double> values, List<Double> 
maxValues) {
+               for (int index = 0; index < values.size(); index++) {
+                       values.set(index, 
values.get(index)/maxValues.get(index));
+               }
+       }
+
        /**
         * Takes a map of objects indexed by a string keyword and returns
         * a map of strings indexed by that keyword.  This involves figuring
@@ -240,6 +281,8 @@
        private static final String     RAINBOW = "rainbow";
        private static final String RANDOM = "random";
        private static final String     UP = "up:";
+       private static final String     ZERO = "zero:";
+       private static final double EPSILON = 1E-8f;
 
        public static List<Color> convertInputToColor(Object input, 
List<Double>values) throws CyCommandException {
                int nColors = values.size();
@@ -263,9 +306,13 @@
                        // Look for up/down special case
                        if (colorArray.length == 2 &&
                            (colorArray[0].toLowerCase().startsWith(UP) ||
-                            colorArray[1].toLowerCase().startsWith(DOWN))) {
+                            colorArray[0].toLowerCase().startsWith(DOWN))) {
                                return parseUpDownColor(colorArray, values);
-                               
+                       } else if (colorArray.length == 3 &&
+                           (colorArray[0].toLowerCase().startsWith(UP) ||
+                            colorArray[0].toLowerCase().startsWith(DOWN) ||
+                            colorArray[0].toLowerCase().startsWith(ZERO))) {
+                               return parseUpDownColor(colorArray, values);
                        } else if (colorArray.length > 1)
                                return parseColorList(colorArray);
                        else
@@ -274,24 +321,38 @@
                        throw new CyCommandException("unknown type for color 
list");
        }
 
+       public static List<Color> parseUpDownColor(String[] colorArray) throws 
CyCommandException {
+               if (colorArray.length < 2)
+                       throw new CyCommandException("Up/Down color spec must 
have at least 2 colors");
+
+               String [] colors = new String[3];
+               colors[2] = "black";
+               for (int index = 0; index < colorArray.length; index++) {
+                       if (colorArray[index].toLowerCase().startsWith(UP)) {
+                               colors[0] = 
colorArray[index].substring(UP.length());
+                       } else if 
(colorArray[index].toLowerCase().startsWith(DOWN)) {
+                               colors[1] = 
colorArray[index].substring(DOWN.length());
+                       } else if 
(colorArray[index].toLowerCase().startsWith(ZERO)) {
+                               colors[2] = 
colorArray[index].substring(ZERO.length());
+                       }
+               } 
+               return parseColorList(colors);
+       }
+
        private static List<Color> parseUpDownColor(String[] colorArray, 
List<Double>values) throws CyCommandException {
-               String [] colors = new String[2];
-               if (colorArray[0].toLowerCase().startsWith(UP)) {
-                       colors[0] = colorArray[0].substring(UP.length());
-                       colors[1] = colorArray[1].substring(DOWN.length());
-               } else {
-                       colors[1] = colorArray[0].substring(DOWN.length());
-                       colors[0] = colorArray[1].substring(UP.length());
-               }
-               List<Color> upDownColors = parseColorList(colors);
+               List<Color> upDownColors = parseUpDownColor(colorArray);
                Color up = upDownColors.get(0);
                Color down = upDownColors.get(1);
+               Color zero = upDownColors.get(2);
+
                List<Color> results = new ArrayList<Color>(values.size());
                for (Double v: values) {
-                       if (v < 0.0) 
+                       if (v < EPSILON) 
                                results.add(down);
+                       else if (v > EPSILON)
+                               results.add(up);
                        else
-                               results.add(up);
+                               results.add(zero);
                }
                return results;
        }

Added: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/HeatStrip.java
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/HeatStrip.java
                                (rev 0)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/HeatStrip.java
        2011-02-26 02:20:31 UTC (rev 24242)
@@ -0,0 +1,183 @@
+package nodeCharts.view;
+
+import giny.view.Position;
+
+import java.awt.Color;
+import java.awt.Shape;
+import java.awt.geom.Area;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import nodeCharts.command.NodeChartCommandHandler;
+import nodeCharts.command.ValueUtils;
+import nodeCharts.view.ViewUtils.TextAlignment;
+import cytoscape.CyNode;
+import cytoscape.command.CyCommandException;
+import cytoscape.render.stateful.CustomGraphic;
+import cytoscape.render.stateful.PaintFactory;
+import cytoscape.view.CyNetworkView;
+
+/**
+ * creates a list of custom graphics where each custom graphic represents a
+ * bar of a heat strip. The data for this is of the format: value1:value2:....
+ * The colors are specified as a colorlist triple: up:zero:down, or a quad
+ * up:zero:down:missing, or a keyword: redgreen, yellowcyan.  If nothing
+ * is specified, yellowcyan is assumed
+ * 
+ * Bar starts at centerline of node and goes upwards (for positive value) or 
+ * downwards (for negative values)
+ * 
+ */
+public class HeatStrip implements NodeChartViewer {
+       private static final String COLORS = "colorlist";
+       private static final String SEPARATION = "separation";
+       private static final String REDGREEN = "redgreen";
+       private static final String YELLOWCYAN = "yellowcyan";
+
+       float[] dist = {0.0f, 0.5f, 1.0f};
+       Color[] redGreen = {Color.GREEN, Color.BLACK, Color.RED};
+       Color[] yellowCyan = {Color.CYAN, Color.BLACK, Color.YELLOW};
+       
+
+       public String getName() {
+               return "heatstrip";
+       }
+
+       public String getDescription() {
+               return "Display the values passed as arguments as a heat strip 
on the node";
+       }
+
+       public Map<String, String> getOptions() {
+               Map<String, String> options = new HashMap<String, String>();
+               options.put(COLORS, "yellowcyan");
+               options.put(SEPARATION, "");
+               return options;
+       }
+
+       public List<CustomGraphic> getCustomGraphics(Map<String, Object> args,
+                       List<Double> values, List<String> labels, CyNode node,
+                       CyNetworkView view, Object position, double scale) 
throws CyCommandException {
+
+               Color[] colorScale = null;
+
+               // Get our colors
+               String colorSpec = args.get(COLORS).toString();
+               if (colorSpec.equalsIgnoreCase(YELLOWCYAN)) {
+                       colorScale = yellowCyan;
+               } else if (colorSpec.equalsIgnoreCase(REDGREEN)) {
+                       colorScale = redGreen;
+               } else {
+                       colorScale = new Color[3];
+                       String [] colorArray = colorSpec.split(",");
+                       List<Color> colors = 
ValueUtils.parseUpDownColor(colorArray);
+                       colorScale[0] = colors.get(0);
+                       colorScale[2] = colors.get(1);
+                       colorScale[1] = colors.get(2);
+               }
+               int separation = 0;
+               Object separationObj = args.get(SEPARATION);
+               if (separationObj instanceof String)
+               {
+                       if (! separationObj.equals(""))
+                       {
+                               separation = 
Integer.parseInt(separationObj.toString());
+                       }
+               }
+
+               int nbrSlices = values.size();
+               List<CustomGraphic> cgList = new ArrayList<CustomGraphic>();
+
+               // We need to get our bounding box in order to scale our graphic
+               // properly
+               Rectangle2D bbox = ViewUtils.getNodeBoundingBox(node, view, 
position, scale);
+               double height = bbox.getHeight();
+               double width = bbox.getWidth();
+               
+               double x = bbox.getX();
+               double y = bbox.getY();
+               
+               double yMid = y + (0.5 * height);       
+               
+               // System.out.println("Node bounding box = " + bbox);
+               // divide width into equal size segments
+               double slice = (width / values.size()) - (values.size() * 
separation) + separation;  // only have n-1 separators
+//             System.out.println("slice = " + slice);
+
+
+               double min = 0.000001;   // endure no division by zero
+               double max = -0.000001;
+               for (double i : values) {
+                       min = Math.min(min, i);
+                       max = Math.max(max, i);
+               }
+
+               // make the graph symmetrical around max and min, set to the 
larger  (maybe will be too influenced by outliers?)
+               if (Math.abs(max) > Math.abs(min))
+               {
+                       min = -1.0 * max;
+               }
+               else
+               {
+                       max = -1.0 * min;
+               }
+
+               Rectangle2D [] barArray = new Rectangle2D[values.size()];
+               double maxY = 0.0;
+               PaintFactory pf = new LinearGradientPaintFactory(x, y+height, 
x, y, colorScale, dist);
+
+               for (int i = 0; i < values.size(); i++) {
+                       double px1 = x + (i * slice);
+                       double w = slice;
+                       double val = values.get(i);
+                       double py1 = y + (0.5 * height);
+                       if (val > 0.0) // positive, work down to midpoint
+                       {
+                               py1 = py1 - ((0.5 * height) * (val / max));
+                       }
+                       else // negative, work down from midpoint
+                       {
+                               val = -val;
+                       }
+
+                       double h = (0.5 * height) * (val / max);
+
+                       barArray[i] = new Rectangle2D.Double(px1, py1, w, h);
+                       // System.out.println ("Got rectangle from: " + px1 + 
"," + py1 + " of width " + w + " and height " + h);
+                       maxY = Math.max(maxY, barArray[i].getMaxY());
+                       
+                       CustomGraphic c = new CustomGraphic(barArray[i], pf);
+//                     System.out.println("added custome graphic for line from 
" + drect.getP1() + " to " + .getP2());
+                       cgList.add(c);
+               }
+
+               if (labels != null && labels.size() > 0) {
+                       // Now, create the labels.  We want to do this here so 
we can adjust the label for the slice
+                       for (int i = 0; i < values.size(); i++) {
+                               
+                               // add labels
+                               TextAlignment tAlign = TextAlignment.ALIGN_LEFT;
+                               
+                               // Now, create the label.  Put the label on the 
outer edge of the circle.
+                               Point2D labelPosition = new 
Point2D.Double(barArray[i].getCenterX(), maxY);
+                               // vals[1] = 
ViewUtils.getLabelCustomGraphic(label, null, 0, 0, labelPosition, tAlign, view);
+                               Shape textShape = 
ViewUtils.getLabelShape(labels.get(i), null, 0, 0, view);
+       
+                               double maxHeight = barArray[i].getWidth();
+                               textShape = ViewUtils.positionLabel(textShape, 
labelPosition, tAlign, maxHeight, 0.0, 70.0);
+                               if (textShape == null) continue;
+       
+       //                      vals[1] = new CustomGraphic(textArea, new 
DefaultPaintFactory(Color.BLACK));
+                               CustomGraphic c1  = new 
CustomGraphic(textShape, new DefaultPaintFactory(Color.BLACK));
+                               cgList.add(c1);
+                       }
+               }
+               return cgList;
+       }
+
+
+}

Added: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/LinearGradientPaintFactory.java
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/LinearGradientPaintFactory.java
                               (rev 0)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/LinearGradientPaintFactory.java
       2011-02-26 02:20:31 UTC (rev 24242)
@@ -0,0 +1,55 @@
+/* vim: set ts=2: */
+/**
+ * Copyright (c) 2010 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions, and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions, and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *   3. Redistributions must acknowledge that this software was
+ *      originally developed by the UCSF Computer Graphics Laboratory
+ *      under support by the NIH National Center for Research Resources,
+ *      grant P41-RR01081.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package nodeCharts.view;
+
+import java.awt.Color;
+import java.awt.Paint;
+import java.awt.LinearGradientPaint;
+import java.awt.geom.Rectangle2D;
+
+import cytoscape.render.stateful.PaintFactory;
+
+class LinearGradientPaintFactory implements PaintFactory {
+       private final LinearGradientPaint paint;
+
+       public LinearGradientPaintFactory(double startx, double starty, double 
endx, double endy,
+                                  final Color[] colorArray, final float[] 
stopArray) {
+               paint = new LinearGradientPaint((float)startx, (float)starty, 
(float)endx, (float)endy,
+                                               stopArray, colorArray);
+       }
+
+       public Paint getPaint(final Rectangle2D bound) {
+               // System.out.println("MyPaintFactory returning: "+color);
+               return paint;
+       }
+}

Modified: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/resources/nodeCharts/plugin.props
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/resources/nodeCharts/plugin.props
  2011-02-26 00:28:15 UTC (rev 24241)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/resources/nodeCharts/plugin.props
  2011-02-26 02:20:31 UTC (rev 24242)
@@ -11,7 +11,7 @@
 pluginDescription=Paint a chart on a node
 
 # Plugin version number, this must be two numbers separated by a decimlal.  
Ex. 0.2, 14.03
-pluginVersion=0.93
+pluginVersion=0.94
 
 # Compatible Cytoscape version
 cytoscapeVersion=2.8
@@ -29,6 +29,6 @@
 projectURL=http://www.rbvi.ucsf.edu/Research/cytoscape/
 
 # Date this plugin/plugin version was released
-releaseDate=December 21, 2010
+releaseDate=February 25, 2011
 
 # -- The following properties should be set ONLY BY CORE PLUGINS -- #

-- 
You received this message because you are subscribed to the Google Groups 
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/cytoscape-cvs?hl=en.

Reply via email to