Hacer que el código C trace un gráfico automáticamente

6 minutos de lectura

avatar de usuario
JMzance

He escrito un programa que escribe una lista de datos en un archivo ‘.dat’ con la intención de trazarlo por separado usando gnuplot. ¿Hay alguna manera de hacer que mi código lo trace automáticamente? Mi salida es de la forma:

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

Idealmente, cuando ejecuto el código, el gráfico también se imprimiría con una etiqueta x, una etiqueta y y un título (que podría cambiarse de mi código C). Muchas gracias.

  • Tal vez echa un vistazo a la system función.

    – sje397

    19 de agosto de 2010 a las 11:23

avatar de usuario
Ben B

Encontré esto mientras buscaba algo más sobre gnuplot. Aunque es una pregunta antigua, pensé en contribuir con un código de muestra. Lo uso para un programa mío, y creo que hace un trabajo bastante ordenado. AFAIK, este PIPEing solo funciona en sistemas Unix (consulte la edición a continuación para usuarios de Windows). Mi instalación de gnuplot es la instalación predeterminada del repositorio de Ubuntu.

#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;
}

EDITAR

En mi aplicación, también me encontré con el problema de que la trama no aparece hasta que se cierra el programa de llamada. Para evitar esto, agregue un fflush(gnuplotPipe) después de haber usado fprintf para enviarle su comando final.

También he visto que los usuarios de Windows pueden usar _popen en lugar de popen — sin embargo, no puedo confirmar esto porque no tengo Windows instalado.

EDITAR 2

Uno puede evitar tener que escribir en un archivo enviando gnuplot el plot '-' comando seguido de puntos de datos seguidos de la letra “e”.

p.ej

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");

  • Sé que ha pasado mucho tiempo desde que se publicó esta respuesta, pero usé el código de su segunda edición más el bucle for con el commandsForGnuplot en él para agregar comandos, y traza pero no agrega ninguno de los comandos (título, xlabel o ylabel). ¿Cómo puedo agregarlos si no es así? Por favor.

    – MO

    22/09/2017 a las 19:34

  • Si alguien encuentra un ‘-‘ y un punto adicional en el gráfico, en realidad no son puntos trazados. Son parte de la leyenda. Hacer fprintf(gnuplotPipe, "plot '-' notitle\n"); y desaparecerían.

    -Tommy Wolfheart

    21 de marzo a las 10:36


Puede crear un script gnuplot y generar un proceso que ejecute gnuplot para trazar este script desde la línea de comandos, o puede usar una de las interfaces provistas. Para C, hay una interfaz basada en tubería POSIX de Nicolas Devillard disponible aquí:
http://ndevilla.free.fr/gnuplot/
…y una versión de C++ basada en iostream está disponible a través de git (ver: http://www.stahlke.org/dan/gnuplot-iostream/ )

Sin embargo, la forma más portátil y probablemente la más fácil sería llamar a gnuplot para trazar un script. Como se mencionó en sje397, consulte su documentación para la llamada system() en stdlib.h.

En una nota al margen, también está GNU plotutils, que ofrece libplot, una biblioteca para trazar conjuntos de datos, que podría usar en su aplicación. Ver: http://www.gnu.org/software/plotutils/

  • No soy fantástico para entender todo este material de documentación, pero encontré la declaración para system(): int system(const char *command); ¿Es entonces solo un caso de agregar algo como esto?: system(gnuplot plot “data_set.dat” with 1:2 using lines);

    – JMzance

    19 de agosto de 2010 a las 11:54


  • Al final opté por algo como esto:

    – JMzance

    23 de septiembre de 2010 a las 11:56

  • #include “gnuplot_i.h” int main(void) { ARCHIVO archivo de salida; outFile = fopen(“Flight_Path.dat”, “w”); / Bucle iterativo que imprime en el archivo de salida: ejemplo.dat */ fclose(outFile); gnuplot_ctrl *k; k = gnuplot_init(); gnuplot_set_xlabel(k, “x”); gnuplot_set_ylabel(k, “y”); gnuplot_cmd(k,entrada_x); gnuplot_cmd(k,entrada_y); gnuplot_cmd(k, “establecer título \”Trayectoria con arrastre\””); gnuplot_cmd(k, “trazar \”Flight_Path.dat\” usando el título 1:2 \”Flight Path\” con líneas, \ sleep(7); gnuplot_close(k); return 0; }

    – JMzance

    23 de septiembre de 2010 a las 12:00

  • Estoy seguro de que le faltan algunos bits de ese código, es decir, está abriendo y cerrando el archivo inmediatamente después. Además, el formato en los comentarios simplemente apesta. Edite su publicación original y agregue código a eso; lo haría yo mismo, pero como dije, creo que a su código le falta algo.

    -Jim Brissom

    23 de septiembre de 2010 a las 21:50

avatar de usuario
Nidish Narayanaa

Aunque he visto muchas maneras de hacer esto, la forma más sencilla de hacerlo sería usando la función system() (de stdlib.h) en C. Primero haga un script gnuplot y guárdelo como “name. gp” (ni el nombre ni la extensión importan).
Un guión simple sería,

plot 'Output.dat' with lines

Después de guardar este archivo de script, simplemente agregue
system("gnuplot -p name.gp");

al final de su código.
Es tan simple como eso.

Asegúrese de agregar la ruta gnuplot a las variables de ruta del sistema de Windows.

He adaptado la respuesta aceptada para trazar una matriz flotante y evitar el uso de un archivo temporal. En eso, float* data_ es la matriz y size_t size_ su tamaño. ¡Ojalá sea útil para alguien!

Salud,
Andrés

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");
}

Sé que es demasiado tarde, pero responder si puede ayudar a alguien. fputs realmente hace el trabajo que quieres. primero debe imprimir los datos que desea trazar en un archivo temporal 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);

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad