How to Use Python’s Matplotlib in C++?
Introduction
When processing data using C++, I often envy the ease with which Python’s rich libraries can be utilized. Among these, matplotlib stands out as particularly useful for its ability to effortlessly display various types of graphs.
In fact, even in C++, you can use a library called matplotlib-cpp to call Python’s matplotlib and directly display graphs.
This time, I have researched how to use this matplotlib-cpp. Here are my notes.
Installation
Download matplotlibcpp.h
from matplotlib-cpp’s GitHub. Alternatively, you can clone the repository.
git clone https://github.com/lava/matplotlib-cpp.git
How to Use matplotlib-cpp
To use matplotlib-cpp, you need to have Python, matplotlib, and NumPy installed beforehand. Make sure to install these in advance.
The matplotlib-cpp itself is just a header file, so you can use it simply by including it in your C++ source code.
On Linux
Specify the path to the Python include files and libraries during the build. With GCC, it would be as follows:
% python3 --version
Python 3.11.4
% g++ sourcefile -std=c++11 -I/usr/include/python3.11 -l/usr/lib/python3.11
The paths to Python include files and libraries should match the installed version.
On Windows
There are some potential stumbling blocks on Windows, so caution is necessary.
Modifying the Source Code
The obtained matplotlibcpp.h cannot be used as it is. When attempting to compile, you should see a message stating that select_npy_type<long long>
and select_npy_type<unsigned long long>
are being redefined.
When reading the source code in matplotlib-cpp
, you can see some comments near the definition of select_npy_type<long long>
as follows.
// Sanity checks; comment them out or change the numpy type below if you're compiling on
// a platform where they don't apply
You should comment out the definition part as follows.
//template <> struct select_npy_type<long long> { const static NPY_TYPES type = NPY_INT64; };
//template <> struct select_npy_type<unsigned long long> { const static NPY_TYPES type = NPY_UINT64; };
This will eliminate the errors.
Build
In Windows, the following paths are required. Make sure to check these paths in advance.
- Python’s include file
- NumPy’s include file
- Python’s library
The default installation directory for Python is C:\Users\[User Name]\AppData\Local\Programs\Python
on Windows. It’s too long. Therefore, it’s advisable to register it in the INCLUDE
or LIB
environment variables.
Additionally, building with GCC is not possible on Windows. You need to use MSVC (cl.exe) or Clang.
MSVC(cl.exe)
cl /EHsc [source-files] /I \path\to\python\include /I \path\to\python\pkgs\[numpy-base-*****]\Lib\site-packages\numpy\core\include /link /LIBPATH \path\to\python\libs
Clang
clang++ [source-files] -I\path\to\python\include -I\path\to\python\pkgs\[numpy-base-*****]\Lib\site-packages\numpy\core\include -l\path\to\python\libs\python311.lib
CMake
If you are using CMake, you can write the CMakeLists.txt
as follows. This way is easier because it automatically searches for the paths of Python and NumPy, so if you have an environment where CMake is available, this is the recommended approach.
cmake_minimum_required(VERSION 3.14)
project([project-name] CXX)
add_executable([executable-file-name] [source-files])
target_compile_features([executable-file-name] PRIVATE cxx_std_11)
find_package(Python COMPONENTS Development NumPy REQUIRED)
target_include_directories([executable-file-name] PRIVATE ${Python_INCLUDE_DIRS} ${Python_NumPy_INCLUDE_DIRS})
target_link_libraries([executable-file-name] Python::Python Python::NumPy)
By using find_package(Python COMPONENTS Development NumPy)
, it automatically locates the paths for Python and NumPy. The last REQUIRED
indicates that they are mandatory. For finding the Python path, CMake version 3.12 or later is required, and for finding the NumPy path, CMake version 3.14 or later is required.
For more details about find_package(Python)
, please refer to the official documentation of CMake.
If you are creating a Makefile, it generates the build by default in DEBUG mode, so (especially on Windows) you need to set the build type to Release.
cmake -DCMAKE_CXX_COMPILER=cl -DCMAKE_BUILD_TYPE=Release -G "MinGW Makefiles" ..
Example Code
You can use it in a similar way to Python’s matplotlib.
#define _USE_MATH_DEFINES
#include <cmath>
#include <map>
#include <string>
#include <vector>
#include "matplotlibcpp.h"
namespace plt = matplotlibcpp;
int main()
{
size_t n = 100;
double sigma = 0.5, mean = 5.0, tx;
std::vector<double> x(n), y(n), z(n);
std::map<std::string, std::string> style;
for(int i = 0; i < n; i++){
x[i] = i / 10.0;
tx = x[i] - mean;
y[i] = 10 / std::sqrt(2 * M_PI * sigma * sigma) * std::exp(-tx * tx / (2 * sigma * sigma));
z[i] = std::sin(2 * M_PI * x[i]) - 2;
}
// Using initializer_list
plt::plot({1, -1.3, 0.1, 0.5, -0.5, 0.8, -0.3, 1, 0, -1, 0.6});
// Using lambda expression
plt::plot(x, [](double t){
return std::log(t) + 4;
}, "b-");
// Setting legends and lines (red dashed) with named_plot
plt::named_plot("gaussian", x, y, "r--");
style["label"] = "y = sin(2 * pi * x) - 2";
style["color"] = "black";
style["marker"] = "+";
style["markeredgecolor"] = "green";
style["linestyle"] = "-.";
// Setting legends and line colors using map
plt::plot(x, z, style);
// Display range
plt::xlim(0, 12);
plt::ylim(-4, 10);
// Axis label
plt::xlabel("x");
plt::ylabel("y");
// Graph title
plt::title("sample graph");
// Legends
plt::legend();
plt::show();
return 0;
}
Output
You can draw various other types of graphs as well. Examples of what kind of graphs you can draw can be found in the sample code on the GitHub repository.
Conclusion
Here, I have summarized how to use matplotlib-cpp, a library that allows you to use Python’s matplotlib in C++. While there are some points to be aware of when using it on Windows, it is a library worth trying out as it allows for easy graph plotting in a manner similar to the original matplotlib.
Discussion
New Comments
No comments yet. Be the first one!