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.5";
84 pname = "matplotlib";
85 pyproject = true;
86
87 disabled = pythonOlder "3.10";
88
89 src = fetchPypi {
90 inherit pname version;
91 hash = "sha256-NS7WzPt5mKAIgWkvOLTKCDxpHT4nW0FFQjcEw0yQkHY=";
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 substituteInPlace pyproject.toml \
104 --replace-fail "meson-python>=0.13.1,<0.17.0" meson-python
105
106 patchShebangs tools
107 ''
108 + lib.optionalString (stdenv.hostPlatform.isLinux && interactive) ''
109 # fix paths to libraries in dlopen calls (headless detection)
110 substituteInPlace src/_c_internal_utils.cpp \
111 --replace-fail libX11.so.6 ${libX11}/lib/libX11.so.6 \
112 --replace-fail libwayland-client.so.0 ${wayland}/lib/libwayland-client.so.0
113 '';
114
115 nativeBuildInputs = [ pkg-config ] ++ lib.optionals enableGtk3 [ gobject-introspection ];
116
117 buildInputs = [
118 ffmpeg-headless
119 freetype
120 qhull
121 ]
122 ++ lib.optionals enableGtk3 [
123 cairo
124 gtk3
125 ];
126
127 # clang-11: error: argument unused during compilation: '-fno-strict-overflow' [-Werror,-Wunused-command-line-argument]
128 hardeningDisable = lib.optionals stdenv.hostPlatform.isDarwin [ "strictoverflow" ];
129
130 build-system = [
131 certifi
132 numpy
133 pybind11
134 meson-python
135 setuptools-scm
136 ];
137
138 dependencies = [
139 # explicit
140 contourpy
141 cycler
142 fonttools
143 kiwisolver
144 numpy
145 packaging
146 pillow
147 pyparsing
148 python-dateutil
149 ]
150 ++ lib.optionals (pythonOlder "3.10") [ importlib-resources ]
151 ++ lib.optionals enableGtk3 [
152 pycairo
153 pygobject3
154 ]
155 ++ lib.optionals enableQt [ pyqt5 ]
156 ++ lib.optionals enableWebagg [ tornado ]
157 ++ lib.optionals enableNbagg [ ipykernel ]
158 ++ lib.optionals enableTk [ tkinter ];
159
160 mesonFlags = lib.mapAttrsToList lib.mesonBool {
161 system-freetype = true;
162 system-qhull = true;
163 # Otherwise GNU's `ar` binary fails to put symbols from libagg into the
164 # matplotlib shared objects. See:
165 # -https://github.com/matplotlib/matplotlib/issues/28260#issuecomment-2146243663
166 # -https://github.com/matplotlib/matplotlib/issues/28357#issuecomment-2155350739
167 b_lto = false;
168 };
169
170 passthru.tests = {
171 inherit sage;
172 withOutdatedFreetype = matplotlib.override {
173 doCheck = true;
174 freetype = freetype.overrideAttrs (_: {
175 src = fetchurl {
176 url = "mirror://savannah/freetype/freetype-old/freetype-2.6.1.tar.gz";
177 hash = "sha256-Cjx9+9ptoej84pIy6OltmHq6u79x68jHVlnkEyw2cBQ=";
178 };
179 patches = [ ];
180 });
181 };
182 };
183
184 pythonImportsCheck = [ "matplotlib" ];
185 inherit doCheck;
186 nativeCheckInputs = [ pytestCheckHook ];
187 preCheck = ''
188 # https://matplotlib.org/devdocs/devel/testing.html#obtain-the-reference-images
189 find lib -name baseline_images -printf '%P\n' | while read p; do
190 cp -r lib/"$p" $out/${python.sitePackages}/"$p"
191 done
192 # Tests will fail without these files as well
193 cp \
194 lib/matplotlib/tests/{mpltest.ttf,cmr10.pfb,Courier10PitchBT-Bold.pfb} \
195 $out/${python.sitePackages}/matplotlib/tests/
196 # https://github.com/NixOS/nixpkgs/issues/255262
197 cd $out
198 '';
199
200 meta = with lib; {
201 description = "Python plotting library, making publication quality plots";
202 homepage = "https://matplotlib.org/";
203 changelog = "https://github.com/matplotlib/matplotlib/releases/tag/v${version}";
204 license = with licenses; [
205 psfl
206 bsd0
207 ];
208 maintainers = with maintainers; [
209 lovek323
210 veprbl
211 ];
212 };
213}