Author: clopes
Date: 2011-07-22 13:51:02 -0700 (Fri, 22 Jul 2011)
New Revision: 26254

Added:
   
cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/model/data/InteractionVOTest.as
Modified:
   cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
   cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/AllTests.as
   cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/GraphProxy.as
   
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/converters/ExternalObjectConverter.as
   
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/data/InteractionVO.as
   
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/layout/ForceDirectedLayout.as
Log:
Created default "merged" data attributes for merged edges, so visual mappers 
can be correctly applied to merged edges.

Modified: cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js    
2011-07-22 19:26:33 UTC (rev 26253)
+++ cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js    
2011-07-22 20:51:02 UTC (rev 26254)
@@ -896,7 +896,7 @@
          * use {@link org.cytoscapeweb.Visualization#visualStyle} or {@link 
org.cytoscapeweb.Visualization#visualStyleBypass}.</p>
          * <p>If you try to change an attribute that has not been previously 
defined, Cytoscape Web will throw an {@link org.cytoscapeweb.Error}.
          * In this case, you have to add the attribute definition first, by 
calling {@link org.cytoscapeweb.Visualization#addDataField}.</p>
-         * <p>Another important thing to remember is that you cannot directly 
change merged edges attributes.</p>
+         * <p>Another important thing to remember is that you cannot update 
merged edges data, since they are derived attributes.</p>
          * <p>Finally, all the continuous and custom mappers - defined by the 
current visual style - will be automatically recomputed after
          * updating the data.</p>
          * 

Modified: 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/GraphProxy.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/GraphProxy.as    
2011-07-22 19:26:33 UTC (rev 26253)
+++ cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/GraphProxy.as    
2011-07-22 20:51:02 UTC (rev 26254)
@@ -56,6 +56,8 @@
        import org.cytoscapeweb.model.data.GraphicsDataTable;
        import org.cytoscapeweb.model.data.InteractionVO;
        import org.cytoscapeweb.model.data.VisualStyleVO;
+       import org.cytoscapeweb.model.error.CWError;
+       import org.cytoscapeweb.util.ErrorCodes;
        import org.cytoscapeweb.util.Groups;
        import org.cytoscapeweb.util.Layouts;
        import org.puremvc.as3.patterns.proxy.Proxy;
@@ -230,7 +232,7 @@
                
                for (var key:String in _interactions) {
                var inter:InteractionVO = _interactions[key];
-               inter.update();
+               inter.update(edgesSchema);
             }
             
             if (value == null) graphData.removeGroup(Groups.FILTERED_EDGES);
@@ -414,20 +416,41 @@
         
         public function updateData(ds:DataSprite, data:Object):void {
             if (ds != null && data != null) {
+                if (ds is EdgeSprite && ds.props.$merged) {
+                    throw new Error("It is not allowed to update a merged edge 
data: " + ds.data.id);
+                }
+                
                 var schema:DataSchema = ds is NodeSprite ? _nodesSchema : 
_edgesSchema;
+                var updated:Boolean = false;
                 
                 for (var k:String in data) {
                     if ( k !== "id" && !(ds is EdgeSprite && (k === "source" 
|| k === "target")) ) {
                         var f:DataField = schema.getFieldByName(k);
+                        
                         if (f != null) {
                             var v:* = data[k];
-                            v = ExternalObjectConverter.normalizeDataValue(v, 
f.type, f.defaultValue);
+                            
+                            try {
+                                v = 
ExternalObjectConverter.normalizeDataValue(v, f.type, f.defaultValue);
+                            } catch (err:Error) {
+                                throw new CWError("Cannot update data for 
'"+k+"':" + err.message,
+                                                  
ErrorCodes.INVALID_DATA_CONVERSION);
+                            }
+                            
                             ds.data[k] = v;
+                            updated = true;
                         } else {
-                            throw new Error("Cannot update data: there is no 
Data Field for '"+k+"'.");
+                            throw new CWError("Cannot update data: there is no 
Data Field for '"+k+"'.");
                         }
                     }
                 }
+                
+                if (ds is EdgeSprite && updated) {
+                    // Update the merged edge data
+                    var edge:EdgeSprite = EdgeSprite(ds);
+                    var interaction:InteractionVO = 
getInteraction(edge.source, edge.target);
+                    interaction.update(edgesSchema);
+                }
             }
         }
 
@@ -537,7 +560,8 @@
                     }
                 }
 
-                for (var key:String in interactions) 
interactions[key].update();
+                for (var key:String in interactions)
+                    interactions[key].update(edgesSchema, false);
             }
             
             return changed;
@@ -594,7 +618,7 @@
             if (inter == null) {
                 inter = createInteraction(e.source, e.target);
             } else {
-                inter.update();
+                inter.update(edgesSchema);
             }
             
             return e;
@@ -656,7 +680,7 @@
                     var edgeCount:int = inter.edges.length;
                     
                     if (edgeCount > 0) {
-                        inter.update();
+                        inter.update(edgesSchema);
                     } else {
                         delete _interactions[inter.key];
                         removeEdge(inter.mergedEdge);
@@ -852,7 +876,7 @@
             var inter:InteractionVO;
             
             if (getInteraction(source, target) == null) {
-                inter = new InteractionVO(source, target);
+                inter = new InteractionVO(source, target, edgesSchema);
                 _interactions[inter.key] = inter;
                 
                 var me:EdgeSprite = inter.mergedEdge;

Modified: 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/converters/ExternalObjectConverter.as
===================================================================
--- 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/converters/ExternalObjectConverter.as
    2011-07-22 19:26:33 UTC (rev 26253)
+++ 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/converters/ExternalObjectConverter.as
    2011-07-22 20:51:02 UTC (rev 26254)
@@ -151,7 +151,12 @@
                                 default: mandatoryDefValue = null;
                             }
                             
-                            defValue = normalizeDataValue(obj[DEF_VALUE], 
type, mandatoryDefValue);
+                            try {
+                                defValue = normalizeDataValue(obj[DEF_VALUE], 
type, mandatoryDefValue);
+                            } catch (err:Error) {
+                                throw new CWError("Invalid default value of '" 
+ name + "'--" + err.message,
+                                                  
ErrorCodes.INVALID_DATA_CONVERSION);
+                            }
                             
                             schema.addField(new DataField(name, type, 
defValue, name));
                         }
@@ -311,7 +316,13 @@
                 field = schema.getFieldAt(i);
                 name = field.name;
                 value = data[name];
-                data[name] = normalizeDataValue(value, field.type, 
field.defaultValue);
+                
+                try {
+                    data[name] = normalizeDataValue(value, field.type, 
field.defaultValue);
+                } catch (err:Error) {
+                    throw new CWError("Invalid value of '" + field.name + 
"'--" + err.message,
+                                      ErrorCodes.INVALID_DATA_CONVERSION);
+                }
             }
             
             // Look for missing fields:

Modified: 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/data/InteractionVO.as
===================================================================
--- 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/data/InteractionVO.as
    2011-07-22 19:26:33 UTC (rev 26253)
+++ 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/model/data/InteractionVO.as
    2011-07-22 20:51:02 UTC (rev 26254)
@@ -28,6 +28,9 @@
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
 package org.cytoscapeweb.model.data {
+       import flare.data.DataField;
+       import flare.data.DataSchema;
+       import flare.data.DataUtil;
        import flare.vis.data.EdgeSprite;
        import flare.vis.data.NodeSprite;
        
@@ -40,7 +43,7 @@
                
         // 
=========================================================================================
                
-               public function InteractionVO(node1:NodeSprite, 
node2:NodeSprite) {
+               public function InteractionVO(node1:NodeSprite, 
node2:NodeSprite, edgesSchema:DataSchema) {
                    _key = InteractionVO.createKey(node1, node2);
                        
                        _node1 = node1;
@@ -50,13 +53,8 @@
                        _mergedEdge = new EdgeSprite(node1, node2, false);
                        node1.addOutEdge(_mergedEdge);
             node2.addInEdge(_mergedEdge);
-                       
-                       if (_mergedEdge.data != null) _mergedEdge.data = {};
-            
-            _mergedEdge.data.source = node1.data.id;
-            _mergedEdge.data.target = node2.data.id;
-            _mergedEdge.data.directed = false;
 
+            // props attributes and functions
             _mergedEdge.props.$merged = true;
             
             mergedEdge.props.$getDataList = function():Array {
@@ -75,7 +73,7 @@
                 return filteredList;
             }
                        
-                       update();
+                       update(edgesSchema);
                }
                
         // ========[ PUBLIC METHODS 
]===============================================================
@@ -114,7 +112,10 @@
                        return (_node1 == node1 && _node2 == node2) || (_node1 
== node2 && _node2 == node1);
                }
                
-               public function update():void {
+               public function update(edgesSchema:DataSchema, 
updateData:Boolean=true):void {
+                   // Merged edge data:
+                   if (updateData) recreateDataFields(edgesSchema);
+                   
             // Update merged edge cached data:
             mergedEdge.props.$selected = false;
             mergedEdge.props.$edges = edges;
@@ -133,11 +134,10 @@
             }
             
             var src:NodeSprite;
-            // This will be the summed merged edge's weight:
-            var weight:Number = 0;
 
-            // Update the each edge index:
             for (var i:int = 0; i < length; i++) {
+                // Update each edge index:
+                
                 // Calculate the curvature coefficient that will give the
                 // direction and distance of each curve:
                 e = edgesList[i];
@@ -155,14 +155,34 @@
                 // Merged edge selection state:
                 if (e.props.$selected) mergedEdge.props.$selected = true;
                 
-                // Summed weight:
-                var w:Number = Number(e.data.weight);
-                if (!isNaN(w)) weight += w;
+                // Merged edge data:
+                if (updateData) {
+                    for each (var df:DataField in edgesSchema.fields) {
+                        if (isMergeable(df)) {
+                            var mv:* = mergedEdge.data[df.name];
+                            var v:* = e.data[df.name];
+                            
+                            switch (df.type) {
+                                case DataUtil.INT:
+                                case DataUtil.NUMBER:
+                                    mv += (isNaN(v) ? 0 : v);
+                                    break;
+                                case DataUtil.BOOLEAN:
+                                    mv |= v;
+                                    break;
+                                default:
+                                    mv.push(v !== undefined ? v : null);
+                            }
+                            
+                            _mergedEdge.data[df.name] = mv;
+                        }
+                    }
+                }
+
                 e.dirty();
             }
 
             // Other cached data:
-            mergedEdge.data.weight = weight;
             mergedEdge.props.$filteredOut = edgesList.length === 0;
             mergedEdge.dirty();
                }
@@ -177,5 +197,31 @@
 
         // ========[ PRIVATE METHODS 
]==============================================================
         
