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.