Script plugin

From Gephi:Wiki
Jump to: navigation, search

General information

The Script Console plugin provides a text input where user can insert and execute python code. This code can interact with the current graph and user can perform many operation on it. Most of the API of the Gephi Toolkit are accessible, but the plugin provides also some easier utility functions to hide some complexity of the gephi toolkit. This easier API is not very complete.

The interface is composed of two text panels: one to write code and one, readonly, which contains results. There are under 8 buttons:

  • Run: execute the script, shortcut ALT+ENTER
  • Run and Clear: execute the script and clear the code panel, shortcut CTRL+ENTER
  • Previous:
  • Next: the input are logged and user can navigate through previous with those buttons. shortcuts ALT+Arrows
  • Load...: load a python file into the code panel
  • Save...: save the code panel into a python file
  • Stop: stop current script execution. Be careful, variables states may be corrupted
  • Reset: restart the script engine, resetting all defined variables.


Example from the toolkit

The script engine relies on jython. Thus, translating java code from the examples of the toolkit to python code usually works with some tricks:

  • null -> None
  • No type declaration
  • No ;
  • Iterating with for n in … instead of for(n : …)
  • Use gephi.getLookUp() to obtain the default lookup (in java : Lookup.getDefault())
  • comments are # and not //
  • true and false become True and False


For instance:

We propose here to apply the Toolkit_-_Manipulate_Graph operations

#some import
import org.gephi.graph.api as graph_api
 
#we do not need to init a project
 
#Get a graph model - it exists because gephi has created the workspace
graphModel = gephi.getLookup().lookup(graph_api.GraphController).getModel()
 
#Create three nodes
n0 = graphModel.factory().newNode("n0") #we just remove the type Node and the ;
n0.getNodeData().setLabel("Node 0")
n1 = graphModel.factory().newNode("n1")
n1.getNodeData().setLabel("Node 1")
n2 = graphModel.factory().newNode("n2")
n2.getNodeData().setLabel("Node 2")
 
#Create three edges
e1 = graphModel.factory().newEdge(n1, n2, 1., True)#we remove Edge, true->True and 1f -> 1.
#it was in java : Edge e1 = graphModel.factory().newEdge(n1, n2, 1f, true);
e2 = graphModel.factory().newEdge(n0, n2, 2., True)
e3 = graphModel.factory().newEdge(n2, n0, 2., True)   #This is e2's mutual edge
 
#Append as a Directed Graph
directedGraph = graphModel.getDirectedGraph()
directedGraph.addNode(n0)
directedGraph.addNode(n1)
directedGraph.addNode(n2)
directedGraph.addEdge(e1)
directedGraph.addEdge(e2)
directedGraph.addEdge(e3)
 
#Count nodes and edges
print "Nodes: ", directedGraph.getNodeCount(), " Edges: ",directedGraph.getEdgeCount() #python does not transform objects into str. We use a more pythonic way to present output
 
#Get a UndirectedGraph now and count edges
undirectedGraph = graphModel.getUndirectedGraph()
print "Edges: ", undirectedGraph.getEdgeCount()   #The mutual edge is automatically merged
 
#Iterate over nodes
for n in directedGraph.getNodes() : 
    neighbors = directedGraph.getNeighbors(n).toArray()
    print n.getNodeData().getLabel(), "has", len(neighbors), "neighbors"
 
 
#Iterate over edges
for e in directedGraph.getEdges() :
    print e.getSource().getNodeData().getId(), " -> ", e.getTarget().getNodeData().getId()
 
 
#Find node by id
node2 = directedGraph.getNode("n2")
 
#Get degree
print "Node2 degree: ", directedGraph.getDegree(node2)

It produces the output, if you have the miserable.gexf file loaded :

Nodes: 80 Edges: 257
Edges: 256
Myriel has 10 neighbors
Napoleon has 1 neighbors
MlleBaptistine has 3 neighbors
MmeMagloire has 3 neighbors
CountessDeLo has 1 neighbors
Geborand has 1 neighbors
Champtercier has 1 neighbors
Cravatte has 1 neighbors
Count has 1 neighbors
OldMan has 1 neighbors
Labarre has 1 neighbors
Valjean has 36 neighbors
...
MmeHucheloup has 7 neighbors
Node 0 has 1 neighbors
Node 1 has 1 neighbors
Node 2 has 2 neighbors
1.0 -> 0.0
2.0 -> 0.0
3.0 -> 0.0
3.0 -> 2.0
4.0 -> 0.0
5.0 -> 0.0
...
76.0 -> 63.0
76.0 -> 64.0
76.0 -> 65.0
76.0 -> 66.0
n0 -> n2
n1 -> n2
n2 -> n0
Node2 degree: 3