+        private function recreateDataFields(edgesSchema:DataSchema):void {
+            _mergedEdge.data = {};
+            _mergedEdge.data.source = node1.data.id;
+            _mergedEdge.data.target = node2.data.id;
+            _mergedEdge.data.directed = false;
+            
+            var v:*;
+            
+            for each (var df:DataField in edgesSchema.fields) {
+                if (isMergeable(df)) {
+                    switch (df.type) {
+                        case DataUtil.INT: v = 0; break;
+                        case DataUtil.NUMBER: v = 0.0; break;
+                        case DataUtil.BOOLEAN: v = false; break;
+                        default: v = [];
+                    }
+                
+                    _mergedEdge.data[df.name] = v;
+                }
+            }
+        }
+        
+        private static function isMergeable(df:DataField):Boolean {
+            var n:String = df.name;
+            return (n != "id" && n != "source" && n !== "target" &&n !== 
"directed");
+        }
        }
 }
\ No newline at end of file

Modified: 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/layout/ForceDirectedLayout.as
===================================================================
--- 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/layout/ForceDirectedLayout.as
     2011-07-22 19:26:33 UTC (rev 26253)
+++ 
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/layout/ForceDirectedLayout.as
     2011-07-22 20:51:02 UTC (rev 26254)
@@ -100,11 +100,7 @@
         public function set maxWeight(max:Number):void { _maxWeight = max; }
         
         public function get edges():DataList {
-            // The layout is optimized for merged edges only if it is not 
weighted,
-            // because it needs to get the weight attribute from regular edges!
-            var gr:String = weighted ? Groups.REGULAR_EDGES : 
Groups.MERGED_EDGES;
-            
-            return visualization.data.group(gr);
+            return visualization.data.group(Groups.MERGED_EDGES);
         }
 
         // ========[ CONSTRUCTOR 
]==================================================================

