Tulip Script Plug-in

2010-09-14
2013-04-20
  • David Auber

    David Auber - 2010-09-14

    We are about to release two scripting plug-in for Tulip. The first one is for Python and the second one is
    for qtscript.
    That thread is for comment about these plugins.

    I post here my first python script, it works really well (thx Antoine and the Boogie Project):

    from tulip import *
    from math import *
    from collections import deque

    #the processGraph function must be defined
    #to run the script on the current graph
    def computeWeights(graph) :
    #insert your script code here
    distMetric = graph.getDoubleProperty("weight");
    layout = graph.getLayoutProperty("viewLayout");       
    itEdges = graph.getEdges();
    while (itEdges.hasNext()) :
    e = itEdges.next();
    src = graph.source(e);
    tgt = graph.target(e);
    pSrc = layout.getNodeValue(src);
    pTgt = layout.getNodeValue(tgt);
    distMetric.setEdgeValue(e, sqrt(pow(pSrc.getX()-pTgt.getX(), 2) +  pow(pSrc.getY()-pTgt.getY(), 2) ) );
    #============================================
    def gauss(x, sigma, mu):
        return 1. / (sigma * sqrt(2. * 3.14159265) )   *   exp(-1./2. *  ( (x-mu)/sigma )**2   );
    #============================================
    def copy(graph, prop1, prop2):
        itn = graph.getNodes();
        while(itn.hasNext()) :
            n = itn.next();
            prop1.setNodeValue(n, prop2.getNodeValue(n));
        ite = graph.getEdges();
        while(ite.hasNext()) :
            e= ite.next();
            prop1.setEdgeValue(e, prop2.getEdgeValue(e));
    #============================================
    def minmaxVal(graph, metric, maxId = 10000000):
    minV = 0.;
    maxV = 0.;
    startB = True;
    itN = graph.getNodes();
    while(itN.hasNext()) :
    n = itN.next();
    if (n.id > maxId):
    return minV, maxV;
    val = metric.getNodeValue(n);
    if (startB):
    minV  = val;
    maxV  =val;
    startB = False;
    else:
    if (val < minV):
    minV = val;
    if (val > maxV):
    maxV = val;
    return minV, maxV
    #============================================
    def normalize(graph, metric):
        minV , maxV = minmaxVal(graph, metric);
        startB = True;
        itN = graph.getNodes();
        while(itN.hasNext()) :
            n = itN.next();
            val = metric.getNodeValue(n);
            if (startB):
                minV  = val;
                maxV  =val;
                startB = False;
            else:
                if (val < minV):
                    minV = val;
                if (val > maxV):
                    maxV = val;
        itN = graph.getNodes();
        while(itN.hasNext()) :
            n = itN.next();
            val = metric.getNodeValue(n);
            metric.setNodeValue(n, (val - minV)/ (maxV - minV) );
    #============================================   
    def applyConvolution(graph, maxId):
        print "Aplly convolution"
        currentValues  = graph.getDoubleProperty("values");
        newValues = graph.getDoubleProperty("tmpVal");
        distMetric = graph.getDoubleProperty("weight");
        itN = graph.getNodes();
        while(itN.hasNext()) :
            n = itN.next();
            sumCoeff = 0.;
    if (n.id < maxId):
    newVal = currentValues.getNodeValue(n);
    sumCoeff += 1.;
    else:
    newVal   = 0.;
            itE = graph.getInOutEdges(n);
            while(itE.hasNext()):
                e = itE.next();
                dist = 1. + distMetric.getEdgeValue(e);
                coeff = 1./ ( dist);# ** 2); #gauss(dist, 0.5, 0.);
                sumCoeff += 1.;
                n2 = graph.opposite(e, n);
                val = currentValues.getNodeValue(n2);
                newVal += val * coeff;
            #newVal   += currentValues.getNodeValue(n)
            #sumCoeff += 1.;
            newValues.setNodeValue(n, newVal / sumCoeff )
        normalize(graph,newValues);
        copy(graph, currentValues, newValues);
    #============================================
    def climb(graph, n):
        values  = graph.getDoubleProperty("values");
        val = values.getNodeValue(n);
        itN = graph.getInOutNodes(n);
        while(itN.hasNext()) :
            ni = itN.next();
            vali = values.getNodeValue(ni);
            if (vali > val):
                return climb(graph, ni)
        return n
    #============================================
    def markDown(graph, n, classId):
    classes  = graph.getDoubleProperty("classes");
    values  = graph.getDoubleProperty("values");
    l = deque();
    l.append(n);
    while(len(l) != 0):
    n = l.popleft();
    if (classes.getNodeValue(n) > 0):
    continue
    classes.setNodeValue(n, classId);
    val = values.getNodeValue(n);
    itN = graph.getInOutNodes(n);
    while(itN.hasNext()) :
    ni = itN.next();
    vali = values.getNodeValue(ni);
    if (vali <= val):
    l.append(ni)
    #===========================================
    def findgroup(graph, maxId):
        print "find group…"
        curClassId = 1.;
        values  = graph.getDoubleProperty("values");
        classes  = graph.getDoubleProperty("classes");
        classes.setAllNodeValue(0.);
        itN = graph.getNodes();
        while(itN.hasNext()) :
            n = itN.next();
            if (classes.getNodeValue(n) == 0.):
                seed = climb(graph, n);
                if (values.getNodeValue(n) > 0) :
                  markDown(graph, seed, curClassId);
                  curClassId += 1.
        minV , maxV = minmaxVal(graph, values, maxId);
        itn = graph.getNodes();
        while(itn.hasNext()) :
            n = itn.next();
    if(values.getNodeValue(n) < minV):
    classes.setNodeValue(n, -1.);
    #============================================
    def applyLaplace(graph):
        print "Laplace …"
        newValues = graph.getDoubleProperty("tmpVal");
        currentValues  = graph.getDoubleProperty("values");
        distMetric = graph.getDoubleProperty("weight");
        itN = graph.getNodes();
        while(itN.hasNext()) :
            n = itN.next();
            sumCoeff = 0.;
            newVal = 0.;
            itE = graph.getInOutEdges(n);
            while(itE.hasNext()):
                e = itE.next();
                dist  = distMetric.getEdgeValue(e);
                coeff = 1.;# / dist;
                sumCoeff += coeff;
                n2 = graph.opposite(e, n);
                val = currentValues.getNodeValue(n2);
                newVal += val * coeff;           
            newVal  =  abs(newVal -  sumCoeff * currentValues.getNodeValue(n));
            #sumCoeff += sumCoeff;
            sumCoeff = 1.;
            newValues.setNodeValue(n,  newVal / sumCoeff );
        normalize(graph,newValues);
        copy(graph, currentValues, newValues);
    #============================================
    def cleanGraph(graph):
        itN = graph.getNodes();
        while(itN.hasNext()) :
            n = itN.next();
            if (graph.deg(n) == 0):
                graph.delAllNode(n)
    #============================================
    def processGraph(graph):
        cleanGraph(graph);
        computeWeights(graph);
        values  = graph.getDoubleProperty("values");
        #we should only init graph nodes to 1 and grid nodes to 0
        values.setAllNodeValue(0.);
        maxId = 4120; #number  of nodes of original graph
        itN = graph.getNodes();
        while(itN.hasNext()) :
            n = itN.next();
    if (n.id < maxId):
    values.setNodeValue(n, 1.);
       
       
        i = 0;
        while(i < 5):
              applyConvolution(graph, maxId);
              i += 1;
        convol  = graph.getDoubleProperty("valuesConv");
        copy(graph, convol, values);

        findgroup(graph, maxId);
       
       
        testm  = graph.getDoubleProperty("valuetst");
        copy(graph, testm, values);
        testm.uniformQuantification(50);
        layout = graph.getLayoutProperty("viewLayout");       
        itn = graph.getNodes();
        while(itn.hasNext()) :
            n = itn.next();
            cp = layout.getNodeValue(n);
            cp.setZ(testm.getNodeValue(n) / 2.);
            layout.setNodeValue(n, cp);
        #i = 0;
        #while(i < 1):
            #applyLaplace(graph);
            #i = i +1;
    #    copy(graph, testm, values);

     
  • David Auber

    David Auber - 2010-09-14

    shorted, easier but maybe more useful my first QtScrip script in Tulip :

    graph.holdObservers();
    layout = graph.getLayoutProperty("viewLayout");
    size = graph.getSizeProperty("viewSize");
    itn = graph.getNodes();
    x  = 0.;
    y  = 0.;
    z  = 0.;
    graph.unholdObservers();
    while(itn.hasNext()) {
        n = itn.next();
        s = size.getNodeValue(n);
        y += s.getH()/2.;
        c = layout.getNodeValue(n);
        c.set(x, y , z);
        layout.setNodeValue(n, c);
        y += s.getH()/2.;   
    }

     
  • packadal

    packadal - 2010-09-15

    Another simple example : applying a circular layout:

    code
    var set = new QDataSet();
    set.set("search cycle", false);
    var property = graph.getProperty("viewLayout");
    graph.computeProperty("Circular", property, "message", set);

     
  • David Auber

    David Auber - 2010-09-23

    What do you think about only using only stable iterators in all the scipt language python/qscript.

    Of course it slow down a little bit, but it prevents from a lot of bugs. Since the script is not down to have
    performance I think that it is not a bad choice.

    Thx,
    David.

     
  • Antoine Lambert

    Antoine Lambert - 2010-09-23

    Hi David,

    You're right, using classic iterators can lead to serious bugs (e.g. adding nodes while iterating on their set). I applied your request to the Python bindings, now all the iterators that can be accessed from the graph are stable ones.

    Antoine

     
  • packadal

    packadal - 2010-09-23

    Fixed in the QtScript plug-in as well :) (only stable iterators can be used)

     
  • David Auber

    David Auber - 2010-09-23

    Thx guys !!!!

    I'm script addict now :-), (just one other addiction on my long list …)

    David.

     
  • David Auber

    David Auber - 2010-09-23

    Re,

    We all agree that the script with be merged in library in the next major version Tulip 4.0.
    However I need some advise from you to know the best way to do it.

    My major problem with both your script engine is that we need to duplicate the prototype of the Tulip func/obj. Thus, one change in the
    Tulip API will lead to a change in PyTulip & QtScriptTulip.

    Do you think that it will be possible to add necessary meta-information directly in the Tulip source-code to be able to automatically generate the sip files and the QtObject.h/cpp files. We can use doxygen (xml output), and then parse it to extract almost what we want.
    Func signature, members of objects etc…, if qe add an extra tag in our doc @SIP @QTSCRIPT we will be able to merge the C++ version the python one and the QtScript one in the same header file. It will be from my point opinion easier to maintain and it will remove a lot duplication for function documentation.

    If it is not possible, will it be possible to generate the sip files when we have the QtScript engine Ok or will it be possible to generate the Qt objects when we have the python script engine Ok ?

    David.

     
  • Antoine Lambert

    Antoine Lambert - 2010-09-23

    Re,

    I think it's possible to automatically generate the SIP files by adding special tags to the header files and parsing the doxygen output or more simply the header files.  I think the best way to do it is to add before each class, function or method definition the corresponding SIP directive to generate the bindings.

    We have to brainstorm about it at the next Tulip developpers meeting.

    Antoine

     

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks