2010-08-19 10 views
16

Ho scritto un programma che scrive un elenco di dati in un file ".dat" con l'intenzione di tracciarlo separatamente utilizzando gnuplot. C'è un modo per far sì che il mio codice lo riproduca automaticamente? Mia uscita è di forma:Creazione automatica di un grafico C per il grafico

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

Idealmente, quando si esegue il codice grafico potrebbe anche essere stampato con un x-label, y-label e titolo (che potrebbe essere cambiato dal mio codice C). Grazie molto.

+1

Forse controllare la funzione di 'system'. – sje397

risposta

32

Mi sono imbattuto in questo mentre cercavo qualcos'altro riguardo a gnuplot. Anche se è una vecchia domanda, ho pensato di contribuire con qualche codice di esempio. Lo uso per un mio programma, e penso che faccia un lavoro piuttosto ordinato. AFAIK, questo PIPEing funziona solo su sistemi Unix (vedi la modifica sotto per gli utenti Windows). L'installazione di gnuplot è l'installazione predefinita dal repository di 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; 
} 

EDIT

Nella mia applicazione, ho anche eseguito nel problema che la trama non viene visualizzato fino a quando il programma chiamante viene chiuso. Per ovviare a questo, aggiungi un fflush(gnuplotPipe) dopo aver usato fprintf per inviarlo il tuo comando finale.

Ho anche visto che gli utenti di Windows possono utilizzare _popen al posto di popen - tuttavia non posso confermarlo poiché non ho installato Windows.

EDIT 2

Si può evitare di dover scrivere in un file con l'invio di gnuplot il comando plot '-' seguito da punti di dati seguiti dalla lettera "e".

ad es.

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

So che è passato molto tempo da quando questa risposta è stata pubblicata, ma ho usato il codice dalla tua seconda modifica più il ciclo for con 'commandsForGnuplot' in esso per aggiungere comandi e traccia ma non aggiunge nessuno dei comandi (titolo, xlabel o ylabel). Come posso aggiungerli se non in questo modo? –

5

È possibile creare uno script gnuplot e generare un processo che esegue gnuplot per tracciare questo script dalla riga di comando, oppure è possibile utilizzare una delle interfacce fornite. Per C, v'è un'interfaccia basata su pipe POSIX di Nicolas Devillard disponibile qui: http://ndevilla.free.fr/gnuplot/ ... e una versione iostream a base di C++ è disponibile tramite git (vedi: http://www.stahlke.org/dan/gnuplot-iostream/)

Il più portatile e probabilmente il più facile way sarebbe comunque chiamato gnuplot per tracciare uno script, comunque. Come citato in sje397, controllare la documentazione per la chiamata system() in stdlib.h.

Su un sidenote, esiste anche GNU plotutils, che offre libplot, una libreria per il tracciamento dei set di dati, che è possibile utilizzare nella propria applicazione. Vedi: http://www.gnu.org/software/plotutils/

+1

Non sono fantastico a capire tutta questa documentazione ma ho trovato la dichiarazione per system(): sistema int (comando const char *); È quindi solo un caso di aggiungere qualcosa di simile ?: sistema (trama gnuplot "data_set.dat" con 1: 2 utilizzando le linee); – JMzance

+1

Alla fine sono andato per qualcosa di simile: – JMzance

+1

#include "gnuplot_i.h" int main (void) { FILE * OUTFILE; outFile = fopen ("Flight_Path.dat", "w"); /* Ciclo iterativo che stampa sul file di output: 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, "imposta titolo \" Traiettoria con trascinamento \ ""); gnuplot_cmd (k, "complotto \" Flight_Path.dat \" con 1: 2 documenti \ "Flight Path \" con le linee, \ sonno (7); gnuplot_close (k); return 0;} – JMzance

2

Anche se ho visto un sacco di modi per farlo, il modo più semplice per farlo sarebbe quello di utilizzare il sistema() (da stdlib.h) funzione in C. Prima di tutto un gnuplot script e salvarlo come "name.gp" (né il nome né l'estensione).
Un semplice script sarebbe,

plot 'Output.dat' with lines 

Dopo aver salvato questo file di script, basta aggiungere
system("gnuplot -p 'name.gp'");
alla fine del codice.
È così semplice.

0

Ho adattato la risposta accettata per tracciare un array mobile evitando l'uso di un file temporaneo. In esso, float* data_ è la matrice e size_t size_ della sua dimensione. Speriamo sia utile per qualcuno!

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