Thus, Toolkit_portal is a good documentation for the script. Just think python :)


Example using the python API

The Gephi Toolkit is nice, but is clearly not a python API. Model View Controller is complicated for small scripts. Thus an API is provided to hide some details.


valjean = findNode("Valjean") #find the node with text Valjean
setSize(valjean, 50)
centerOn(valjean)
x,y = getPos(valjean)
setPos(valjean, x+10, y+10)
toto = newNode('toto')#create the node
graph = getGraph()#attach it to the graph
graph.addNode(toto)
 
test_atr = addNodeAttribute("Test attribute")
for count, n in enumerate(graph.getNodes()) :
    setNodeValue(n, count, test_atr)
 
#another way :
attr_dict = dict([])
for count, n in enumerate(graph.getNodes()) :
    attr_dict[n] = count
 
setNodeValues(attr_dict, test_atr)
 
pagerank = getNodeAttribute("PageRank") #it must be already computed in the Data Laboratory
pagerank_dict = getNodesValues(pagerank)
#it is a dictionnary, you can iterate on it
for node, value in pagerank_dict.iteritems() :
    print node, value
 
#finnally, discard the attribute :
delNodeAttribute(test_attr)
 
#the same thing exist for edges
 
 
 
#apply a force atlas (other layout are not provided)
 
forceAtlas(max_iter=500, repulsion_strength=1000, adjust_by_sizes=True)
 
 
#and save it as a pdf :
export("test.pdf")
 
#or as a graph :
export("mygraph.gexf")

Several API are already imported such as graph API, Attributes API, project API and importer API as name_api. There is also an help() function that gives help about its parameter or the list of available function if called without parameter.

Be careful, script execution access directly to gephi, and thus you can break internal variables. You should save regularly. The gephi toolkit is also less intensively tested than the application and bugs may remain.

Another example showing how to transform all the edges of the graph into undirected edges, keeping the weight :

#first, we store all the edges
dg = getDirectedGraph()
edges = []
for e in dg.edges :
    edges.append(newEdge(e.getSource(), e.getTarget(), e.getWeight(), directed=False))
 
#then we remove them
dg.clearEdges()
 
#and add them again to an UndirectedGraph()
g = getGraphModel().getUndirectedGraph()
for e in edges :
    g.addEdge(e)

Code of the API

This is loaded during the first script execution and can be a good example. Is contains the documentation.


import org.gephi.graph.api as graph_api
import org.gephi.data.attributes.api as attributes_api
import org.gephi.data.attributes.api.AttributeType as AttributeType
import org.gephi.visualization.VizController as viz
import java.io
import org.gephi.project.api as project_api
import org.gephi.io.importer.api as importer_api
import sys
"""
This file is loaded when the gephi script engine is used first (before the first user script execution)
It contains the specific gephi python api accessible from script
"""
 
 
def help(obj = None) :
    """
    See help
    """
    if obj == None :
        print "Python console"
        print "Available functions : "
        print dir(sys.modules[__name__])
 
    else :
        try :
            print obj.__doc__
        except :
            print "Object has no documentation"
 
def getGraphModel() :
    """
    getGraphModel() :
    Return the graph model of the currently displayed graph.
    """
    return gephi.getLookup().lookup(graph_api.GraphController).getModel()
 
def getAttributeModel() :
    """
    getAttributeModel() :
    Return the attribute model of the currently displayed graph
    """
    return gephi.getLookup().lookup(attributes_api.AttributeController).getModel()
 
 
#graph management
def getDirectedGraph() :
    """
    getDirectedGraph() :
    Get the currently displayed graph as a directed graph
 
    Example :
        dg = getDirectedGraph()
        #values :
        print "Nodes:", dg.getNodeCount(),"Edges: ", dg.getEdgeCount()
 
        #iterating :
        for e in dg.edges :
            print "source : ", e.getSource(), "dest:", e.getTarget()
        node2 = dg.getNode("n2") #using its id, see find_node to search with label.
 
        print "Degree:", dg.getDegree(node2)
    """
    return getGraphModel().getDirectedGraph()
 
def getGraph() :
    """
    getGraph() :
        Get the currently displayed graph as a non directed graph
 
    Example :
    dg = getDirectedGraph()
    #values :
    print "Nodes:", dg.getNodeCount(),"Edges: ", dg.getEdgeCount()
 
    #iterating :
    for e in dg.edges :
    print "source : ", e.getSource(), "dest:", e.getTarget()
    node2 = dg.getNode("n2") #using its id, see find_node to search with label.
 
    print "Degree:", dg.getDegree(node2)
    """
    return getGraphModel().getGraph()
 
