如何通过C程序绘制数据?

30

我是一名机械工程师,对于C编程只有有限的知识。我编写了一些代码来进行模拟,并且想要可视化模拟结果。目前我正在使用Dev-C来编写我的代码。利用fopenfprintf命令,我生成一个包含结果的.dat文件。然后我打开GNUPLOT程序并导入我的.dat文件以绘制结果。这需要时间,我必须等待模拟结束。是否有一种简单的方法将我的绘图器与Dev-C连接起来,以便在模拟期间开始绘制数据?是否有任何库或其他东西可以做到这一点?


1
如果模拟还没有完成,你有数据可以绘制吗? - James Black
1
究竟需要花费多少时间?是手动执行 gnuplot 并导入数据所需的时间,还是 gnuplot 本身绘图所需要的时间较长?如果是前者,您可以通过在模拟器本身中执行 gnuplot 来轻松摆脱它。例如,在类 POSIX 的操作系统中,有 exec 函数 - ArjunShankar
我在想,你是否可以使用管道而不是文件。 - Hot Licks
据我所知,像gnuplot和mathGL这样的流行绘图库需要在绘图之前准备好所有数据。 - Eddy_Em
大家好,感谢回复。 我会简单介绍一下。每次手动编写gnuplot命令需要花费很长时间。通过在我的C程序中编写一些命令,我希望gnuplot能够自动绘制我的数据。由于这很困难,因此在模拟期间或结束时并不是非常重要...鉴于我在这里阅读到的其他内容,我正在使用“_popen”命令。但是不知何故,程序显示:“popen未声明(在此函数中首次使用)”。(我正在使用win7,并添加了#include <stdio.h>)有什么想法吗? - CrazyHorse
7个回答

21

既然您已经熟悉了gnuplot,那么最简单的方法可能就是从程序中直接调用gnuplot并向其传递数据:

FILE *gnuplot = popen("gnuplot", "w");
fprintf(gnuplot, "plot '-'\n");
for (i = 0; i < count; i++)
    fprintf(gnuplot, "%g %g\n", x[i], y[i]);
fprintf(gnuplot, "e\n");
fflush(gnuplot);

我在Unix环境和Windows上使用Cygwin时都用过这个。它总是对我有用的 :)。 - mgilson
@Edgar 嗨,埃德加,感谢您的回答。从我的程序中调用gnuplot并将数据传输到它是我想要做的。我将您的代码添加到我的程序中(当然我也更改了X [i]和y [i])。但是我得到了这个编译错误:“'popen'未声明(在此函数中首次使用)。我正在使用Win 7,您有任何想法为什么我会得到这个错误? 谢谢。 - CrazyHorse
由于popen()是POSIX标准,因此在Windows上您可以尝试使用下划线:_popen()。 - Edgar Bonet
@Edgar, 那也不行。你写的代码似乎是我目标最简单的方法,但我无法编译它 :) - CrazyHorse
在绘图中前置 set nokey; 可以移除烦人的图例。 - sitilge

5

我一直在使用PLPlot进行C语言绘图,发现它既有效又易用。它支持跨平台、开源,并支持丰富的绘图功能。建议先查看示例以开始使用。


4

好的,一个解决方案是,在输出到文件时,使用system()调用并调用gnuplot。

但这意味着您每次都应更改文件名,但我担心如果您这样做,它看起来不正确,因为您每次发送的数据量很小。

http://www.gnu.org/software/libc/manual/html_node/System-Calls.html

