Graph Plugin Full Documentation


The ability to draw custom graphs is a core feature of the Understand Python API. Using the Understand Plugin system, advanced users can develop their own custom graphs addressing specific information needs.


For this tutorial we will look at how to generate a simple architecture tree graph. This capability is already built into Understand by right clicking on any folder or architecture in the architecture browser and going to Graphical Views > Graph Architecture but this code will provide a good template for expanding and tweaking the graphs to fit your needs. 




Understand Plugins


This tutorial will introduce the primary method of adding your personal scripts to Understand, Plugins. Up until now we have only seen how to run uPython scripts from the command line, but Understand can turn any uPython script into a plugin by simply dragging and dropping the .upy file onto the Understand GUI.


You can also place your plugin in one of the following directories:

Windows – e.g. C:\Program Files\SciTools\conf\plugin\User\Graph

Mac – e.g. /Users/username/Library/Application Support/SciTools/plugin/Graph

Linux – e.g. /home/username/.config/SciTools/plugin/Graph


To start creating your own plugin file, simply create a new file with the .upy extension, for this example I will use arch_tree.upy




Graph Plugin Basics


Every plugin will likely start with the following lines:

import understand

def name():
  return "Tutorial: Architecture Tree"

def description():
  return "Visually displays the hierarchical structure of a software architecture."

def test_architecture(arch):
  return True

def init(graph, target):
   graph.options().define("Fill", ["On","Off"], "Off")
   graph.legend().define("func", "roundedrect", "Function", "blue", "#FFFFFF")
  pass


name() sets the name of the plugin, description() sets the description, test_architecture(arch) will check if a graph exists for the selected architecture, and init(graph, target) will initialize the graph and is also where you can set graph options and a legend. After adding your plugin to Understand it will show up in the Graphical View list with the name you set, like this:




Graph Plugin Logic


Now for the actual plugin logic. Understand uses Graphviz to generate the graph layout, your plugin will need to define the nodes, edges, and/or subgraphs to draw. Lets start by creating a function that we will use later to grab our nodes. Each node is one piece of the graph, represented by boxes in my example graph at the top of this page:

def grabNode(graph, nodes, arch):
  if arch in nodes:
    node = nodes[arch]
  else:
    node = graph.node(arch.name())
    node.sync(arch); # architectures must be synced instead of given at creation
    nodes[arch] = node

  return node



This will make more sense after viewing our draw function, this is where the logic takes place:

def draw(graph, target):
  """
  Draw the graph

  The second argument can be a database or an entity depending on whether
  the graph was created at a project level or entity level.
  """

  graph.set("rankdir", "LR")

  # store the arch->graphviz node so that each arch node appears only
  # once no matter how many edges
  nodes = dict()

  curLevel = []
  curLevel.append(target)

  while curLevel:
    nextLevel = []
    for arch in curLevel:
      tail = grabNode(graph, nodes, arch)
      for child in arch.children():
        edge = graph.edge(tail,grabNode(graph,nodes,child))
        nextLevel.append(child)
    curLevel = nextLevel



For the function "draw(graph, target)", both variables come from our understand library imported at the start of the script. Graph is an object that we will use in the function, and target is the entity that was selected by the user. Since we already filtered for architectures, the target in this case will be an architecture.


graph.set() is used to set a variety of graph options. In the above example we are telling the graph to flow left to right. These options come directly from Graphviz, you can see the documentation for graph() here.


Now for the while loop, the curLevel is set to the architecture that was initially selected. Picture this like a hierarchy of folders in your code base, you likely have a folder called src with several folders and subfolders underneath. If src had 0 folders the loop would only complete once and our graph would just have one box called "src". Since src actually has many folders the next loop will look for all folders, or nodes, on the next level and create edges between them and their children, it will then add those children to nextLevel[] so that on the next loop it can search for their children and so on until the entire architecture has been graphed.


Ready to play around with this graph yourself? You can visit our public plugin repository to see a variety of plugins and templates. The code I used above can be found here.



Continue to API Tutorial 6: Interactive Reports ->


<- Return to API Tutorial 4: Lexers and Lexemes 



Need help? Contact [email protected] or visit our About the Understand Python API page.