def newNode(name) :
    """
    newNode(name) :
        return a new node of name 'name'. You next have to add the node to the graph.
 
    Example :
        toto = newNode('toto')
        getGraph().addNode(toto)
    """
    return getGraphModel().factory().newNode(name)
 
def newEdge(node_src, node_dst, weight=1.0, directed=True) :
    """
    newEdge(node_src, node_dst, weight=1.0, directed=True) :
    return a new edge between node_src and node_dst
 
    Example :
    edge = newEdge(node1, node2)
    getGraph().addEdge(edge)
    """
    return getGraphModel().factory().newEdge(node_src, node_dst, weight, directed)
 
def findNode(node_label, graph = None) :
    """
    findNode(node_label, graph = None) :
        find a node by its label. If graph is None, current visible graph is used.
    Example :
        valjean = findNode("Valjean")
    """
    if graph == None :
        graph = getGraph()
    for node in graph.nodes :
        if node.getNodeData().getLabel() == node_label :
            return node
    return None
 
 
#position and layout
def setPos(node, x = None, y = None):
    """
    setPos(node, x = None, y = None):
        set node position to x and y. If a coordinate is None, it is not moved
    """
    if x != None:
        node.getNodeData().setX(x)
    if y != None:
        node.getNodeData().setY(y)
 
def getPos(node):
    """
    getPos(node):
        Return a pair of float containing node coordinate
    """
    d = node.getNodeData()
    return d.x(), d.y()
 
def setSize(node, size) :
    """
    setSize(node, size) :
        set node size
    """
    node.getNodeData().setSize(size)
 
def centerOn(node) :
    """
    centerOn(node) :
        center view on node
    """
    viz.getInstance().getSelectionManager().centerOnNode(node)
 
def setSelection(nodes) :
    """
    setSelection(nodes) :
        select all the nodes of the list nodes
    WARNING : highly experimental now. For example, do not group the selection after that
    """
    viz.getInstance().getSelectionManager().selectNodes(nodes)
    print "Warning, set_selection is experimental. Use reset_selection before doing anything on the selection"
 
def getSelection() :
    """
    getSelection() :
        will return the selection. Does not work yet
    """
    print "Does not work yet"
    return []
 
def resetSelection() :
    """
    resetSelection() :
        clear the selection and reset gephi to an almost good state.
 
    """
    viz.getInstance().getSelectionManager().resetSelection()
 
 
def forceAtlas(max_iter=100, inertia=0.1, repulsion_strength=200.0, attraction_strength=10.0, maximum_displacement=10.0, auto_stabilize_function=True, autostab_strenght=80.0, autostab_sensibility=0.2, gravity=30.0, attraction_distrib=False, adjust_by_sizes=False, speed=0.1) :
    """
    force_atlas(max_iter=100, inertia=0.1, repulsion_strength=200.0, attraction_strength=10.0, maximum_displacement=10.0, auto_stabilize_function=True, autostab_strenght=80.0, autostab_sensibility=0.2, gravity=30.0, attraction_distrib=False, adjust_by_sizes=False, speed=0.1) :
        apply a force atlas layout algorithm to the current graph. The algorithm is iterated max_iter times or infinitely if max_iter = -1. In this case, you will have to stop script execution. Parameters correspond to the graphical interface inputs.
 
    """
    import org.gephi.layout.plugin.forceAtlas as FA
    layout = FA.ForceAtlasLayout(None)
    layout.setGraphModel(getGraphModel())
    layout.resetPropertiesValues()
    layout.setInertia(inertia)
    layout.setRepulsionStrength(repulsion_strength)
    layout.setAttractionStrength(attraction_strength)
    layout.setMaxDisplacement(maximum_displacement)
    layout.setFreezeBalance(auto_stabilize_function)
    layout.setFreezeStrength(autostab_strenght)
    layout.setFreezeInertia(autostab_sensibility)#
    layout.setGravity(gravity)
    layout.setOutboundAttractionDistribution(attraction_distrib)
    layout.setAdjustSizes(adjust_by_sizes)
    layout.setSpeed(speed)
 
    if max_iter == -1 :
        while layout.canAlgo() :
            layout.goAlgo()
    else :
        for i in range(max_iter) :
            if layout.canAlgo() :
                layout.goAlgo()
 
    layout.endAlgo();
 
#stuff related to attribute management
def addNodeAttribute(name, attr_typ = AttributeType.INT) :
    """
    addNodeAttribute(name, attr_typ = AttributeType.INT) :
        create a new node attribute of type attr_typ in gephi and return it
    """
    return getAttributeModel().getNodeTable().addColumn(name, attr_typ)
 
def delNodeAttribute(col) :
    """
    delNodeAttribute(col) :
        delete a node attribute
    """
    return getAttributeModel().getNodeTable().removeColumn(col)
 
