Python matplotlib can't show plot in NixOS

Hi people, I’m in Plasma 6 + wayland setup. When I try to plot using matplotlib in virtuelenv with files below, I got test.py:15: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown plt.show(). I’ve run out of ideas about how to fix this error. Any new perspective?

The Flake

{
  description = "Debug Matplotlib";
  inputs = {
    nixpkgs.url = "nixpkgs/nixos-24.05";
    flake-utils.url = "github:numtide/flake-utils";
  };
  outputs = {
    nixpkgs,
    flake-utils,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = nixpkgs.legacyPackages.${system};
      buildInputs = [
        (pkgs.python3.withPackages (python-pkgs: [
          python-pkgs.pip
          python-pkgs.virtualenv
        ]))
      ];
    in {
      devShells.default = pkgs.mkShell {
        inherit buildInputs;
        shellHook = ''
          export LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib/:$LD_LIBRARY_PATH"
          export LD_LIBRARY_PATH="${pkgs.lib.makeLibraryPath buildInputs}:$LD_LIBRARY_PATH"
          source .venv/bin/activate
        '';
      };
      devShells.setupShell = pkgs.mkShell {
        inherit buildInputs;
        shellHook = ''
          export LD_LIBRARY_PATH=${pkgs.stdenv.cc.cc.lib}/lib/
          rm -rf .venv
          virtualenv --no-setuptools .venv
          source .venv/bin/activate
          pip install -r requirements.txt
        '';
      };
    });
}

The requirement.txt

matplotlib
PyQt6

The test.py

import matplotlib.pyplot as plt
import numpy as np

# Data for plotting
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t)

fig, ax = plt.subplots()
ax.plot(t, s)

ax.set(xlabel='time (s)', ylabel='voltage (mV)',
       title='About as simple as it gets, folks')
ax.grid()

plt.show()

Edit: when I put matplotlib.use('QtAgg') in test.py I got

ImportError: Failed to import any of the following Qt binding modules: PyQt6, PySide6, PyQt5, PySide2

Wierd, my pip list shows

contourpy       1.3.0
cycler          0.12.1
fonttools       4.53.1
kiwisolver      1.4.7
matplotlib      3.9.2
numpy           2.1.1
packaging       24.1
pillow          10.4.0
pip             24.2
pyparsing       3.1.4
PyQt6           6.7.1
PyQt6-Qt6       6.7.2
PyQt6_sip       13.8.0
python-dateutil 2.9.0.post0
six             1.16.0
wheel           0.44.0

Edit 2: When I run import PyQt6.QtCore in this environment, I got

ImportError: libglib-2.0.so.0: cannot open shared object file: No such file or directory
1 Like

Okay I got it, matplotlib requires these nix pkgs to run on wayland plasma 6. NixOS is insane for python development

pkgs.glib
pkgs.zlib
pkgs.libGL
pkgs.fontconfig
pkgs.xorg.libX11
pkgs.libxkbcommon
pkgs.freetype
pkgs.dbus
4 Likes

Thanks for sharing, I was looking for a solution a long time. Yes, NixOS and Python are a challenge…

Just for context: An easy workaround is not using PyQt6 but the Tkinter backend.

matplotlib.use('TkAgg')
...
figure.show()

The above solutions did never really work out for me, and I always return to this flake I got inspired from somewhere:

{
  inputs = {
    utils.url = "github:numtide/flake-utils";
  };
  outputs = { self, nixpkgs, utils }: utils.lib.eachDefaultSystem (system:
    let
      pkgs = nixpkgs.legacyPackages.${system};
      pythonEnv = pkgs.python313.withPackages ( ps: with ps; [
      ] );
    in
      {
        devShell = pkgs.mkShell {
          buildInputs = with pkgs; [
            uv
            pythonEnv
            
            glib
            zlib
            libGL
            stdenv.cc.cc.lib
            libsForQt5.wrapQtAppsHook
            (python313Packages.matplotlib.override {
              enableQt = true;
            })
          ];

          LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath [
            pkgs.stdenv.cc.cc.lib
            pkgs.zlib
            pkgs.libGL
            pkgs.glib.out
          ]}:$LD_LIBRARY_PATH";
          
          UV_PYTHON="${pythonEnv}/bin/python";
          UV_PYTHON_PREFERENCE = "only-system";
          # shellHook = ''
          # '' ;
        };
      }
  );

}

This gives an environment with uv (tested with poetry too) that has working SSL, as able to import numpy, pandas and the other usual suspects, and can correctly show the Qt matplitlib windows.

Since PyQt is slow at catching up with plasma qt version, I switch to official PySide. We should make github repo that have minimal working example to plot with matplotlib

You could also try out one of these solutions to get PyQt running in a venv on nixos: Pyhton: use PyQt6 within an virtual environment (venv)

This has been working out for me, for quite some time. Simply adding xorg.libX11 to the LD_LIBRARY_PATH

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    utils.url = "github:numtide/flake-utils";
  };
  outputs = { self, nixpkgs, utils }:
    utils.lib.eachDefaultSystem (system:
      let pkgs = nixpkgs.legacyPackages.${system};
      in {
        devShell = pkgs.mkShell {
          buildInputs = with pkgs; [
            uv
          ];

          LD_LIBRARY_PATH = "${
            pkgs.lib.makeLibraryPath (with pkgs; [
              xorg.libX11
            ])
          }:$LD_LIBRARY_PATH";
          shellHook = ''
            export UV_PYTHON_PREFERENCE="managed"
          '';
        };
      });
}