Open ju1m opened 6 years ago
Thanks for the report, I will take a look at the plugin.
Guessing and pondering lead me to the following Python-only workaround:
# -*- coding: utf-8 -*-
import java.awt.Color as Color
import org.openide.util.Lookup as Lookup
def getWorkSpace():
import org.gephi.project.api.ProjectController as ProjectController
return Lookup.getDefault().lookup(ProjectController).getCurrentWorkspace()
def getGraphModel():
import org.gephi.graph.api.GraphModel as GraphModel
return getWorkSpace().getLookup().lookup(GraphModel)
def getFilterModel():
import org.gephi.filters.api.FilterModel as FilterModel
return getWorkSpace().getLookup().lookup(FilterModel)
def filterEdgesByType(edgeType):
import org.gephi.filters.plugin.edge.EdgeTypeBuilder as EdgeTypeBuilder
filterEdgeType = getFilterModel().getLibrary().getLookup().lookup(EdgeTypeBuilder).getFilter(getWorkSpace())
graphModel = getGraphModel()
edgeTypes = graphModel.getEdgeTypes() # NOTE: tricky table mapping label index to edge type
edgeTypeLabels = graphModel.getEdgeTypeLabels()
edgeTypeIndex = edgeTypeLabels.index(edgeType)
filterEdgeType.setType(edgeTypes[edgeTypeIndex])
import org.gephi.filters.api.FilterController as FilterController
filterController = Lookup.getDefault().lookup(FilterController)
query = filterController.createQuery(filterEdgeType)
newGyFilter = (type == type) # NOTE: by lack of a better way to get a new GyFilter
newGyFilter.setUnderlyingQuery(query)
return newGyFilter
def filterEdgesNot(filter):
import org.gephi.filters.plugin.operator.NOTBuilderEdge as NOTBuilderEdge
filterNOTEdge = getFilterModel().getLibrary().getLookup().lookup(NOTBuilderEdge).getFilter(getWorkSpace())
import org.gephi.filters.api.FilterController as FilterController
filterController = Lookup.getDefault().lookup(FilterController)
query = filterController.createQuery(filterNOTEdge)
filterController.setSubQuery(query, filter.getUnderlyingQuery());
newGyFilter = (type == type)
newGyFilter.setUnderlyingQuery(query)
return newGyFilter
Beware that I am NOT knowledgeable about Java nor Python, and thus could be doing bad things without my knowing.
Below an example of using the above code in a filterEdgesByType.py
file put in gephi launching directory:
>>> execfile("./filterEdgesByType.py")
>>> filterEdgesByType("usage")
<org.gephi.scripting.wrappers.GyFilter object at 0x2>
>>> len(g.filter(filterEdgesByType("usage")).edges)
201
>>> len(g.edges) == len(g.filter(filterEdgesByType("usage") | filterEdgesNot(filterEdgesByType("usage"))).edges)
True
So, in the end, the Java->Python binding is quite exhaustive and flexible.
I think it would be great to emphasize better that power in the wiki because the Gython code mislead me into thinking it was an ad hoc binding, not an easily extensible one. On the contrary, the Python can access most of (if not all) the Java code of Gephi! Sometimes in convoluted ways, but once we know the tricks, it's not that hard.
I first engaged on this journey by reading gephi-plugins/modules/ScriptingPlugin/src/main/resources/org/gephi/scripting/util/preload.py
, which let me hope there was something that could be done without hacking the Java with all its difficulties and lack of shareability.
Introspection capabilities in Gephi's Console helped, but mostly educated greps on the Java did the heavy lifting.
This said, coming from an Haskell background, I was eager to have a more assisting type system to teach me the codebase and check my guesses. Anyway, thanks for producing Gephi as a Free Software :) Keep it up!
I guess next step may be to get into the gephi-toolkit, but not sure at this point if there would be a gain for my usecase.
In case it helps someone following the same Python path, I'm dumping my current .py below because it contains other useful tricks (maybe improvable):
# -*- coding: utf-8 -*-
import sys
import time
import java.awt.Color as Color
import java.awt.Font as Font
import org.openide.util.Lookup as Lookup
import org.gephi.layout.api.LayoutController as LayoutController
layoutController = Lookup.getDefault().lookup(LayoutController)
import org.gephi.layout.plugin.labelAdjust.LabelAdjustBuilder as LabelAdjust
import org.gephi.layout.plugin.forceAtlas.ForceAtlas as ForceAtlas
#import org.gephi.layout.plugin.circularLayout.CircularLayout as CircularLayout
#import org.gephi.scripting.plugin as ScriptingPlugin
#import org.gephi.desktop.scripting.ConsoleTopComponent as ConsoleTopComponent
communs = g.filter(type == u"Commun")
personnes = g.filter(type == u"Personne")
usage = g.filter(cat == u"usage")
economique = g.filter(cat == u"économique")
def getWorkSpace():
import org.gephi.project.api.ProjectController as ProjectController
return Lookup.getDefault().lookup(ProjectController).getCurrentWorkspace()
def getGraphModel():
import org.gephi.graph.api.GraphModel as GraphModel
return getWorkSpace().getLookup().lookup(GraphModel)
def getFilterModel():
import org.gephi.filters.api.FilterModel as FilterModel
return getWorkSpace().getLookup().lookup(FilterModel)
def filterEdgesByType(edgeType):
import org.gephi.filters.plugin.edge.EdgeTypeBuilder as EdgeTypeBuilder
filterEdgeType = getFilterModel().getLibrary().getLookup().lookup(EdgeTypeBuilder).getFilter(getWorkSpace())
graphModel = getGraphModel()
edgeTypes = graphModel.getEdgeTypes()
edgeTypeLabels = graphModel.getEdgeTypeLabels()
edgeTypeIndex = edgeTypeLabels.index(edgeType)
filterEdgeType.setType(edgeTypes[edgeTypeIndex])
import org.gephi.filters.api.FilterController as FilterController
filterController = Lookup.getDefault().lookup(FilterController)
query = filterController.createQuery(filterEdgeType)
newGyFilter = (type == type)
newGyFilter.setUnderlyingQuery(query)
return newGyFilter
def filterEdgesNot(filter):
import org.gephi.filters.plugin.operator.NOTBuilderEdge as NOTBuilderEdge
filterNOTEdge = getFilterModel().getLibrary().getLookup().lookup(NOTBuilderEdge).getFilter(getWorkSpace())
import org.gephi.filters.api.FilterController as FilterController
filterController = Lookup.getDefault().lookup(FilterController)
query = filterController.createQuery(filterNOTEdge)
filterController.setSubQuery(query, filter.getUnderlyingQuery());
newGyFilter = (type == type)
newGyFilter.setUnderlyingQuery(query)
return newGyFilter
def getConsole():
return getWorkSpace().getLookup().lookup(org.python.core.PyObject)
def getLocals():
return getConsole().locals
def getNameSpace():
#import org.gephi.scripting.api.ScriptingController as ScriptingController
#scriptingController = Lookup.getDefault().lookup(ScriptingController)
import org.gephi.scripting.api.ScriptingModel as ScriptingModel
scriptingModel = getWorkSpace().getLookup().lookup(ScriptingModel)
return scriptingModel.getLocalNamespace()
def getVizController():
import org.gephi.visualization.VizController as VizController
vizController = Lookup.getDefault().lookup(VizController)
return vizController
#workspace = getWorkSpace()
#return workspace.getLookup().lookup(VizController)
def debug(msg):
console = getConsole()
console.stdout.write(msg)
# XXX: useless, not better than print():
# there does not seem to be a flush+refresh
# of the Console while executing a layout.
def aspectEdges():
graphModel = getGraphModel()
edgeTypes = graphModel.getEdgeTypes()
edgeTypeLabels = graphModel.getEdgeTypeLabels()
for e in g.edges:
edgeType = edgeTypeLabels[edgeTypes.index(graphModel.getGraph().getEdge(e.id).getType())]
if edgeType == u"usage":
e.color = Color(0xFA8072) # salmon
if edgeType == u"économique":
e.color = Color(0xCDAD00) # gold3
def aspectNodes(nodeSize=150):
graphModel = getGraphModel()
for node in personnes.nodes:
node.color = Color(0xE5E5E5) # gray90
node.size = nodeSize
textProperties = graphModel.getDirectedGraph().getNode(node.id).getTextProperties()
textProperties.setColor(Color.BLACK)
textProperties.setVisible(True)
for node in communs.nodes:
node.color = Color(0xB0E2FF) # LightSkyBlue
node.size = nodeSize
textProperties = graphModel.getDirectedGraph().getNode(node.id).getTextProperties()
textProperties.setColor(Color(0x0000CD)) # medium blue
textProperties.setVisible(True)
def aspect():
aspectNodes()
aspectEdges()
import org.gephi.project.api.ProjectController as ProjectController
import org.gephi.preview.api.PreviewController as PreviewController
import org.gephi.preview.api.PreviewProperty as PreviewProperty
import org.gephi.preview.api.PreviewProperties as PreviewProperties
import org.gephi.io.exporter.api.ExportController as ExportController
import org.gephi.preview.api.PreviewModel as PreviewModel
projectController = Lookup.getDefault().lookup(ProjectController)
workspace = projectController.getCurrentWorkspace()
exportController = Lookup.getDefault().lookup(ExportController)
previewController = Lookup.getDefault().lookup(PreviewController)
previewModel = previewController.getModel(workspace)
previewProperties = previewModel.getProperties()
import org.gephi.preview.types.DependantOriginalColor as DependantOriginalColor
import org.gephi.preview.types.DependantColor as DependantColor
import org.gephi.preview.types.EdgeColor as EdgeColor
# See: modules/PreviewAPI/src/main/java/org/gephi/preview/api/PreviewProperty.java
previewProperties.putValue(PreviewProperty.BACKGROUND_COLOR, Color.WHITE)
# NODE
previewProperties.putValue(PreviewProperty.SHOW_NODE_LABELS, True)
previewProperties.putValue(PreviewProperty.NODE_BORDER_COLOR, DependantColor(Color.BLACK))
previewProperties.putValue(PreviewProperty.NODE_BORDER_WIDTH, 1.0)
previewProperties.putValue(PreviewProperty.NODE_OPACITY, 0)
previewProperties.putValue(PreviewProperty.NODE_LABEL_BOX_COLOR, DependantColor(DependantColor.Mode.PARENT))
previewProperties.putValue(PreviewProperty.NODE_LABEL_BOX_OPACITY, 100)
previewProperties.putValue(PreviewProperty.NODE_LABEL_COLOR, DependantOriginalColor(DependantOriginalColor.Mode.ORIGINAL))
previewProperties.putValue(PreviewProperty.NODE_LABEL_FONT, Font("DejaVu Sans Condensed", Font.BOLD, 3))
previewProperties.putValue(PreviewProperty.NODE_LABEL_MAX_CHAR, 100)
previewProperties.putValue(PreviewProperty.NODE_LABEL_OUTLINE_COLOR, DependantColor(Color.WHITE))
previewProperties.putValue(PreviewProperty.NODE_LABEL_OUTLINE_OPACITY, 80)
previewProperties.putValue(PreviewProperty.NODE_LABEL_OUTLINE_SIZE, 0)
previewProperties.putValue(PreviewProperty.NODE_LABEL_PROPORTIONAL_SIZE, True)
previewProperties.putValue(PreviewProperty.NODE_LABEL_SHORTEN, False)
previewProperties.putValue(PreviewProperty.NODE_LABEL_SHOW_BOX, False)
# EDGE
previewProperties.putValue(PreviewProperty.SHOW_EDGES, True)
previewProperties.putValue(PreviewProperty.SHOW_EDGE_LABELS, False)
previewProperties.putValue(PreviewProperty.ARROW_SIZE, 3)
previewProperties.putValue(PreviewProperty.EDGE_COLOR, EdgeColor(EdgeColor.Mode.ORIGINAL))
previewProperties.putValue(PreviewProperty.EDGE_CURVED, True)
previewProperties.putValue(PreviewProperty.EDGE_RESCALE_WEIGHT, False)
previewProperties.putValue(PreviewProperty.EDGE_OPACITY, 100)
previewProperties.putValue(PreviewProperty.EDGE_RADIUS, 0)
previewProperties.putValue(PreviewProperty.EDGE_THICKNESS, 4)
previewProperties.putValue(PreviewProperty.EDGE_LABEL_COLOR, DependantOriginalColor(DependantOriginalColor.Mode.ORIGINAL))
previewProperties.putValue(PreviewProperty.EDGE_LABEL_FONT, Font("DejaVu Sans Condensed", Font.BOLD, 1))
previewProperties.putValue(PreviewProperty.EDGE_LABEL_MAX_CHAR, 30)
previewProperties.putValue(PreviewProperty.EDGE_LABEL_OUTLINE_COLOR, DependantColor(Color.WHITE))
previewProperties.putValue(PreviewProperty.EDGE_LABEL_OUTLINE_OPACITY, 80)
previewProperties.putValue(PreviewProperty.EDGE_LABEL_OUTLINE_SIZE, 0)
previewProperties.putValue(PreviewProperty.EDGE_LABEL_SHORTEN, False)
#previewController.refreshPreview(workspace)
#return previewProperties
def layoutForceAtlas(iters):
layout = ForceAtlas().buildLayout()
layout.resetPropertiesValues()
layoutController.setLayout(layout)
# See: gephi/modules/LayoutPlugin/src/main/java/org/gephi/layout/plugin/forceAtlas/ForceAtlasLayout.java
layout.setRepulsionStrength(10000)
layout.setAttractionStrength(20)
layout.setMaxDisplacement(10)
layout.setFreezeBalance(True)
layout.setFreezeStrength(80)
layout.setFreezeInertia(0.2)
layout.setGravity(50)
layout.setOutboundAttractionDistribution(True)
layout.setAdjustSizes(True)
layout.setSpeed(1)
layout.setCooling(1)
layoutController.executeLayout(iters)
while layoutController.canStop():
time.sleep(0.5)
def getCircularLayout():
# NOTE: I don't know why I cannot get it like the other layouts,
# maybe because it's a plugin from an extension.
for l in getLayoutBuilders():
if l.name == "Circular Layout":
return l
def layoutCircularLayout():
CircularLayout = getCircularLayout()
layout = CircularLayout.buildLayout()
layout.resetPropertiesValues()
layoutController.setLayout(layout)
# See: gephi/modules/LayoutPlugin/src/main/java/org/gephi/layout/plugin/circularLayout/CircularLayout.java
layout.setNodePlacement(u"Random")
#layout.setNodePlacement(u"NodeID")
layout.setNodePlacementNoOverlap(True)
layout.setNodePlacementTransition(False)
#layout.setAdjustBySize(True)
layoutController.executeLayout()
while layoutController.canStop():
time.sleep(0.5)
def layoutLabelAdjust():
layout = LabelAdjust().buildLayout()
layout.resetPropertiesValues()
layoutController.setLayout(layout)
# See: gephi/modules/LayoutPlugin/src/main/java/org/gephi/layout/plugin/labelAdjust/LabelAdjust.java
layout.setSpeed(1)
layout.setAdjustBySize(True)
layoutController.executeLayout(100)
while layoutController.canStop():
time.sleep(0.5)
def layout():
setVisible(g.filter(filterEdgesByType(u"usage")).filter(degree >= 1))
layoutCircularLayout()
layoutForceAtlas(4000)
layoutLabelAdjust()
#setVisible(g)
def export():
import java.io.File as File
import org.gephi.io.exporter.api.ExportController as ExportController
exportController = Lookup.getDefault().lookup(ExportController)
fileName = File("out_"+time.strftime('%Y-%m-%d_%H-%M-%S')+".png")
fileExporter = exportController.getFileExporter(fileName)
# See: gephi/modules/PreviewExport/src/main/java/org/gephi/io/exporter/preview/PNGExporter.java
fileExporter.setWidth(4000)
fileExporter.setHeight(4000)
fileExporter.setMargin(4)
fileExporter.setTransparentBackground(False)
exportController.exportFile(fileName, fileExporter)
def run():
aspect()
layout()
export()
There is no .kind or .Kind on edges. This handling appears to be missing in
__findattr_ex__
ingephi-plugins/modules/ScriptingPlugin/src/main/java/org/gephi/scripting/wrappers/GyEdge.java
. Not knowing the java tools, I am unable to easily get a compiling gephi-plugins to investigate further. My understanding of theREADME.md
instructions lead me to a failure, apparently due to missing dependencies:A workaround is to add a new column (say 'Category') copying the 'Kind' column. This is a bit painful because it doesn't seem to be doable within gephi, so I had to export the links to a CSV, copying the column with gnumeric, and reimporting the CSV. By the way, mass deleting links in gephi 0.9.2 does not seem to work, it only deletes one link. So, I had to start a new project to then import the links from CSV. HTH.