GnuPlot: Realtime Plots in 20 lines

There are some excellent charting and plotting packages but if you’re like me you sometimes want to do a quick test plot to capture some realtime data.

Gnuplot has been around for quite awhile and I was happily surprised at what it can do. I was amazed that I could make real-time bar and line charts in only 20 lines of scripting code. In this blog I’ll introduce Gnuplot and show two examples. The first will show the status Raspberry Pi I/O pins, and the second example will be a line chart of CPU diagnostics.

Getting Started

Gnuplot can be installed on Linux, Windows, and Mac. To install Gnuplot on Ubuntu:

sudo apt-get install gnuplot

Gnuplot is typically run as a command line utility, but it can also be run manually. When Gnuplot is run manually the charting instructions and data values can be inserted directly. Below is an example where 4 sets of data points are plotted in a line chart.

pi@raspberrypi: $ gnuplot

gnuplot> $Mydata << EOD
# Now enter some data                                
2 1
3 1.5
4 2.1
5 3.3
EOD
gnuplot> plot $Mydata with line

Data block names must begin with a $ character, which distinguishes them from other types of persistent variables. The end-of-data delimiter (EOD in the example) may be any sequence of characters. For this example the plot command will use the data in the $Mydata variable and create a line chart.

A Static Bar Chart

A simple but useful example of Gnuplot would be to show the realtime status of the Raspberry Pi General Purpose Input/Output (GPIO) pins as a bar chart.

A bar chart presentation can be created using a data file of:

# gpio.dat - data file for GPIO pin values
# column1 = chart position, column2 = heading, column3 = value
0 GPIO2 0
1 GPI03 1
2 GPI04 1
#....

To plot a bar chart the fill style and bar width needs to be defined. The plot using 1:3:xtic(2) argument will make the first column in the data file the x-position, the third column the y-value and the x-labels be the second column. The interactive commands to plot the file:

pi@raspberrypi:~/pete/gnuplot $ gnuplot 

gnuplot> set style fill solid
gnuplot> set boxwidth 0.5
gnuplot> plot "gpio.dat" using 1:3:xtic(2) with boxes title ""

Real-Time Bar Chart of PI GPIO

The previous example used a manually created gpio.dat data file. The status of GPIO pins can be found using the gpio command line utility. To get the status of GPIO pin 9:

gpio read 9

By adding some Bash and awk script it is possible to create a gpio.dat file:

$ gpio read 9
1
$ gpio read 9 | awk '{ print "9 GPIO9 " $1 }'
9 GPIO9 1
$ gpio read 9 | awk '{ print "9 GPIO9 " $1 }' > gpio.dat
$ cat gpio.dat
9 GPIO9 1

To make a dynamic bar chart I created a Gnuplot script file (gpio_bars.txt). The Gnuplot scripting language is quite powerful, and it support a wide range of functions and control statements.

Rather than manually adding lines for each GPIO pin status a for loop can iterate from pins 2-29. A system command is used to run the gpio utility and bash commands. To refresh the data a replot and a pause command is used.

# Create Dynamic bar that read GPIO pins every 5 seconds
#
set title "PI GPIO Data"
set boxwidth 0.5
set style fill solid

# Create a dummy file to get started
system "echo '0 GPIO2 1' > gpio.dat"

plot "gpio.dat" using 1:3:xtic(2) with boxes title ""

while (1) {  # make a new 'gpio.dat' every cycle with fresh data
  system "echo '' > gpio.dat"
  do for [i=2:29] {
    j = i-2 # put first GPIO pin at position 0
    system "gpio read " .i.  "  | awk '{ print  \"" . j . " GPIO" . i . " \" $1 }' >> gpio.dat
  }
  replot
  pause 5
}

To run this script enter:

gnuplot -persist gpio_bars.txt

A Simple Line Chart

A bar chart presentation can be created using a data file of:

# GPU.dat - a time stamp with two data points
18:48:30 51.0 49.0
18:48:40 50.5 49.5
18:48:45 51.5 49.0
18:48:50 50.0 50.5
18:48:55 50.5 49.5

