Tag: dot

2009-04-20 22:30 UTC Updated Graphviz tools on Github

I just added a new repository on GitHub containing the tools from my Graphviz / diagram related posts.
The repository can be found at: http://github.com/vidarh/diagram-tools/tree/master

These are the ones included and the appropriate articles:

The only new thing so far is that notugly.xsl is updated to work with Graphviz 2.22.2





2009-02-01 02:07 UTC Creating Graphviz graphs from Ruby arrays

As part of my compiler project I wanted a way to visualize the programs, and since the syntax tree (so far at least) is represented with plain Ruby arrays I decided to throw together a script to use Graphviz to generate some graphs. I've written about using Graphviz previously here
The code does not make any assumptions tied to my compiler, but it's NOT an attempt at visualizing arbitrary object structures. You need to pass it an Array object, which can contain other arrays or objects that responds to #to_s.
NOTE: The code makes NO attempt to deal with structures that have loops - you'll run out of stack space soon enough if you try that. Feel free to post your fixes to do that in the comments (easy enough - just need to keep track of visited objects).

An example example. Given this:

 [:defun, :parse_quoted, [:c],
 [:while, [:and, [:ne, [:assign, :c, [:getchar]], -1], [:ne, :c, 34]], [:do,
  [:putchar, :c]
  ]
 ]
 ]


I generate this image (the gradients and shadows are thanks to my previously described XSL transform to pretty up the Graphviz SVG output):



The code is quite straightforward, though I'm not quite happy with the amount of monkey-patching. There were two easy choices: monkey-patching or lots of #is_a? calls, which made it horribly messy. I wouldn't advocate including this into a larger app without cleaning it up first, but as a quick hack it works well.