我从未使用过gnuplot,但如果您查看此页面(http://gnuplot-tricks.blogspot.com/),您可能会发现一些技巧可以使其正常工作。

但是,除非您打算自己绘制所有内容并跳过gnuplot,否则您可能只需要等待。

您可能会发现gnuplot的C接口对您有所帮助:

http://ndevilla.free.fr/gnuplot/


3

pbPlots非常易于使用,并且适用于所有C编译器。

github页面下载pbPlots.c/h和supportLib.c/h文件,并将它们包含在您的构建中。

这里是一个完整的示例,将生成一个PNG文件中的绘图。

#include "pbPlots.h"
#include "supportLib.h"

int main(){

    double x [] = {-1, 0, 1, 2, 3, 4, 5, 6};
    double y [] = {-5, -4, -3, -2, 1, 0, 1, 2};

    RGBABitmapImageReference *imageRef = CreateRGBABitmapImageReference();

    DrawScatterPlot(imageRef, 600, 400, x, 8, y, 8);

    size_t length;
    double *pngData = ConvertToPNG(&length, imageRef->image);
    WriteToFile(pngData, length, "plot.png");

    return 0;
 }

生成的图表

还有很多其他选项可用,这些在 Github 页面上进行了描述。


我将pbPlots.c/h和supportLib.c/h文件添加到CLion项目中,但当我尝试运行您的示例时,出现错误:C:/Users/flori/CLionProjects/Plottest/main.c:9: undefined reference to `CreateRGBABitmapImageReference'(+更多未解决的引用) ...我做错了什么? - le_lemon
@le_lemon,你在构建中是否包含了pbPlots.c和supportLib.c文件?在C语言中,编译器使用.h文件,而链接器使用.c文件。链接器需要知道哪些C文件已被包含。错误来自于链接器未获取已编译的.c文件。 - Martin Johansen
@MartinJohansen,你是作者吗? - Chef Gladiator
@ChefGladiator,是的,我就是作者。 - Martin Johansen

1

有一个名为DISLIN的广泛应用于科学目的的库,甚至可用于Fortran语言。

您可以在官方网站上查看示例。

您可以在DISLIN主页免费获取。


1
请解释这与问题的关系以及它是如何工作的。 - M-Chen-3
@m-chen-3 你可以在Dislin examples找到一系列的示例。只需点击其中一个绘图教程,然后选择您的语言(C)即可。 - user13305144

0

我稍微查看了一下其他人在gnuplot中实时绘图的做法,发现了这个:

http://users.softlab.ntua.gr/~ttsiod/gnuplotStreaming.html

有一个小的Perl脚本可以驱动绘图,您只需将信息输入即可。

由于您的数据正在写入文件,您可能希望tail -f yourdata.dat并将其导入实时绘图器。

此外,因为您正在使用stdio文件调用,所以需要定期刷新(通过调用fflush

显然,您的模拟将在后台或另一个shell中运行。这样,您可以随时退出绘图而不会中断模拟。

希望对您有所帮助。


嗨Paddy,感谢你的回答。我查看了你提供的网页。实际上,在我在公司完成硕士论文时,我就使用了这种方法(准备make文件、bash文件)。那里我们使用的是Linux系统,并且所有程序都由IT设置好了。现在在我的个人电脑上,我使用的是Windows系统,所以这次我需要学习如何在Windows平台上进行这些操作(尽管我知识有限)。有没有办法在Windows上完成这些操作呢? - CrazyHorse
最有前途的方法是安装Cygwin,但你也可以尝试在Windows上安装Perl。有一个移植版本可供使用。如果您能坚持使用您已知的工具和方法而不是学习全新的(在Windows的情况下是残缺的)工具集,那就太好了。 - paddy

0

使用C编程语言绘图的逐步解决方案:

第一步要求:1. Windows 10/11 64位操作系统 2. 安装 Eclipse IDE(CDT或科学计算)3. 安装MSYS2 4. 安装mingw64,使用MSYS2并将其二进制路径添加到Windows环境变量中,作为C编译器所需的组件。5. 使用MSYS2安装mathgl库: Installing mathgl

第二步创建包含所需mathgl库的Eclipse项目。 Create library 将所需库添加到项目中:

右键单击项目 -> 展开 C/C++ Build -> 设置 -> 展开 MinGW C 链接器(如果未展开) -> 库 -> 库 (-l) -> 添加...

在这里,您必须添加 mgl2mgl2-fltklibrary inclution 第三步(最后一步)编写绘图代码:在项目下创建一个 .c 文件,并将以下代码写入其中。

#include <mgl2/mgl_cf.h>
//#include <mgl2/wnd_cf.h>
#include <mgl2/fltk.h>

#include <synchapi.h>



HMGL gr = NULL;//HMGL mgl_create_graph_fltk

int main(int argc,char **argv)
{

gr = mgl_create_graph_fltk(NULL, "First C graph", NULL, NULL);

double x[50]={0};
HMDT dat=mgl_create_data_size(50, 1, 1);

while(1)
{
    Sleep(100);
    mgl_clf ( gr) ;
    mgl_set_range_val(gr, 'y', -1, 1);
    mgl_set_range_val(gr, 'x', 0, 512);
    mgl_set_origin(gr, 0, 0, 0);
//  mgl_box(gr);
    mgl_axis(gr, "", "", "");
    mgl_set_font_size(gr, 1.5);
//  mgl_grid(gr, a, "", "");




    int i=0;
    while(i<50)
    {
        x[i]=(mgl_rnd()*2)-1;
        i++;
    }

    mgl_data_set_double(dat, x, 50, 1, 1);
//  mgl_line(gr,0,0,0,2*mgl_rnd()-1,2*mgl_rnd()-1,0,"Ar2",-.5);
    mgl_stem(gr, dat, "ro", "");


//   mgl_wnd_update(gr);
}
return 0;
}

构建完这段代码后,您会在 debug 文件夹中找到一个可执行文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接