2010-08-19 20 views
16

Tôi đã viết một chương trình ghi danh sách dữ liệu vào tệp '.dat' với ý định sau đó vẽ riêng nó bằng gnuplot. Có cách nào để làm cho mã của tôi âm mưu nó tự động? Đầu ra của tôi có dạng:Làm cho mã C vẽ đồ thị một cách tự động

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

Lý tưởng nhất, khi tôi chạy mã đồ thị cũng sẽ được in từ mã C của tôi). Cảm ơn nhiều.

+1

lẽ kiểm tra 'chức năng system'. – sje397

Trả lời

32

Tôi đã xem xét điều này trong khi tìm kiếm nội dung khác liên quan đến gnuplot. Mặc dù đó là một câu hỏi cũ, tôi nghĩ tôi sẽ đóng góp một số mã mẫu. Tôi sử dụng nó cho một chương trình của tôi, và tôi nghĩ nó có một công việc khá gọn gàng. AFAIK, PIPEing này chỉ hoạt động trên các hệ thống Unix (xem bản chỉnh sửa bên dưới dành cho người dùng Windows). Cài đặt gnuplot của tôi là cài đặt mặc định từ kho lưu trữ 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

Trong ứng dụng của tôi, tôi cũng chạy vào các vấn đề mà cốt truyện không xuất hiện cho đến khi chương trình gọi điện thoại được đóng lại. Để giải quyết vấn đề này, hãy thêm fflush(gnuplotPipe) sau khi bạn đã sử dụng fprintf để gửi lệnh cuối cùng của mình.

Tôi cũng thấy rằng người dùng Windows có thể sử dụng _popen thay cho popen - tuy nhiên tôi không thể xác nhận điều này vì tôi chưa cài đặt Windows.

EDIT 2

Người ta có thể tránh được việc phải viết vào một tập tin bằng cách gửi gnuplot lệnh plot '-' tiếp theo điểm dữ liệu tiếp theo là chữ "e".

ví dụ:

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

Tôi biết nó đã được một thời gian rất dài kể từ khi câu trả lời này được xuất bản, nhưng tôi đã sử dụng mã từ bản chỉnh sửa thứ hai của bạn cộng với vòng lặp for với 'commandsForGnuplot' trong đó để thêm lệnh , và nó lô nhưng nó không thêm bất kỳ lệnh (tiêu đề, xlabel hoặc ylabel) Làm thế nào tôi có thể thêm chúng nếu không theo cách đó? –

5

Bạn có thể tạo tập lệnh gnuplot và sinh ra quy trình chạy gnuplot để vẽ kịch bản lệnh này từ dòng lệnh hoặc bạn có thể sử dụng một trong các giao diện được cung cấp. Đối với C, có một giao diện POSIX ống dựa trên từ Nicolas Devillard sẵn ở đây: http://ndevilla.free.fr/gnuplot/ ... và một phiên bản C iostream dựa trên ++ có sẵn thông qua git (xem: http://www.stahlke.org/dan/gnuplot-iostream/)

Các xách tay nhất và có lẽ là dễ nhất Tuy nhiên, vẫn có thể gọi gnuplot để vẽ một kịch bản. Như sje397 đã đề cập, kiểm tra tài liệu của bạn cho hệ thống() gọi trong stdlib.h.

Trên một sidenote, cũng có các biểu đồ GNU, cung cấp libplot, một thư viện để vẽ các tập dữ liệu mà bạn có thể sử dụng trong ứng dụng của mình. Xem: http://www.gnu.org/software/plotutils/

+1

Im không tuyệt vời tại hiểu tất cả các công cụ tài liệu này nhưng tôi đã tìm thấy tuyên bố cho hệ thống(): int hệ thống (const char * lệnh); Sau đó, chỉ cần thêm một trường hợp như thế này ?: hệ thống (gnuplot plot "data_set.dat" với 1: 2 sử dụng dòng); – JMzance

+1

Cuối cùng tôi đã đi cho một cái gì đó như thế này: – JMzance

+1

#include "gnuplot_i.h" int chính (void) { FILE * outFile; outFile = fopen ("Flight_Path.dat", "w"); /* Vòng lặp lặp lại sẽ in ra tệp đầu ra: 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, "đặt tiêu đề \" Quỹ đạo bằng cách kéo \ ""); gnuplot_cmd (k, "âm mưu \" Flight_Path.dat \" sử dụng 1: 2 danh hiệu \ "Flight Path \" với những đường nét, \ ngủ (7); gnuplot_close (k); return 0;} – JMzance

2

Mặc dù tôi đã nhìn thấy rất nhiều cách để làm điều này, cách đơn giản nhất nhất để làm điều này sẽ là bằng cách sử dụng hệ thống() (từ stdlib.h) hàm trong C. Đầu tiên tạo một gnuplot kịch bản và lưu nó dưới dạng "name.gp" (không phải tên hay phần mở rộng).
Một kịch bản đơn giản sẽ là,

plot 'Output.dat' with lines 

Sau khi lưu tập tin kịch bản này, chỉ cần thêm
system("gnuplot -p 'name.gp'");
ở phần cuối của mã của bạn.
Nó đơn giản như vậy.

0

Tôi đã điều chỉnh câu trả lời được chấp nhận để vẽ một mảng phao trong khi tránh sử dụng tệp tạm thời. Trong đó, float* data_ là mảng và size_t size_ kích thước của nó. Hy vọng rằng nó là hữu ích cho một ai đó!

Chúc mừng,
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"); 
}