18

I have written a program which writes a list of data to a '.dat' file with the intention of then plotting it separately using gnuplot. Is there a way of making my code plot it automatically? My output is of the form:

x-coord    analytic    approximation
x-coord    analytic    approximation
x-coord    analytic    approximation
x-coord    analytic    approximation
x-coord    analytic    approximation
 ....

Ideally, when I run the code the graph would also be printed with an x-label, y-label and title (which could be changed from my C code). Many thanks.

Svante
  • 50,694
  • 11
  • 78
  • 122
JMzance
  • 1,704
  • 4
  • 30
  • 49

5 Answers5

51

I came across this while searching for something else regarding gnuplot. Even though it's an old question, I thought I'd contribute some sample code. I use this for a program of mine, and I think it does a pretty tidy job. AFAIK, this PIPEing only works on Unix systems (see the edit below for Windows users). My gnuplot installation is the default install from the Ubuntu repository.

#include <stdlib.h>
#include <stdio.h>
#define NUM_POINTS 5
#define NUM_COMMANDS 2

int main()
{
    char * commandsForGnuplot[] = {"set title \"TITLEEEEE\"", "plot 'data.temp'"};
    double xvals[NUM_POINTS] = {1.0, 2.0, 3.0, 4.0, 5.0};
    double yvals[NUM_POINTS] = {5.0 ,3.0, 1.0, 3.0, 5.0};
    FILE * temp = fopen("data.temp", "w");
    /*Opens an interface that one can use to send commands as if they were typing into the
     *     gnuplot command line.  "The -persistent" keeps the plot open even after your
     *     C program terminates.
     */
    FILE * gnuplotPipe = popen ("gnuplot -persistent", "w");
    int i;
    for (i=0; i < NUM_POINTS; i++)
    {
    fprintf(temp, "%lf %lf \n", xvals[i], yvals[i]); //Write the data to a temporary file
    }

    for (i=0; i < NUM_COMMANDS; i++)
    {
    fprintf(gnuplotPipe, "%s \n", commandsForGnuplot[i]); //Send commands to gnuplot one by one.
    }
    return 0;
}

EDIT

In my application, I also ran into the problem that the plot doesn't appear until the calling program is closed. To get around this, add a fflush(gnuplotPipe) after you've used fprintf to send it your final command.

I've also seen that Windows users may use _popen in place of popen -- however I can't confirm this as I don't have Windows installed.

EDIT 2

One can avoid having to write to a file by sending gnuplot the plot '-' command followed by data points followed by the letter "e".

e.g.

fprintf(gnuplotPipe, "plot '-' \n");
int i;

for (int i = 0; i < NUM_POINTS; i++)
{
  fprintf(gnuplotPipe, "%lf %lf\n", xvals[i], yvals[i]);
}

fprintf(gnuplotPipe, "e");
BenB
  • 1,010
  • 12
  • 17
  • I know it has been a really long time since this answer was published, but I used the code from your second edit plus the for loop with the `commandsForGnuplot` in it to add commands, and it plots but it doesn't add any of the commands (title, xlabel or ylabel). How can I add them if not that way? Please. – M.O. Sep 22 '17 at 19:34
  • If anyone comes across a '-' and an extra point on the plot, they are not actually plotted points. They are part of the legend. Do ```fprintf(gnuplotPipe, "plot '-' notitle\n");``` and they would disappear. – Tommy Wolfheart Mar 21 '22 at 10:36
6

You can either create a gnuplot script and spawn a process running gnuplot to plot this script from the commandline, or you may use one of the provided interfaces. For C, there is a POSIX pipe-based interface from Nicolas Devillard available here: http://ndevilla.free.fr/gnuplot/ ...and an iostream-based C++ version is available via git (see: http://www.stahlke.org/dan/gnuplot-iostream/ )

The most portable and probably the easiest way would still be calling gnuplot to plot a script, though. As sje397 mentioned, check your documentation for the system() call in stdlib.h.

On a sidenote, there is also GNU plotutils, which offers libplot, a library for plotting datasets, which you could use in your application. See: http://www.gnu.org/software/plotutils/

Jim Brissom
  • 31,821
  • 4
  • 39
  • 33
  • 1
    Im not fantastic at understand all this documentation stuff but I've found the declaration for system(): int system(const char *command); Is it then just a case of adding something like this?: system(gnuplot plot "data_set.dat" with 1:2 using lines); – JMzance Aug 19 '10 at 11:54
  • 1
    In the end I went for something like this: – JMzance Sep 23 '10 at 11:56
  • 1
    #include "gnuplot_i.h" int main(void) { FILE *outFile; outFile = fopen("Flight_Path.dat", "w"); /* Iterative loop which prints to output file: example.dat */ fclose(outFile); gnuplot_ctrl *k; k = gnuplot_init(); gnuplot_set_xlabel(k, "x"); gnuplot_set_ylabel(k, "y"); gnuplot_cmd(k,input_x); gnuplot_cmd(k,input_y); gnuplot_cmd(k, "set title \"Trajectory with Drag\""); gnuplot_cmd(k, "plot \"Flight_Path.dat\" using 1:2 title \"Flight Path\" with lines, \ sleep(7); gnuplot_close(k); return 0; } – JMzance Sep 23 '10 at 12:00
  • 1
    I'm sure you are missing some bits of that code, i.e. you are opening and closing the file immediately afterwards. Also, formatting in comments just sucks. Please edit your original post and add code to that - I would do this myself, but as I said, I believe your code is missing something. – Jim Brissom Sep 23 '10 at 21:50
3

Although I've seen a lot of ways of doing this, the most simplest way of doing this would be by using the system() (from stdlib.h) function in C. First make a gnuplot script and save it as "name.gp" (neither the name nor the extension matter).
A simple script would be,

plot 'Output.dat' with lines

After saving this script file, just add
system("gnuplot -p name.gp");
at the end of your code.
It's as simple as that.

Make sure to add gnuplot path to the Windows System Path variables.

Martin
  • 80
  • 8
Nidish Narayanaa
  • 338
  • 3
  • 12
2

I've adapted the accepted answer to plot a float array while avoiding the use of a temporary file. In it, float* data_ is the array and size_t size_ its size. Hopefully it is helpful for someone!

Cheers,
Andres

void plot(const char* name="FloatSignal"){
  // open persistent gnuplot window
  FILE* gnuplot_pipe = popen ("gnuplot -persistent", "w");
  // basic settings
  fprintf(gnuplot_pipe, "set title '%s'\n", name);
  // fill it with data
  fprintf(gnuplot_pipe, "plot '-'\n");
  for(size_t i=0; i<size_; ++i){
    fprintf(gnuplot_pipe, "%zu %f\n", i, data_[i]);
  }
  fprintf(gnuplot_pipe, "e\n");
  // refresh can probably be omitted
  fprintf(gnuplot_pipe, "refresh\n");
}
fr_andres
  • 5,927
  • 2
  • 31
  • 44
2

I know it's too late, but answering if it may help someone. fputs really does the job, you want. first you need to print the data you want to plot in a temporary file data.temp.

FILE *pipe_gp = popen("gnuplot -p", "w");
fputs("set terminal png \n",pipe_gp);
fputs("set output 'abc.png' \n",pipe_gp);
fputs("set xlabel 'f' \n",pipe_gp);
fputs("set xrange [0:100] \n",pipe_gp);
fputs("set yrange [0:100] \n",pipe_gp);
fputs("plot 'data.temp' u 1:2 w circles lc rgb 'pink' notitle \n",pipe_gp);
pclose(pipe_gp);
yasir
  • 123
  • 8