18

I have a set of measurements of a variable over time. I have these measurements in a file called "results" with this format:

# time sample
0      5
12     43
234    342

etc...

I can easily plot this in gnuplot with:

plot "results"

Is there any way to plot the derivative of these measurements with regard to time (i.e. dsample/dt) directly from gnuplot, or do I have to calculate the derivative separately and plot that directly in gnuplot?

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319

2 Answers2

19

You can do it by defining a function to take the derivative:

#!/usr/bin/env gnuplot

set term pngcairo
set output 'test.png'

# derivative functions.  Return 1/0 for first point, otherwise delta y or (delta y)/(delta x)
d(y) = ($0 == 0) ? (y1 = y, 1/0) : (y2 = y1, y1 = y, y1-y2)
d2(x,y) = ($0 == 0) ? (x1 = x, y1 = y, 1/0) : (x2 = x1, x1 = x, y2 = y1, y1 = y, (y1-y2)/(x1-x2))

set key bottom left Left reverse

# offset for derivatives (half the x spacing)
dx = 0.25

plot 'data.dat' title 'data', \
     '' u ($1-dx):(d($2)) title '1-variable derivative', \
     '' u ($1-dx):(d2($1,$2)) title '2-variable derivative', \
     '' u ($1-dx):(d2($1,$2)) smooth csplines title '2-variable derivative (smoothed)'

d2(x,y) (which is probably what you are looking for) just computes rise over run (delta y over delta x) at all but the first data point, and d(y) computes delta y in the same way. Given this data file

0.0 1
0.5 2
1.0 3
1.5 4
2.0 5
2.5 3
3.0 1

The result is

enter image description here

andyras
  • 15,542
  • 6
  • 55
  • 77
  • I don't really think that the derivative here should start at 0. from the look of your plots it should either be undefined or some finite value (depending on the algorithm that OP wants to implement to find the derivative). But, kudos for the effort on this one and +1 for demonstrating the inline function. – mgilson Apr 02 '13 at 01:20
  • 1
    @andyras, interesting approach, you ought to add a bit of explination. Also i think this can be modified to plot the derivative at the midpoints between the initial data instead - might look a tad better. In the end I think finding the right tool for the job applies here though.. – agentp Apr 02 '13 at 15:44
  • @george -- I couldn't agree more. While you *can* do this with gnuplot, I don't know that you *should*. It would be a lot easier to understand/modify if you wrote a quick script to take the derivative in another language and piped that into gnuplot I think. – mgilson Apr 02 '13 at 19:41
  • 1
    I updated the functions a bit, now it puts the derivative points at the midpoints of the data. I definitely agree that it usually makes sense to do this kind of processing outside of gnuplot. I keep these functions in my `.gnuplot` file for a quick-and-dirty look at derivatives. I usually have closely-spaced data so the offset doesn't matter if I'm just looking for rough locations of minima/maxima. – andyras Apr 02 '13 at 23:04
6

An alternative (more generic) syntax to plot the derivative is given here by Viktor T. Toth

x0=NaN
y0=NaN
plot 'test.dat' using (dx=$1-x0,x0=$1,$1-dx/2):(dy=$2-y0,y0=$2,dy/dx) w l t 'dy/dx'

Explanation: The datafile modifier (after using) within the brackets is to be interpreted as the computed coordinates of the point (x):(y), computed row by row from the datafile. For each row, the column values ($1, $2, ...) are modified by allowed arithmetic operations. The value of the bracket is the last expression in a list of comma-separated expressions. The first two are evaluated first and stored in variables, that are used later and for the next row. A pseudo code for the above syntax is:

  x0 = NaN // Initialise to 'Not a number' for plot to ignore the first row
  y0 = NaN
  foreach row in 'test.dat' with col1 as $1, and col2 as $2:
    dx = $1-x0
    x0 = $1
    x = $1 - dx/2 // Derivative at the midpoint of the interval
    dy = $2-y0
    y0 = $2
    y = dy/dx
    plot x:y  // Put the point on the graph

Extra: This explanation can also be used to interpret @andryas solution to the derivative function d2(x,y). The only difference being the usage of $0. $0 in gnuplot is the 'zeroth' column of the datafile, essentially the row number (as in a spreadsheet, after ignoring the comment lines in the datafile). $0==0? checks if it is the first row and assigns a 1/0 (NaN) so the plot command ignores and does not plot it. The code, however, is correct only if the interval length is fixed (in the above case 0.5). On the other hand, Viktor's code computes the interval for every row.

Viktor Toth
  • 707
  • 6
  • 13
Sunthar
  • 3,731
  • 1
  • 13
  • 4
  • It seems like this solution assumes each point is equally spaced along the x (or time) axis. Can it be extended to handle the case where datapoints are separated by a variable amount of time? – Todd Freed Dec 25 '17 at 00:08