Skip to content

Commit 3a7f314

Browse files
committed
WIP
1 parent 92835b9 commit 3a7f314

File tree

11 files changed

+375
-16
lines changed

11 files changed

+375
-16
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
dist
1+
dist
2+
__pycache__
3+
.pytest_cache
4+
gephi-toolkit-all.jar

README.md

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,112 @@
1-
# Gephipy
1+
# Gephipy
2+
3+
This project is Python wrapper of [Gephi toolkit](https://gephi.org/toolkit/), thanks to [Jpype](https://www.jpype.org) which does the bindings between Java and Python.
4+
5+
It provides helpers to easy the use of Gephy toolkit for Pythonist, even if you still ned to know the Java API.
6+
7+
## How to use
8+
9+
* Install the lib `pip install gephipy`
10+
11+
* Initialize the GephiPy context
12+
13+
```python
14+
from gephipy import gephipy
15+
16+
gephipy.initialize()
17+
```
18+
19+
Then you can use the Gephi toolkit or the GephiPy features.
20+
21+
## Example
22+
23+
```python
24+
from gephipy import gephipy
25+
from org.gephi.statistics.plugin import Modularity, GraphDistance
26+
27+
#
28+
# Init context
29+
#
30+
gephipy.initialize()
31+
32+
#
33+
# Create a workspace
34+
#
35+
workspace = gephipy.create_workspace()
36+
37+
#
38+
# Import a GEXF file
39+
#
40+
gephipy.import_gexf(workspace, "./graph.gexf")
41+
graphModel = gephipy.get_graph_model(workspace)
42+
43+
#
44+
# Compute some metrics
45+
#
46+
47+
# Louvain
48+
modularity = Modularity()
49+
modularity.execute(graphModel)
50+
51+
# Betweeness centrality
52+
centrality = GraphDistance()
53+
centrality.setDirected(True)
54+
centrality.execute(graphModel)
55+
56+
#
57+
# Apply appearance
58+
# Here it is really looks like java code
59+
#
60+
61+
appearanceController = Lookup.getDefault().lookup(AppearanceController)
62+
appearanceModel = appearanceController.getModel()
63+
64+
# Size Make node size based on centrality
65+
centralityColumn = graphModel.getNodeTable().getColumn(GraphDistance.BETWEENNESS)
66+
centralityRanking = appearanceModel.getNodeFunction(centralityColumn, RankingNodeSizeTransformer)
67+
centralityTransformer = centralityRanking.getTransformer()
68+
centralityTransformer.setMinSize(10)
69+
centralityTransformer.setMaxSize(100)
70+
appearanceController.transform(centralityRanking)
71+
72+
73+
# Color by community
74+
communityColumn = graphModel.getNodeTable().getColumn(Modularity.MODULARITY_CLASS)
75+
colorPartition = appearanceModel.getNodeFunction(communityColumn, PartitionElementColorTransformer)
76+
partition = colorPartition.getPartition()
77+
palette = PaletteManager.getInstance().generatePalette(partition.size(graphModel.getGraph()))
78+
partition.setColors(graphModel.getGraph(), palette.getColors())
79+
appearanceController.transform(colorPartition)
80+
81+
82+
#
83+
# Run Layouts
84+
#
85+
86+
# Random layout
87+
random = Random().buildLayout()
88+
random.setGraphModel(gephipy.get_graph_model(workspace))
89+
random.initAlgo();
90+
random.goAlgo()
91+
random.endAlgo();
92+
93+
# FA2 layout
94+
fa2 = ForceAtlas2Builder().buildLayout()
95+
fa2.setGraphModel(gephipy.get_graph_model(workspace))
96+
fa2.resetPropertiesValues();
97+
fa2.initAlgo();
98+
for x in range(1000):
99+
fa2.goAlgo()
100+
101+
# Noverlap layout
102+
noverlap = NoverlapLayoutBuilder().buildLayout()
103+
noverlap.setGraphModel(gephipy.get_graph_model(workspace))
104+
noverlap.initAlgo()
105+
noverlap.endAlgo()
106+
107+
#
108+
# Export your graph
109+
#
110+
111+
gephipy.export_gexf(workspace, "my-gephi-graph.gexf")
112+
```
-2.97 KB
Binary file not shown.

dist/gephipy-0.0.1.tar.gz

-2.19 KB
Binary file not shown.

gephipy/gephipy.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import jpype
2+
23
from pathlib import Path
34
import urllib.request
45
import networkx as nx
56

7+
from java.io import File
68
from org.openide.util import Lookup
79
from org.gephi.graph.api import GraphController
810
from org.gephi.project.api import ProjectController
11+
from org.gephi.io.processor.plugin import DefaultProcessor
12+
from org.gephi.io.exporter.api import ExportController
13+
from org.gephi.io.importer.api import ImportController, EdgeDirectionDefault
914

1015
GTK_URL="https://repo1.maven.org/maven2/org/gephi/gephi-toolkit/0.10.1/gephi-toolkit-0.10.1-all.jar"
1116

@@ -24,23 +29,27 @@ def initialize(gephi_jar_path="./gephi-toolkit-all.jar"):
2429
print(f"Warning: {e}")
2530

2631
#
27-
# Create a new Gephi project in a fresh workspace and returns it associated graph model instance
32+
# Create a new Gephi workspace
2833
#
29-
def gephi_create_graph():
34+
def create_workspace():
3035
# Create a Gephi workspace
3136
pc = Lookup.getDefault().lookup(ProjectController)
3237
pc.newProject()
33-
workspace = pc.getCurrentWorkspace()
34-
# returns the graph model
38+
return pc.getCurrentWorkspace()
39+
40+
#
41+
# Get the graph model of
42+
#
43+
def get_graph_model(workspace):
3544
return Lookup.getDefault().lookup(GraphController).getGraphModel(workspace)
3645

3746
#
3847
# Function to load a NetworkX instance in Gephi
3948
# This function takes a networkX instance and returns a Gephi graphModel
4049
#
41-
def networkx_to_gephi(graphX):
50+
def networkx_to_gephi(workspace, graphX):
4251
# Get the Graph
43-
graphModel = gephi_create_graph()
52+
graphModel = Lookup.getDefault().lookup(GraphController).getGraphModel(workspace)
4453
directedGraph = graphModel.getDirectedGraph()
4554

4655
# Cast NetworkX graph to Gephi
@@ -61,12 +70,12 @@ def networkx_to_gephi(graphX):
6170
# TODO: add edge attributes
6271
directedGraph.addEdge(edge)
6372

64-
return graphModel
6573

6674
#
6775
# Gephi to NetworkX
6876
#
69-
def gephi_to_networkx(graphModel):
77+
def gephi_to_networkx(workspace):
78+
graphModel = Lookup.getDefault().lookup(GraphController).getGraphModel(workspace)
7079
directedGraph = graphModel.getDirectedGraph()
7180
graphX = nx.Graph()
7281

@@ -83,33 +92,47 @@ def gephi_to_networkx(graphModel):
8392
return graphX
8493

8594
#
95+
# Import a GEXF
96+
#
97+
def import_gexf(workspace, file_path=""):
98+
importController = Lookup.getDefault().lookup(ImportController)
99+
file = File(file_path)
100+
container = importController.importFile(file)
101+
container.getLoader().setEdgeDefault(EdgeDirectionDefault.DIRECTED)
102+
importController.process(container, DefaultProcessor(), workspace);
103+
#
86104
# Export the current Gephi graph to an GEXF file
87105
#
88-
def export_gexf(file_path="./graph.gexf"):
106+
def export_gexf(workspace, file_path="./graph.gexf"):
89107
export = Lookup.getDefault().lookup(ExportController)
108+
gexf = export.getExporter("gexf")
109+
gexf.setWorkspace(workspace)
90110
export.exportFile(File(file_path))
91111

92112

93113
#
94114
# Export the current Gephi graph to an PDF file
95115
#
96-
def export_pdf(file_path="./graph.pdf"):
116+
def export_pdf(workspace, file_path="./graph.pdf"):
97117
export = Lookup.getDefault().lookup(ExportController)
98118
pdf = export.getExporter("pdf")
119+
pdf.setWorkspace(workspace)
99120
export.exportFile(File(file_path),pdf)
100121

101122
#
102123
# Export the current Gephi graph to an SVG file
103124
#
104-
def export_svg(file_path="./graph.svg"):
125+
def export_svg(workspace, file_path="./graph.svg"):
105126
export = Lookup.getDefault().lookup(ExportController)
106127
svg = export.getExporter("svg")
128+
svg.setWorkspace(workspace)
107129
export.exportFile(File(file_path), svg)
108130

109131
#
110132
# Export the current Gephi graph to an PNG file
111133
#
112-
def export_png(file_path="./graph.png"):
134+
def export_png(workspace, file_path="./graph.png"):
113135
export = Lookup.getDefault().lookup(ExportController)
114136
png = export.getExporter("png")
137+
png.setWorkspace(workspace)
115138
export.exportFile(File(file_path), png)

gephipy/jupyter.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from IPython.display import HTML
2+
3+
#
4+
# Display a SVG in Jupyter notebook with pan & zoom
5+
#
6+
def display_svg(file_path, width="100%", height="500px"):
7+
with open(file_path, 'r') as file_svg:
8+
svg = file_svg.read()
9+
10+
html_code = f"""
11+
<script src="//bumbu.me/svg-pan-zoom/dist/svg-pan-zoom.js"></script>
12+
<div id="svg-container">
13+
{svg}
14+
</div>
15+
<script>
16+
var svgElement = document.getElementById("svg-container").children[0];
17+
svgElement.style.width = "{width}";
18+
svgElement.style.height = "{height}";
19+
svgPanZoom(svgElement, {{
20+
zoomEnabled: true,
21+
controlIconsEnabled: true
22+
}});
23+
</script>
24+
"""
25+
26+
HTML(html_code)

gephipy/jvm.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import jpype
2+
3+
from pathlib import Path
4+
import urllib.request
5+
6+
GTK_URL="https://repo1.maven.org/maven2/org/gephi/gephi-toolkit/0.10.1/gephi-toolkit-0.10.1-all.jar"
7+
8+
#
9+
# Initialize the context
10+
#
11+
def initialize(gephi_jar_path="./gephi-toolkit-all.jar"):
12+
gtk_jar = Path(gephi_jar_path)
13+
if not gtk_jar.is_file():
14+
print("Download the Gephi toolkit jar")
15+
urllib.request.urlretrieve(GTK_URL, gephi_jar_path)
16+
# Starts the JVM with the GTK in the classpath
17+
try:
18+
jpype.startJVM(classpath=[gephi_jar_path])
19+
except OSError as e:
20+
print(f"Warning: {e}")

poetry.lock

Lines changed: 73 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "Gephipy"
33
version = "0.0.1"
44
description = "A wrapper of Gephi toolkit for Python"
5-
authors = ["OuestWare <contact@ouestware.com>"]
5+
authors = ["Gephi <contact@gephi.org>"]
66
readme = "README.md"
77
license="MIT"
88

@@ -11,6 +11,9 @@ python = "^3.11"
1111
JPype1 = "^1.6.0"
1212
networkx = "^3.5"
1313

14+
[tool.poetry.group.test.dependencies]
15+
pytest = "^8.2.0"
16+
1417
[build-system]
1518
requires = ["poetry-core"]
1619
build-backend = "poetry.core.masonry.api"

0 commit comments

Comments
 (0)