Merge lp:~mathieu-jacomy/gephi/forceatlas2 into lp:~gephi.team/gephi/0.8

Proposed by Mathieu Bastian
Status: Merged
Merged at revision: 2240
Proposed branch: lp:~mathieu-jacomy/gephi/forceatlas2
Merge into: lp:~gephi.team/gephi/0.8
Diff against target: 1540 lines (+1460/-0)
14 files modified
ForceAtlas2/build.xml (+8/-0)
ForceAtlas2/manifest.mf (+5/-0)
ForceAtlas2/nbproject/build-impl.xml (+45/-0)
ForceAtlas2/nbproject/genfiles.properties (+8/-0)
ForceAtlas2/nbproject/project.properties (+2/-0)
ForceAtlas2/nbproject/project.xml (+69/-0)
ForceAtlas2/nbproject/suite.properties (+1/-0)
ForceAtlas2/src/org/webatlas/forceatlas2/Bundle.properties (+33/-0)
ForceAtlas2/src/org/webatlas/forceatlas2/Bundle_fr.properties (+33/-0)
ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2.java (+450/-0)
ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2Builder.java (+75/-0)
ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2LayoutData.java (+24/-0)
ForceAtlas2/src/org/webatlas/forceatlas2/ForceFactory.java (+510/-0)
ForceAtlas2/src/org/webatlas/forceatlas2/Region.java (+197/-0)
To merge this branch: bzr merge lp:~mathieu-jacomy/gephi/forceatlas2
Reviewer Review Type Date Requested Status
Mathieu Bastian Approve
Review via email: mp+63504@code.launchpad.net

Description of the change

New awesome ForceAtlas2 algorithm

To post a comment you must log in.
Revision history for this message
Mathieu Bastian (mathieu.bastian) wrote :

