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 use this argument to define the overridden
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.hostPlatform.isDarwin && !isPyPy),
56 tkinter,
57
58 # Qt
59 enableQt ? false,
60 pyqt5,
61
62 # Webagg
63 enableWebagg ? false,
64 tornado,
65
66 # nbagg
67 enableNbagg ? false,
68 ipykernel,
69
70 # required for headless detection
71 libX11,
72 wayland,
73
74 # Reverse dependency
75 sage,
76}:
77
78let
79 interactive = enableTk || enableGtk3 || enableQt;
80in
81
82buildPythonPackage rec {
83 version = "3.10.1";
84 pname = "matplotlib";
85 pyproject = true;
86
87 disabled = pythonOlder "3.10";
88
89 src = fetchPypi {
90 inherit pname version;
91 hash = "sha256-6NLQ44gbEpJoWFv0dlrT7nOkWR13uaGMIUrH46efsro=";
92 };
93
94 env.XDG_RUNTIME_DIR = "/tmp";
95
96 # Matplotlib tries to find Tcl/Tk by opening a Tk window and asking the
97 # corresponding interpreter object for its library paths. This fails if
98 # `$DISPLAY` is not set. The fallback option assumes that Tcl/Tk are both
99 # installed under the same path which is not true in Nix.
100 # With the following patch we just hard-code these paths into the install
101 # script.
102 postPatch =
103 ''
104 substituteInPlace pyproject.toml \
105 --replace-fail "meson-python>=0.13.1,<0.17.0" meson-python
106
107 patchShebangs tools
108 ''
109 + lib.optionalString (stdenv.hostPlatform.isLinux && interactive) ''
110 # fix paths to libraries in dlopen calls (headless detection)
111 substituteInPlace src/_c_internal_utils.cpp \
112 --replace-fail libX11.so.6 ${libX11}/lib/libX11.so.6 \
113 --replace-fail libwayland-client.so.0 ${wayland}/lib/libwayland-client.so.0
114 '';
115
116 nativeBuildInputs = [ pkg-config ] ++ lib.optionals enableGtk3 [ gobject-introspection ];
117
118 buildInputs =
119 [
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 [
142 # explicit
143 contourpy
144 cycler
145 fonttools
146 kiwisolver
147 numpy
148 packaging
149 pillow
150 pyparsing
151 python-dateutil
152 ]
153 ++ lib.optionals (pythonOlder "3.10") [ importlib-resources ]
154 ++ lib.optionals enableGtk3 [
155 pycairo
156 pygobject3
157 ]
158 ++ lib.optionals enableQt [ pyqt5 ]
159 ++ lib.optionals enableWebagg [ tornado ]
160 ++ lib.optionals enableNbagg [ ipykernel ]
161 ++ lib.optionals enableTk [ tkinter ];
162
163 mesonFlags = lib.mapAttrsToList lib.mesonBool {
164 system-freetype = true;
165 system-qhull = true;
166 # Otherwise GNU's `ar` binary fails to put symbols from libagg into the
167 # matplotlib shared objects. See:
168 # -https://github.com/matplotlib/matplotlib/issues/28260#issuecomment-2146243663
169 # -https://github.com/matplotlib/matplotlib/issues/28357#issuecomment-2155350739
170 b_lto = false;
171 };
172
173 passthru.tests = {
174 inherit sage;
175 withOutdatedFreetype = matplotlib.override {
176 doCheck = true;
177 freetype = freetype.overrideAttrs (_: {
178 src = fetchurl {
179 url = "mirror://savannah/freetype/freetype-old/freetype-2.6.1.tar.gz";
180 hash = "sha256-Cjx9+9ptoej84pIy6OltmHq6u79x68jHVlnkEyw2cBQ=";
181 };
182 patches = [ ];
183 });
184 };
185 };
186
187 pythonImportsCheck = [ "matplotlib" ];
188 inherit doCheck;
189 nativeCheckInputs = [ pytestCheckHook ];
190 preCheck = ''
191 # https://matplotlib.org/devdocs/devel/testing.html#obtain-the-reference-images
192 find lib -name baseline_images -printf '%P\n' | while read p; do
193 cp -r lib/"$p" $out/${python.sitePackages}/"$p"
194 done
195 # Tests will fail without these files as well
196 cp \
197 lib/matplotlib/tests/{mpltest.ttf,cmr10.pfb,Courier10PitchBT-Bold.pfb} \
198 $out/${python.sitePackages}/matplotlib/tests/
199 # https://github.com/NixOS/nixpkgs/issues/255262
200 cd $out
201 '';
202
203 meta = with lib; {
204 description = "Python plotting library, making publication quality plots";
205 homepage = "https://matplotlib.org/";
206 changelog = "https://github.com/matplotlib/matplotlib/releases/tag/v${version}";
207 license = with licenses; [
208 psfl
209 bsd0
210 ];
211 maintainers = with maintainers; [
212 lovek323
213 veprbl
214 ];
215 };
216}