2

I have N input files and I want to plot the data of these files together with their fit function into one single plot (i.e. one plot for all files, data and fit-function).

After a long time of fiddling I found a solution (see below), but I find it "cumbersome and ugly" and I'm wondering if there is a better, more elegant way of achieving the same thing.

I should say that I'm on gnuplot 5.0 under Windows. The test script below doesn't specify a terminal (I'm testing with windows and wxt), but the final script will use pngcairo terminal.

Things that I find sub-optimal about my solution:

  • I need two intermediary tables $data and $fit. My original attempt was to use a do for{} loop to read each file in turn perform the fit and generate the plot, but that didn't work out.
  • Rather than using a fit function, I plot the fit curve (in this simple case a straight line) as data into a table. I experimented with creating on-the-fly user functions using eval but just couldn't quite figure it out (especially how to keep them in sync with the data).
  • I want the fit-equation to be displayed in the chart. I do this by setting labels, but it would be nicer if it would just be part of the key.

My test data:

data1.dat
100 0.15
200 0.29
300 0.46
400 0.58

data2.dat
100 0.12
200 0.22
300 0.35
400 0.48

data3.dat
100 0.1
200 0.22
300 0.29
400 0.40

My gnuplot script:

set key left
set xrange [0:*]
set yrange [0:0.5]

# user function for linear fit
lin(x) = slope * x + offset
max(a,b) = ((a>=b)? a : b)

file_list = "data1 data2 data3"

x_max = 0
# first write all data of interest into a (memory) table
set table $data
do for [name in file_list] {
  filename = name . ".dat"
  plot filename u 1:2
  print ""
  print ""
  x_max = max(GPVAL_DATA_X_MAX, x_max)
}
unset table
x_max = max(GPVAL_DATA_X_MAX, x_max)

num_indices = words(file_list)

# now calculate a linear fit for each dataset
set sample 2
set table $fit
do for [i = 0:(num_indices-1)]{
  fit lin(x) $data index i using 1:2 via slope, offset
  plot [0:x_max][0:0.5] lin(x)
  set label (i+1) sprintf("%s = %.3g*x + %.3g", word(file_list, i+1)."(x) ", slope, offset) at 200,(0.20 - 0.05*i)
}
unset table

set title "Data and Linear Fit"
set xlabel "x"
set ylabel "y"

#now we got both data and fit for all files, plot everything at once
plot for [i = 0:(num_indices-1)] $data index i title word(file_list,i+1) with points lc i+1, for [i = 0:(num_indices-1)] $fit index i with lines lc i+1 noti
3
  • See Gnuplot workflow involving loops of fits that get multiplotted for an approach using eval for fitting, and replot with macros for plotting. That is also quite ugly, but there is no clean solution know to me for this kind of task. Commented May 11, 2015 at 20:47
  • I tried your suggestion, but can't seem to make it work (see below). show plot gives me: last plot command was: plot filename, f1(x), filename, f1(x), filename, f1(x) The relevant code looks like this: filename = sprintf("%s.dat", word(file_list, 1)) f = sprintf("f%d(x)",1) plot filename, @f do for [i=2:num_indices] { filename = sprintf("%s.dat", word(file_list, i)) f = sprintf("f%d(x)",i) replot filename, @f } Commented May 12, 2015 at 14:50
  • The recent 5.2 release has array variables, but it is not straightforward to use them for fitting. I think you have to fit using an extra set of variables, and then copy the resulting values into the arrays. Commented Sep 13, 2017 at 17:13

1 Answer 1

1

There is always the stupid, brute force way. You can create a new datafile containing all points you want to fit (e.g. using "cat data1.dat data2.dat data3.dat > newdata.dat" in a linux system and then fit newdata).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.