Modified: cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/AllTests.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/AllTests.as       
2011-07-22 19:26:33 UTC (rev 26253)
+++ cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/AllTests.as       
2011-07-22 20:51:02 UTC (rev 26254)
@@ -39,6 +39,7 @@
        import org.cytoscapeweb.model.data.ContinuousVizMapperVOTest;
        import org.cytoscapeweb.model.data.DiscreteVizMapperVOTest;
        import org.cytoscapeweb.model.data.FirstNeighborsVOTest;
+       import org.cytoscapeweb.model.data.InteractionVOTest;
        import org.cytoscapeweb.model.data.VisualPropertyVOTest;
        import org.cytoscapeweb.model.data.VisualStyleBypassVOTest;
        import org.cytoscapeweb.model.data.VisualStyleVOTest;
@@ -56,6 +57,8 @@
                        addTestSuite(UtilsTest);
                        addTestSuite(VisualPropertiesTest);
                        
+                       addTestSuite(InteractionVOTest);
+                       
                        addTestSuite(VisualPropertyVOTest);
                        addTestSuite(VisualStyleVOTest);
                        addTestSuite(VisualStyleBypassVOTest);

Added: 
cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/model/data/InteractionVOTest.as
===================================================================
--- 
cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/model/data/InteractionVOTest.as
                           (rev 0)
