12
12
import os
13
13
import re
14
14
import struct
15
+ import typing
15
16
import zlib
17
+ from typing import Any , Callable , Union
16
18
17
19
from jinja2 import Environment , PackageLoader
18
20
26
28
except ImportError :
27
29
np = None
28
30
31
+ if typing .TYPE_CHECKING :
32
+ from branca .colormap import ColorMap
33
+
29
34
30
35
rootpath = os .path .abspath (os .path .dirname (__file__ ))
31
36
@@ -276,7 +281,11 @@ def image_to_url(image, colormap=None, origin="upper"):
276
281
return url .replace ("\n " , " " )
277
282
278
283
279
- def write_png (data , origin = "upper" , colormap = None ):
284
+ def write_png (
285
+ data : Any ,
286
+ origin : str = "upper" ,
287
+ colormap : Union ["ColorMap" , Callable , None ] = None ,
288
+ ) -> bytes :
280
289
"""
281
290
Transform an array of data into a PNG string.
282
291
This can be written to disk using binary I/O, or encoded using base64
@@ -292,28 +301,31 @@ def write_png(data, origin="upper", colormap=None):
292
301
----------
293
302
data: numpy array or equivalent list-like object.
294
303
Must be NxM (mono), NxMx3 (RGB) or NxMx4 (RGBA)
295
-
296
304
origin : ['upper' | 'lower'], optional, default 'upper'
297
305
Place the [0,0] index of the array in the upper left or lower left
298
306
corner of the axes.
299
-
300
- colormap : callable, used only for ` mono` image.
301
- Function of the form [x -> (r,g,b)] or [x -> (r,g,b,a)]
302
- for transforming a mono image into RGB.
303
- It must output iterables of length 3 or 4, with values between
304
- 0. and 1. Hint: you can use colormaps from `matplotlib.cm` .
307
+ colormap : ColorMap subclass or callable, optional
308
+ Only needed to transform mono images into RGB. You have three options:
309
+ - use a subclass of `ColorMap` like `LinearColorMap`
310
+ - use a colormap from `matplotlib.cm`
311
+ - use a custom function of the form [x -> (r,g,b)] or [x -> (r,g,b,a)].
312
+ It must output iterables of length 3 or 4 with values between 0 and 1 .
305
313
306
314
Returns
307
315
-------
308
316
PNG formatted byte string
309
317
"""
318
+ from branca .colormap import ColorMap
319
+
310
320
if np is None :
311
321
raise ImportError ("The NumPy package is required" " for this functionality" )
312
322
313
- if colormap is None :
314
-
315
- def colormap (x ):
316
- return (x , x , x , 1 )
323
+ if isinstance (colormap , ColorMap ):
324
+ colormap_callable = colormap .rgba_floats_tuple
325
+ elif callable (colormap ):
326
+ colormap_callable = colormap
327
+ else :
328
+ colormap_callable = lambda x : (x , x , x , 1 ) # noqa E731
317
329
318
330
array = np .atleast_3d (data )
319
331
height , width , nblayers = array .shape
@@ -323,7 +335,7 @@ def colormap(x):
323
335
assert array .shape == (height , width , nblayers )
324
336
325
337
if nblayers == 1 :
326
- array = np .array (list (map (colormap , array .ravel ())))
338
+ array = np .array (list (map (colormap_callable , array .ravel ())))
327
339
nblayers = array .shape [1 ]
328
340
if nblayers not in [3 , 4 ]:
329
341
raise ValueError (
@@ -340,7 +352,9 @@ def colormap(x):
340
352
341
353
# Normalize to uint8 if it isn't already.
342
354
if array .dtype != "uint8" :
343
- array = array * 255.0 / array .max (axis = (0 , 1 )).reshape ((1 , 1 , 4 ))
355
+ with np .errstate (divide = "ignore" , invalid = "ignore" ):
356
+ array = array * 255.0 / array .max (axis = (0 , 1 )).reshape ((1 , 1 , 4 ))
357
+ array [~ np .isfinite (array )] = 0
344
358
array = array .astype ("uint8" )
345
359
346
360
# Eventually flip the image.
0 commit comments