Skip to content

Commit b9eb10c

Browse files
authored
Merge pull request #2 from finnor/feature_Concentric-Layout
Feature concentric layout
2 parents 7a705d9 + cc42678 commit b9eb10c

File tree

8 files changed

+359
-21
lines changed

8 files changed

+359
-21
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<artifactId>wkshelldecomposition</artifactId>
1818
<name>wk-shell-decomposition</name>
1919
<packaging>bundle</packaging>
20-
<version>1.0.1</version>
20+
<version>1.1.0</version>
2121

2222
<build>
2323
<resources>

src/main/java/edu/uab/mukhtarlab/wkshelldecomposition/internal/CyActivator.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
package edu.uab.mukhtarlab.wkshelldecomposition.internal;
22

3-
import static org.cytoscape.work.ServiceProperties.COMMAND;
4-
import static org.cytoscape.work.ServiceProperties.COMMAND_NAMESPACE;
5-
import static org.cytoscape.work.ServiceProperties.COMMAND_DESCRIPTION;
6-
import static org.cytoscape.work.ServiceProperties.COMMAND_LONG_DESCRIPTION;
7-
83
import java.util.Properties;
94

105
import org.cytoscape.application.swing.CyAction;
11-
import org.cytoscape.application.swing.CySwingApplication;
126
import org.cytoscape.service.util.AbstractCyActivator;
137
import org.cytoscape.service.util.CyServiceRegistrar;
148
import org.cytoscape.work.TaskFactory;
@@ -17,6 +11,8 @@
1711
import edu.uab.mukhtarlab.wkshelldecomposition.internal.action.DecomposeAction;
1812
import edu.uab.mukhtarlab.wkshelldecomposition.internal.task.DecomposeCommandTaskFactory;
1913

