C++ 结合 gnuplot 实现数据可视化
之前做课题时,使用的是C++结合OpenCV编程实现,过程中想要对一组数据作图表的可视化,但是C++和OpenCV中都没有提供相应的图表可视化接口,当时是自己利用OpenCV写了一个粗糙的曲线显示函数,但总觉不方便。今天想着来解决这个问题,在网上搜索,找到了gnuplot以及gnuplot在C++中调用的一个函数库:
A. 这个gnuplot库的链接是:http://www.deuxmille.org/archives/1529 (可能需要代理)
B. 同时这篇文章对程序调试也给了很大的启示:https://gist.github.com/zhaojkun/5895566
gnuplot 是一个通用、强大的科学绘图软件,可以跨平台调用,之前自己用SVM的时候有接触过一点(优化参数选取的时候,库函数调用了gnuplot来可视化显示参数的影响)。
利用上述 gnuplot 库的链接得到压缩包GNUPlot1.zip。另外需要到官网去下载 gnuplot 软件。
解压GNUPlot1.zip后会得到一个VC06的工程文件,个人用VS2008打开、重新编译。
若直接运行该工程,会得到如下结果:
因为该库需要提供gnuplot的可执行文件,但是直接按A 链接所说的,拷贝gnuplot的bin文件中的pgnuplot.exe到该工程目录,仍旧不能解决问题。
根据B链接的提示,调试代码,发现Gnuplot这个类有个关键的init函数:
void Gnuplot::init() { m_sGNUPlotFileName = "pgnuplot.exe"; if (!this->get_program_path(m_sGNUPlotFileName)) { this->valid = false; throw GnuplotException("Can't find gnuplot in your PATH"); } this->gnucmd = _popen(m_sGNUPlotFileName.c_str(),"w"); if (!this->gnucmd) { this->valid = false; throw GnuplotException("Couldn't open connection to gnuplot"); } this->nplots = 0; this->valid = true; }
其中第一个if 处是对pgnuplot.exe文件是否存在的检查,进入该函数,发现
bool Gnuplot::get_program_path(const string pname) { list<string> ls; char *path; path = getenv("PATH"); if (!path) { cerr << "Path is not set" << endl; return false; } else { #ifdef WIN32 stringtok(ls,path,";"); #else stringtok(ls,path,":"); #endif for (list<string>::const_iterator i = ls.begin(); i != ls.end(); ++i) { string tmp = (*i) + "/" + pname; #ifdef WIN32 if (_access(tmp.c_str(),0) == 0) #else if (access(tmp.c_str(),X_OK) == 0) #endif return true; } } return false; }
path = getenv("path")代码处指示,其对pgnuplot.exe文件做检查时,依据的是环境变量(env) ‘path’ ,所以只要将环境变量‘path’ 中加入gnuplot软件所在的路径:
本人使用:D:\Program Files\Gnuplot\gnuplot\bin,这个路径要一直指到pgnuplot.exe 所在文件。
而后重新编译工程,应该就能够直接运行了,运行结果如下:
该库提供的demo中有直线、函数、用户自定义数据等数据的曲线显示,并提供了一些简单的图形设置接口。若用户有需要,可以在熟悉了gnuplot的编程命令后,自行扩展该库。如此,就能在C++中调用gnuplot实现数据的图表可视化了。
备注:设置环境变量的方法的一个缺点就是需要 ‘安装’,不能‘脱机’。因为要在不同电脑上使用的话,必须设置环境变量,添加路径。如果不想这样,一个最笨的办法是:
1、屏蔽第一个if 段检测代码
void Gnuplot::init() { m_sGNUPlotFileName = "pgnuplot.exe"; //if (!this->get_program_path(m_sGNUPlotFileName)) //{ // this->valid = false; // throw GnuplotException("Can't find gnuplot in your PATH"); //} this->gnucmd = _popen(m_sGNUPlotFileName.c_str(),"w"); if (!this->gnucmd) { this->valid = false; throw GnuplotException("Couldn't open connection to gnuplot"); } this->nplots = 0; this->valid = true; }
2、将gnuplot文件bin中的所有文件拷贝到工程文件中(这样gnuplot就跟着工程文件走了,不用管电脑配置问题),然后就可以直接运行了。
(直接将bin文件拷过来,在现有代码下是不行的,但其实这样是更好的处理方式,以免gnuplot的文件和工程文件混淆。若路过的各位能提供修改代码的方式,在工程下用一个bin文件管理gnuplot的文件,希望指教。)