backend_graphviz.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. from nodeset import *
  2. import graphviz as gv
  3. def nodePrintDot(node):
  4. cleanname = "node_" + str(node.id).replace(";", "").replace("=", "")
  5. dot = cleanname + " [label = \"{" + str(node.id) + "|" + str(node.browseName) + \
  6. "}\", shape=\"record\"]"
  7. for r in node.references:
  8. if isinstance(r.target, Node):
  9. tgtname = "node_" + str(r.target.id).replace(";", "").replace("=", "")
  10. dot = dot + "\n"
  11. if r.isForward == True:
  12. dot = dot + cleanname + " -> " + tgtname + " [label=\"" + \
  13. str(r.referenceType.browseName) + "\"]\n"
  14. else:
  15. if len(r.referenceType.inverseName) == 0:
  16. logger.warn("Inverse name of reference is null " + str(r.referenceType.id))
  17. dot = dot + cleanname + " -> " + tgtname + \
  18. " [label=\"" + str(r.referenceType.inverseName) + "\"]\n"
  19. return dot
  20. def printDotGraphWalk(nodeset, depth=1, filename="out.dot", rootNode=None,
  21. followInverse=False, excludeNodeIds=[]):
  22. """ Outputs a graphiz/dot description the nodes centered around rootNode.
  23. References beginning from rootNode will be followed for depth steps. If
  24. "followInverse = True" is passed, then inverse (not Forward) references
  25. will also be followed.
  26. Nodes can be excluded from the graph by passing a list of NodeIds as
  27. string representation using excludeNodeIds (ex ["i=53", "ns=2;i=453"]).
  28. Output is written into filename to be parsed by dot/neato/srfp...
  29. """
  30. iter = depth
  31. processed = []
  32. if rootNode == None or not isinstance(rootNode, Node) or not rootNode in nodeset.nodes:
  33. root = nodeset.getRoot()
  34. else:
  35. root = rootNode
  36. file = open(filename, 'w+')
  37. if root == None:
  38. return
  39. file.write("digraph ns {\n")
  40. file.write(nodePrintDot(root))
  41. refs = []
  42. if followInverse == True:
  43. refs = root.references # + root.getInverseReferences()
  44. else:
  45. for ref in root.references:
  46. if ref.isForward:
  47. refs.append(ref)
  48. while iter > 0:
  49. tmp = []
  50. for ref in refs:
  51. if isinstance(ref.target, NodeId):
  52. tgt = nodeset.nodes[ref.target]
  53. if not str(tgt.id) in excludeNodeIds:
  54. if not tgt in processed:
  55. file.write(nodePrintDot(tgt))
  56. processed.append(tgt)
  57. if ref.isForward == False and followInverse == True:
  58. for ref in tgt.inverseReferences:
  59. refs.append(ref)
  60. tmp = tmp + tgt.references # + tgt.getInverseReferences()
  61. elif ref.isForward == True:
  62. for ref in tgt.references:
  63. refs.append(ref)
  64. refs = tmp
  65. iter = iter - 1
  66. file.write("}\n")
  67. file.close()
  68. def getNodeString(node):
  69. return node.browseName.name + " (" + str(node.id) + ")"
  70. def getReferenceString(nodeset, ref):
  71. refNode = nodeset.nodes[ref.referenceType]
  72. return refNode.browseName.name
  73. def getNodeStyle(node):
  74. if isinstance(node, ReferenceTypeNode):
  75. return {'shape': 'box', 'style': 'filled', 'fillcolor': '1', 'colorscheme': "pastel19"}
  76. if isinstance(node, VariableTypeNode):
  77. return {'shape': 'box', 'style': 'filled', 'fillcolor': '2', 'colorscheme': "pastel19"}
  78. if isinstance(node, ObjectTypeNode):
  79. return {'shape': 'box', 'style': 'filled', 'fillcolor': '3', 'colorscheme': "pastel19"}
  80. if isinstance(node, DataTypeNode):
  81. return {'shape': 'box', 'style': 'filled', 'fillcolor': '4', 'colorscheme': "pastel19"}
  82. if isinstance(node, VariableNode):
  83. return {'shape': 'ellipse', 'style': 'rounded,filled', 'fillcolor': '5', 'colorscheme': "pastel19"}
  84. if isinstance(node, ObjectNode):
  85. return {'shape': 'box', 'style': 'rounded,filled', 'fillcolor': '6', 'colorscheme': "pastel19"}
  86. if isinstance(node, MethodNode):
  87. return {'shape': 'box', 'style': 'rounded,filled', 'fillcolor': '7', 'colorscheme': "pastel19"}
  88. if isinstance(node, ViewNode):
  89. return {'shape': 'box', 'style': 'rounded,filled', 'fillcolor': '8', 'colorscheme': "pastel19"}
  90. def add_edges(graph, edges):
  91. for e in edges:
  92. if isinstance(e[0], tuple):
  93. graph.edge(*e[0], **e[1])
  94. else:
  95. graph.edge(*e)
  96. return graph
  97. def add_nodes(graph, nodes):
  98. for n in nodes:
  99. if isinstance(n, tuple):
  100. graph.node(n[0], **n[1])
  101. else:
  102. graph.node(n)
  103. return graph
  104. def addReferenceToGraph(nodeset, nodeFrom, nodeTo, reference, graph):
  105. add_edges(graph, [((getNodeString(nodeFrom), getNodeString(nodeTo)), {'label': getReferenceString(nodeset, reference)})])
  106. def addNodeToGraph(nodeset, node, graph, alreadyAdded=[], relevantReferences=[], isRoot=False, depth = 0):
  107. if node.id in alreadyAdded:
  108. return
  109. alreadyAdded.append(node.id)
  110. add_nodes(graph, [(getNodeString(node), getNodeStyle(node))])
  111. for ref in node.references:
  112. if ref.referenceType in relevantReferences and ref.isForward:
  113. targetNode = nodeset.nodes[ref.target]
  114. addNodeToGraph(nodeset, targetNode, graph, alreadyAdded, depth=depth+1, relevantReferences=relevantReferences)
  115. addReferenceToGraph(nodeset, node, targetNode, ref, graph)
  116. def printDependencyGraph(nodeset, filename="dependencies", rootNode=None, excludeNodeIds=[]):
  117. if rootNode == None or not isinstance(rootNode, Node) or not rootNode in nodeset.nodes:
  118. root = nodeset.getRoot()
  119. else:
  120. root = rootNode
  121. if root == None:
  122. return
  123. g = gv.Digraph(name="NodeSet Dependency", format='pdf')
  124. alreadyAdded = []
  125. addNodeToGraph(nodeset, root, g, alreadyAdded, isRoot=True, relevantReferences=nodeset.getRelevantOrderingReferences())
  126. g.render(filename)