matplotlib-cpp
欢迎来到matplotlib-cpp,这可能是最简单的C++绘图库。它是为了类似于Matlab和matplotlib使用的绘图API而建立的。
使用方法
完成最小的例子。
#include "matplotlibcpp.h"
namespace plt = matplotlibcpp;
int main() {
plt::plot({1,3,2,4});
plt::show();
}
g++ minimal.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7
结果
一个更全面的例子。
#include "matplotlibcpp.h"
#include <cmath>
namespace plt = matplotlibcpp;
int main()
{
// Prepare data.
int n = 5000;
std::vector<double> x(n), y(n), z(n), w(n,2);
for(int i=0; i<n; ++i) {
x.at(i) = i*i;
y.at(i) = sin(2*M_PI*i/360.0);
z.at(i) = log(i);
}
// Set the size of output image to 1200x780 pixels
plt::figure_size(1200, 780);
// Plot line from given x and y data. Color is selected automatically.
plt::plot(x, y);
// Plot a red dashed line from given x and y data.
plt::plot(x, w,"r--");
// Plot a line whose name will show up as "log(x)" in the legend.
plt::named_plot("log(x)", x, z);
// Set x-axis to interval [0,1000000]
plt::xlim(0, 1000*1000);
// Add graph title
plt::title("Sample figure");
// Enable legend.
plt::legend();
// Save the image (file format is determined by the extension)
plt::save("./basic.png");
}
g++ basic.cpp -I/usr/include/python2.7 -lpython2.7
结果
另外,matplotlib-cpp也支持一些由C++11支持的语法糖。
#include <cmath>
#include "matplotlibcpp.h"
using namespace std;
namespace plt = matplotlibcpp;
int main()
{
// Prepare data.
int n = 5000; // number of data points
vector<double> x(n),y(n);
for(int i=0; i<n; ++i) {
double t = 2*M_PI*i/n;
x.at(i) = 16*sin(t)*sin(t)*sin(t);
y.at(i) = 13*cos(t) - 5*cos(2*t) - 2*cos(3*t) - cos(4*t);
}
// plot() takes an arbitrary number of (x,y,format)-triples.
// x must be iterable (that is, anything providing begin(x) and end(x)),
// y must either be callable (providing operator() const) or iterable.
plt::plot(x, y, "r-", x, [](double d) { return 12.5+abs(sin(d)); }, "k-");
// show plots
plt::show();
}
g++ modern.cpp -std=c++11 -I/usr/include/python2.7 -lpython
结果
或者一些看起来很有趣的xkcd风格的例子。
#include "matplotlibcpp.h"
#include <vector>
#include <cmath>
namespace plt = matplotlibcpp;
int main() {
std::vector<double> t(1000);
std::vector<double> x(t.size());
for(size_t i = 0; i < t.size(); i++) {
t[i] = i / 100.0;
x[i] = sin(2.0 * M_PI * 1.0 * t[i]);
}
plt::xkcd();
plt::plot(t, x);
plt::title("AN ORDINARY SIN WAVE");
plt::save("xkcd.png");
}
g++ xkcd.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7
结果
在处理矢量场时,你可能会对quiver图感兴趣。
#include "../matplotlibcpp.h"
namespace plt = matplotlibcpp;
int main()
{
// u and v are respectively the x and y components of the arrows we're plotting
std::vector<int> x, y, u, v;
for (int i = -5; i <= 5; i++) {
for (int j = -5; j <= 5; j++) {
x.push_back(i);
u.push_back(-i);
y.push_back(j);
v.push_back(-j);
}
}
plt::quiver(x, y, u, v);
plt::show();
}
g++ quiver.cpp -std=c++11 -I/usr/include/python2.7 -lpython2.7
结果
在处理三维函数时,你可能对三维图感兴趣。
#include "../matplotlibcpp.h"
namespace plt = matplotlibcpp;
int main()
{
std::vector<std::vector<double>> x, y, z;
for (double i = -5; i <= 5; i += 0.25) {
std::vector<double> x_row, y_row, z_row;
for (double j = -5; j <= 5; j += 0.25) {
x_row.push_back(i);
y_row.push_back(j);
z_row.push_back(::std::sin(::std::hypot(i, j)));
}
x.push_back(x_row);
y.push_back(y_row);
z.push_back(z_row);
}
plt::plot_surface(x, y, z);
plt::show();
}
结果
安装
matplotlib-cpp通过包装流行的python绘图库matplotlib来工作。(matplotlib.org)这意味着你必须有一个可用的python安装,包括开发头文件。在Ubuntu上。
sudo apt-get install python-matplotlib python-numpy python2.7-dev
如果由于某种原因,你的系统无法安装numpy,你可以在包含头文件之前定义宏WITHOUT_NUMPY ,以消除这种依赖性。
该库的C++部分由单一的头文件matplotlibcpp.h ,可以放在任何地方。
由于内部打开了一个Python解释器,为了使用matplotlib-cpp,有必要链接到libpython 。大多数版本应该可以工作,尽管python喜欢时不时地随机破坏兼容性,所以在使用边缘的时候建议谨慎一些。
CMake
C++代码与python2和python3都是兼容的。然而,CMakeLists.txt 文件目前被设置为默认使用python3,所以如果需要使用python2,则必须手动更改。(如果能添加一个cmake选项,我们将非常欢迎)
注意: 根据设计(python),每个进程只能创建一个python解释器。当使用这个库时,不能使用其他在内部产生python解释器的库。
为了不使用cmake来编译代码,编译器的调用应该是这样的。
g++ example.cpp -I/usr/include/python2.7 -lpython2.7
这也可以用于与定制的python构建相连接
g++ example.cpp -I/usr/local/include/fancy-python4 -L/usr/local/lib -lfancy-python4
Vcpkg
你可以使用vcpkg依赖性管理器下载并安装matplotlib-cpp。
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install matplotlib-cpp
vcpkg中的matplotlib-cpp端口是由微软团队成员和社区贡献者保持更新的。如果版本已经过时,请在vcpkg仓库中创建一个问题或拉动请求。
C++11
目前,构建matplotlib-cpp需要C++11。最后一次没有这个要求的工作提交是717e98e752260245407c5329846f5d62605eff08 。
请注意,对c++98的支持或多或少是意外放弃的,所以如果你不得不使用一个古老的编译器,但仍想享受最新的附加功能,我可能会合并一个恢复支持的PR。
为什么?
我最初在我的毕业论文中开始了这个库。通常的方法是将c++算法中的数据写入文件,然后在python中使用matplotlib进行解析和绘制,这被证明是不够的。当C++代码经常发生重大变化时,保持算法和绘图代码的同步需要大量的努力。此外,Python的yaml解析器无法处理超过几百兆的文件。
因此,我一直在寻找一个非常容易使用的C++绘图库,并且可以添加到现有的代码库中,最好是只用头文件。当我发现没有的时候,我决定自己写一个,这基本上是一个围绕matplotlib的C++包装器。正如你在上面的例子中所看到的,绘制数据并将其保存到图像文件中,只需要两行代码就可以完成。
提供一个简单的C++ API来利用Python代码的一般方法,后来在我的另一个项目wrappy中被概括并提取为一个独立的、更强大的库。
Todo/Issues/Wishlist
-
这个库不是线程安全的。用mutex来保护所有的并发访问。遗憾的是,这个问题不容易解决,因为它不是由库本身造成的,而是由Python解释器造成的,它本身不是线程安全的。
-
如果有一个更加面向对象的设计,有一个Plot类,允许每个程序有多个独立的绘图,那就更好了。
-
现在,只有matplotlibs的一小部分功能是公开的。像xlabel()/ylabel()之类的东西应该很容易添加。
-
如果你在Windows上使用Anaconda,你可能需要将PYTHONHOME设置为Anaconda主目录,将QT_QPA_PLATFORM_PLUGIN_PATH设置为%PYTHONHOME%Library/plugins/platforms。后者是为特别是当你得到错误时,它说'这个应用程序未能启动,因为它不能找到或加载Qt平台插件 "windows "在""。
-
MacOS:
Unable to import matplotlib.pyplot.原因。在mac os中,matplotlib的图像渲染后端(默认使用Cocoa的API进行渲染的是什么后端)。有Qt4Agg和GTKAgg,作为后端不是默认的。设置macosx的后端,与其他windows或linux操作系统相比是不同的。这里描述了解决方案,其他信息也可以在这里找到(见答案中的链接)。