## 16 April 2011

### Using gnuplot from the command line

gnuplot is excellent for both quick 'n' dirty and lengthy plotting projects. Still, for truly quick work of just plottin' some column against some other column, I've always felt like gnuplot demands too many keystrokes:

[1000 rhys@tiresias 16]$gnuplot G N U P L O T Version 4.2 patchlevel 6 last modified Sep 2009 System: Linux 2.6.32-30-generic Copyright (C) 1986 - 1993, 1998, 2004, 2007 - 2009 Thomas Williams, Colin Kelley and many others Type help to access the on-line reference manual. The gnuplot FAQ is available from http://www.gnuplot.info/faq/ Send bug reports and suggestions to Terminal type set to 'x11' gnuplot> plot 'restart0.mean' using 2:17 gnuplot> exit  Of course, one can turn this process into a one-liner at the cost of quoting: gnuplot -e "plot 'restart0.mean' using 2:17"  Call me picky, but the signal-to-noise ratio in that one-liner still feels too high. After some quoting experimentation using printf's %q and %b format specifiers, the following little function definition gplot () { local fileexpr=$(printf "'%q'" $1) shift local plotexpr=$(printf '%b' "plot ${fileexpr}$*")
gnuplot -persist -raise -e "$plotexpr" }  makes gplot restart0.mean using 2:17  behave like the previous two examples. This function happily hides the file name quoting requirements and remains tab-completion-friendly. Providing computed column values like gnuplot's using 1:$(cos($2)) on the command line still requires thought, but the straightforward tasks work thoughtlessly. Suggestions for improvements definitely welcome in the comments. One glaring bug is that passing a pipe expression as the file bombs. Update 20110504: I've decided that I much prefer creating a gplot script containing #!/bin/bash file=$1
shift
gnuplot -persist -raise <(cat <<-GNUPLOTSCRIPT
plot '$file'$*
GNUPLOTSCRIPT
)

as it is much simpler to work through the quoting and far more extensible.

Update 20111031: Globbing, labelling, and a handful of other enhancements:

#!/bin/bash

# Fail on first error
set -e

# Create temporary files to hold gnuplot script
tmp1=mktemp
tmp2=mktemp
trap "rm -f $tmp1$tmp2" EXIT

# Process (and then remove) command line options
# Build up any post-terminal processing in tmp2 for later use
autotitle=
title="date +%r: gplot $*" terminal="set terminal x11 title '$title' enhanced persist"
cmd=plot
forexpr=
raise=
showhelp=
while getopts "3cf:ghils:re:t:x:y:z:F:SX:Y:Z:" opt
do
case $opt in 3) cmd=splot ;; c) autotitle=true ;; e) terminal='set term postscript eps enhanced color dashed rounded "Arial,14"' pause='' # Disable interactive on EPS output echo set output \"$OPTARG\" >> $tmp2 ;; f) forexpr=" for [$OPTARG] "
;;
g) echo "set grid" >> $tmp2 ;; h) showhelp=0 ;; i) pause='pause -1 "Plot interactive until Enter pressed.\nHit h in plot window for help.\n"' ;; l) echo "set logscale y" >>$tmp2
;;
r) raise="-raise"
;;
s) savescript="$OPTARG" ;; t) echo set title \"$OPTARG\" >> $tmp2 ;; x) echo set xlabel \"$OPTARG\" >> $tmp2 ;; y) echo set ylabel \"$OPTARG\" >> $tmp2 ;; z) echo set zlabel \"$OPTARG\" >> $tmp2 ;; F) pause="pause$OPTARG; replot; reread"
;;
S) stdin=true
;;
X) echo set xrange $OPTARG$ >> $tmp2 ;; Y) echo set yrange $OPTARG$ >>$tmp2
;;
Z) echo set zrange $OPTARG$ >> $tmp2 ;; esac done shift$((OPTIND-1))