+++ 
cytoscapeweb/trunk/cytoscapeweb/src-test/org/cytoscapeweb/model/data/InteractionVOTest.as
   2011-07-22 20:51:02 UTC (rev 26254)
@@ -0,0 +1,161 @@
+/*
+  This file is part of Cytoscape Web.
+  Copyright (c) 2009, The Cytoscape Consortium (www.cytoscape.org)
+
+  The Cytoscape Consortium is:
+    - Agilent Technologies
+    - Institut Pasteur
+    - Institute for Systems Biology
+    - Memorial Sloan-Kettering Cancer Center
+    - National Center for Integrative Biomedical Informatics
+    - Unilever
+    - University of California San Diego
+    - University of California San Francisco
+    - University of Toronto
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+package org.cytoscapeweb.model.data {
+    import flare.data.DataField;
+    import flare.data.DataSchema;
+    import flare.data.DataUtil;
+    import flare.vis.data.Data;
+    import flare.vis.data.EdgeSprite;
+    import flare.vis.data.NodeSprite;
+    
+    import flexunit.framework.TestCase;
+    
+    
+    public class InteractionVOTest extends TestCase {
+        
+        // ========[ PRIVATE PROPERTIES 
]===========================================================
+        
+        private var data:Data;
+        private var src:NodeSprite;
+        private var tgt:NodeSprite;
+        private var edge1:EdgeSprite;
+        private var edge2:EdgeSprite;
+        private var edge3:EdgeSprite;
+        private var interaction:InteractionVO;
+        private var edgesSchema:DataSchema;
+        // ========[ PUBLIC METHODS 
]===============================================================
+        
+        override public function setUp():void {
+            data = new Data(false);
+            
+            src = data.addNode({ id: "n1" });
+            tgt = data.addNode({ id: "n2" });
+            
+            edge1 = data.addEdgeFor(src, tgt, true, { id: "e1", source: "n1", 
target: "n2", directed: true,
+                                                      s: "a", i: 1, n: 0.5, b: 
false });
+            edge2 = data.addEdgeFor(src, tgt, false, { id: "e2", source: "n1", 
target: "n2", directed: false,
+                                                       s: "b", i: 2, n: 1.5, 
b: true });
+            edge3 = data.addEdgeFor(tgt, src, true, { id: "e3", source: "n2", 
target: "n1", directed: true });
+            
+            edgesSchema = new DataSchema();
+            edgesSchema.addField(new DataField("id", DataUtil.STRING));
+            edgesSchema.addField(new DataField("source", DataUtil.STRING));
+            edgesSchema.addField(new DataField("target", DataUtil.STRING));
+            edgesSchema.addField(new DataField("id", DataUtil.STRING));
+            edgesSchema.addField(new DataField("directed", DataUtil.BOOLEAN));
+            edgesSchema.addField(new DataField("s", DataUtil.STRING));
+            edgesSchema.addField(new DataField("i", DataUtil.INT));
+            edgesSchema.addField(new DataField("n", DataUtil.NUMBER));
+            edgesSchema.addField(new DataField("b", DataUtil.BOOLEAN));
+            
+            interaction = new InteractionVO(src, tgt, edgesSchema);
+        }
+        
+        public function testGetKey():void {
+            var key1:String = InteractionVO.createKey(src, tgt);
+            var key2:String = InteractionVO.createKey(tgt, src);
+            
+            assertNotNull(key1);
+            assertEquals(key1, key2);
+            assertEquals(key1, interaction.key);
+        }
+        
+        public function testGetNodes():void {
+            assertEquals(src, interaction.node1);
+            assertEquals(tgt, interaction.node2);
+        }
+        
+        public function testGetEdges():void {
+            assertEquals(3, interaction.edges.length);
+        }
+        
+        public function testGetMergedEdge():void {
+            var me:EdgeSprite = interaction.mergedEdge;
+            
+            assertTrue(me.props.$merged);
+            assertEquals(3, me.props.$edges.length);
+            assertEquals(3, me.props.$getFilteredEdges().length);
+        }
+        
+        public function testCurvatureFactors():void {
+            assertEquals(0, edge1.props.$curvatureFactor);
+            assertEquals(-1, edge2.props.$curvatureFactor);
+            assertEquals(-1, edge3.props.$curvatureFactor); // would be +1, 
but it is inverted (tgt->src)
+        }
+        
+        public function testIsLoop():void {
+            assertFalse(interaction.loop);
+            interaction = new InteractionVO(src, src, edgesSchema);
+            assertTrue(interaction.loop);
+        }
+        
+        public function testHasNodes():void {
+            assertTrue(interaction.hasNodes(tgt, src));
+            assertTrue(interaction.hasNodes(src, tgt));
+            assertFalse(interaction.hasNodes(src, src));
+            assertFalse(interaction.hasNodes(tgt, tgt));
+        }
+        
+        public function testGetMergedEdgeData():void {
+            var me:EdgeSprite = interaction.mergedEdge;
+            
+            // should never be merged
+            assertNull(me.data.id); // not created yet
+            assertTrue(me.data.source is String);
+            assertTrue(me.data.target is String);
+            assertFalse(me.data.directed); // always undirected
+            
+            // s
+            assertStrictlyEquals(null, me.data.s[0]);
+            assertEquals("a", me.data.s[1]);
+            assertEquals("b", me.data.s[2]);
+            // i
+            assertEquals(3, me.data.i);
+            // n
+            assertEquals(2.0, me.data.n);
+            // b
+            assertTrue(me.data.b);
+        }
+        
+        public function testUpdateMergedEdgeData():void {
+            var me:EdgeSprite = interaction.mergedEdge;
+            
+            edge3.data.s = "c";
+            edge3.data.i = 2;
+            edge2.data.b = false;
+            
+            interaction.update(edgesSchema);
+            
+            assertEquals("c", me.data.s[0]);
+            assertEquals(5, me.data.i);
+            assertFalse(me.data.b);
+        }
+    }
+}
\ No newline at end of file

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