Graphing mtr reports with gnuplot

I wasn’t able to find any clear examples online of scripting gnuplot to graph mtr output, and I had a directory full of report files that I needed to turn into SVG graphs. If you’d like to follow along, here are the assumptions:

  1. You have mtr reports as text files generated by the -r switch.
  2. You want a stacked column chart of the best, average and worst response times.
  3. You need SVG output suitable for including in web pages.
  4. You are vaguely familiar with gnuplot (enough to tweak a .gp file).

My report files are completely ordinary, generated in the following way:

$ mtr -r static.soku.com
Start: Mon Feb  3 12:27:03 2014
HOST: ophelia                     Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 111.194.0.1                0.0%    10    7.5  11.1   5.9  40.5  10.4
  2.|-- 61.148.149.241             0.0%    10    8.2  11.2   3.8  33.5   9.3
  3.|-- bt-228-181.bta.net.cn      0.0%    10    8.4  11.9   7.1  33.6   7.8
  4.|-- 123.126.6.238              0.0%    10    9.0  10.0   7.3  20.1   3.7
  5.|-- 123.126.0.69               0.0%    10   11.4  10.7   7.5  16.8   2.5
  6.|-- 219.158.5.218              0.0%    10   12.7  10.5   8.2  13.0   1.4
  7.|-- 219.158.32.94              0.0%    10   37.6  36.9  34.5  39.5   1.5
  8.|-- 202.97.50.197              0.0%    10   26.2  27.9  26.0  30.2   1.4
  9.|-- 202.101.63.233             0.0%    10   28.8  32.1  27.5  58.3   9.2
 10.|-- 61.129.94.178              0.0%    10   33.3  35.9  29.8  57.7   8.9
 11.|-- 222.73.88.69               0.0%    10   31.2  32.0  28.7  39.6   3.7
 12.|-- 180.153.115.82             0.0%    10   31.5  33.1  29.5  45.4   4.6
 13.|-- 114.80.185.48              0.0%    10   34.0  35.9  33.8  42.6   2.6

I have a directory full of these with filenames in the form “host-date-time”. I want to turn each one into an SVG chart that looks like this:

Example SVG chart of mtr output

After some fiddling around with gnuplot’s interactive mode I came up with this script which plots the graph from a file called infile:

# Use a stacked column histogram
set style data histograms
set style histogram rowstacked

# Columns are 60% of max width (i.e. not touching, set 1.0 for touching)
set boxwidth 0.6

# Define colours - 1:yellow 2:orange 3:red
unset style line
set style line 1  linetype 1 linecolor rgb "#ffff99"
set style line 2  linetype 2 linecolor rgb "#ffdb99"
set style line 3  linetype 3 linecolor rgb "#ff9999"
set style increment userstyles

# Use fill colours with a black border on each segment
set style fill solid 1.00 border lt -1

# Print border/axis only on bottom & left
unset grid
set xtics nomirror
set ytics nomirror
set border 3

# Legend in top left, get column titles from input file
set key inside left top invert autotitles columnheader

set xlabel "Hops"
set ylabel "Response time (ms)"

# Uncomment next 2 lines to print SVG to standard out
#set terminal svg size 600,300 dynamic  fname 'Source Sans Pro'  fsize 12 butt solid 
#set output
plot "infile" u 2:xticlabel(1), "" u 3, "" u 4

Hopefully it’s easy enough to work out from the comments what’s going on. As an example tweak, if you were less interested in the variance between best/average/worst and wanted the y-axis to be accurate for each, you would use a clustered rather than stacked histogram:

set style histogram clustered
set grid noxtics ytics

Here’s what that would look like:

Example chart with clustered columns

The infile format strips the unnecessary columns and header cruft from the raw mtr report. I couldn’t figure out an easy way to do this in the gnuplot script itself so I settled for creating an intermediary file in the following format:

$ cat infile
Hop     Best    Average Worst
1        5.9     11.1    40.5
2        3.8     11.2    33.5
3        7.1     11.9    33.6
4        7.3     10.0    20.1
5        7.5     10.7    16.8
6        8.2     10.5    13.0
7        34.5    36.9    39.5
8        26.0    27.9    30.2
9        27.5    32.1    58.3
10       29.8    35.9    57.7
11       28.7    32.0    39.6
12       29.5    33.1    45.4
13       33.8    35.9    42.6

To automate the process I turned the gnuplot script into a shell script which uses awk and mktemp to reformat the raw mtr report into an infile suitable for gnuplot. It writes the SVG output to STDOUT so invoking it looks like this:

$ ./mtr_graph.sh report.txt > report.svg

The mtr_graph.sh script is available as a gist along with the commented version of the gnuplot file.