web-dev-qa-db-fra.com

Faire en sorte que le code C trace un graphique automatiquement

J'ai écrit un programme qui écrit une liste de données dans un fichier '.dat' avec l'intention de la tracer séparément à l'aide de gnuplot. Est-il possible de faire en sorte que mon code le trace automatiquement? Ma sortie est de la forme:

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

Idéalement, lorsque je lance le code, le graphique doit également être imprimé avec une étiquette x, une étiquette y et un titre (qui peut être modifié à partir de mon code C). Merci beaucoup.

16
JMzance

Je suis tombé sur ça en cherchant autre chose à propos de gnuplot. Même si c'est une vieille question, je pensais apporter un exemple de code. J'utilise cela pour un programme à moi et je pense que ça fait un travail bien rangé. Autant que je sache, ce PIPEing ne fonctionne que sur les systèmes Unix (voir l'édition ci-dessous pour les utilisateurs Windows). Mon installation gnuplot est l'installation par défaut à partir du référentiel 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;
}

MODIFIER

Dans ma candidature, j'ai également rencontré le problème suivant: l'intrigue n'apparaît que lorsque le programme appelant est fermé. Pour résoudre ce problème, ajoutez une fflush(gnuplotPipe) après avoir utilisé fprintf pour lui envoyer votre dernière commande. 

J'ai également vu que les utilisateurs de Windows peuvent utiliser _popen à la place de popen - mais je ne peux pas le confirmer car Windows n'est pas installé.

EDIT 2

On peut éviter de devoir écrire dans un fichier en envoyant à gnuplot la commande plot '-' suivie de points de données suivie de la lettre "e". 

par exemple.

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

Vous pouvez créer un script gnuplot et générer un processus exécutant gnuplot pour tracer ce script à partir de la ligne de commande ou utiliser l'une des interfaces fournies. Pour C, une interface POSIX de Nicolas Devillard est disponible à cette adresse: http://ndevilla.free.fr/gnuplot/ ... et une version C++ basée sur iostream est disponible via git (voir: http://www.stahlke.org/dan/gnuplot-iostream/ )

Le moyen le plus portable et probablement le plus simple serait toujours d'appeler gnuplot pour tracer un script, cependant. Comme mentionné dans sje397, vérifiez votre documentation pour l'appel system () dans stdlib.h.

Sur une note de bas de page, il y a aussi GNU plotutils, qui offre libplot, une bibliothèque pour tracer des jeux de données, que vous pouvez utiliser dans votre application. Voir: http://www.gnu.org/software/plotutils/

5
Jim Brissom

J'ai adapté la réponse acceptée pour tracer un tableau flottant tout en évitant l'utilisation d'un fichier temporaire. Dans celui-ci, float* data_ est le tableau et size_t size_ sa taille. J'espère que c'est utile pour quelqu'un! 

À votre santé,
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");
}
0
fr_andres