Matplotlib-cpp on Nix/NixOS

Have anyone got matplotlib-cpp working on Nix/NixOS?

Or is it Debian specific?

It would be great to have MatPlotLib available directly in C++ code.

If I understood correctly, matplotlib-cpp is a header-only library. You can copy the matplotlibcpp.h file inside you project and compile.

Thank you!

The main problem now is that g++ doesn’t find the NumPy C++ headers.

Where can I get them?

$ make Plot.o
g++ -o Plot.o -std=c++11 -g -Wall -Iresult/include/python3.8 -lpython3.8 src/Plot.cpp matplotlib-cpp/matplotlibcpp.h NumericDifferentiation.so
In file included from src/Plot.cpp:7:
src/../matplotlib-cpp/matplotlibcpp.h:17:12: fatal error: numpy/arrayobject.h: No such file or directory
   17 | #  include <numpy/arrayobject.h>
      |            ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
matplotlib-cpp/matplotlibcpp.h:1:9: warning: #pragma once in main file
    1 | #pragma once
      |         ^~~~
matplotlib-cpp/matplotlibcpp.h:17:12: fatal error: numpy/arrayobject.h: No such file or directory
   17 | #  include <numpy/arrayobject.h>
      |            ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:10: Plot.o] Error 1

Try to add this to this g++ command:

-I$(python -c "import numpy as np; print(np.get_include())")
1 Like

The examples can now be built successfully, but the output executable complains ModuleNotFound at run time.

I run it in nix-shell with a derivation generated using python38.withPackages.

shamrock@nixos-202104:~/Documents/Reports_1092/NumericSimulation/W04/matplotlib-cpp/examples]$ python3
Python 3.8.8 (default, Feb 19 2021, 11:04:50) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib.pyplot as plt
>>> exit()

[shamrock@nixos-202104:~/Documents/Reports_1092/NumericSimulation/W04/matplotlib-cpp/examples]$ echo g++ -o basic.o -std=c++11 -g -Wall -I$(python3.8 -c "from sysconfig import get_paths; print(get_paths()['include'])") -lpython3.8 -I$(python3.8 -c "import numpy as np; print(np.get_include())") ./basic.cpp    
g++ -o basic.o -std=c++11 -g -Wall -I/nix/store/qy5z9gcld7dljm4i5hj3z8a9l6p37y81-python3-3.8.8/include/python3.8 -lpython3.8 -I/nix/store/fkhwf951i9bdcmxsb2jijihq599jlkfh-python3-3.8.8-env/lib/python3.8/site-packages/numpy/core/include ./basic.cpp

[shamrock@nixos-202104:~/Documents/Reports_1092/NumericSimulation/W04/matplotlib-cpp/examples]$ g++ -o basic.o -std=c++11 -g -Wall -I$(python3.8 -c "from sysconfig import get_paths; print(get_paths()['include'])") -lpython3.8 -I$(python3.8 -c "import numpy as np; print(np.get_include())") ./basic.cpp

[shamrock@nixos-202104:~/Documents/Reports_1092/NumericSimulation/W04/matplotlib-cpp/examples]$ ./basic.o 
ModuleNotFoundError: No module named 'numpy'
ModuleNotFoundError: No module named 'matplotlib'
terminate called after throwing an instance of 'std::runtime_error'
  what():  Error loading module matplotlib!
Aborted (core dumped)

I fixed this problem exporting $PYTHONPATH. It’s easier to create a shell.nix like this:

with (import <nixpkgs> { });

let
  my_python = python3.withPackages (ps:
    with ps; [
      numpy
      matplotlib
    ]);
in
mkShell {
  nativeBuildInputs = [
    cmake
    my_python
  ];

  PYTHONPATH = "${my_python}/${my_python.sitePackages}";
}

Also, it’s better to use cmake to ease the compilation process. I create this one, just replace test with the name the executable do you want to create:

cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
project(test LANGUAGES CXX)

find_package(Python3 COMPONENTS Interpreter Development NumPy REQUIRED)
include_directories(${Python_INCLUDE_DIRS})
include_directories(${Python_NumPy_INCLUDE_DIRS})

message(STATUS "PYTHON_EXECUTABLE = ${Python3_EXECUTABLE}")
message(STATUS "PYTHON_INCLUDE_DIRS = ${Python3_INCLUDE_DIRS}")
message(STATUS "NumPy_INCLUDE_DIRS = ${Python3_NumPy_INCLUDE_DIRS}")
message(STATUS "Python_LIBRARIES = ${Python3_LIBRARIES}")

add_executable(test test.cpp)
target_link_libraries(test  Python3::Python)
target_link_libraries(test  Python3::Module)
target_link_libraries(test Python3::NumPy)
1 Like

The error indicates that the python interpreter that gets invoked by the library doesn’t have numpy and matplotlib in its site-packages. Maybe you have another python in your PATH?

1 Like

As an alternative to @brogos solution you can also use NIX_CFLAGS_COMPILE & co as a backchannel to cc-wrapper like so:

{ pkgs ? import <nixpkgs> {} }:
let
  py3 = pkgs.python3;
in pkgs.mkShell {
  buildInputs = [
    py3.pkgs.numpy
    py3.pkgs.matplotlib
  ];
  NIX_CFLAGS_COMPILE = [
    "-isystem ${py3}/include/${py3.libPrefix}"
    "-isystem ${py3.pkgs.numpy}/${py3.sitePackages}/numpy/core/include"
  ];
  NIX_LDFLAGS = [
    "-l${py3.libPrefix}"
  ];
}

g++ basic.cpp should work in this shell, and it doesn’t require CMake to do its magic.

1 Like

@brogos @tobim Thank you for the solutions!

1 Like