if [ x$showhelp != x ]; then cat <<-HERE Usage: gplot [OPTION]... (FILE|EXTGLOB) GNUPLOTCMD... Use gnuplot to plot one or more files directly from the command line. -3 Perform 3D plotting using gnuplot's splot command. -c Populate the key using autotitling. -e FILE Save an Encapsulated Postscript (eps) called FILE. -f FOREXPR Prepend a 'for [FOREXPR]' to the plotting command. -g Show grid lines. -h Show this help message. -i Interactive plotting mode. Hit 'h' on plot for help. -l Use logarithmic scale for y axis. -s FILE Save the generated gnuplot as a script called FILE. -r Have the window manager raise the plot window. -t TITLE Set TITLE as the plot's title. -x XLABEL Specify XLABEL as the x axis label. -y YLABEL Specify YLABEL as the y axis label. -z ZLABEL Specify ZLABEL as the z axis label. -F FREQUENCY Replot the inputs every FREQUENCY seconds. -S Prior to plotting, read auxililary gunplot from stdin. -X XLOW:XHIGH Specify an explicit x axis range instead of autoscaling. -Y YLOW:YHIGH Specify an explicit y axis range instead of autoscaling. -Z ZLOW:ZHIGH Specify an explicit z axis range instead of autoscaling. Examples (see gnuplot documentation for complete GNUPLOTCMD details): gplot -i foo.dat using 1:2 with linespoints gplot -s foo.gp -X 0:1 -Y 0:2 foo.dat using 1:2 with linespoints gplot -e foo.eps foo.dat using 1:2 with linespoints gplot -3 restart\*.dat using 1:2:3 On error, the failing gnuplot script is shown. HERE exit$showhelp
fi

# Set terminal
echo "$terminal" >>$tmp1

# Slurp any settings built up during getops processing
cat $tmp2 >>$tmp1

# Obtain file(s) to plot from first argument using extended globbing
# Deliberately allow globbing to occur in this assignment
shopt -s extglob
declare -a files=($1) shift # Tweak autotitle based on options and incoming argument details if [ "$autotitle" ]; then
# Use columnheader option iff only one file provided
if [ ${#files[@]} -eq 1 -a$cmd != splot ]; then
echo 'set key autotitle columnheader' >> $tmp1 else echo 'set key autotitle' >>$tmp1
fi
else
echo 'set key noautotitle' >> $tmp1 fi # Possibly slurp standard input for further options # FIXME Not working for 'echo foo | gplot' if [ "$stdin" ]; then
cat <&1 >> $tmp1 fi # Build gnuplot script to plot possibly multiple files declare -i count=0 for file in "${files[@]}"
do
count+=1
if [ $count -eq 1 ]; then echo "$cmd" "$forexpr" \'$file\' $* \\ >>$tmp1
else
echo "   "  , "$forexpr" \'$file\' $* \\ >>$tmp1
fi
done
echo '' >> $tmp1 # If requested, save the plotting commands as an executable script if [ "$savescript" ]; then
echo '#!/usr/bin/env gnuplot' > "$savescript" cat "$tmp1" >> "$savescript" chmod a+x "$savescript"
fi

# If requested, add a pause command to the end of the script. Notice this was
# not added to the $savescript as it would be annoying in that context. if [ "$pause" ]; then
echo "$pause" >>$tmp1
fi

# Generate the plot
# Display the script when an error occurs to aid debugging
gnuplot $raise$tmp1 || cat \$tmp1


## 01 April 2011

### Noise.

Following up on some quasi-1D success I'm ready to calculate some 3D fields. I seed them by taking my 1D solution and add noise. This is purportedly a terrible way to kick off turbulence as the fluctuations have to be massive to ultimately take and transition into a correct field. I've been warned...

Needing a way to monitor the fluctuation strengths and being in coefficient-space for a mixed Fourier/B-Spline discretization, I'm trying out the L^2 norm of the fluctuating signal. By Parseval's theorem along with some minor linear algebra, this turns into a sum over the complex-valued coefficient magnitudes: Computation of the L^2 norm in a mixed Fourier/B-spline collocation discretization

Now, for the first case of the L^2 norm over all three directions I need the matrix M which computes the L^2 inner product of two functions given their B-spline coefficient expansions. The code to do this atop some old contributions to the GSL isn't bad, but testing that my banded derivative operator coefficients are correct is awful.

Happily, Mathematica 7 includes BSplineBasis which I can use to cook analytic results to test my implementation. Unhappily, BSplineBasis has issues computing derivatives and an awful amount of mucking around is required to get my analytical test cases: Finding Galerkin L^2-based Operators for B-spline discretizations

In the end, this is all The Right Thing ™ to do but man it eats time. Recognizing this particular rabbit hole and how often such things ensnare my little mind, I sent the following email to my wonderful wife today:

In case you ever wonder what I do with my days....

1. I stare at things like this for far too long to work out the math.
2. Then I sit and stare at the math for far too long to figure out the computer implementation.
3. Then I stare at the computer implementation to test it and clean it up.
4. Then I use the implementation at a single line within my thesis research code.
5. Then I go talk to my advisor on Mondays and report that a single line now works this week that didn't work last week.

— Rhys