The interactive Gnuplot commands to show a line chart of this data would be:

pi@raspberrypi: $ gnuplot

gnuplot> set xdata time
gnuplot> set timefmt "%H:%M:%S"
gnuplot> set format x "%H:%M:%S"
gnuplot> plot "gpu.dat" using 1:2 with line title "GPU temp" ,\
>"gpu.dat" using 1:3:3 with line title "CPU temp"  

A few extra lines are needed in the Gnuplot script. First the plot needs to know that the x-axis is time data, and it needs to know the format of the time data. Multiple data points can be plotted at the same time, and the using argument tells Gnuplot the x:y-point data. (If the data file had a third point the using reference would be 1:4:4 ).

A Real-Time Line Chart

Linux has a lot of useful command line trouble shooting tools, one of these is the sensors utility that allows users to get fan speed and temperatures.

$ sensors
dell_smm-virtual-0
Adapter: Virtual device
Processor Fan: 2676 RPM
CPU: +47.0°C
Ambient: +38.0°C
SODIMM: +37.0°C
...

Using some Bash and Awk commands it is possible to get the fan speed and CPU temperature:

$ sensors | grep RPM
Processor Fan: 2685 RPM
$ sensors | grep RPM | awk '{print $3}'
2685

$ sensors | grep CPU
CPU: +50.0°C
$ sensors | grep CPU | awk '{print $2}'
+48.0°C
$ sensors | grep CPU | awk '{print substr($2,2,4)}'
48.0

Awk supports a systime() call to return the present date/time, and a strftime() call to customize the presentation of the time/date. (Note: a Raspberry Pi might need to have gawk installed to get this functionality, use “sudo apt-get install gawk”).

The next step is to format the sensor output with a timestamp:

$ sensors |grep RPM | awk '{print strftime("%H:%M:%S ", systime()) $3}'

10:26:46 2687

$sensors | grep CPU | awk '{print strftime(\"%H:%M:%S \",systime()) substr($2,2,4)}'

10:27:46 49.0

Now that a time and value string can be generated a Gnuplot script can be created (line_fan_cpu.txt) to show real time data.

To make the Bash code a little easier two data files are created, fan.dat and cpu.dat.

The plot has to account for different scale ranges, so y2range and y2label definitions are used. The final script addition is to include an axes (x1y2 or x1y2) to each plot point, this lines up the data value to the right or left y-axis.

The complete Gnuplot script to show fan speed and CPU temperature is only 20 lines of code!

# Create a Plot or User and System CPU Usage, update every 5 seconds
#
set title "GnuPlot - Fan Speed  and CPU Temperature"
set yrange [2650:2700] 
set ylabel "Fan Speed"
set y2range [43:49] 
set y2label "CPU Temp (C)"
set y2tics
set xdata time
set timefmt "%H:%M:%S"
set format x "%H:%M:%S"

system "sensors |grep RPM | awk '{print strftime(\"%H:%M:%S \", systime()) $3}' > fan.dat"
system "sensors | grep CPU | awk '{print strftime(\"%H:%M:%S \",systime()) substr($2,2,4)}'  > cpu.dat"

plot "fan.dat" using 1:2  with lines axes x1y1 title "fan speed (RPM)",  "cpu.dat" using 1:2 with lines axes x1y2 title "CPU Temp (C)"
while (1) {
	pause 5
	system "sensors |grep RPM | awk '{print strftime(\"%H:%M:%S \", systime()) $3}' >> fan.dat"
	system "sensors | grep CPU | awk '{print strftime(\"%H:%M:%S \", systime()) substr($2,2,4)}'  >> cpu.dat"
	replot
}

To run this script enter: $ gnuplot -persist line_fan_cpu.txt

Final Comments

I won’t give up using plotting packages like MatPlotlib or ggplot, but I was very impressed how easy it was to create real-time plots using Gnuplot.

Manipulating the Bash/awk script can be a little complex but it’s incredible useful to be able to use output from almost any command line utility in Gnuplot.

Gnuplot can plot a very large number of data points, but it makes sense to a tail command to only show the latest x-number of points.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s