1{
2 lib,
3 stdenv,
4 fetchPypi,
5 buildPythonPackage,
6 isPyPy,
7 pythonAtLeast,
8 pythonOlder,
9
10 # build-system
11 certifi,
12 pkg-config,
13 pybind11,
14 meson-python,
15 setuptools-scm,
16 pytestCheckHook,
17 python,
18 matplotlib,
19 fetchurl,
20
21 # native libraries
22 ffmpeg-headless,
23 freetype,
24 # By default, almost all tests fail due to the fact we use our version of
25 # freetype. We still use this argument to define the overridden
26 # derivation `matplotlib.passthru.tests.withoutOutdatedFreetype` - which
27 # builds matplotlib with the freetype version they default to, with which all
28 # tests should pass.
29 doCheck ? false,
30 qhull,
31
32 # propagates
33 contourpy,
34 cycler,
35 fonttools,
36 kiwisolver,
37 numpy,
38 packaging,
39 pillow,
40 pyparsing,
41 python-dateutil,
42
43 # optional
44 importlib-resources,
45
46 # GTK3
47 enableGtk3 ? false,
48 cairo,
49 gobject-introspection,
50 gtk3,
51 pycairo,
52 pygobject3,
53
54 # Tk
55 # Darwin has its own "MacOSX" backend, PyPy has tkagg backend and does not support tkinter
56 # tkinter fails to build on Python 3.11
57 enableTk ? (!stdenv.hostPlatform.isDarwin && !isPyPy && pythonAtLeast "3.12"),
58 tkinter,
59
60 # Qt
61 enableQt ? false,
62 pyqt5,
63
64 # Webagg
65 enableWebagg ? false,
66 tornado,
67
68 # nbagg
69 enableNbagg ? false,
70 ipykernel,
71
72 # required for headless detection
73 libX11,
74 wayland,
75
76 # Reverse dependency
77 sage,
78}:
79
80let
81 interactive = enableTk || enableGtk3 || enableQt;
82in
83
84buildPythonPackage rec {
85 version = "3.10.5";
86 pname = "matplotlib";
87 pyproject = true;
88
89 disabled = pythonOlder "3.10";
90
91 src = fetchPypi {
92 inherit pname version;
93 hash = "sha256-NS7WzPt5mKAIgWkvOLTKCDxpHT4nW0FFQjcEw0yQkHY=";
94 };
95
96 env.XDG_RUNTIME_DIR = "/tmp";
97
98 # Matplotlib tries to find Tcl/Tk by opening a Tk window and asking the
99 # corresponding interpreter object for its library paths. This fails if
100 # `$DISPLAY` is not set. The fallback option assumes that Tcl/Tk are both
101 # installed under the same path which is not true in Nix.
102 # With the following patch we just hard-code these paths into the install
103 # script.
104 postPatch = ''
105 substituteInPlace pyproject.toml \
106 --replace-fail "meson-python>=0.13.1,<0.17.0" meson-python
107
108 patchShebangs tools
109 ''
110 + lib.optionalString (stdenv.hostPlatform.isLinux && interactive) ''
111 # fix paths to libraries in dlopen calls (headless detection)
112 substituteInPlace src/_c_internal_utils.cpp \
113 --replace-fail libX11.so.6 ${libX11}/lib/libX11.so.6 \
114 --replace-fail libwayland-client.so.0 ${wayland}/lib/libwayland-client.so.0
115 '';
116
117 nativeBuildInputs = [ pkg-config ] ++ lib.optionals enableGtk3 [ gobject-introspection ];
118
119 buildInputs = [
120 ffmpeg-headless
121 freetype
122 qhull
123 ]
124 ++ lib.optionals enableGtk3 [
125 cairo
126 gtk3
127 ];
128
129 # clang-11: error: argument unused during compilation: '-fno-strict-overflow' [-Werror,-Wunused-command-line-argument]
130 hardeningDisable = lib.optionals stdenv.hostPlatform.isDarwin [ "strictoverflow" ];
131
132 build-system = [
133 certifi
134 numpy
135 pybind11
136 meson-python
137 setuptools-scm
138 ];
139
140 dependencies = [
141 # explicit
142 contourpy
143 cycler
144 fonttools
145 kiwisolver
146 numpy
147 packaging
148 pillow
149 pyparsing
150 python-dateutil
151 ]
152 ++ lib.optionals (pythonOlder "3.10") [ importlib-resources ]
153 ++ lib.optionals enableGtk3 [
154 pycairo
155 pygobject3
156 ]
157 ++ lib.optionals enableQt [ pyqt5 ]
158 ++ lib.optionals enableWebagg [ tornado ]
159 ++ lib.optionals enableNbagg [ ipykernel ]
160 ++ lib.optionals enableTk [ tkinter ];
161
162 mesonFlags = lib.mapAttrsToList lib.mesonBool {
163 system-freetype = true;
164 system-qhull = true;
165 # Otherwise GNU's `ar` binary fails to put symbols from libagg into the
166 # matplotlib shared objects. See:
167 # -https://github.com/matplotlib/matplotlib/issues/28260#issuecomment-2146243663
168 # -https://github.com/matplotlib/matplotlib/issues/28357#issuecomment-2155350739
169 b_lto = false;
170 };
171
172 passthru.tests = {
173 inherit sage;
174 withOutdatedFreetype = matplotlib.override {
175 doCheck = true;
176 freetype = freetype.overrideAttrs (_: {
177 src = fetchurl {
178 url = "mirror://savannah/freetype/freetype-old/freetype-2.6.1.tar.gz";
179 hash = "sha256-Cjx9+9ptoej84pIy6OltmHq6u79x68jHVlnkEyw2cBQ=";
180 };
181 patches = [ ];
182 });
183 };
184 };
185
186 pythonImportsCheck = [ "matplotlib" ];
187 inherit doCheck;
188 nativeCheckInputs = [ pytestCheckHook ];
189 preCheck = ''
190 # https://matplotlib.org/devdocs/devel/testing.html#obtain-the-reference-images
191 find lib -name baseline_images -printf '%P\n' | while read p; do
192 cp -r lib/"$p" $out/${python.sitePackages}/"$p"
193 done
194 # Tests will fail without these files as well
195 cp \
196 lib/matplotlib/tests/{mpltest.ttf,cmr10.pfb,Courier10PitchBT-Bold.pfb} \
197 $out/${python.sitePackages}/matplotlib/tests/
198 # https://github.com/NixOS/nixpkgs/issues/255262
199 cd $out
200 '';
201
202 meta = with lib; {
203 description = "Python plotting library, making publication quality plots";
204 homepage = "https://matplotlib.org/";
205 changelog = "https://github.com/matplotlib/matplotlib/releases/tag/v${version}";
206 license = with licenses; [
207 psfl
208 bsd0
209 ];
210 maintainers = with maintainers; [
211 lovek323
212 veprbl
213 ];
214 };
215}