Author: clopes
Date: 2012-01-02 09:42:19 -0800 (Mon, 02 Jan 2012)
New Revision: 27893
Added:
cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/
cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/
cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as
Modified:
cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
Log:
Implemented #2611: Deterministic Force Directed Layout (using a seeded random
generator)
Modified: cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
2012-01-02 16:29:19 UTC (rev 27892)
+++ cytoscapeweb/trunk/cytoscapeweb/html-template/js/cytoscapeweb.js
2012-01-02 17:42:19 UTC (rev 27893)
@@ -2570,6 +2570,9 @@
* Any lesser distances
will be treated as the minimum.</li>
* <li><code>maxDistance</code> {Number}: The maximum distance
over which forces are exerted.
* Any greater distances
will be ignored.</li>
+ * <li><code>seed</code> {Number}: Optional positive integer which
is used to set the random seed for generating the initial node positions.
+ * Force-directed layouts are
non-deterministic by nature, but this option can be used to reproduce the same
topology.
+ * Just leave this property
<code>undefined</code> or set <code>0</code> if you want to keep the layout
non-deterministic (i.e. a random seed is used).</li>
* <li><code>autoStabilize</code> {Boolean}: A common problem with
force-directed layouts is that they can be highly unstable.
* If this parameter is
<code>true</code> and the edges are being stretched too much
* between each
iteration, Cytoscape Web automatically tries to stabilize
Added: cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as
(rev 0)
+++ cytoscapeweb/trunk/cytoscapeweb/src/com/gskinner/utils/Rndm.as
2012-01-02 17:42:19 UTC (rev 27893)
@@ -0,0 +1,121 @@
+/**
+* Rndm by Grant Skinner. Jan 15, 2008
+* Visit www.gskinner.com/blog for documentation, updates and more free code.
+*
+* Incorporates implementation of the Park Miller (1988) "minimal standard"
linear
+* congruential pseudo-random number generator by Michael Baczynski,
www.polygonal.de.
+* (seed * 16807) % 2147483647
+*
+* Slightly modified by Christian Lopes
+*
+* Copyright (c) 2008 Grant Skinner
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use,
+* copy, modify, merge, publish, distribute, sublicense, and/or sell
+* copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following
+* conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*/
+package com.gskinner.utils {
+
+ import flash.display.BitmapData;
+
+ /**
+ * Provides common random functions using a seeded random system.
+ */
+ public class Rndm {
+
+ // ========[ PRIVATE PROPERTIES
]===========================================================
+
+ private var _seed:uint;
+ private var _currentSeed:uint;
+
+ // ========[ PUBLIC PROPERTIES
]============================================================
+
+ /**
+ * seed = Math.random()*0xFFFFFF; // sets a random seed
+ * seed = 50; // sets a static seed
+ */
+ public function get seed():uint {
+ return _seed;
+ }
+
+ public function set seed(value:uint):void {
+ _seed = _currentSeed = value;
+ }
+
+ public function get currentSeed():uint {
+ return _currentSeed;
+ }
+
+ // ========[ CONSTRUCTOR
]==================================================================
+
+ public function Rndm(seed:uint=1) {
+ this.seed = seed;
+ }
+
+ // ========[ PROTECTED METHODS
]============================================================
+
+ /**
+ * @return a number between 0-1 exclusive.
+ */
+ public function random():Number {
+ return (_currentSeed = (_currentSeed * 16807) %
2147483647)/0x7FFFFFFF+0.000000000233;
+ }
+
+ // float(50); // returns a number between 0-50 exclusive
+ // float(20,50); // returns a number between 20-50 exclusive
+ public function float(min:Number,max:Number=NaN):Number {
+ if (isNaN(max)) { max = min; min=0; }
+ return random()*(max-min)+min;
+ }
+
+ // boolean(); // returns true or false (50% chance of true)
+ // boolean(0.8); // returns true or false (80% chance of true)
+ public function boolean(chance:Number=0.5):Boolean {
+ return (random() < chance);
+ }
+
+ // sign(); // returns 1 or -1 (50% chance of 1)
+ // sign(0.8); // returns 1 or -1 (80% chance of 1)
+ public function sign(chance:Number=0.5):int {
+ return (random() < chance) ? 1 : -1;
+ }
+
+ // bit(); // returns 1 or 0 (50% chance of 1)
+ // bit(0.8); // returns 1 or 0 (80% chance of 1)
+ public function bit(chance:Number=0.5):int {
+ return (random() < chance) ? 1 : 0;
+ }
+
+ // integer(50); // returns an integer between 0-49 inclusive
+ // integer(20,50); // returns an integer between 20-49 inclusive
+ public function integer(min:Number,max:Number=NaN):int {
+ if (isNaN(max)) { max = min; min=0; }
+ // Need to use floor instead of bit shift to work properly with
negative values:
+ return Math.floor(float(min,max));
+ }
+
+ /**
+ * Resets the number series, retaining the same seed.
+ */
+ public function reset():void {
+ _seed = _currentSeed;
+ }
+ }
+}
Modified:
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as
2012-01-02 16:29:19 UTC (rev 27892)
+++ cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/ApplicationFacade.as
2012-01-02 17:42:19 UTC (rev 27893)
@@ -180,7 +180,7 @@
public function ApplicationFacade(lock:SingletonLock) {
super();
if (lock == null)
- throw new Error( "Invalid Singleton access. Use
ApplicationFacade.instance().");
+ throw new Error("Invalid Singleton access. Use
ApplicationFacade.getInstance().");
}
public static function getInstance():ApplicationFacade {
Modified: cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as
===================================================================
--- cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as
2012-01-02 16:29:19 UTC (rev 27892)
+++ cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/util/Layouts.as
2012-01-02 17:42:19 UTC (rev 27893)
@@ -73,6 +73,7 @@
mass: 3,
tension: 0.1,
restLength: "auto",
+ seed: undefined, // optional integer
weightAttr: null,
weightNorm: ForceDirectedLayout.NORMALIZED_WEIGHT,
minWeight: undefined,
Modified:
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
===================================================================
---
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
2012-01-02 16:29:19 UTC (rev 27892)
+++
cytoscapeweb/trunk/cytoscapeweb/src/org/cytoscapeweb/view/components/GraphVis.as
2012-01-02 17:42:19 UTC (rev 27893)
@@ -28,6 +28,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.cytoscapeweb.view.components {
+ import com.gskinner.utils.Rndm;
import com.senocular.drawing.DashedLine;
import flare.animate.Sequence;
@@ -291,14 +292,17 @@
_appliedLayouts.push(layout);
} else {
if (_layoutName === Layouts.FORCE_DIRECTED) {
+ // Is there a seed?
+ var seed:* = layoutObj.options.seed;
+ var rndm:* = (seed is Number && uint(seed) > 0) ? new
Rndm(uint(seed)) : Math;
// If the previous layout is ForceDirected, we need to set
the nodes' particles and
// the edges' springs to null, otherwise the layout may
not render very well
// when it is applied again.
data.nodes.visit(function(n:NodeSprite):void {
n.props.particle = null;
// It is also important to set random positions to
nodes:
- n.x = Math.random() * _initialWidth;
- n.y = Math.random() * _initialHeight;
+ n.x = rndm.random() * _initialWidth;
+ n.y = rndm.random() * _initialHeight;
});
data.edges.visit(function(e:EdgeSprite):void {
e.props.spring = null;
--
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.