Menu

Improving the plotter program with pipes

In Class 13 we produced a program plotter that used gnuplot to plot a function, allowing the user to enter different ranges and see different plots as a result. That program wrote a file to communicated with gnuplot, and (of course) used fork and exec. Now that we have pipes, we can do this a lot more gracefully! Here are some fun new versions of the program.

/*
  NOTE: This modifies the original plotter program by communicating
  via a pipe rather than a file.
  plotter:  This program plots the function

  f(x) = sin(x)*sin(5*x)*10/(1+x)

  in the range 0..B, where B is read from stdin.  You may enter as
  many B values as you like, each pops up a new plot window.
  The program spawns a gnuplot process to display the plot.
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
  /* Loop over each user input B and plot f(x) in the range 0..B. */
  double B;
  while(scanf("%lf",&B) == 1)
  {
    /* Create pipe with which to send gnuplot commands. */
    int pfd[2];
    pipe(pfd);
  
    if (fork() == 0)
    {
      /* Child: Spawn a gnuplot process to plot data file */
      close(pfd[1]);
      dup2(pfd[0],STDIN_FILENO);
      execlp("gnuplot","gnuplot","-persist",NULL);
    }
    else
    {
      /* Parent: Write plot commands to pipe.*/
      close(pfd[0]);
      FILE *fq = fdopen(pfd[1],"w");    
      fprintf(fq,"set samples 500\n");
      fprintf(fq,"plot [x=0:%f] sin(x)*sin(5*x)*10/(1+x) smooth csplines\n",B);
      fclose(fq); /* NOTE: The man page says fclose: 
                     "It will perform a close(2) operation on the file
                      descriptor that is associated with the stream 
                      pointed to  by stream." */
    }

  }

  return 0;
}
/*
  NOTE: This modifies the original plotter program by communicating
  via a pipe rather than a file and using a single spawned gnuplot
  process, which plots successive inputs.  Thus, only one plot
  window is created, its contents just change as the user requests
  different ranges.

  plotter:  This program plots the function

  f(x) = sin(x)*sin(5*x)*10/(1+x)

  in the range 0..B, where B is read from stdin.  You may enter as
  many B values as you like, each pops up a new plot window.
  The program spawns a gnuplot process to display the plot.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
  /* Create pipe with which to send gnuplot commands. */
  int pfd[2];
  pipe(pfd);
  
  if (fork() == 0)
  {
    /* Child: Spawn a gnuplot process to plot data file */
    close(pfd[1]);
    dup2(pfd[0],STDIN_FILENO);
    execlp("gnuplot","gnuplot",NULL);
  }
  else
  {
    /* Parent: Write plot commands to pipe.*/
    close(pfd[0]);
    FILE *fq = fdopen(pfd[1],"w");    
    setbuf(fq,0);

    /* Loop over each user input B and plot f(x) in the range 0..B. */
    double B;
    while(scanf("%lf",&B) == 1)
    {
      fprintf(fq,"set samples 500\n");
      fprintf(fq,"plot [x=0:%f] sin(x)*sin(5*x)*10/(1+x) smooth csplines\n",B);
    }
    fclose(fq); /* NOTE: The man page says fclose: 
		   "It will perform a close(2) operation on the file
		   descriptor that is associated with the stream 
		   pointed to  by stream." */
  }
  
  return 0;
}
/*
  NOTE: This modifies the original plotter program substantially!
  It produces an animation of the plot of f(x) as the upper bound
  of the plot window increases.  Once again, this relies on pipes!

  plotter:  This program plots the function

  f(x) = sin(x)*sin(5*x)*10/(1+x)

  in the range 0..B, where B is read from stdin.  You may enter as
  many B values as you like, each pops up a new plot window.
  The program spawns a gnuplot process to display the plot.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
  /* Create pipe with which to send gnuplot commands. */
  double B;
  int pfd[2];
  pipe(pfd);
  
  if (fork() == 0)
  {
    /* Child: Spawn a gnuplot process to plot data file */
    close(pfd[1]);
    dup2(pfd[0],STDIN_FILENO);
    execlp("gnuplot","gnuplot",NULL);
  }
  else
  {
    /* Parent: Write plot commands to pipe.*/
    close(pfd[0]);
    FILE *fq = fdopen(pfd[1],"w");    
    setbuf(fq,0);

    /* Gradually extend range by .1 every 50ms. */
    int i;
    for(i = 0; i < 10000; ++i)
    {
      B = 1 + i/10.0;
      fprintf(fq,"set samples 500\n");
      fprintf(fq,"plot [x=0:%f] sin(x)*sin(5*x)*10/(1+x) smooth csplines\n",B);
      usleep(50000); /* Process sleeps for 50 milliseconds. */
    }
    fclose(fq); /* NOTE: The man page says fclose: 
		   "It will perform a close(2) operation on the file
		   descriptor that is associated with the stream 
		   pointed to  by stream." */
  }
  
  return 0;
}

Christopher W Brown
Last modified: Wed Mar 11 14:06:11 EDT 2009