package uk.ac.rhul.cs.cl1.ui.cytoscape;
import giny.model.Node;
import java.awt.Color;
import java.util.List;
import cytoscape.CyNetwork;
import cytoscape.Cytoscape;
import cytoscape.data.CyAttributes;
import cytoscape.visual.CalculatorCatalog;
import cytoscape.visual.NodeAppearanceCalculator;
import cytoscape.visual.NodeShape;
import cytoscape.visual.VisualMappingManager;
import cytoscape.visual.VisualPropertyType;
import cytoscape.visual.VisualStyle;
import cytoscape.visual.calculators.BasicCalculator;
import cytoscape.visual.calculators.Calculator;
import cytoscape.visual.mappings.BoundaryRangeValues;
import cytoscape.visual.mappings.ContinuousMapping;
import cytoscape.visual.mappings.DiscreteMapping;
import cytoscape.visual.mappings.LinearNumberToColorInterpolator;
import cytoscape.visual.mappings.ObjectMapping;
/**
* Class responsible for registering and maintaining ClusterONE related
* visual styles in Cytoscape.
*
* @author ntamas
*/
public class VisualStyleManager {
/**
* VizMapper visual style name for coloring nodes by their status
*/
public static final String VISUAL_STYLE_BY_STATUS = "ClusterONE - Status";
/**
* VizMapper visual style name for coloring nodes by their status
*/
public static final String VISUAL_STYLE_BY_AFFINITY = "ClusterONE - Affinity";
/**
* Ensure that the ClusterONE VizMapper styles are registered
*
* @param recreate whether to re-create the styles even if they exist
*/
public static void ensureVizMapperStylesRegistered(boolean recreate) {
VisualMappingManager visualMappingManager = Cytoscape.getVisualMappingManager();
if (visualMappingManager == null)
return; /* no visual mapping manager, we cannot do anything */
CalculatorCatalog calculatorCatalog = visualMappingManager.getCalculatorCatalog();
if (calculatorCatalog == null)
return; /* no calculator catalog, we cannot do anything */
ensureVisualStyleByStatusRegistered(calculatorCatalog, recreate);
ensureVisualStyleByAffinityRegistered(calculatorCatalog, recreate);
}
/**
* Ensure that the visual style that colors nodes by their statuses is registered.
*
* This method uses some features of Cytoscape that are deprecated from 2.8
* onwards. We suppress the deprecation warnings since we want to keep on
* supporting older versions of Cytoscape for as long as possible. The
* Cytoscape documentation says that the deprecated functions will be removed
* in Nov 2011.
*
* @param catalog the Cytoscape {@link CalculatorCatalog} where the style
* has to be registered
* @param recreate whether to re-create the styles even if they exist
*/
@SuppressWarnings("deprecation")
private static void ensureVisualStyleByStatusRegistered(
CalculatorCatalog catalog, boolean recreate) {
if (catalog.getVisualStyleNames().contains(VISUAL_STYLE_BY_STATUS)) {
if (!recreate)
return;
catalog.removeVisualStyle(VISUAL_STYLE_BY_STATUS);
}
/* Get the default visual style (if exists) */
VisualStyle defaultStyle = catalog.getVisualStyle("default");
if (defaultStyle == null)
defaultStyle = new VisualStyle("default");
VisualStyle myStyle = new VisualStyle(defaultStyle, VISUAL_STYLE_BY_STATUS);
NodeAppearanceCalculator nac = myStyle.getNodeAppearanceCalculator();
/* Create the node color calculator */
DiscreteMapping colorMapping = new DiscreteMapping(Color.WHITE, CytoscapePlugin.ATTRIBUTE_STATUS, ObjectMapping.NODE_MAPPING);
colorMapping.putMapValue("Outlier", Color.LIGHT_GRAY);
colorMapping.putMapValue("Cluster", Color.RED);
colorMapping.putMapValue("Overlap", Color.ORANGE);
Calculator nodeColorCalculator = new BasicCalculator("Vertex color calculator", colorMapping, VisualPropertyType.NODE_FILL_COLOR);
/* Create the node shape calculator */
DiscreteMapping shapeMapping = new DiscreteMapping(NodeShape.RECT, CytoscapePlugin.ATTRIBUTE_STATUS, ObjectMapping.NODE_MAPPING);
shapeMapping.putMapValue("Outlier", NodeShape.ELLIPSE);
shapeMapping.putMapValue("Cluster", NodeShape.RECT);
shapeMapping.putMapValue("Overlap", NodeShape.DIAMOND);
Calculator nodeShapeCalculator = new BasicCalculator("Vertex shape calculator", shapeMapping, VisualPropertyType.NODE_SHAPE);
nac.setCalculator(nodeColorCalculator);
nac.setCalculator(nodeShapeCalculator);
myStyle.setNodeAppearanceCalculator(nac);
catalog.addVisualStyle(myStyle);
}
/**
* Ensure that the visual style that colors nodes by their affinities to
* a cluster is registered.
*
* This method uses some features of Cytoscape that are deprecated from 2.8
* onwards. We suppress the deprecation warnings since we want to keep on
* supporting older versions of Cytoscape for as long as possible. The
* Cytoscape documentation says that the deprecated functions will be removed
* in Nov 2011.
*
* @param catalog the Cytoscape {@link CalculatorCatalog} where the style
* has to be registered
* @param recreate whether to re-create the styles even if they exist
*/
@SuppressWarnings("deprecation")
private static void ensureVisualStyleByAffinityRegistered(
CalculatorCatalog catalog, boolean recreate) {
if (catalog.getVisualStyleNames().contains(VISUAL_STYLE_BY_AFFINITY)) {
if (!recreate)
return;
catalog.removeVisualStyle(VISUAL_STYLE_BY_AFFINITY);
}
/* Get the maximum absolute value corresponding to the affinity attribute (if any) */
CyAttributes nodeAttrs = Cytoscape.getNodeAttributes();
CyNetwork currentNetwork = Cytoscape.getCurrentNetwork();
double maxAbsValue = 0.0;
@SuppressWarnings("unchecked")
List<Node> nodeList = (List<Node>)currentNetwork.nodesList();
for (Node node: nodeList) {
Object obj = nodeAttrs.getAttribute(node.getIdentifier(), CytoscapePlugin.ATTRIBUTE_AFFINITY);
if (obj == null)
continue;
try {
Double affinity = (Double)obj;
if (Math.abs(affinity) > maxAbsValue)
maxAbsValue = Math.abs(affinity);
} catch (ClassCastException ex) {
}
}
/* Get the default visual style (if exists) */
VisualStyle defaultStyle = catalog.getVisualStyle("default");
if (defaultStyle == null)
defaultStyle = new VisualStyle("default");
VisualStyle myStyle = new VisualStyle(defaultStyle, VISUAL_STYLE_BY_AFFINITY);
NodeAppearanceCalculator nac = myStyle.getNodeAppearanceCalculator();
/* Create the node color calculator */
Color minColor = Color.blue;
Color midColor = Color.white;
Color maxColor = Color.red;
ContinuousMapping colorMapping = new ContinuousMapping(Color.WHITE, ObjectMapping.NODE_MAPPING);
colorMapping.setControllingAttributeName(CytoscapePlugin.ATTRIBUTE_AFFINITY, Cytoscape.getCurrentNetwork(), false);
colorMapping.setInterpolator(new LinearNumberToColorInterpolator());
colorMapping.addPoint(-maxAbsValue, new BoundaryRangeValues(minColor, minColor, minColor));
colorMapping.addPoint(0.0, new BoundaryRangeValues(midColor, midColor, midColor));
colorMapping.addPoint(maxAbsValue, new BoundaryRangeValues(maxColor, maxColor, maxColor));
Calculator nodeColorCalculator = new BasicCalculator("Vertex color calculator", colorMapping, VisualPropertyType.NODE_FILL_COLOR);
/* Create the node shape calculator */
DiscreteMapping shapeMapping = new DiscreteMapping(NodeShape.RECT, CytoscapePlugin.ATTRIBUTE_STATUS, ObjectMapping.NODE_MAPPING);
shapeMapping.putMapValue("Outlier", NodeShape.ELLIPSE);
shapeMapping.putMapValue("Cluster", NodeShape.RECT);
shapeMapping.putMapValue("Overlap", NodeShape.DIAMOND);
Calculator nodeShapeCalculator = new BasicCalculator("Vertex shape calculator", shapeMapping, VisualPropertyType.NODE_SHAPE);
nac.setCalculator(nodeColorCalculator);
nac.setCalculator(nodeShapeCalculator);
myStyle.setNodeAppearanceCalculator(nac);
catalog.addVisualStyle(myStyle);
}
/**
* Updates the continuous mapping used to colour the vertices by their affinities to
* reflect the new range of affinity values after some of the attribute values changed.
*/
public static void updateAffinityStyleRange() {
// TODO Auto-generated method stub
}
}