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