Author: scooter
Date: 2010-09-04 22:55:50 -0700 (Sat, 04 Sep 2010)
New Revision: 21702

Modified:
   
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/NodeCharts.java
   
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/java/nodeCharts/view/PieChart.java
   
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/ViewUtils.java
Log:
Pie labels now reasonable & nodeCharts are saved with sessions, and restored
when sessions are restored


Modified: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/NodeCharts.java
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/NodeCharts.java
    2010-09-05 01:46:49 UTC (rev 21701)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/NodeCharts.java
    2010-09-05 05:55:50 UTC (rev 21702)
@@ -36,11 +36,16 @@
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 
+import java.util.List;
+
 // Cytoscape imports
+import cytoscape.CyNetwork;
 import cytoscape.Cytoscape;
+import cytoscape.command.CyCommandException;
 import cytoscape.command.CyCommandHandler;
 import cytoscape.logger.CyLogger;
 import cytoscape.plugin.CytoscapePlugin;
+import cytoscape.view.CyNetworkView;
 import cytoscape.view.CytoscapeDesktop;
 
 import nodeCharts.command.NodeChartCommandHandler;
@@ -51,7 +56,8 @@
  */
 public class NodeCharts extends CytoscapePlugin implements 
PropertyChangeListener {
        CyLogger logger;
-       CyCommandHandler handler;
+       NodeChartCommandHandler handler;
+       boolean sessionLoading = false;
 
        /**
         * The main constructor
@@ -63,6 +69,11 @@
                Cytoscape.getDesktop().getSwingPropertyChangeSupport()
                                      .addPropertyChangeListener( 
CytoscapeDesktop.NETWORK_VIEW_CREATED, this );
 
+               Cytoscape.getPropertyChangeSupport()
+                        .addPropertyChangeListener( 
Integer.toString(Cytoscape.SESSION_OPENED), this );
+               Cytoscape.getPropertyChangeSupport()
+                        .addPropertyChangeListener( Cytoscape.SESSION_LOADED, 
this );
+
                // Register our command handler
                handler = new NodeChartCommandHandler("nodecharts", logger);
        }
@@ -73,9 +84,29 @@
         * @param evt the event that triggered us
         */
        public void propertyChange(PropertyChangeEvent evt) {
-               if (evt.getPropertyName() == 
CytoscapeDesktop.NETWORK_VIEW_CREATED) {
-                       // look for our attributes
-                       // call the command handler
+               if 
(evt.getPropertyName().equals(Integer.toString(Cytoscape.SESSION_OPENED))) {
+                       sessionLoading = true;
+               } else if (evt.getPropertyName() == 
CytoscapeDesktop.NETWORK_VIEW_CREATED && !sessionLoading) {
+                       CyNetworkView newView = 
(CyNetworkView)evt.getNewValue();
+                       try {
+                               handler.reloadCharts(newView);
+                       } catch (CyCommandException e) {
+                               logger.error(e.getMessage());
+                       }
+               } else if (evt.getPropertyName() == Cytoscape.SESSION_LOADED) {
+                       sessionLoading = false;
+                       // For each loaded network that we have a view for, 
call reload charts
+                       List<String> loadedNetworks = 
(List<String>)evt.getNewValue();
+                       for (String netName: loadedNetworks) {
+                               CyNetworkView view = 
Cytoscape.getNetworkView(netName);
+                               if (view == null || view == 
Cytoscape.getNullNetworkView())
+                                       continue;
+                               try {
+                                       handler.reloadCharts(view);
+                               } catch (CyCommandException e) {
+                                       logger.error(e.getMessage());
+                               }
+                       }
                }
        }
 }

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
       2010-09-05 01:46:49 UTC (rev 21701)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/NodeChartCommandHandler.java
       2010-09-05 05:55:50 UTC (rev 21702)
@@ -44,6 +44,7 @@
 import cytoscape.CyNetwork;
 import cytoscape.CyNode;
 import cytoscape.Cytoscape;
+import cytoscape.data.CyAttributes;
 
 import cytoscape.command.AbstractCommandHandler;
 import cytoscape.command.CyCommandException;
@@ -101,9 +102,17 @@
 
        public CyCommandResult execute(String command, Map<String, Object>args)
                                                       throws 
CyCommandException, RuntimeException {
-               CyCommandResult result = new CyCommandResult();
+
                CyNetworkView view = Cytoscape.getCurrentNetworkView();
+               return executeNodeChart(command, args, true, view);
+       }
 
+
+       private CyCommandResult executeNodeChart(String command, Map<String, 
Object>args, 
+                                                boolean saveCommand, 
CyNetworkView view)
+                                                      throws 
CyCommandException, RuntimeException {
+               CyCommandResult result = new CyCommandResult();
+
                if (!args.containsKey(NODE) && !args.containsKey(NODELIST)) {
                        throw new CyCommandException("node or nodelist to map 
chart to must be specified");
                }
@@ -118,6 +127,7 @@
                        for (CyNode node: nodeList) {
                                ViewUtils.clearCustomGraphics(node, view);
                                result.addMessage("Cleared  charts for node 
"+node.getIdentifier());
+                               clearCharts(node);
                        }
                        return result;
                }
@@ -177,8 +187,10 @@
                        List<CustomGraphic> cgList = 
viewer.getCustomGraphics(args, values, labels, node, view, pos);
                        ViewUtils.addCustomGraphics(cgList, node, view);
                        result.addMessage("Created "+viewer.getName()+" chart 
for node "+node.getIdentifier());
+                       // If we succeeded, serialize the command and save it 
in the appropriate nodeAttribute
+                       if (saveCommand)
+                               saveChart(node, command, args);
                }
-
                return result;
        }
 
@@ -202,7 +214,76 @@
                viewerMap.put(viewer.getName(), viewer);
        }
 
+       
/**************************************************************************************
+        *                  Methods to save and restore chart information       
              *
+        
*************************************************************************************/
+       private static final String CHARTLISTATTR = "__nodeChartList";
+       private static final String CHARTATTR = "__nodeChart_%s_%d";
 
+       public List<CyCommandResult> reloadCharts(CyNetworkView view) throws 
CyCommandException {
+               List<CyCommandResult> resultList = new 
ArrayList<CyCommandResult>();
+               CyAttributes nodeAttributes = Cytoscape.getNodeAttributes();
+               // For each node:
+               for (CyNode node: (List<CyNode>)view.getNetwork().nodesList()) {
+                       String nodeName = node.getIdentifier();
+                       // looking for our attribute
+                       if (nodeAttributes.hasAttribute(nodeName, 
CHARTLISTATTR)) {
+                               List<String> chartList = 
nodeAttributes.getListAttribute(nodeName, CHARTLISTATTR);
+                               // for each command in the command list
+                               for (String chart: chartList) {
+                                       String command = 
chart.substring(12,chart.lastIndexOf('_'));
+                                       // Get the command args
+                                       Map<String,Object> args = 
nodeAttributes.getMapAttribute(nodeName, chart);
+                                       // Execute it
+                                       CyCommandResult comResult = 
executeNodeChart(command, args, false, view);
+                                       resultList.add(comResult);
+                               }
+                       }
+               }
+               return resultList;
+       }
+
+       private void saveChart(CyNode node, String command, 
Map<String,Object>args) {
+               // Get the list of charts we have so far
+               CyAttributes nodeAttributes = Cytoscape.getNodeAttributes();
+               String nodeName = node.getIdentifier();
+               List<String> chartList = null;
+               if (!nodeAttributes.hasAttribute(nodeName, CHARTLISTATTR)) {
+                       chartList = new ArrayList<String>();
+               } else {
+                       chartList = nodeAttributes.getListAttribute(nodeName, 
CHARTLISTATTR);
+               }
+               int nCharts = chartList.size();
+
+               // Create the new chart attribute
+               String newChartAttribute = String.format(CHARTATTR, command, 
nCharts);
+               Map<String,String> argMap = ValueUtils.serializeArgMap(args);
+               nodeAttributes.setMapAttribute(nodeName, newChartAttribute, 
argMap);
+
+               // Add it to the list
+               chartList.add(newChartAttribute);
+
+               // Save the updated list
+               nodeAttributes.setListAttribute(nodeName, CHARTLISTATTR, 
chartList);
+               nodeAttributes.setUserVisible(CHARTATTR, false);
+               nodeAttributes.setUserVisible(newChartAttribute, false);
+       }
+
+       private void clearCharts(CyNode node) {
+               CyAttributes nodeAttributes = Cytoscape.getNodeAttributes();
+               String nodeName = node.getIdentifier();
+               if (nodeAttributes.hasAttribute(nodeName, CHARTLISTATTR)) {
+                       List<String>chartList = 
nodeAttributes.getListAttribute(nodeName, CHARTLISTATTR);
+                       for (String chartAttr: chartList) {
+                               nodeAttributes.deleteAttribute(nodeName, 
chartAttr);
+                       }
+                       nodeAttributes.deleteAttribute(nodeName, CHARTLISTATTR);
+               }
+       }
+
+       
/**************************************************************************************
+        *                  Methods for special command handling                
              *
+        
*************************************************************************************/
        private CyNetwork getNetwork(String command, Map<String, Object> args) 
throws CyCommandException {
                String netName = getArg(command, 
NodeChartCommandHandler.NETWORK, args);
                if (netName == null || 
netName.equals(NodeChartCommandHandler.CURRENT))

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
    2010-09-05 01:46:49 UTC (rev 21701)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/command/ValueUtils.java
    2010-09-05 05:55:50 UTC (rev 21702)
@@ -172,7 +172,41 @@
                String[] inputArray = input.split(",");
                return Arrays.asList(inputArray);
        }
-               
+
+       /**
+        * Takes a map of objects indexed by a string keyword and returns
+        * a map of strings indexed by that keyword.  This involves figuring
+        * out if the object is a list, and if so converting it to a comma
+        * separated string
+        *
+        * @param argMap the map of objects indexed by strings
+        * @return the serialized map
+        */
+       public static Map<String,String> serializeArgMap(Map<String, Object> 
argMap) {
+               Map<String,String> sMap = new HashMap<String,String>();
+               for (String key: argMap.keySet()) {
+                       sMap.put(key, serializeObject(argMap.get(key)));
+               }
+               return sMap;
+       }
+
+       /**
+        * Serialize an object that might be a list to a string
+        */
+       private static String serializeObject(Object obj) {
+               String result;
+               if (obj instanceof List) {
+                       result = "";
+                       for (Object o: (List)obj) {
+                               result += o.toString()+",";
+                       }
+                       result = result.substring(0, result.length()-1);
+               } else
+                       result = obj.toString();
+
+               return result;
+       }
+
        private static final String RANDOM = "random";
        private static final String     CONTRASTING = "contrasting";
        private static final String     RAINBOW = "rainbow";

Modified: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/PieChart.java
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/PieChart.java
 2010-09-05 01:46:49 UTC (rev 21701)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/PieChart.java
 2010-09-05 05:55:50 UTC (rev 21702)
@@ -41,7 +41,10 @@
 
 import java.awt.Color;
 import java.awt.Paint;
+import java.awt.Shape;
 import java.awt.geom.Arc2D;
+import java.awt.geom.Area;
+import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 
 // Cytoscape imports
@@ -53,6 +56,7 @@
 import cytoscape.view.CyNetworkView;
 
 import nodeCharts.command.ValueUtils;
+import nodeCharts.view.ViewUtils.TextAlignment;
 
 /**
  * The PieChart creates a list of custom graphics where each custom graphic 
represents
@@ -137,7 +141,7 @@
        private CustomGraphic[] createSlice(Rectangle2D bbox, double arcStart, 
Double arc, String label, Color color,
                                            CyNetworkView view) {
                CustomGraphic[] vals = new CustomGraphic[2];
-               // System.out.println("Creating arc from "+arcStart+" to 
"+arc+" with color: "+color);
+               // System.out.println("Creating arc from "+arcStart+" to 
"+(arc.doubleValue()+arcStart)+" with color: "+color);
                double x = bbox.getX();
                double y = bbox.getY();
                double width = bbox.getWidth();
@@ -149,9 +153,54 @@
                PaintFactory pf = new DefaultPaintFactory(color);
                vals[0] = new CustomGraphic(slice, pf);
 
-               // Now, create the label.  We want to do this here so we can 
adjust the label for the slice
-               vals[1] = ViewUtils.getLabelCustomGraphic(label, null, 0, 0, 
slice.getBounds2D(), view);
+               double midpointAngle = arcStart + arc.doubleValue()/2;
 
+               TextAlignment tAlign = getLabelAlignment(midpointAngle);
+               
+               // Now, create the label.  Put the label on the outer edge of 
the circle.
+               Point2D labelPosition = getLabelPosition(bbox, midpointAngle, 
1.4);
+               // vals[1] = ViewUtils.getLabelCustomGraphic(label, null, 0, 0, 
labelPosition, tAlign, view);
+               Shape textShape = ViewUtils.getLabelShape(label, null, 0, 0, 
labelPosition, tAlign, view);
+
+               // Draw a line between our label and the slice
+               labelPosition = getLabelPosition(bbox, midpointAngle, 1.0);
+               Shape labelLine = 
ViewUtils.getLabelLine(textShape.getBounds2D(), labelPosition, tAlign);
+
+               // Combine the shapes
+               Area textArea = new Area(textShape);
+               textArea.add(new Area(labelLine));
+
+
+               vals[1] = new CustomGraphic(textArea, new 
DefaultPaintFactory(Color.BLACK));
+
                return vals;
        }
+
+       // Return a point on the midpoint of the arc
+       private Point2D getLabelPosition(Rectangle2D bbox, double angle, double 
scale) {
+               double midpoint = Math.toRadians(360.0-angle);
+               double length = bbox.getWidth()/2; // Assumes width = height!
+               double x = Math.cos(midpoint)*length*scale;
+               double y = Math.sin(midpoint)*length*scale;
+
+               // System.out.println("getLabelPosition: bbox = "+bbox+", 
midpoint = "+angle+" arcpoint = ("+x+","+y+")");
+
+               return new Point2D.Double(x, y);
+       }
+
+       private TextAlignment getLabelAlignment(double midPointAngle) {
+               if (midPointAngle >= 280.0 && midPointAngle < 80.0)
+                       return TextAlignment.ALIGN_LEFT;
+
+               if (midPointAngle >= 80.0 && midPointAngle < 100.0)
+                       return TextAlignment.ALIGN_CENTER_TOP;
+
+               if (midPointAngle >= 100.0 && midPointAngle < 260.0)
+                       return TextAlignment.ALIGN_RIGHT;
+
+               if (midPointAngle >= 260.0 && midPointAngle < 280.0)
+                       return TextAlignment.ALIGN_CENTER_BOTTOM;
+
+               return TextAlignment.ALIGN_LEFT;
+       }
 }

Modified: 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/ViewUtils.java
===================================================================
--- 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/ViewUtils.java
        2010-09-05 01:46:49 UTC (rev 21701)
+++ 
csplugins/trunk/ucsf/scooter/nodeCharts/src/main/java/nodeCharts/view/ViewUtils.java
        2010-09-05 05:55:50 UTC (rev 21702)
@@ -32,6 +32,7 @@
  */
 package nodeCharts.view;
 
+import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Font;
 import java.awt.Graphics2D;
@@ -39,6 +40,7 @@
 import java.awt.font.FontRenderContext;
 import java.awt.font.TextLayout;
 import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
 
@@ -178,10 +180,12 @@
        private static final int DEFAULT_STYLE=Font.PLAIN;
        private static final int DEFAULT_SIZE=8;
 
-       public static CustomGraphic getLabelCustomGraphic(String label, String 
fontName, int fontStyle, int fontSize,
-                                                         Rectangle2D bbox, 
CyNetworkView view) {
+       public static enum TextAlignment {ALIGN_LEFT, ALIGN_CENTER_TOP, 
ALIGN_RIGHT, ALIGN_CENTER_BOTTOM};
 
+       public static Shape getLabelShape(String label, String fontName, int 
fontStyle, int fontSize,
+                                         Point2D position, TextAlignment 
tAlign, CyNetworkView view) {
 
+
                if (fontName == null) fontName = DEFAULT_FONT;
                if (fontStyle == 0) fontStyle = DEFAULT_STYLE;
                if (fontSize == 0) fontSize = DEFAULT_SIZE;
@@ -194,41 +198,89 @@
                TextLayout tl = new TextLayout(label, font, frc);
                Shape lShape = tl.getOutline(null);
 
+               // System.out.println("  Label = "+label);
+
                // Figure out how to move the text to center it on the bbox
-               double textWidth = lShape.getBounds2D().getMaxX(); // This 
assumes that our text starts at 0
-               double xStart = bbox.getBounds2D().getMinX();
-               double width = bbox.getBounds2D().getMaxX() - xStart;
-               double textStartX = xStart+(width-textWidth)/2;
+               double textWidth = lShape.getBounds2D().getMaxX() - 
lShape.getBounds2D().getMinX(); 
+               double textHeight = lShape.getBounds2D().getMaxY() - 
lShape.getBounds2D().getMinY();
 
-               double textHeight = lShape.getBounds2D().getMaxY();
-               double yStart = bbox.getBounds2D().getMinY();
-               double height = bbox.getBounds2D().getMaxY() - yStart;
-               double textStartY = yStart+(height-textHeight)/2;
+               // System.out.println("  Text size = 
("+textWidth+","+textHeight+")");
 
-               // System.out.println("  Label = "+label);
+               double pointX = position.getX();
+               double pointY = position.getY();
+
+               double textStartX = pointX;
+               double textStartY = pointY;
+
+               switch (tAlign) {
+               case ALIGN_CENTER_TOP:
+                       // System.out.println("  Align = CENTER_TOP");
+                       textStartX = pointX + textWidth/2;
+                       textStartY = pointY + textHeight;
+                       break;
+               case ALIGN_CENTER_BOTTOM:
+                       // System.out.println("  Align = CENTER_BOTTOM");
+                       textStartX = pointX + textWidth/2;
+                       textStartY = pointY - textHeight;
+                       break;
+               case ALIGN_RIGHT:
+                       // System.out.println("  Align = RIGHT");
+                       textStartX = pointX - textWidth;
+                       textStartY = pointY + textHeight/2;
+                       break;
+               case ALIGN_LEFT:
+                       // System.out.println("  Align = LEFT");
+                       textStartX = pointX;
+                       textStartY = pointY + textHeight/2;
+                       break;
+               default:
+                       // System.out.println("  Align = "+tAlign);
+               }
+
                // System.out.println("  Text bounds = "+lShape.getBounds2D());
-               // System.out.println("  Bounding box = "+bbox);
+               // System.out.println("  Position = "+position);
 
                // System.out.println("  Offset = 
("+textStartX+","+textStartY+")");
 
-               double scale = 1.0;
-               // If our bounds are much larger than the bounding box, scale 
ourselves.
-               if (textWidth < width/3) 
-                       scale = 2;
-               else if (width < textWidth/3) 
-                       scale = .5;
-
                // Use the bounding box to create an Affine transform.  We may 
need to scale the font
                // shape if things are too cramped, but not beneath some 
arbitrary minimum
                AffineTransform trans = new AffineTransform();
-               trans.setToScale(scale, scale);
                trans.translate(textStartX, textStartY);
 
                // System.out.println("  Transform: "+trans);
-               
-               return new CustomGraphic(trans.createTransformedShape(lShape), 
new DefaultPaintFactory(Color.BLACK));
+               return trans.createTransformedShape(lShape);
        }
 
+       /**
+        * This is used to draw a line from a text box to an object -- for 
example from a pie label to
+        * the pie slice itself.
+        */
+       public static Shape getLabelLine(Rectangle2D textBounds, Point2D 
labelPosition, TextAlignment tAlign) {
+               double lineStartX = 0;
+               double lineStartY = 0;
+               switch (tAlign) {
+                       case ALIGN_CENTER_TOP:
+                               lineStartY = textBounds.getMaxY();
+                               lineStartX = textBounds.getCenterX();
+                       break;
+                       case ALIGN_CENTER_BOTTOM:
+                               lineStartY = textBounds.getMinY();
+                               lineStartX = textBounds.getCenterX();
+                       break;
+                       case ALIGN_RIGHT:
+                               lineStartY = textBounds.getCenterY();
+                               lineStartX = textBounds.getMaxX();
+                       break;
+                       case ALIGN_LEFT:
+                               lineStartY = textBounds.getCenterY();
+                               lineStartX = textBounds.getMinX();
+                       break;
+               }
+
+               BasicStroke stroke = new BasicStroke(0.5f);
+               return stroke.createStrokedShape(new Line2D.Double(lineStartX, 
lineStartY, labelPosition.getX(), labelPosition.getY()));
+       }
+
        private static Rectangle2D positionAdjust(Rectangle2D.Double bbox, 
Object pos) {
                if (pos == null)
                        return bbox;

-- 
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