module ToDot
 def self.escape str
  str.gsub(/([<>{} |\])/) { "\"+$1 }
 end
end

class String def to_dot_label; '\"'+ToDot::escape(self)+'\"'; end end

class Array def to_dot_label; "..."; end

def to_dot_edge src, shorten " #{src}" + (shorten ? "" : ":#{object_id}") + " -> #{object_id};\n" end

def to_dot_subgraph return "" if nil ary = self[0].is_a?(Array) shorten = !ary && self[1..-1].detect{|o| !o.is_a?(Array)} == nil s = " #{object_id} [label=\"" if shorten s += self[0].to_dot_label + "\", shape=rect];\n" else s += collect { |o| "<#{o.object_id}> " + o.to_dot_label }.join("|") s += "\"];\n" end s += collect {|o| o.to_dot_edge(object_id,shorten) }.join s += collect {|o| o.to_dot_subgraph }.join s end end

class Object def to_dot_subgraph; end def to_dot_edge src, shorten; end def to_dot_label; ToDot::escape(to_s); end

def to_dot s = "digraph G {\n" s += " node [shape=record style=filled fillcolor=lightblue " s += "fontname=Verdana height=0.05 fontsize=10.0 ];\n" s += to_a.to_dot_subgraph s += "}\n" end end


As for how to use it:

require 'arytodot'

puts someArray.to_dot

Then pipe the output to "dot -Tsvg >output file" and use your favorite XSL processor to render an image from it. I used "rsvg file.svg file.png". If you want to use my XSL transform to pretty it up, follow the instructions in the article linked to above.

Here's the full "parser" example from my compiler series (click for the full size version):




2008-05-29 14:32 UTC TraceViz: Visualizing traceroute output with graphivz

At Edgeio we had a fairly complicated network setup, and at one point I quickly hacked together a Ruby script to merge the paths generated by multiple traceroute runs together into directed graphs, showing the routing from a few selected host in our environment to all our other hosts. I generated dot-files suitable for Graphviz from it.

It was a helpful way of looking for weird inconsistencies in routing, in particular between our two locations.

Unfortunately, when Edgeio closed down I think the script was lost, and in any case if it isn't I wouldn't be able to get permission to release it without more hassle than it'd take me to recreate it from scratch. So recreate it from scratch is exactly what I did.

Here's an example of a traceroute from www.hokstad.com to www.gmail.com, docs.google.com and www.google.com (scaled down):

(Gradients and shadows courtesy of my XSL transform to make graphviz output prettier)

There's a couple of caveats: I just strip out failed probes, and I don't try to reconcile the names of the endpoints (which I preferred to include for readability) with the IP addresses of the trace, so the first/last grey nodes before the named/blue nodes may be redundant.

This script by default runs traceroute 3 times for each target, and that's the reason why there are more possible paths than endpoints, and it illustrates failover and/or load balancing mostly, but can also be affected by fluctuations in dynamic routing. It's usually fairly stable, and in fact at Edgeio I found several network problems by re-running the script when something was up and looking at how the routing had changed. 3 runs seemed sufficient for my use, but for large networks adding more may give a better picture of the routing.

The Ruby script

You can find the full script here, but here are the guts:

First I defined a convenience method to run traceroute and capture the output. This is intended for a POSIX OS (Linux / Unix / BSD's), but mainly requires a working traceroute where the output is a number of lines starting with a hop count and then the ip address. TRACEROUTE must be set to a valid traceroute command.

TRACEROUTE=`which traceroute`.chomp

def traceroute host `#{TRACEROUTE} -n #{host}` end

The TraceViz class does the gruntwork. @edges contains the edges of the graph, in other words which pairs of ip addresses represent a hop further in the network. @nodes contains a set of the ip addresses found. @targets contains the hostnames of the start and end-points - it's used only to style them differently:

class TraceViz
  def initialize(times,timeout)
    @times,@timeout = times,timeout
    @edges = Set.new
    @nodes = Set.new
    @targets = Set.new
    @this_host = Socket.gethostname
    @targets << @this_host
  end

The #trace method executes the traceroutes, and enforces a timeout:

  def trace host
    @times.times do |i|
      STDERR.puts "Trace ##{i+1} for #{host}"
      Timeout::timeout(@timeout) do
        process_trace(host,traceroute(host))
      end rescue nil
    end
  end

#process_trace handles the parsing of the trace, by splitting the output into lines, extracting the IP addresses, and then adding each of them to @nodes, and adding each pair to @edges. I don't care if we've seen them before, since I use Set's so the previous (identical) nodes/edges will just overwrite the same values:

  def process_trace host,trace
    @targets << host
    trace = [@this_host] + trace.collect do |line|
      line=line.split
      line[0].to_i > 0 && line[1] != "*" ? line[1] : nil
    end.compact
    trace << host
    trace.each {|h| @nodes << h }
    trace.each_cons(2) {|h1,h2| @edges << [h1,h2] }
  end

Finally #to_dot generates a graphviz compatible directed graph:

 def to_dot
    res = "digraph G {"
    @edges.each { |h1,h2| res << "   \"#{h1}\"->\"#{h2}\"\n" }
    @nodes.each do |n|
      color = @targets.member?(n) ? "lightblue" : "lightgrey"
      res << "  \"#{n}\" [style=filled fillcolor=#{color}]\n"
    end
    res << "}"
  end
end

Running it and generating the image

First run the script to generate the dot-files, and then generate an SVG file from it:

ruby traceviz.rb www.google.com www.gmail.com docs.google.com >trace.dot
dot -Tsvg trace.dot >trace.svg

Optionally, process the script with my XSL transform to make it prettier (adding the gradients from above etc) - I'm using xsltproc from libxslt:

xsltproc notugly.xsl trace.svg >trace-notugly.svg

Then I used "rsvg" from librsvg2 to turn it into a PNG:

rsvg trace-notugly.svg traceviz.png

Of course these steps are easily enough wrapped into a script.



2008-03-31 00:59 UTC Making Graphviz output pretty with XSL

Posted in: , , , , ,
NOTE: See the updated version of this stylesheet HERE

UPDATED: Example of the latest version here

A couple of years back I posted some about an XSL transformation I used to clean up Graphviz output to make my diagrams prettier. These days I use Omni Graffle for most of my diagramming needs, and making diagrams look nice with it is trivial, but Graphviz is still my tool of choice whenever I need to generate diagrams from code automatically, because its automated layout is reasonably good.

Last year I got an e-mail from Ryan Shea who asked about the stylesheet I'd used, and we went back and forth and fixed various problems and made it a lot cleaner. Just the other day I wanted to generate a Graphviz graph and looked up the stylesheet again, and figured it was about time I actually posted it so others can benefit.

Here's a "hello world" Graphviz diagram:

digraph G {
        Hello->World

Hello [style=filled fillcolor=lightblue] World [style=filled fillcolor=lightgrey] }

Here's how Graphviz renders it (with "dot -Tsvg"). The image on the left (if it shows up for you) is the SVG file. The image on the right is a screenshot in case your browser doesn't support SVG:



Fair enough, but we can do a lot better:




The XSL is pretty simple and can be found here (updated to link to a GitHub repository that will be regularly updated)  NOTE: The Graphviz SVG output has changed quite a few times - if the XSL linked here doesn't work for you, I'd very much appreciate if you post what version of Graphviz you've tested it with in the comments, and/or a sample of the SVG, so I can fix the XSL

The one caveat is that for any color you want turned into a gradient, you need to add an extra "linearGradient" tag to the XSL file like the ones that are already there.

You will need an XSL processor to convert the files. Personally I use "xsltproc" on my Linux box, which is from libxslt RPM if you're on Fedora Core or Redhat EL - chances are it's already installed if you use Linux. If so, you convert your Graphviz files like this (assuming your dot file is names "hello.dot" and you've saved the XSL file as notugly.xsl):

dot -Tsvg hello.dot >hello.svg
xsltproc notugly.xsl hello.svg >hello-notugly.svg



Older Entries

About me

E-mail: vidar@hokstad.com Skype: vhokstad
Twitter: vhokstad
View my LinkedIn profile.

I was born April 21st, 1975, in Oslo, Norway. Since 2000 I've been living in London, UK. I'm married and we just had our first child, Tristan Ikemefuna Hokstad.

I'm working for Aardvark Media as Director of Technology. I'm also currently on the board of SpatialQ, a startup in the GIS space, and an advisor to Skoach, a startup doing a time management app for people with ADD.

Twitter Updates

    follow me on Twitter