<> == Basic definitions == A '''data attribute''' is a key-value pair, where the key is a string identifying the attribute and the value is a number, String, or other type of object. A data attribute is attached to a name, which itself is associated with a particular graph object, but the class of a particular data attribute will be the same for all graph objects of the same type. For example, the "interaction" attribute for edges is of the same type for every edge (a String, in this case). Cytoscape holds two data structures, one for all node attributes and one for all edge attributes. Usage is of the form {{{#!java nodeAttributes.set(objectName, attributeName, value); Object value = nodeAttributes.get(objectName, attributeName); }}} A '''Network''' is an object that contains a Graph and the associated node and edge attribute structures. A '''visual attribute''' is a single atomic component of the visual appearance of the objects in the graph. For example, the shape of a node is one visual attribute, while the fill color of the node is a different visual attribute. There are many visual attributes for nodes and edges, and there are also a few global visual attributes, such as the background color of the window in which the graph is displayed. A '''calculator''' is an object that, given a Network and a particular node or edge of interest, can calculate a value of an appropriate type for a particular visual attribute. Calculators are typed by the graph object type (Node or Edge) and by the class of the value to return: for example, Color, String, or {{{LineType}}}. Some visual attributes use the same type of calculator; for example, calculators for the node fill color and node border color are both {{{NodeColorCalculator}}} objects. Currently there are no calculators for the global visual attributes. Calculators are referenced by name and stored in a global catalog. An '''appearance calculator''' is an object that holds default values and calculators for a set of related individual visual attributes, and methods to apply these given a particular node or edge of interest. There are three different appearance calculators: one for nodes, one for edges, and one for global visual attributes. A '''visual style''' bundles one each of the three appearance calculators and thus contains a complete definition of all the customizable visual attributes. Visual styles are also referenced by name and stored in the global catalog. A common usage is to define a visual style for each distinct Cytoscape project, often sharing individual attribute calculators. == Conceptual overview == Cytoscape maintains a catalog of all the known visual styles and all the known calculators. Each of these has an identifying name which is unique among its type; for example, every {{{NodeColorCalculator}}} has a unique name, but {{{NodeLabelCalculators}}} can use those names as well. Cytoscape itself constructs a visual style called "default" which is used in the absence of any user-specified style. At any point in time, one particular visual style is being used by Cytoscape to control the appearance of the graph. A visual style is represented by an object of class {{{VisualStyle}}} and contains three other objects, one for the node appearance, one for the edge appearance, and one for the global appearance. The first two of these can compute, for a given node or edge, a data bundle (formally a class with public members) that contains a full set of values to use for the visual attributes of that particular node or edge. Similarly, the global appearance member of the visual style can construct a data object holding the global visual attribute values. These data objects are then used by Cytoscape, via calls to the graph visualization library, to set the visual appearance of the whole graph. Thus, except for the very top-level class that applies the appearances, the visual package is conceptually independent of the details of the graph library used to display the graph. This independence is broken in two ways: 1. The particular names and types of visual attributes have been chosen to be meaningful with respect to to the particular graph library (GINY) we're currently using; 2. The references to Node and Edge objects, plus certain special visual attributes like Arrow, require importing the defintion of these objects from the graph library. For every visual attribute defined, the visual style will contain (within one of it's three members) a default value; there may also be a calculator for that visual attribute that can compute a value based on the available data attributes. Typical usage includes: creating a new visual style or copying an existing one; changing the default values for a particular visual attribute; getting a calculator from the catalog and installing it in the visual style; modifying the parameters of an existing calculator; or creating a new calculator and adding it to both the catalog and the visual style. The visual package contains utilities to store the catalog of known visual styles and calculators as a Java properties file, and to reconstruct the catalog from this file. This allows visual style defintions to be persistent across Cytoscape sessions. The {{{CytoscapeWindow}}} class contains methods that use these features, for example saving the catalog when the program exits and reconstructing it at startup. The next section will give a quick presentation of the classes that provide these features. == Top-down class descriptions == === A basic understanding of how the conceptual model is implemented in Java classes === In the previous section, we presented the conceptual model of the visual pacakge. Here, we'll see how this model is implemented in concrete Java classes. The objective here is to give you a general understanding of the responsibilities of each class, without going into detail concerning implementations or the full API of each class. Refer to the class documentation for more information on any of these classes. This section begins at the top-level class and continues to the level of abstract calculators; a later section will describe how individual calculators are implemented within the visual package. The figure below illustrates the relationships of the classes we will describe here. === VisualMappingManger === At the top is the {{{VisualMappingManager}}} class. {{{CytoscapeWindow}}} holds one instance of this class, which encapsulates all the data structures relevant to visual mapping. {{{VisualMappingManager}}} contains a {{{CalculatorCatalog}}}, which contains all of the known {{{VisualStyle}}} and calculator objects, and one {{{VisualStyle}}} object which represents the current visual style. === CalculatorCatalog === {{{CalculatorCatalog}}} contains a Map structure for visual styles and a Map for each type of calculator. Within each Map the key is the name and the value is the {{{VisualStyle}}} or calculator object. This class includes the obvious methods to add a new object or get one with a specified name, as well as a number of helper methods for the user interface to the visual package. === VisualStyle, Appearances, and AppearanceCalculators === The {{{VisualStyle}}} object has a name and contains three member objects; a {{{NodeAppearanceCalculator}}}, an {{{EdgeAppearanceCalculator}}}, and a {{{GlobalAppearanceCalculator}}}. Each of these objects, in turn, contains a default value for each visual attribute and a (possibly null) reference to a calculator for each visual attribute. Each of these three appearance calculators has a method for calculating an appearance object; the signatures are, respectively, {{{#!java public NodeAppearance calculateNodeAppearance(Network network, Node node); public EdgeAppearance calculateEdgeAppearance(Network network, Edge edge); public GlobalAppearance calculateGlobalAppearance(Network network); }}} These methods work by calling the appropriate calculator (if it exists) for each visual attribute; using the default value if no calculator is installed or if it returns a null value; and storing the resulting value in the constructed appearance object. These three appearance objects are simply data bundles, classes with all public members, each holding a value for a particular visual attribute. When the top-level {{{VisualMappingManager}}} is told to apply its visual appearances, it calls the calculate methods on the three appearance calculator objects in its {{{VisualStyle}}} to get the appearance objects, then uses the data within those objects in calls to the graph library to set the visual appearance of the displayed graph. This code is contained in the applyAppearances method of {{{VisualMappingManager}}}. Thus, everything below {{{VisualMappingManager}}} is conceptually independent of the particular graph library in use. In practice, the default values and calculators that the appearance calculators recognize are tuned to the particular visual attributes supported by the graph library. In addition, some specific classes such as Node, Edge, Arrow, and {{{LineType}}} are defined within the graph package itself, so the appearance calculators, as well as the invididual attribute calculators, import these classes from the graph library. === Attribute Calculators === Individual attribute calculators are identified by an interface whose name contains the type of graph object (Node or Edge) and the type of the visual attribute value. Examples include {{{NodeColorCalculator}}}, {{{NodeLabelCalculator}}}, and {{{EdgeLineTypeCalculator}}}. Each interface specifies a method that calculates the visual attribute value; the signatures for these three examples are, respectively, {{{#!java public Color calculateNodeColor(Network network, Node node); public String calculateNodeLabel(Network network, Node node); public LineType calculateEdgeLineType(Network network, Edge edge); }}} Currently there are no calculators for global visual attributes; this is only because there is currently no need for this feature, but the calculator design could easily be extended to support such calculators. in addition to the main calculate method, these interfaces all inherit from the abstract Calculator interface that defines several methods all calculators must support. These include a getUI() method that returns a user interface to the calculator; methods to get and set the name of the calculator, and methods to convert the calculator to and from a Properties object, to support storing calculators as a properties file. Note that in some cases, different visual attributes use the same type of calculator. For example, {{{NodeAppearanceCalculator}}} contains a {{{nodeFillColorCalculator}}} and a {{{nodeBorderColorCalculator}}}; both of these are instances of {{{NodeColorCalculator}}}, since it makes perfect sense to apply the same calculator to either of these visual attributes that share the same type. However, edge colors are calculated by instances of {{{EdgeColorCalculator}}}; this difference exists because these calculators expect to operate on different data attributes (edge attributes instead of node attributes). The node width and node height visual attributes require special mention. In some cases it's desired for these attributes to be independent (allowing arbitrary aspect ratios), while in other cases these attributes should always hold the same value to produce symmetric shapes. This often depends on the node shape; for example, rectangles require a width different from the height, while circles require the two to be equal. This is supported within {{{NodeAppearanceCalculator}}} by a boolean flag which, if true, uses only the default node height and node height calculator for both the width and height of a node, thus forcing the width of every node to be equal to the height. In either case, a {{{NodeSizeCalculator}}} is used for either or both of these visual attributes. === Input and Output from file === Input and output of the {{{CalculatorCatalog}}} from a properties file is provided by the {{{CalculatorIO}}} class. This class contains static methods that, given a properties file and a catalog, either load the definitions from the file and install them in the catalog, or represent the catalog as properties and save it to file. These methods work by grouping the properties that define each object and delegating to helper methods and factory objects that convert between calculator objects and their properties description. Before this visual package was created, a different package (called cytoscape.vizmap) was used to specify visual mappings, which used entries in the cytoscape.props file. The class {{{OldStyleCalculatorIO}}} contains methods to handle this old format. They search the properties object read from the various cytoscape.props files for these old-style mappings, and guide the user (via a window interface) to convert them to the new format. This works by converting key-value pairs of the old properties format into the new format, then sending these converted properties through the machinery of CalculatorIO. This functionality is expected to go away once all users have had a chance to convert their visual specifications into the new format. == Common usage of the visual package == === Code snippets that show how to do common operations === In this section, we present code snippets that illustrate the calls a plugin writer would use to perform some common operations. To access the top-level objects: {{{#!java //returns CytoscapeWindow's VisualMappingManager object VisualMappingManager vmm = cytoscapeWindow.getVizMapManager(); //gets the global catalog of visual styles and calculators CalculatorCatalog catalog = vmm.getCalculatorCatalog(); //gets the currently active visual style VisualStyle currentStyle = vmm.getVisualStyle(); //methods to access the node, edge, and global appearance calculators NodeAppearanceCalculator nodeAC = currentStyle.getNodeAppearanceCalculator(); EdgeAppearanceCalculator edgeAC = currentStyle.getEdgeAppearanceCalculator(); GlobalAppearanceCalculator globalAC = currentStyle.getGlobalAppearanceCalculator(); }}} Default values: {{{#!java nodeAC.setDefaultNodeHeight(50.0); nodeAC.setDefaultNodeShape(ShapeNodeRealizer.ELLIPSE); nodeAC.setNodeSizeLocked(true); //width==height, so default will be a circle edgeAC.setDefaultEdgeArrow(Arrow.STANDARD); globalAC.setDefaultBackgroundColor( new Color(255,255,204) );//pale yellow Color defaultNodeFillColor = nodeAC.getDefaultNodeFillColor(); LineType defaultEdgeLineType = edgeAC.getDefaultEdgeLineType(); Color newBackgroundColor = globalAC.getDefaultBackgroundColor();//pale yellow }}} Calculators: {{{#!java NodeColorCalculator ncc = catalog.getNodeColorCalculator("myFillColor"); nodeAC.setNodeFillColorCalculator(ncc); EdgeArrowCalculator eac = catalog.getEdgeArrowCalculator("mySourceArrow"); edgeAC.setEdgeSourceArrowCalculator(eac); NodeLabelCalculator nlc = nodeAC.getNodeLabelCalculator(); EdgeFontCalculator efc = edgeAC.getEdgeFontCalculator(); }}} Changing styles: {{{#!java VisualStyle newStyle = catalog.getVisualStyle("Project B"); vmm.setVisualStyle(newStyle); }}} Creating a new style with default settings: {{{#!java VisualStyle newStyle = new VisualStyle("name of new style"); catalog.addVisualStyle(newStyle); }}} Copying an existing style: {{{#!java VisualStyle newStyle = new VisualStyle(oldStyle); newStyle.setName("name of new style"); vatalog.addVisualStyle(newStyle); }}} == Generic calculators and mappings == === How calculators are implemented within the visual package, and how to set their parameters === The top-level classes of the visual package were described in a previous section. The actual calculation of visual attribute values from data attribute values is performed by calculator objects, which are described here. The relevant classes are found in the visual.calculators and visual.mappings packages. Formally, a calculator object is any object that implements one of the interfaces defined in the visual.calculators package. The names of these interfaces are all of the form '''''Calculator''''' where the object type is either "Node" or "Edge" and the return type is the name of the returned type class. Examples include {{{NodeColorCalculator}}} and {{{EdgeArrowCalculator}}}. Each of these interfaces defines a particular calculate method that takes appropriate arguments and returns an object of the correct type. For example, the methods in {{{NodeColorCalculator}}} and {{{EdgeArrowCalculator}}} have the following signatures: {{{#!java public Color calculateNodeColor(Network network, Node node); public Arrow calculatorEdgeArrow(Network network, Edge edge); }}} Recall that a Network object contains the graph and data attributes, and thus contains all the data needed to calculate the return value. All of these interfaces extend the generic Calculator interface, which defines other methods shared by all calculators. A key pair of methods allow getting and setting the name of the calculator. Every calculator must have a name, which is used to uniquely identify that calculator. For example, the name of the calculator is used in the {{{CalculatorCatalog}}} as the key to the Map of calculator objects, and in the property keys used to save the calculator to file. Note that two calculators of different types may share the same name, but two calculators that implement the same interface should have different names. When creating a new calculator, it is essential to make sure that a unique name is provided to prevent collisions with an existing calculator. For this reason, {{{CalculatorCatalog}}} provides methods of the form {{{ public String checkNodeColorCalculatorName(String name); }}} If no {{{NodeColorCalculator}}} currently has the given name, then that name is returned. Otherwise, this method adds an integer to the end of the name to make a unique name (for example, "myCalc", "myCalc2", "myCalc3", etc.). === Implementation === The calculator interfaces, by themselves, do not specify how the actual calculation of the return value should be done. Thus, in theory, any arbitrarily complex function could be used; for example, calculating the color of a node based on the data attributes of the nodes in its graph neighborhood. The visual package provides a generic implementation that is useful in many circumstances. The basic idea of the generic calculator implementations is to delegate to another object that performs two services: 1. Given the data attributes for the particular node or edge of interest, it extracts one of the data attributes by name 2. Using that data value, it gets an Object according to some kind of lookup table and returns it. The generic calculators then cast that Object to the desired type and return it. Type safety is ensured by controlling the entries in the lookup table. The advantage of this implementation is that all of the different types of calculators can be supported with a small set of objects that provide different types of mappings. This makes the job of implementation (especially of the user interface to these objects) much simpler. The disadvantage is that these implementations only allow the visual attribute value to depend on a single data attribute of the particular node or edge being considered. All of the generic calculator class names are of the form '''''Generic''''' For example, {{{GenericNodeColorCalculator}}} or {{{GenericEdgeArrowCalculator}}}. Each of these classes inherit either from {{{NodeCalculator}}} or {{{EdgeCalculator}}}, which in turn inherit from {{{AbstractCalculator}}}. These abstract superclasses provide utilities used by all the generic calculators, for example holding the calculator name. Each generic calculator wraps an instance of the {{{ObjectMapping}}} interface. The key method defined in this interface is {{{ public Object calculateRangeValue(Map attrBundle); }}} Here, the argument is the set of attributes defined for the particular node or edge being considered. All instances of {{{ObjectMapping}}} extract one attribute from this Map using the name defined by {{{#!java public String getControllingAttributeName(); public void setControllingAttributeName(String attrName, Network network, boolean preserveMapping); }}} To get the data value. (In the set method, the extra arguments are provided to allow the mapping to get the existing data values for the new attribute to help in building the lookup table.) How this data value is used depends on the particular instance; the visual package defines three instances, {{{PassthroughMapping}}}, {{{DiscreteMapping}}}, and {{{ContinuousMapping}}}. In a {{{PassthroughMapping}}}, the data value is itself type-checked and returned. This kind of mapping is most commonly used for labels, where one data attribute of the node or edge is a String name, and that String itself should be returned as the label. This type of mapping can be used whenever the data attribute holds the actual value to use for the visual attribute. In a {{{DiscreteMapping}}}, the data value is used as the key in a lookup table (formally a Map structure). The entries in a {{{DiscreteMapping}}} are restricted so that the keys are of the same type as the data value, and the values are of the correct return type. Currently, only String and Number data attributes are supported. This kind of mapping is best used when the data attribute can have a small number of discrete values, and one wants to define a visual attribute value to use for each different case. For example, if there are a few different types of edges, a {{{DiscreteMapping}}} can be used to set the color to use for each edge type. In a {{{ContinuousMapping}}}, the data attribute must be a number (formally, an instance of java.lang.Number). Certain special data values, termed boundary values, are defined and mapped to visual attribute values. If the visual attribute is itself continuous (like Color or Number), then a data value associated with a particular node or edge is used in a linear interpolation between the boundary values to compute the visual attribute value. For example, if the data value 0.0 is mapped to white and 1.0 is mapped to green, then the data value 0.5 would map to 50% green. If the visual attribute is instead discrete, for example node shape, then a range of input values maps to a particular visual attribute value. == Building and using your own calculator class == '''To be filled in'''