def addEdgeAttribute(name, attr_typ = AttributeType.INT) :
    """
    addEdgeAttribute(name, attr_typ = AttributeType.INT) :
        create a new edge attribute of type attr_typ in gephi and return it
    """
    return getAttributeModel().getEdgeTable().addColumn(name, attr_typ)
 
def delEdgeAttribute(col) :
    """
    delNodeAttribute(col) :
        delete an edge attribute
    """
    return getAttributeModel().getEdgeTable().removeColumn(col)
 
def getNodeAttribute(name) :
    """
    getNodeAttribute(name) :
        get the node attribute of name name
 
    for instance :
    pr = getNodeAttribute("PageRank")
    pageranks = getNodesValue(pr)
    for node, val in pageranks.iteritems() :
        print node, val
    """
    return getAttributeModel().getNodeTable().getColumn(name)
 
def getEdgeAttribute(name) :
    """
    getEdgeAttribute(name) :
        get the edge attribute of name name
 
    for instance :
    wa = getEdgeAttribute("Weight")
    weights = getEdgesValue(wa)
    for edge, val in weights.iteritems() :
        print edge, val
    """
    return getAttributeModel().getEdgeTable().getColumn(name)
 
def getNodesValues(attribute, graph = None) :
    """
    getNodesValues(attribute, graph = None) :
        return a dictionnary with keys the nodes of graph and value the value
        of the given attribute for the node
 
        if graph is None, the current visible graph is used
 
    for instance :
    pr = getNodeAttribute("PageRank")
    pageranks = getNodesValue(pr)
    for node, val in pageranks.iteritems() :
        print node, val
    """
    if graph == None :
        graph = getGraph()
    ret = dict([])
    for n in graph.getNodes():
        ret[n] = n.getNodeData().getAttributes().getValue(attribute)
    return ret
 
def getEdgesValues(attribute, graph = None) :
    """
    getEdgesValues(attribute, graph = None) :
        return a dictionnary with keys the edges of graph and value the value
        of the given attribute for the edge
 
        if graph is None, the current visible graph is used
 
    for instance for nodes:
    pr = getNodeAttribute("PageRank")
    pageranks = getNodesValue(pr)
    for node, val in pageranks.iteritems() :
        print node, val
    """
    if graph == None :
        graph = getGraph()
    ret = dict([])
    for e in graph.getEdges():
        ret[e] = e.getEdgeData().getAttributes().getValue(attribute)
    return ret
 
def setNodeValue(node, value, attribute) :
    """
    setNodeValue(node, value, attribute) :
        set the value of attribute for the given node
 
 
    for instance :
 
    zeroAttr = addNodeAttribute("Zero Attribute")
    for node in getGraph().nodes :
        setNodeValue(node, 0, zeroAttr)
 
    """
    node.getNodeData().getAttributes().setValue(attribute, value)
 
def setEdgeValue(edge, value, attribute) :
    """
    setEdgeValue(edge, value, attribute) :
        set the value of attribute for the given edge
    """
    edge.getEdgeData().getAttributes().setValue(attribute, value)
 
def setNodeValues(values, attribute) :
    """
    setNodeValues(values, attribute) :
        take a dictionnary with nodes as keys and assign values in the given gephi attribute
 
    for instance :
 
    zeroAttr = addNodeAttribute("Zero Attribute")
    values = dict([])
    for node in getGraph().nodes :
        values[node] = 0
    setNodeValues(values, zeroAttr)
    """
    for n, v in values.iteritems():
        n.getNodeData().getAttributes().setValue(attribute, v)
 
def setEdgeValues(values, attribute) :
    """
    setEdgeValues(values, attribute) :
        take a dictionnary with edges as keys and assign values in the given gephi attribute
    """
    for e, v in values.iteritems():
        e.getEdgeData().getAttributes().setValue(attribute, v)
 
 
#export
def export(filename) :
    """
    export(filename) :
        Depends on file type. It exports graph pictures to pdf or svg or the current graph in gexf
    """
    gephi.getExportController().exportFile(java.io.File(filename))
 
 
def load(filename) :
    """
    load(filename) :
        Load the graph of the specified filename. It requires that a graph has been already loaded :(
    """
    pc = gephi.getLookup().lookup(project_api.ProjectController)
    workspace = pc.getCurrentWorkspace()
    ic = gephi.getLookup().lookup(importer_api.ImportController)
    cont = ic.importFile(java.io.File(filename))
    ic.process(cont, gephi.getDefaultProcessor(), workspace)
 
##group management ?
def groupNodes(l) :
    """
    To group a list of nodes in a hierarchical graph
    Does not work yet
    """
    #seems to fail.
    print "Does not work yet..."
    return
    getGraphModel().getHierarchicalGraph().groupNodes(l)