Making C code plot a graph automatically
Asked Answered
E

5

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.

Eyehole answered 19/8, 2010 at 11:18 Comment(1)
Maybe check out the system function.Subvert
S
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");
Sperry answered 3/8, 2011 at 23:5 Comment(2)
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.Septavalent
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.Theona
E
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/

Emmert answered 19/8, 2010 at 11:48 Comment(4)
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);Eyehole
In the end I went for something like this:Eyehole
#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; }Eyehole
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.Emmert
M
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.

Marathon answered 3/9, 2015 at 14:59 Comment(0)
G
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");
}
Gleda answered 6/12, 2017 at 6:58 Comment(0)
M
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);
Monto answered 8/10, 2020 at 6:7 Comment(1)
still not opening :(Jaimeejaimes

© 2022 - 2024 — McMap. All rights reserved.