14+
import static org.cytoscape.work.ServiceProperties.*;
15+
2016
/**
2117
* CyActivator for app
2218
*/
@@ -29,13 +25,12 @@ public class CyActivator extends AbstractCyActivator {
2925
@SuppressWarnings("unchecked")
3026
public void start(BundleContext bc) {
3127
registrar = getService(bc, CyServiceRegistrar.class);
32-
33-
CySwingApplication swingApp = getService(bc, CySwingApplication.class);
34-
28+
3529
DecomposeAction decomposeAction = new DecomposeAction("wk-shell decomposition", registrar);
3630

3731
registerService(bc, decomposeAction, CyAction.class);
38-
32+
33+
3934
// Commands
4035
{
4136
DecomposeCommandTaskFactory factory = new DecomposeCommandTaskFactory(registrar);

src/main/java/edu/uab/mukhtarlab/wkshelldecomposition/internal/action/DecomposeAction.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
import org.cytoscape.model.*;
1111
import org.cytoscape.service.util.CyServiceRegistrar;
1212

13+
import org.cytoscape.view.model.CyNetworkView;
14+
import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
15+
import org.cytoscape.view.vizmap.VisualStyleFactory;
1316
import org.cytoscape.work.FinishStatus;
1417
import org.cytoscape.work.ObservableTask;
1518
import org.cytoscape.work.TaskObserver;
@@ -42,6 +45,11 @@ public DecomposeAction(
4245
@Override
4346
public void actionPerformed(final ActionEvent event) {
4447
final CyNetwork network = applicationManager.getCurrentNetwork();
48+
CyNetworkView nView = applicationManager.getCurrentNetworkView();
49+
50+
VisualStyleFactory visualStyleFactoryServiceRef = registrar.getService(VisualStyleFactory.class);
51+
VisualMappingFunctionFactory vmfFactoryC = registrar.getService(VisualMappingFunctionFactory.class, "(mapping.type=continuous)");
52+
VisualMappingFunctionFactory vmfFactoryP = registrar.getService(VisualMappingFunctionFactory.class, "(mapping.type=passthrough)");
4553

4654
TaskObserver taskObserver = new TaskObserver() {
4755
@Override
@@ -69,11 +77,11 @@ public void allFinished(FinishStatus finishStatus) {
6977
}
7078
};
7179

72-
execute(network, taskObserver);
80+
execute(network, nView, visualStyleFactoryServiceRef, vmfFactoryC, vmfFactoryP, taskObserver);
7381
}
7482

75-
private void execute(CyNetwork network, TaskObserver taskObserver) {
76-
DecomposeTaskFactory tf = new DecomposeTaskFactory(network);
83+
private void execute(CyNetwork network, CyNetworkView nView, VisualStyleFactory visualStyleFactoryServiceRef, VisualMappingFunctionFactory vmfFactoryC, VisualMappingFunctionFactory vmfFactoryP, TaskObserver taskObserver) {
84+
DecomposeTaskFactory tf = new DecomposeTaskFactory(network, nView, visualStyleFactoryServiceRef, vmfFactoryC, vmfFactoryP);
7785
registrar.getService(DialogTaskManager.class).execute(tf.createTaskIterator(), taskObserver);
7886
}
7987
}
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
package edu.uab.mukhtarlab.wkshelldecomposition.internal.task;
2+
3+
import com.google.gson.Gson;
4+
import org.cytoscape.model.*;
5+
import org.cytoscape.view.model.CyNetworkView;
6+
import org.cytoscape.view.model.View;
7+
import org.cytoscape.view.presentation.property.BasicVisualLexicon;
8+
import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
9+
import org.cytoscape.view.vizmap.VisualStyle;
10+
import org.cytoscape.view.vizmap.VisualStyleFactory;
11+
import org.cytoscape.view.vizmap.mappings.BoundaryRangeValues;
12+
import org.cytoscape.view.vizmap.mappings.ContinuousMapping;
13+
import org.cytoscape.view.vizmap.mappings.DiscreteMapping;
14+
import org.cytoscape.view.vizmap.mappings.PassthroughMapping;
15+
import org.cytoscape.work.ObservableTask;
16+
import org.cytoscape.work.TaskMonitor;
17+
import org.cytoscape.work.json.JSONResult;
18+
19+
import java.awt.*;
20+
import java.util.*;
21+
import java.util.List;
22+
23+
24+
/**
25+
* Performs the weighted k-shell decomposition
26+
*/
27+
28+
public class ConcentricLayoutTask implements ObservableTask {
29+
30+
private boolean cancelled;
31+
private final CyNetwork network;
32+
private final CyNetworkView nView;
33+
private final VisualStyleFactory visualStyleFactoryServiceRef;
34+
private final VisualMappingFunctionFactory vmfFactoryC;
35+
private final VisualMappingFunctionFactory vmfFactoryP;
36+
37+
public ConcentricLayoutTask(
38+
CyNetwork network,
39+
CyNetworkView nView,
40+
VisualStyleFactory visualStyleFactoryServiceRef,
41+
VisualMappingFunctionFactory vmfFactoryC,
42+
VisualMappingFunctionFactory vmfFactoryP
43+
) {
44+
this.network = network;
45+
this.nView = nView;
46+
this.visualStyleFactoryServiceRef = visualStyleFactoryServiceRef;
47+
this.vmfFactoryC = vmfFactoryC;
48+
this.vmfFactoryP = vmfFactoryP;
49+
}
50+
51+
/**
52+
* Runs the layout
53+
*/
54+
@Override
55+
public void run(TaskMonitor tm) throws Exception {
56+
double nodeDiameter = 20.0;
57+
58+
int layers = 20;
59+
60+
int currentNode = 0;
61+
int nodesPerCircle = 1;
62+
int currentCircle = 0;
63+
double circleGap = 5.0;
64+
int currentLayer = 0;
65+
double layerGap = 50.0;
66+
67+
double currentPositionRadius = 0;
68+
double angle = 0;
69+
double x = 0;
70+
double y = 0;
71+
double angleOffset = 0;
72+
73+
CyRow row;
74+
Integer percentileBucket;
75+
Integer shell;
76+
double circlePerimeter;
77+
int maxShell = 0;
78+
79+
List<CyNode> nodes = network.getNodeList();
80+
//sort nodes by bucket, shell
81+
Comparator<CyNode> comparator = new Comparator<CyNode>() {
82+
@Override
83+
public int compare(CyNode a, CyNode b) {
84+
CyRow aRow = network.getRow(a);
85+
CyRow bRow = network.getRow(b);
86+
87+
Integer aShell = aRow.get("_wkshell", Integer.class);
88+
Integer bShell = bRow.get("_wkshell", Integer.class);
89+
aShell = (aShell!=null) ? aShell : 0;
90+
bShell = (bShell!=null) ? bShell : 0;
91+
if(bShell!=aShell) {
92+
return bShell - aShell;
93+
} else {
94+
Integer aBucket = aRow.get("_wks_percentile_bucket", Integer.class);
95+
Integer bBucket = bRow.get("_wks_percentile_bucket", Integer.class);
96+
aBucket = (aBucket!=null) ? aBucket : 0;
97+
bBucket = (bBucket!=null) ? bBucket : 0;
98+
return bBucket - aBucket;
99+
}
100+
101+
}
102+
};
103+
nodes.sort(comparator);
104+
105+
boolean layerChange = false;
106+
boolean circleChange = false;
107+
108+
for (final CyNode node : nodes) {
109+
View<CyNode> nodeView = nView.getNodeView(node);
110+
row = network.getRow(node);
111+
112+
//Get max shell for gradient mapping later
113+
shell = row.get("_wkshell", Integer.class);
114+
shell = (shell!=null) ? shell : 0;
115+
if(shell>maxShell) {
116+
maxShell = shell;
117+
}
118+
119+
//For unimplemented layering
120+
percentileBucket = row.get("_wks_percentile_bucket", Integer.class);
121+
percentileBucket = (percentileBucket!=null) ? percentileBucket : 0;
122+
layerChange = false;//((layers-1-(percentileBucket/5))>currentLayer);
123+
if(layerChange) {
124+
currentLayer = layers-1-(percentileBucket/5);
125+
}
126+
127+
//Does this node need to start a new circle for filling
128+
circleChange = (currentNode>=(nodesPerCircle));
129+
if(circleChange) {
130+
currentCircle++;
131+
}
132+
133+
//If new circle for filling, update radius
134+
if(layerChange || circleChange){
135+
currentNode = 0;
136+
currentPositionRadius = (((double) currentCircle)*(nodeDiameter+circleGap)) + (((double) currentLayer)*layerGap);
137+
circlePerimeter = Math.PI*currentPositionRadius*2.0;
138+
nodesPerCircle = (int) (circlePerimeter/((nodeDiameter+circleGap)));
139+
}
140+
141+
//TODO Maybe
142+
//Add an extra angle offset for the last circle if its empty to evenly space out the nodes within the circle
143+
//Would have to if on last circle and how many nodes there are in the last circle
144+
145+
146+
angle = Math.toRadians((((double) currentNode)/((double) nodesPerCircle))*360.0);
147+
x = Math.cos(angle) * currentPositionRadius;
148+
y = Math.sin(angle) * currentPositionRadius;
149+
150+
nodeView.setVisualProperty(BasicVisualLexicon.NODE_X_LOCATION,x);
151+
nodeView.setVisualProperty(BasicVisualLexicon.NODE_Y_LOCATION,y);
152+
153+
currentNode++;
154+
}
155+
156+
157+
158+
VisualStyle vs = getVisualStyle(nodeDiameter, maxShell);
159+
vs.apply(nView);
160+
161+
nView.updateView();
162+
nView.fitContent();
163+
}
164+
165+
private VisualStyle getVisualStyle(double nodeDiameter, int maxShell) {
166+
VisualStyle vs = visualStyleFactoryServiceRef.createVisualStyle("Shell gradient");
167+
vs.setDefaultValue(BasicVisualLexicon.NODE_BORDER_PAINT, Color.BLACK); //Default handles null shell
168+
//Mapping for border paint handled below
169+
vs.setDefaultValue(BasicVisualLexicon.NODE_BORDER_WIDTH, nodeDiameter/10.0);
170+
vs.setDefaultValue(BasicVisualLexicon.NODE_FILL_COLOR, Color.WHITE); //Default handles null shell
171+
//Mapping for fill color handled below
172+
vs.setDefaultValue(BasicVisualLexicon.NODE_HEIGHT, nodeDiameter);
173+
//Mapping for label handled below
174+
vs.setDefaultValue(BasicVisualLexicon.NODE_LABEL_COLOR, Color.BLACK);
175+
vs.setDefaultValue(BasicVisualLexicon.NODE_LABEL_FONT_SIZE, (int)(nodeDiameter*0.3));
176+
vs.setDefaultValue(BasicVisualLexicon.NODE_TRANSPARENCY, 255);
177+
vs.setDefaultValue(BasicVisualLexicon.NODE_WIDTH, nodeDiameter);
178+
179+
vs.setDefaultValue(BasicVisualLexicon.NODE_SIZE, nodeDiameter);
180+
vs.setDefaultValue(BasicVisualLexicon.NODE_OPACITY, 200);
181+
182+
183+
//Fill Color
184+
ContinuousMapping fillMapping = (ContinuousMapping)
185+
vmfFactoryC.createVisualMappingFunction("_wkshell", Integer.class, BasicVisualLexicon.NODE_FILL_COLOR);
186+
// Define the points
187+
Double val1 = 1d;
188+
BoundaryRangeValues<Paint> brv1 = new BoundaryRangeValues<Paint>(Color.BLUE, Color.BLUE, Color.BLUE);
189+
Double val2 = (double) maxShell;
190+
BoundaryRangeValues<Paint> brv2 = new BoundaryRangeValues<Paint>(Color.RED, Color.RED, Color.RED);
191+
// Set the points
192+
fillMapping.addPoint(val1, brv1);
193+
fillMapping.addPoint(val2, brv2);
194+
// add the mapping to visual style
195+
vs.addVisualMappingFunction(fillMapping);
196+
197+
//Border paint
198+
ContinuousMapping borderMapping = (ContinuousMapping)
199+
vmfFactoryC.createVisualMappingFunction("_wkshell", Integer.class, BasicVisualLexicon.NODE_BORDER_PAINT);
200+
//Reuse points from fill color
201+
// Set the points
202+
borderMapping.addPoint(val1, brv1);
203+
borderMapping.addPoint(val2, brv2);
204+
//add the mapping to visual style
205+
vs.addVisualMappingFunction(borderMapping);
206+
207+
//Label
208+
PassthroughMapping labelMapping = (PassthroughMapping)
209+
vmfFactoryP.createVisualMappingFunction("name", String.class, BasicVisualLexicon.NODE_LABEL);
210+
211+
212+
213+
vs.addVisualMappingFunction(labelMapping);
214+
215+
return vs;
216+
}
217+
218+
@Override
219+
public void cancel() {
220+
cancelled = true;
221+
}
222+
223+
@Override
224+
@SuppressWarnings({ "rawtypes", "unchecked" })
225+
public Object getResults(Class type) {
226+
if (type == CyNetworkView.class)
227+
return nView;
228+
229+
if (type == String.class) {
230+
return "Created view: " + nView;
231+
}
232+
233+
if (type == JSONResult.class) {
234+
Gson gson = new Gson();
235+
JSONResult res = () -> { return gson.toJson(nView); };
236+
237+
return res;
238+
}
239+
240+
return null;
241+
}
242+
243+
@Override
244+
public List<Class<?>> getResultClasses() {
245+
return Arrays.asList(CyNetworkView.class, String.class, JSONResult.class);
246+
}
247+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package edu.uab.mukhtarlab.wkshelldecomposition.internal.task;
2+
3+
4+
import org.cytoscape.model.CyNetwork;
5+
import org.cytoscape.view.model.CyNetworkView;
6+
import org.cytoscape.view.vizmap.VisualMappingFunctionFactory;
7+
import org.cytoscape.view.vizmap.VisualStyleFactory;
8+
import org.cytoscape.work.TaskFactory;
9+
import org.cytoscape.work.TaskIterator;
10+
11+
/**
12+
* Applies ConcentricLayout to the given CyNetworkView
13+
*/
14+
public class ConcentricLayoutTaskFactory implements TaskFactory {
15+
private CyNetwork network;
16+
private CyNetworkView nView;
17+
private VisualStyleFactory visualStyleFactoryServiceRef;
18+
private VisualMappingFunctionFactory vmfFactoryC;
19+
private VisualMappingFunctionFactory vmfFactoryP;
20+
21+
public ConcentricLayoutTaskFactory(
22+
CyNetwork network,
23+
CyNetworkView nView,
24+
VisualStyleFactory visualStyleFactoryServiceRef,
25+
VisualMappingFunctionFactory vmfFactoryC,
26+
VisualMappingFunctionFactory vmfFactoryP
27+
) {
28+
this.network = network;
29+
this.nView = nView;
30+
this.visualStyleFactoryServiceRef = visualStyleFactoryServiceRef;
31+
this.vmfFactoryC = vmfFactoryC;
32+
this.vmfFactoryP = vmfFactoryP;
33+
}
34+
35+
@Override
36+
public TaskIterator createTaskIterator() {
37+
return new TaskIterator(new ConcentricLayoutTask(network, nView, visualStyleFactoryServiceRef, vmfFactoryC, vmfFactoryP));
38+
}
39+
40+
@Override
41+
public boolean isReady() {
42+
return true;
43+
}
44+
45+
46+
public boolean isReady(CyNetworkView view) {
47+
return view != null;
48+
};
49+
}

0 commit comments

Comments
 (0)