lava / matplotlib-cpp使用代码示例和安装指南

938 阅读4分钟

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操作系统相比是不同的。这里描述了解决方案,其他信息也可以在这里找到(见答案中的链接)。