The algorithm classes will be moved to the LayoutPlugin module

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'ForceAtlas2'
=== added file 'ForceAtlas2/build.xml'
--- ForceAtlas2/build.xml 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/build.xml 2011-06-05 20:50:57 +0000
@@ -0,0 +1,8 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!-- You may freely edit this file. See harness/README in the NetBeans platform -->
3<!-- for some information on what you could do (e.g. targets to override). -->
4<!-- If you delete this file and reopen the project it will be recreated. -->
5<project name="org.webatlas.forceatlas2" default="netbeans" basedir=".">
6 <description>Builds, tests, and runs the project org.webatlas.forceatlas2.</description>
7 <import file="nbproject/build-impl.xml"/>
8</project>
09
=== added file 'ForceAtlas2/manifest.mf'
--- ForceAtlas2/manifest.mf 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/manifest.mf 2011-06-05 20:50:57 +0000
@@ -0,0 +1,5 @@
1Manifest-Version: 1.0
2OpenIDE-Module: org.webatlas.forceatlas2
3OpenIDE-Module-Localizing-Bundle: org/webatlas/forceatlas2/Bundle.properties
4OpenIDE-Module-Specification-Version: 1.6
5
06
=== added directory 'ForceAtlas2/nbproject'
=== added file 'ForceAtlas2/nbproject/build-impl.xml'
--- ForceAtlas2/nbproject/build-impl.xml 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/nbproject/build-impl.xml 2011-06-05 20:50:57 +0000
@@ -0,0 +1,45 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!--
3*** GENERATED FROM project.xml - DO NOT EDIT ***
4*** EDIT ../build.xml INSTEAD ***
5-->
6<project name="org.webatlas.forceatlas2-impl" basedir="..">
7 <fail message="Please build using Ant 1.7.1 or higher.">
8 <condition>
9 <not>
10 <antversion atleast="1.7.1"/>
11 </not>
12 </condition>
13 </fail>
14 <property file="nbproject/private/suite-private.properties"/>
15 <property file="nbproject/suite.properties"/>
16 <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
17 <property file="${suite.dir}/nbproject/private/platform-private.properties"/>
18 <property file="${suite.dir}/nbproject/platform.properties"/>
19 <macrodef name="property" uri="http://www.netbeans.org/ns/nb-module-project/2">
20 <attribute name="name"/>
21 <attribute name="value"/>
22 <sequential>
23 <property name="@{name}" value="${@{value}}"/>
24 </sequential>
25 </macrodef>
26 <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
27 <attribute name="property"/>
28 <attribute name="value"/>
29 <sequential>
30 <property name="@{property}" value="@{value}"/>
31 </sequential>
32 </macrodef>
33 <property file="${user.properties.file}"/>
34 <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
35 <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
36 <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
37 <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
38 <condition>
39 <not>
40 <contains string="${cluster.path.evaluated}" substring="platform"/>
41 </not>
42 </condition>
43 </fail>
44 <import file="${harness.dir}/build.xml"/>
45</project>
046
=== added file 'ForceAtlas2/nbproject/genfiles.properties'
--- ForceAtlas2/nbproject/genfiles.properties 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/nbproject/genfiles.properties 2011-06-05 20:50:57 +0000
@@ -0,0 +1,8 @@
1build.xml.data.CRC32=0a8bc1d8
2build.xml.script.CRC32=7eaa9dd0
3build.xml.stylesheet.CRC32=a56c6a5b@1.45.1
4# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
5# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
6nbproject/build-impl.xml.data.CRC32=0a8bc1d8
7nbproject/build-impl.xml.script.CRC32=eb5b8ec7
8nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.45.1
09
=== added file 'ForceAtlas2/nbproject/project.properties'
--- ForceAtlas2/nbproject/project.properties 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/nbproject/project.properties 2011-06-05 20:50:57 +0000
@@ -0,0 +1,2 @@
1javac.source=1.6
2javac.compilerargs=-Xlint -Xlint:-serial
03
=== added file 'ForceAtlas2/nbproject/project.xml'
--- ForceAtlas2/nbproject/project.xml 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/nbproject/project.xml 2011-06-05 20:50:57 +0000
@@ -0,0 +1,69 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<project xmlns="http://www.netbeans.org/ns/project/1">
3 <type>org.netbeans.modules.apisupport.project</type>
4 <configuration>
5 <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
6 <code-name-base>org.webatlas.forceatlas2</code-name-base>
7 <suite-component/>
8 <module-dependencies>
9 <dependency>
10 <code-name-base>org.gephi.data.attributes.api</code-name-base>
11 <build-prerequisite/>
12 <compile-dependency/>
13 <run-dependency>
14 <specification-version>0.8</specification-version>
15 </run-dependency>
16 </dependency>
17 <dependency>
18 <code-name-base>org.gephi.dynamic.api</code-name-base>
19 <build-prerequisite/>
20 <compile-dependency/>
21 <run-dependency>
22 <specification-version>0.8</specification-version>
23 </run-dependency>
24 </dependency>
25 <dependency>
26 <code-name-base>org.gephi.graph.api</code-name-base>
27 <build-prerequisite/>
28 <compile-dependency/>
29 <run-dependency>
30 <specification-version>0.8</specification-version>
31 </run-dependency>
32 </dependency>
33 <dependency>
34 <code-name-base>org.gephi.layout.api</code-name-base>
35 <build-prerequisite/>
36 <compile-dependency/>
37 <run-dependency>
38 <specification-version>0.8.0.1</specification-version>
39 </run-dependency>
40 </dependency>
41 <dependency>
42 <code-name-base>org.gephi.project.api</code-name-base>
43 <build-prerequisite/>
44 <compile-dependency/>
45 <run-dependency>
46 <specification-version>0.8</specification-version>
47 </run-dependency>
48 </dependency>
49 <dependency>
50 <code-name-base>org.openide.util</code-name-base>
51 <build-prerequisite/>
52 <compile-dependency/>
53 <run-dependency>
54 <specification-version>8.14.1</specification-version>
55 </run-dependency>
56 </dependency>
57 <dependency>
58 <code-name-base>org.openide.util.lookup</code-name-base>
59 <build-prerequisite/>
60 <compile-dependency/>
61 <run-dependency>
62 <specification-version>8.6.1</specification-version>
63 </run-dependency>
64 </dependency>
65 </module-dependencies>
66 <public-packages/>
67 </data>
68 </configuration>
69</project>
070
=== added file 'ForceAtlas2/nbproject/suite.properties'
--- ForceAtlas2/nbproject/suite.properties 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/nbproject/suite.properties 2011-06-05 20:50:57 +0000
@@ -0,0 +1,1 @@
1suite.dir=${basedir}/..
02
=== added directory 'ForceAtlas2/src'
=== added directory 'ForceAtlas2/src/org'
=== added directory 'ForceAtlas2/src/org/webatlas'
=== added directory 'ForceAtlas2/src/org/webatlas/forceatlas2'
=== added file 'ForceAtlas2/src/org/webatlas/forceatlas2/Bundle.properties'
--- ForceAtlas2/src/org/webatlas/forceatlas2/Bundle.properties 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/src/org/webatlas/forceatlas2/Bundle.properties 2011-06-05 20:50:57 +0000
@@ -0,0 +1,33 @@
1OpenIDE-Module-Display-Category=Plugin
2OpenIDE-Module-Long-Description=Quality Layout, used in SNA. \
3 A linear-attraction linear-repulsion model with few approximations (BarnesHut). \
4 Features an optimal speed vs. precision balance and degree-driven repulsion for a high readability. \
5 Works on medium-sized graphs: 10 to 10000 nodes.
6OpenIDE-Module-Name=ForceAtlas 2, Quality Layout
7OpenIDE-Module-Short-Description=Quality Layout
8
9ForceAtlas2.name=ForceAtlas 2
10ForceAtlas2.description=Quality layout: a linear-attraction linear-repulsion model with few approximations (BarnesHut). Speed automatically computed.
11
12ForceAtlas2.tuning=Tuning
13ForceAtlas2.behavior=Behavior Alternatives
14ForceAtlas2.performance=Performance
15
16ForceAtlas2.scalingRatio.name=Scaling
17ForceAtlas2.scalingRatio.desc=How much repulsion you want. More makes a more sparse graph.
18ForceAtlas2.gravity.name=Gravity
19ForceAtlas2.gravity.desc=Attracts nodes to the center. Prevents islands from drifting away.
20ForceAtlas2.distributedAttraction.name=Dissuade Hubs
21ForceAtlas2.distributedAttraction.desc=Distributes attraction along outbound edges. Hubs attract less and thus are pushed to the borders.
22ForceAtlas2.linLogMode.name=LinLog mode
23ForceAtlas2.linLogMode.desc=Switch ForceAtlas' model from lin-lin to lin-log (tribute to Andreas Noack). Makes clusters more tight.
24ForceAtlas2.adjustSizes.name=Prevent Overlap
25ForceAtlas2.adjustSizes.desc=Use only when spatialized. Should not be used with "Approximate Repulsion"
26ForceAtlas2.jitterTolerance.name=Tolerance (speed)
27ForceAtlas2.jitterTolerance.desc=How much swinging you allow. Above 1 discouraged. Lower gives less speed and more precision.
28ForceAtlas2.barnesHutOptimization.name=Approximate Repulsion
29ForceAtlas2.barnesHutOptimization.desc=Barnes Hut optimization: n\u00b2 complexity to n.ln(n) ; allows larger graphs.
30ForceAtlas2.barnesHutTheta.name=Approximation
31ForceAtlas2.barnesHutTheta.desc=Theta of the Barnes Hut optimization.
32ForceAtlas2.edgeWeightInfluence.name=Edge Weight Influence
33ForceAtlas2.edgeWeightInfluence.desc=How much influence you give to the edges weight. 0 is "no influence" and 1 is "normal".
034
=== added file 'ForceAtlas2/src/org/webatlas/forceatlas2/Bundle_fr.properties'
--- ForceAtlas2/src/org/webatlas/forceatlas2/Bundle_fr.properties 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/src/org/webatlas/forceatlas2/Bundle_fr.properties 2011-06-05 20:50:57 +0000
@@ -0,0 +1,33 @@
1OpenIDE-Module-Display-Category=Plugin
2OpenIDE-Module-Long-Description=Spatialisation qualitative, utilis\u00e9e dans l'analyse des r\u00e9seaux sociaux. \
3 Attraction et r\u00e9pulsion lin\u00e9aires avec quelques approximations (Barnes Hut)\
4 Comprend un \u00e9quilibrage dynamique de la vitesse contre la pr\u00e9cision, et une r\u00e9pulsion par degree qui rend le graphe plus lisible.\
5 Fonctionne sur des graphes de 10 \u00e0 10000 noeuds.
6OpenIDE-Module-Name=ForceAtlas 2, Spatialisation qualitative
7OpenIDE-Module-Short-Description=Spatialisation qualitative
8
9ForceAtlas2.name=ForceAtlas 2
10ForceAtlas2.description=Spatialisation qualitative: mod\u00e8le \u00e0 attraction et r\u00e9pulsion lin\u00e9aires avec quelques optimisations (Barnes Hut). Param\u00e9trage automatis\u00e9.
11
12ForceAtlas2.tuning=R\u00e9glages fins
13ForceAtlas2.behavior=Options de comportement
14ForceAtlas2.performance=Performances
15
16ForceAtlas2.scalingRatio.name=Dimensionnement
17ForceAtlas2.scalingRatio.desc=Quantit\u00e9 de r\u00e9pulsion, par rapport \u00e0 l'attraction. Rend le graphe plus \u00e9tal\u00e9.
18ForceAtlas2.gravity.name=Gravit\u00e9
19ForceAtlas2.gravity.desc=Attire les noeuds vers le centre. Emp\u00eache les \u00eelots de d\u00e9river \u00e0 l'infini.
20ForceAtlas2.distributedAttraction.name=Dissuader les Hubs
21ForceAtlas2.distributedAttraction.desc=Distribue l'attraction dans les liens sortants. Les Hubs attirent moins et sont donc repouss\u00e9s en p\u00e9riph\u00e9rie.
22ForceAtlas2.linLogMode.name=Mode LinLog
23ForceAtlas2.linLogMode.desc=Passer le mod\u00e8le de ForceAtlas de lin-lin \u00e0 lin-log (hommage \u00e0 Andreas Noack). Rend les concentrations de noeuds sont plus resserr\u00e9es.
24ForceAtlas2.adjustSizes.name=Emp\u00eacher Recouvrement
25ForceAtlas2.adjustSizes.desc=Utilisez lorsque le graphe a d\u00e9j\u00e0 converg\u00e9. Permet d'emp\u00eacher les noeuds de se recouvrir. Utilisation d\u00e9conseill\u00e9e avec l'approximation de la r\u00e9pulsion.
26ForceAtlas2.jitterTolerance.name=Tol\u00e9rance (vitesse)
27ForceAtlas2.jitterTolerance.desc=Quantit\u00e9 de vibration autoris\u00e9e (valeurs > 1 d\u00e9conseill\u00e9es). Baisser la valeur apporte plus de pr\u00e9cision et moins de vitesse.
28ForceAtlas2.barnesHutOptimization.name=Approximer R\u00e9pulsion
29ForceAtlas2.barnesHutOptimization.desc=L'optimisation de Barnes Hut: permet une r\u00e9duction de la complexit\u00e9 du calcul de n\u00b2 \u00e0 n.ln(n). Permet de spatialiser de plus gros graphes.
30ForceAtlas2.barnesHutTheta.name=Approximation
31ForceAtlas2.barnesHutTheta.desc=param\u00e8tre Theta de l'optimisation de Barnes Hut.
32ForceAtlas2.edgeWeightInfluence.name=Influence Poids des liens
33ForceAtlas2.edgeWeightInfluence.desc=L'influence du poides des liens. 0 c'est aucune influence, 1 c'est une influence normale et au-del\u00e0 \u00e7a accentue l'importance du poids des liens dans la spatialisation.
034
=== added file 'ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2.java'
--- ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2.java 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2.java 2011-06-05 20:50:57 +0000
@@ -0,0 +1,450 @@
1/*
2Copyright 2008-2011 Gephi
3Authors : Mathieu Jacomy <Mathieu.Jacomy@gmail.com>
4Website : http://www.webatlas.fr
5
6You should have received a copy of the GNU Affero General Public License
7along with ForceAtlas 2. If not, see <http://www.gnu.org/licenses/>.
8*/
9package org.webatlas.forceatlas2;
10
11import java.util.ArrayList;
12import java.util.List;
13import org.gephi.data.attributes.type.TimeInterval;
14import org.gephi.dynamic.DynamicUtilities;
15import org.gephi.dynamic.api.DynamicController;
16import org.gephi.dynamic.api.DynamicModel;
17import org.gephi.graph.api.Edge;
18import org.gephi.graph.api.GraphModel;
19import org.gephi.graph.api.HierarchicalGraph;
20import org.gephi.graph.api.Node;
21import org.gephi.graph.api.NodeData;
22import org.gephi.layout.spi.Layout;
23import org.gephi.layout.spi.LayoutBuilder;
24import org.gephi.layout.spi.LayoutProperty;
25import org.gephi.project.api.Workspace;
26import org.openide.util.Lookup;
27import org.openide.util.NbBundle;
28import org.webatlas.forceatlas2.ForceFactory.AttractionForce;
29import org.webatlas.forceatlas2.ForceFactory.RepulsionForce;
30
31/**
32 * ForceAtlas 2 Layout, manages each step of the computations.
33 * @author Mathieu Jacomy
34 */
35public class ForceAtlas2 implements Layout{
36 private GraphModel graphModel;
37 private HierarchicalGraph graph;
38 private ForceAtlas2Builder layoutBuilder;
39 private DynamicModel dynamicModel;
40
41 private double edgeWeightInfluence;
42 private double jitterTolerance;
43 private double scalingRatio;
44 private double gravity;
45 private double speed;
46 private boolean outboundAttractionDistribution;
47 private boolean adjustSizes;
48 private boolean barnesHutOptimize;
49 private double barnesHutTheta;
50 private boolean linLogMode;
51 private Region rootRegion;
52
53 double outboundAttCompensation = 1;
54
55 //Dynamic Weight
56 private TimeInterval timeInterval;
57
58 public ForceAtlas2(ForceAtlas2Builder layoutBuilder) {
59 this.layoutBuilder = layoutBuilder;
60 }
61
62 @Override
63 public void initAlgo() {
64 speed = 1.;
65
66 graph = graphModel.getHierarchicalGraphVisible();
67 this.timeInterval = DynamicUtilities.getVisibleInterval(dynamicModel);
68
69 graph.readLock();
70 Node[] nodes = graph.getNodes().toArray();
71
72 // Initialise layout data
73 for (Node n : nodes) {
74 if (n.getNodeData().getLayoutData() == null || !(n.getNodeData().getLayoutData() instanceof ForceAtlas2LayoutData)) {
75 ForceAtlas2LayoutData nLayout = new ForceAtlas2LayoutData();
76 n.getNodeData().setLayoutData(nLayout);
77 }
78 NodeData nData = n.getNodeData();
79 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
80 nLayout.mass = 1 + graph.getDegree(n);
81 nLayout.old_dx = 0;
82 nLayout.old_dy = 0;
83 nLayout.dx = 0;
84 nLayout.dy = 0;
85 }
86 }
87
88 @Override
89 public void goAlgo() {
90 // Initialize graph data
91 if (graphModel == null) {
92 return;
93 }
94 graph = graphModel.getHierarchicalGraphVisible();
95 this.timeInterval = DynamicUtilities.getVisibleInterval(dynamicModel);
96
97 graph.readLock();
98 Node[] nodes = graph.getNodes().toArray();
99 Edge[] edges = graph.getEdgesAndMetaEdges().toArray();
100
101 // Initialise layout data
102 for (Node n : nodes) {
103 if (n.getNodeData().getLayoutData() == null || !(n.getNodeData().getLayoutData() instanceof ForceAtlas2LayoutData)) {
104 ForceAtlas2LayoutData nLayout = new ForceAtlas2LayoutData();
105 n.getNodeData().setLayoutData(nLayout);
106 }
107 NodeData nData = n.getNodeData();
108 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
109 nLayout.mass = 1 + graph.getDegree(n);
110 nLayout.old_dx = nLayout.dx;
111 nLayout.old_dy = nLayout.dy;
112 nLayout.dx = 0;
113 nLayout.dy = 0;
114 }
115
116 // If Barnes Hut active, initialize root region
117 if(isBarnesHutOptimize()){
118 rootRegion = new Region(nodes);
119 rootRegion.buildSubRegions();
120 }
121
122 // If outboundAttractionDistribution active, compensate.
123 if(isOutboundAttractionDistribution()){
124 outboundAttCompensation = 0;
125 for(Node n : nodes){
126 NodeData nData = n.getNodeData();
127 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
128 outboundAttCompensation += nLayout.mass;
129 }
130 outboundAttCompensation /= nodes.length;
131 }
132
133 // Repulsion
134 RepulsionForce Repulsion = ForceFactory.builder.buildRepulsion(isAdjustSizes(), getScalingRatio());
135 if(isBarnesHutOptimize()){
136 for(Node n : nodes){
137 rootRegion.applyForce(n, Repulsion, getBarnesHutTheta());
138 }
139 } else {
140 for (int n1Index = 0; n1Index<nodes.length; n1Index++) {
141 Node n1 = nodes[n1Index];
142 for (int n2Index = 0; n2Index<n1Index; n2Index++) {
143 Node n2 = nodes[n2Index];
144 Repulsion.apply(n1, n2);
145 }
146 }
147 }
148
149 // Attraction
150 AttractionForce Attraction = ForceFactory.builder.buildAttraction(isLinLogMode(), isOutboundAttractionDistribution(), isAdjustSizes(), 1*((isOutboundAttractionDistribution())?(outboundAttCompensation):(1)));
151 for (Edge e : edges) {
152 Attraction.apply(e.getSource(), e.getTarget(), Math.pow(getWeight(e),getEdgeWeightInfluence()));
153 }
154
155 // Gravity
156 for (Node n : nodes) {
157 Repulsion.apply(n, getGravity()/getScalingRatio());
158 }
159
160 // Auto adjust speed
161 double totalSwinging = 0d; // How much irregular movement
162 double totalEffectiveTraction = 0d; // Hom much useful movement
163 for (Node n : nodes) {
164 NodeData nData = n.getNodeData();
165 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
166 if (!nData.isFixed()) {
167 double swinging = Math.sqrt(Math.pow(nLayout.old_dx - nLayout.dx,2) + Math.pow(nLayout.old_dy - nLayout.dy,2));
168 totalSwinging += nLayout.mass * swinging; // If the node has a burst change of direction, then it's not converging.
169 totalEffectiveTraction += nLayout.mass * 0.5 * Math.sqrt(Math.pow(nLayout.old_dx + nLayout.dx,2) + Math.pow(nLayout.old_dy + nLayout.dy,2));
170 }
171 }
172 // We want that swingingMovement < tolerance * convergenceMovement
173 double targetSpeed = getJitterTolerance() * getJitterTolerance() * totalEffectiveTraction / totalSwinging;
174
175 // But the speed shoudn't rise too much too quickly, since it would make the convergence drop dramatically.
176 double maxRise = 0.5; // Max rise: 50%
177 speed = speed + Math.min(targetSpeed - speed, maxRise * speed);
178
179 // Apply forces
180 if(isAdjustSizes()){
181 // If nodes overlap prevention is active, it's not possible to trust the swinging mesure.
182 for (Node n : nodes) {
183 NodeData nData = n.getNodeData();
184 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
185 if (!nData.isFixed()) {
186
187 // Adaptive auto-speed: the speed of each node is lowered
188 // when the node swings.
189 double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy));
190 double factor = 0.1 * speed / (1f + speed * Math.sqrt(swinging));
191
192 double df = Math.sqrt(Math.pow(nLayout.dx, 2)+Math.pow(nLayout.dy, 2));
193 factor = Math.min(factor*df, 10.)/df;
194
195 double x = nData.x() + nLayout.dx*factor;
196 double y = nData.y() + nLayout.dy*factor;
197
198 nData.setX((float) x);
199 nData.setY((float) y);
200 }
201 }
202 } else {
203 for (Node n : nodes) {
204 NodeData nData = n.getNodeData();
205 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
206 if (!nData.isFixed()) {
207
208 // Adaptive auto-speed: the speed of each node is lowered
209 // when the node swings.
210 double swinging = Math.sqrt((nLayout.old_dx - nLayout.dx) * (nLayout.old_dx - nLayout.dx) + (nLayout.old_dy - nLayout.dy) * (nLayout.old_dy - nLayout.dy));
211 //double factor = speed / (1f + Math.sqrt(speed * swinging));
212 double factor = speed / (1f + speed * Math.sqrt(swinging));
213
214 double x = nData.x() + nLayout.dx*factor;
215 double y = nData.y() + nLayout.dy*factor;
216
217 nData.setX((float) x);
218 nData.setY((float) y);
219 }
220 }
221 }
222 graph.readUnlock();
223 }
224
225 @Override
226 public boolean canAlgo() {
227 return graphModel != null;
228 }
229
230 @Override
231 public void endAlgo() {
232 for (Node n : graph.getNodes()) {
233 n.getNodeData().setLayoutData(null);
234 }
235 graph.readUnlock();
236 }
237
238 @Override
239 public LayoutProperty[] getProperties() {
240 List<LayoutProperty> properties = new ArrayList<LayoutProperty>();
241 final String FORCEATLAS2_TUNING = NbBundle.getMessage(getClass(), "ForceAtlas2.tuning");
242 final String FORCEATLAS2_BEHAVIOR = NbBundle.getMessage(getClass(), "ForceAtlas2.behavior");
243 final String FORCEATLAS2_PERFORMANCE = NbBundle.getMessage(getClass(), "ForceAtlas2.performance");
244
245 try {
246 properties.add(LayoutProperty.createProperty(
247 this, Double.class,
248 NbBundle.getMessage(getClass(), "ForceAtlas2.scalingRatio.name"),
249 FORCEATLAS2_TUNING,
250 NbBundle.getMessage(getClass(), "ForceAtlas2.scalingRatio.desc"),
251 "getScalingRatio", "setScalingRatio"));
252
253 properties.add(LayoutProperty.createProperty(
254 this, Double.class,
255 NbBundle.getMessage(getClass(), "ForceAtlas2.gravity.name"),
256 FORCEATLAS2_TUNING,
257 NbBundle.getMessage(getClass(), "ForceAtlas2.gravity.desc"),
258 "getGravity", "setGravity"));
259
260 properties.add(LayoutProperty.createProperty(
261 this, Boolean.class,
262 NbBundle.getMessage(getClass(), "ForceAtlas2.distributedAttraction.name"),
263 FORCEATLAS2_BEHAVIOR,
264 NbBundle.getMessage(getClass(), "ForceAtlas2.distributedAttraction.desc"),
265 "isOutboundAttractionDistribution", "setOutboundAttractionDistribution"));
266
267 properties.add(LayoutProperty.createProperty(
268 this, Boolean.class,
269 NbBundle.getMessage(getClass(), "ForceAtlas2.linLogMode.name"),
270 FORCEATLAS2_BEHAVIOR,
271 NbBundle.getMessage(getClass(), "ForceAtlas2.linLogMode.desc"),
272 "isLinLogMode", "setLinLogMode"));
273
274 properties.add(LayoutProperty.createProperty(
275 this, Boolean.class,
276 NbBundle.getMessage(getClass(), "ForceAtlas2.adjustSizes.name"),
277 FORCEATLAS2_BEHAVIOR,
278 NbBundle.getMessage(getClass(), "ForceAtlas2.adjustSizes.desc"),
279 "isAdjustSizes", "setAdjustSizes"));
280
281 properties.add(LayoutProperty.createProperty(
282 this, Double.class,
283 NbBundle.getMessage(getClass(), "ForceAtlas2.edgeWeightInfluence.name"),
284 FORCEATLAS2_BEHAVIOR,
285 NbBundle.getMessage(getClass(), "ForceAtlas2.edgeWeightInfluence.desc"),
286 "getEdgeWeightInfluence", "setEdgeWeightInfluence"));
287
288 properties.add(LayoutProperty.createProperty(
289 this, Double.class,
290 NbBundle.getMessage(getClass(), "ForceAtlas2.jitterTolerance.name"),
291 FORCEATLAS2_PERFORMANCE,
292 NbBundle.getMessage(getClass(), "ForceAtlas2.jitterTolerance.desc"),
293 "getJitterTolerance", "setJitterTolerance"));
294
295 properties.add(LayoutProperty.createProperty(
296 this, Boolean.class,
297 NbBundle.getMessage(getClass(), "ForceAtlas2.barnesHutOptimization.name"),
298 FORCEATLAS2_PERFORMANCE,
299 NbBundle.getMessage(getClass(), "ForceAtlas2.barnesHutOptimization.desc"),
300 "isBarnesHutOptimize", "setBarnesHutOptimize"));
301
302 properties.add(LayoutProperty.createProperty(
303 this, Double.class,
304 NbBundle.getMessage(getClass(), "ForceAtlas2.barnesHutTheta.name"),
305 FORCEATLAS2_PERFORMANCE,
306 NbBundle.getMessage(getClass(), "ForceAtlas2.barnesHutTheta.desc"),
307 "getBarnesHutTheta", "setBarnesHutTheta"));
308
309 } catch (Exception e) {
310 e.printStackTrace();
311 }
312
313 return properties.toArray(new LayoutProperty[0]);
314 }
315
316 @Override
317 public void resetPropertiesValues() {
318 int nodesCount = 0;
319
320 if(graphModel != null){
321 nodesCount = graphModel.getHierarchicalGraphVisible().getNodeCount();
322 }
323
324 // Tuning
325 if(nodesCount>=100){
326 setScalingRatio(2.0);
327 } else {
328 setScalingRatio(10.0);
329 }
330 setGravity(1.);
331
332 // Behavior
333 setOutboundAttractionDistribution(false);
334 setLinLogMode(false);
335 setAdjustSizes(false);
336 setEdgeWeightInfluence(1.);
337
338 // Performance
339 if(nodesCount>=50000){
340 setJitterTolerance(10d);
341 } else if(nodesCount>=5000){
342 setJitterTolerance(1d);
343 } else {
344 setJitterTolerance(0.1d);
345 }
346 if(nodesCount>=1000){
347 setBarnesHutOptimize(true);
348 } else {
349 setBarnesHutOptimize(false);
350 }
351 setBarnesHutTheta(1.2);
352 }
353
354 @Override
355 public LayoutBuilder getBuilder() {
356 return layoutBuilder;
357 }
358
359 @Override
360 public void setGraphModel(GraphModel graphModel) {
361 this.graphModel = graphModel;
362 Workspace workspace = graphModel.getWorkspace();
363 DynamicController dynamicController = Lookup.getDefault().lookup(DynamicController.class);
364 if (dynamicController != null && workspace != null) {
365 dynamicModel = dynamicController.getModel(workspace);
366 }
367 // Trick: reset here to take the profile of the graph in account for default values
368 resetPropertiesValues();
369 }
370
371 public Double getBarnesHutTheta() {
372 return barnesHutTheta;
373 }
374
375 public void setBarnesHutTheta(Double barnesHutTheta) {
376 this.barnesHutTheta = barnesHutTheta;
377 }
378
379 public Double getEdgeWeightInfluence() {
380 return edgeWeightInfluence;
381 }
382
383 public void setEdgeWeightInfluence(Double edgeWeightInfluence) {
384 this.edgeWeightInfluence = edgeWeightInfluence;
385 }
386
387 public Double getJitterTolerance() {
388 return jitterTolerance;
389 }
390
391 public void setJitterTolerance(Double jitterTolerance) {
392 this.jitterTolerance = jitterTolerance;
393 }
394
395 public Boolean isLinLogMode() {
396 return linLogMode;
397 }
398
399 public void setLinLogMode(Boolean linLogMode) {
400 this.linLogMode = linLogMode;
401 }
402
403 public Double getScalingRatio() {
404 return scalingRatio;
405 }
406
407 public void setScalingRatio(Double scalingRatio) {
408 this.scalingRatio = scalingRatio;
409 }
410
411 public Double getGravity() {
412 return gravity;
413 }
414
415 public void setGravity(Double gravity) {
416 this.gravity = gravity;
417 }
418
419 public Boolean isOutboundAttractionDistribution() {
420 return outboundAttractionDistribution;
421 }
422
423 public void setOutboundAttractionDistribution(Boolean outboundAttractionDistribution) {
424 this.outboundAttractionDistribution = outboundAttractionDistribution;
425 }
426
427 public Boolean isAdjustSizes() {
428 return adjustSizes;
429 }
430
431 public void setAdjustSizes(Boolean adjustSizes) {
432 this.adjustSizes = adjustSizes;
433 }
434
435 public Boolean isBarnesHutOptimize() {
436 return barnesHutOptimize;
437 }
438
439 public void setBarnesHutOptimize(Boolean barnesHutOptimize) {
440 this.barnesHutOptimize = barnesHutOptimize;
441 }
442
443 private float getWeight(Edge edge) {
444 if(timeInterval!=null) {
445 return edge.getWeight(timeInterval.getLow(), timeInterval.getHigh());
446 } else {
447 return edge.getWeight();
448 }
449 }
450}
0451
=== added file 'ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2Builder.java'
--- ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2Builder.java 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2Builder.java 2011-06-05 20:50:57 +0000
@@ -0,0 +1,75 @@
1/*
2Copyright 2008-2011 Gephi
3Authors : Mathieu Jacomy <Mathieu.Jacomy@gmail.com>
4Website : http://www.webatlas.fr
5
6You should have received a copy of the GNU Affero General Public License
7along with ForceAtlas 2. If not, see <http://www.gnu.org/licenses/>.
8*/
9
10package org.webatlas.forceatlas2;
11
12import javax.swing.Icon;
13import javax.swing.JPanel;
14import org.gephi.layout.spi.Layout;
15import org.gephi.layout.spi.LayoutBuilder;
16import org.gephi.layout.spi.LayoutUI;
17import org.openide.util.NbBundle;
18import org.openide.util.lookup.ServiceProvider;
19
20/**
21 * Layout Builder
22 * @author Mathieu Jacomy
23 */
24@ServiceProvider(service = LayoutBuilder.class)
25public class ForceAtlas2Builder implements LayoutBuilder{
26
27 private ForceAtlas2UI ui = new ForceAtlas2UI();
28
29 @Override
30 public String getName() {
31 return NbBundle.getMessage(ForceAtlas2.class, "ForceAtlas2.name");
32 }
33
34 @Override
35 public LayoutUI getUI() {
36 return ui;
37 }
38
39 @Override
40 public ForceAtlas2 buildLayout() {
41 ForceAtlas2 layout = new ForceAtlas2(this);
42 return layout;
43 }
44
45
46 private class ForceAtlas2UI implements LayoutUI{
47
48 @Override
49 public String getDescription() {
50 return NbBundle.getMessage(ForceAtlas2.class, "ForceAtlas2.description");
51 }
52
53 @Override
54 public Icon getIcon() {
55 return null;
56 }
57
58 @Override
59 public JPanel getSimplePanel(Layout layout) {
60 return null;
61 }
62
63 @Override
64 public int getQualityRank() {
65 return 4;
66 }
67
68 @Override
69 public int getSpeedRank() {
70 return 4;
71 }
72
73 }
74
75}
0\ No newline at end of file76\ No newline at end of file
177
=== added file 'ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2LayoutData.java'
--- ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2LayoutData.java 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/src/org/webatlas/forceatlas2/ForceAtlas2LayoutData.java 2011-06-05 20:50:57 +0000
@@ -0,0 +1,24 @@
1/*
2Copyright 2008-2011 Gephi
3Authors : Mathieu Jacomy <Mathieu.Jacomy@gmail.com>
4Website : http://www.webatlas.fr
5
6You should have received a copy of the GNU Affero General Public License
7along with ForceAtlas 2. If not, see <http://www.gnu.org/licenses/>.
8*/
9package org.webatlas.forceatlas2;
10
11import org.gephi.graph.spi.LayoutData;
12
13/**
14 * Data stored in Nodes and used by ForceAtlas2
15 * @author Mathieu Jacomy
16 */
17public class ForceAtlas2LayoutData implements LayoutData{
18 //Data
19 public double dx = 0;
20 public double dy = 0;
21 public double old_dx = 0;
22 public double old_dy = 0;
23 public double mass = 1;
24}
025
=== added file 'ForceAtlas2/src/org/webatlas/forceatlas2/ForceFactory.java'
--- ForceAtlas2/src/org/webatlas/forceatlas2/ForceFactory.java 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/src/org/webatlas/forceatlas2/ForceFactory.java 2011-06-05 20:50:57 +0000
@@ -0,0 +1,510 @@
1/*
2Copyright 2008-2011 Gephi
3Authors : Mathieu Jacomy <Mathieu.Jacomy@gmail.com>
4Website : http://www.webatlas.fr
5
6You should have received a copy of the GNU Affero General Public License
7along with ForceAtlas 2. If not, see <http://www.gnu.org/licenses/>.
8*/
9package org.webatlas.forceatlas2;
10
11import org.gephi.graph.api.Node;
12import org.gephi.graph.api.NodeData;
13
14/**
15 * Generates the forces on demand, here are all the formulas for attraction and repulsion.
16 * @author Mathieu Jacomy
17 */
18public class ForceFactory {
19 public static ForceFactory builder = new ForceFactory();
20
21 private ForceFactory(){};
22
23 public RepulsionForce buildRepulsion(boolean adjustBySize, double coefficient){
24 if(adjustBySize){
25 return new linRepulsion_antiCollision(coefficient);
26 } else {
27 return new linRepulsion(coefficient);
28 }
29 }
30
31 public AttractionForce buildAttraction(boolean logAttraction, boolean distributedAttraction, boolean adjustBySize, double coefficient){
32 if(adjustBySize){
33 if(logAttraction){
34 if(distributedAttraction){
35 return new logAttraction_degreeDistributed_antiCollision(coefficient);
36 } else {
37 return new logAttraction_antiCollision(coefficient);
38 }
39 } else {
40 if(distributedAttraction){
41 return new linAttraction_degreeDistributed_antiCollision(coefficient);
42 } else {
43 return new linAttraction_antiCollision(coefficient);
44 }
45 }
46 } else {
47 if(logAttraction){
48 if(distributedAttraction){
49 return new logAttraction_degreeDistributed(coefficient);
50 } else {
51 return new logAttraction(coefficient);
52 }
53 } else {
54 if(distributedAttraction){
55 return new linAttraction_massDistributed(coefficient);
56 } else {
57 return new linAttraction(coefficient);
58 }
59 }
60 }
61 }
62
63 public abstract class AttractionForce {
64 public abstract void apply(Node n1, Node n2, double e); // Model for node-node attraction (e is for edge weight if needed)
65 }
66
67 public abstract class RepulsionForce {
68 public abstract void apply(Node n1, Node n2); // Model for node-node repulsion
69 public abstract void apply(Node n, Region r); // Model for Barnes Hut approximation
70 public abstract void apply(Node n, double g); // Model for gravitation (anti-repulsion)
71 }
72
73 /*
74 * Repulsion force: Linear
75 */
76 private class linRepulsion extends RepulsionForce{
77 private double coefficient;
78
79 public linRepulsion(double c){
80 coefficient = c;
81 }
82
83 @Override
84 public void apply(Node n1, Node n2) {
85 NodeData n1Data = n1.getNodeData();
86 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
87 NodeData n2Data = n2.getNodeData();
88 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
89
90 // Get the distance
91 double xDist = n1Data.x() - n2Data.x();
92 double yDist = n1Data.y() - n2Data.y();
93 double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
94
95 if (distance > 0) {
96 // NB: factor = force / distance
97 double factor = coefficient * n1Layout.mass * n2Layout.mass / distance / distance;
98
99 n1Layout.dx += xDist * factor;
100 n1Layout.dy += yDist * factor;
101
102 n2Layout.dx -= xDist * factor;
103 n2Layout.dy -= yDist * factor;
104 }
105 }
106
107 @Override
108 public void apply(Node n, Region r) {
109 NodeData nData = n.getNodeData();
110 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
111
112 // Get the distance
113 double xDist = nData.x() - r.getMassCenterX();
114 double yDist = nData.y() - r.getMassCenterY();
115 double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
116
117 if (distance > 0) {
118 // NB: factor = force / distance
119 double factor = coefficient * nLayout.mass * r.getMass() / distance / distance;
120
121 nLayout.dx += xDist * factor;
122 nLayout.dy += yDist * factor;
123 }
124 }
125
126 @Override
127 public void apply(Node n, double g) {
128 NodeData nData = n.getNodeData();
129 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
130
131 // Get the distance
132 double xDist = nData.x();
133 double yDist = nData.y();
134 double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
135
136 if (distance > 0) {
137 // NB: factor = force / distance
138 double factor = coefficient * nLayout.mass * g / distance;
139
140 nLayout.dx -= xDist * factor;
141 nLayout.dy -= yDist * factor;
142 }
143 }
144 }
145
146 /*
147 * Repulsion force: Linear with Anti-collision
148 */
149 private class linRepulsion_antiCollision extends RepulsionForce{
150 private double coefficient;
151
152 public linRepulsion_antiCollision(double c){
153 coefficient = c;
154 }
155
156 @Override
157 public void apply(Node n1, Node n2) {
158 NodeData n1Data = n1.getNodeData();
159 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
160 NodeData n2Data = n2.getNodeData();
161 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
162
163 // Get the distance
164 double xDist = n1Data.x() - n2Data.x();
165 double yDist = n1Data.y() - n2Data.y();
166 double distance = Math.sqrt(xDist * xDist + yDist * yDist) - n1Data.getSize() - n2Data.getSize();
167
168 if (distance > 0) {
169 // NB: factor = force / distance
170 double factor = coefficient * n1Layout.mass * n2Layout.mass / distance / distance;
171
172 n1Layout.dx += xDist * factor;
173 n1Layout.dy += yDist * factor;
174
175 n2Layout.dx -= xDist * factor;
176 n2Layout.dy -= yDist * factor;
177
178 } else if(distance < 0){
179 double factor = 100 * coefficient * n1Layout.mass * n2Layout.mass;
180
181 n1Layout.dx += xDist * factor;
182 n1Layout.dy += yDist * factor;
183
184 n2Layout.dx -= xDist * factor;
185 n2Layout.dy -= yDist * factor;
186 }
187 }
188
189 @Override
190 public void apply(Node n, Region r) {
191 NodeData nData = n.getNodeData();
192 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
193
194 // Get the distance
195 double xDist = nData.x() - r.getMassCenterX();
196 double yDist = nData.y() - r.getMassCenterY();
197 double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
198
199 if (distance > 0) {
200 // NB: factor = force / distance
201 double factor = coefficient * nLayout.mass * r.getMass() / distance / distance;
202
203 nLayout.dx += xDist * factor;
204 nLayout.dy += yDist * factor;
205 } else if(distance < 0){
206 double factor = -coefficient * nLayout.mass * r.getMass() / distance;
207
208 nLayout.dx += xDist * factor;
209 nLayout.dy += yDist * factor;
210 }
211 }
212
213 @Override
214 public void apply(Node n, double g) {
215 NodeData nData = n.getNodeData();
216 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
217
218 // Get the distance
219 double xDist = nData.x();
220 double yDist = nData.y();
221 double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
222
223 if (distance > 0) {
224 // NB: factor = force / distance
225 double factor = coefficient * nLayout.mass * g / distance;
226
227 nLayout.dx -= xDist * factor;
228 nLayout.dy -= yDist * factor;
229 }
230 }
231 }
232
233 /*
234 * Attraction force: Linear
235 */
236 private class linAttraction extends AttractionForce{
237 private double coefficient;
238
239 public linAttraction(double c){
240 coefficient = c;
241 }
242
243 @Override
244 public void apply(Node n1, Node n2, double e) {
245 NodeData n1Data = n1.getNodeData();
246 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
247 NodeData n2Data = n2.getNodeData();
248 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
249
250 // Get the distance
251 double xDist = n1Data.x() - n2Data.x();
252 double yDist = n1Data.y() - n2Data.y();
253
254 // NB: factor = force / distance
255 double factor = -coefficient * e;
256
257 n1Layout.dx += xDist * factor;
258 n1Layout.dy += yDist * factor;
259
260 n2Layout.dx -= xDist * factor;
261 n2Layout.dy -= yDist * factor;
262 }
263 }
264
265 /*
266 * Attraction force: Linear, distributed by mass (typically, degree)
267 */
268 private class linAttraction_massDistributed extends AttractionForce{
269 private double coefficient;
270
271 public linAttraction_massDistributed(double c){
272 coefficient = c;
273 }
274
275 @Override
276 public void apply(Node n1, Node n2, double e) {
277 NodeData n1Data = n1.getNodeData();
278 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
279 NodeData n2Data = n2.getNodeData();
280 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
281
282 // Get the distance
283 double xDist = n1Data.x() - n2Data.x();
284 double yDist = n1Data.y() - n2Data.y();
285
286 // NB: factor = force / distance
287 double factor = -coefficient * e / n1Layout.mass;
288
289 n1Layout.dx += xDist * factor;
290 n1Layout.dy += yDist * factor;
291
292 n2Layout.dx -= xDist * factor;
293 n2Layout.dy -= yDist * factor;
294 }
295 }
296
297 /*
298 * Attraction force: Logarithmic
299 */
300 private class logAttraction extends AttractionForce{
301 private double coefficient;
302
303 public logAttraction(double c){
304 coefficient = c;
305 }
306
307 @Override
308 public void apply(Node n1, Node n2, double e) {
309 NodeData n1Data = n1.getNodeData();
310 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
311 NodeData n2Data = n2.getNodeData();
312 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
313
314 // Get the distance
315 double xDist = n1Data.x() - n2Data.x();
316 double yDist = n1Data.y() - n2Data.y();
317 double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
318
319 if (distance > 0) {
320
321 // NB: factor = force / distance
322 double factor = -coefficient * e * Math.log(1+distance) / distance;
323
324 n1Layout.dx += xDist * factor;
325 n1Layout.dy += yDist * factor;
326
327 n2Layout.dx -= xDist * factor;
328 n2Layout.dy -= yDist * factor;
329 }
330 }
331 }
332
333 /*
334 * Attraction force: Linear, distributed by Degree
335 */
336 private class logAttraction_degreeDistributed extends AttractionForce{
337 private double coefficient;
338
339 public logAttraction_degreeDistributed(double c){
340 coefficient = c;
341 }
342
343 @Override
344 public void apply(Node n1, Node n2, double e) {
345 NodeData n1Data = n1.getNodeData();
346 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
347 NodeData n2Data = n2.getNodeData();
348 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
349
350 // Get the distance
351 double xDist = n1Data.x() - n2Data.x();
352 double yDist = n1Data.y() - n2Data.y();
353 double distance = (float) Math.sqrt(xDist * xDist + yDist * yDist);
354
355 if (distance > 0) {
356
357 // NB: factor = force / distance
358 double factor = -coefficient * e * Math.log(1+distance) / distance / n1Layout.mass;
359
360 n1Layout.dx += xDist * factor;
361 n1Layout.dy += yDist * factor;
362
363 n2Layout.dx -= xDist * factor;
364 n2Layout.dy -= yDist * factor;
365 }
366 }
367 }
368
369 /*
370 * Attraction force: Linear, with Anti-Collision
371 */
372 private class linAttraction_antiCollision extends AttractionForce{
373 private double coefficient;
374
375 public linAttraction_antiCollision(double c){
376 coefficient = c;
377 }
378
379 @Override
380 public void apply(Node n1, Node n2, double e) {
381 NodeData n1Data = n1.getNodeData();
382 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
383 NodeData n2Data = n2.getNodeData();
384 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
385
386 // Get the distance
387 double xDist = n1Data.x() - n2Data.x();
388 double yDist = n1Data.y() - n2Data.y();
389 double distance = Math.sqrt(xDist * xDist + yDist * yDist) - n1Data.getSize() - n2Data.getSize();
390
391 if(distance>0){
392 // NB: factor = force / distance
393 double factor = -coefficient * e;
394
395 n1Layout.dx += xDist * factor;
396 n1Layout.dy += yDist * factor;
397
398 n2Layout.dx -= xDist * factor;
399 n2Layout.dy -= yDist * factor;
400 }
401 }
402 }
403
404 /*
405 * Attraction force: Linear, distributed by Degree, with Anti-Collision
406 */
407 private class linAttraction_degreeDistributed_antiCollision extends AttractionForce{
408 private double coefficient;
409
410 public linAttraction_degreeDistributed_antiCollision(double c){
411 coefficient = c;
412 }
413
414 @Override
415 public void apply(Node n1, Node n2, double e) {
416 NodeData n1Data = n1.getNodeData();
417 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
418 NodeData n2Data = n2.getNodeData();
419 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
420
421 // Get the distance
422 double xDist = n1Data.x() - n2Data.x();
423 double yDist = n1Data.y() - n2Data.y();
424 double distance = Math.sqrt(xDist * xDist + yDist * yDist) - n1Data.getSize() - n2Data.getSize();
425
426 if(distance>0){
427 // NB: factor = force / distance
428 double factor = -coefficient * e / n1Layout.mass;
429
430 n1Layout.dx += xDist * factor;
431 n1Layout.dy += yDist * factor;
432
433 n2Layout.dx -= xDist * factor;
434 n2Layout.dy -= yDist * factor;
435 }
436 }
437 }
438
439 /*
440 * Attraction force: Logarithmic, with Anti-Collision
441 */
442 private class logAttraction_antiCollision extends AttractionForce{
443 private double coefficient;
444
445 public logAttraction_antiCollision(double c){
446 coefficient = c;
447 }
448
449 @Override
450 public void apply(Node n1, Node n2, double e) {
451 NodeData n1Data = n1.getNodeData();
452 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
453 NodeData n2Data = n2.getNodeData();
454 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
455
456 // Get the distance
457 double xDist = n1Data.x() - n2Data.x();
458 double yDist = n1Data.y() - n2Data.y();
459 double distance = Math.sqrt(xDist * xDist + yDist * yDist) - n1Data.getSize() - n2Data.getSize();
460
461 if(distance>0){
462
463 // NB: factor = force / distance
464 double factor = -coefficient * e * Math.log(1+distance) / distance;
465
466 n1Layout.dx += xDist * factor;
467 n1Layout.dy += yDist * factor;
468
469 n2Layout.dx -= xDist * factor;
470 n2Layout.dy -= yDist * factor;
471 }
472 }
473 }
474
475 /*
476 * Attraction force: Linear, distributed by Degree, with Anti-Collision
477 */
478 private class logAttraction_degreeDistributed_antiCollision extends AttractionForce{
479 private double coefficient;
480
481 public logAttraction_degreeDistributed_antiCollision(double c){
482 coefficient = c;
483 }
484
485 @Override
486 public void apply(Node n1, Node n2, double e) {
487 NodeData n1Data = n1.getNodeData();
488 ForceAtlas2LayoutData n1Layout = n1Data.getLayoutData();
489 NodeData n2Data = n2.getNodeData();
490 ForceAtlas2LayoutData n2Layout = n2Data.getLayoutData();
491
492 // Get the distance
493 double xDist = n1Data.x() - n2Data.x();
494 double yDist = n1Data.y() - n2Data.y();
495 double distance = Math.sqrt(xDist * xDist + yDist * yDist) - n1Data.getSize() - n2Data.getSize();
496
497 if(distance>0){
498
499 // NB: factor = force / distance
500 double factor = -coefficient * e * Math.log(1+distance) / distance / n1Layout.mass;
501
502 n1Layout.dx += xDist * factor;
503 n1Layout.dy += yDist * factor;
504
505 n2Layout.dx -= xDist * factor;
506 n2Layout.dy -= yDist * factor;
507 }
508 }
509 }
510}
0511
=== added file 'ForceAtlas2/src/org/webatlas/forceatlas2/Region.java'
--- ForceAtlas2/src/org/webatlas/forceatlas2/Region.java 1970-01-01 00:00:00 +0000
+++ ForceAtlas2/src/org/webatlas/forceatlas2/Region.java 2011-06-05 20:50:57 +0000
@@ -0,0 +1,197 @@
1/*
2Copyright 2008-2011 Gephi
3Authors : Mathieu Jacomy <Mathieu.Jacomy@gmail.com>
4Website : http://www.webatlas.fr
5
6You should have received a copy of the GNU Affero General Public License
7along with ForceAtlas 2. If not, see <http://www.gnu.org/licenses/>.
8*/
9package org.webatlas.forceatlas2;
10
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.List;
14import org.gephi.graph.api.Node;
15import org.gephi.graph.api.NodeData;
16import org.webatlas.forceatlas2.ForceFactory.RepulsionForce;
17
18/**
19 * Barnes Hut optimization
20 * @author Mathieu Jacomy
21 */
22public class Region{
23
24 private double mass;
25
26 private double massCenterX;
27 private double massCenterY;
28 private double size;
29
30 private List<Node> nodes;
31 private List<Region> subregions = new ArrayList<Region>();
32
33 public Region(Node[] nodes){
34 this.nodes = new ArrayList<Node>();
35 this.nodes.addAll(Arrays.asList(nodes));
36 updateMassAndGeometry();
37 }
38
39 public Region(ArrayList<Node> nodes){
40 this.nodes = new ArrayList<Node>(nodes);
41 updateMassAndGeometry();
42 }
43
44 public void updateMassAndGeometry(){
45 if(nodes.size()>1){
46 // Compute Mass
47 mass = 0;
48 double massSumX = 0;
49 double massSumY = 0;
50 for(Node n : nodes){
51 NodeData nData = n.getNodeData();
52 ForceAtlas2LayoutData nLayout = nData.getLayoutData();
53 mass += nLayout.mass;
54 massSumX += nData.x() * nLayout.mass;
55 massSumY += nData.y() * nLayout.mass;
56 }
57 massCenterX = massSumX / mass;
58 massCenterY = massSumY / mass;
59
60 // Compute size
61 size = Double.MIN_VALUE;
62 for(Node n : nodes){
63 NodeData nData = n.getNodeData();
64 double distance = Math.sqrt((nData.x()-massCenterX)*(nData.x()-massCenterX) + (nData.y()-massCenterY)*(nData.y()-massCenterY));
65 size = Math.max(size, 2*distance);
66 }
67 }
68 }
69
70 public void buildSubRegions(){
71 if(nodes.size()>1){
72 ArrayList<Node> leftNodes = new ArrayList<Node>();
73 ArrayList<Node> rightNodes = new ArrayList<Node>();
74 for(Node n : nodes){
75 NodeData nData = n.getNodeData();
76 ArrayList<Node> nodesColumn = (nData.x()<massCenterX)?(leftNodes):(rightNodes);
77 nodesColumn.add(n);
78 }
79
80 ArrayList<Node> topleftNodes = new ArrayList<Node>();
81 ArrayList<Node> bottomleftNodes = new ArrayList<Node>();
82 for(Node n : leftNodes){
83 NodeData nData = n.getNodeData();
84 ArrayList<Node> nodesLine = (nData.y()<massCenterY)?(topleftNodes):(bottomleftNodes);
85 nodesLine.add(n);
86 }
87
88 ArrayList<Node> bottomrightNodes = new ArrayList<Node>();
89 ArrayList<Node> toprightNodes = new ArrayList<Node>();
90 for(Node n : rightNodes){
91 NodeData nData = n.getNodeData();
92 ArrayList<Node> nodesLine = (nData.y()<massCenterY)?(toprightNodes):(bottomrightNodes);
93 nodesLine.add(n);
94 }
95
96 if(topleftNodes.size()>0){
97 if(topleftNodes.size()<nodes.size()){
98 Region subregion = new Region(topleftNodes);
99 subregions.add(subregion);
100 } else {
101 for(Node n : topleftNodes){
102 ArrayList<Node> oneNodeList = new ArrayList<Node>();
103 oneNodeList.add(n);
104 Region subregion = new Region(oneNodeList);
105 subregions.add(subregion);
106 }
107 }
108 }
109 if(bottomleftNodes.size()>0){
110 if(bottomleftNodes.size()<nodes.size()){
111 Region subregion = new Region(bottomleftNodes);
112 subregions.add(subregion);
113 } else {
114 for(Node n : bottomleftNodes){
115 ArrayList<Node> oneNodeList = new ArrayList<Node>();
116 oneNodeList.add(n);
117 Region subregion = new Region(oneNodeList);
118 subregions.add(subregion);
119 }
120 }
121 }
122 if(bottomrightNodes.size()>0){
123 if(bottomrightNodes.size()<nodes.size()){
124 Region subregion = new Region(bottomrightNodes);
125 subregions.add(subregion);
126 } else {
127 for(Node n : bottomrightNodes){
128 ArrayList<Node> oneNodeList = new ArrayList<Node>();
129 oneNodeList.add(n);
130 Region subregion = new Region(oneNodeList);
131 subregions.add(subregion);
132 }
133 }
134 }
135 if(toprightNodes.size()>0){
136 if(toprightNodes.size()<nodes.size()){
137 Region subregion = new Region(toprightNodes);
138 subregions.add(subregion);
139 } else {
140 for(Node n : toprightNodes){
141 ArrayList<Node> oneNodeList = new ArrayList<Node>();
142 oneNodeList.add(n);
143 Region subregion = new Region(oneNodeList);
144 subregions.add(subregion);
145 }
146 }
147 }
148
149 for(Region subregion : subregions){
150 subregion.buildSubRegions();
151 }
152 }
153 }
154
155 public void applyForce(Node n, RepulsionForce Force, double theta){
156 NodeData nData = n.getNodeData();
157 if(nodes.size() < 2){
158 Node regionNode = nodes.get(0);
159 Force.apply(n, regionNode);
160 } else {
161 double distance = Math.sqrt((nData.x()-massCenterX)*(nData.x()-massCenterX) + (nData.y() - massCenterY)*(nData.y()-massCenterY));
162 if(distance * theta > size){
163 Force.apply(n, this);
164 } else {
165 for (Region subregion : subregions) {
166 subregion.applyForce(n, Force, theta);
167 }
168 }
169 }
170 }
171
172 public double getMass() {
173 return mass;
174 }
175
176 public void setMass(double mass) {
177 this.mass = mass;
178 }
179
180 public double getMassCenterX() {
181 return massCenterX;
182 }
183
184 public void setMassCenterX(double massCenterX) {
185 this.massCenterX = massCenterX;
186 }
187
188 public double getMassCenterY() {
189 return massCenterY;
190 }
191
192 public void setMassCenterY(double massCenterY) {
193 this.massCenterY = massCenterY;
194 }
195
196
197}
0198
=== added directory 'ForceAtlas2/test'
=== added directory 'ForceAtlas2/test/unit'
=== added directory 'ForceAtlas2/test/unit/src'

Subscribers

People subscribed via source and target branches