SimpleJSON and NumPy array SimpleJSON and NumPy array python python

SimpleJSON and NumPy array


In order to keep dtype and dimension try this:

import base64import jsonimport numpy as npclass NumpyEncoder(json.JSONEncoder):    def default(self, obj):        """If input object is an ndarray it will be converted into a dict         holding dtype, shape and the data, base64 encoded.        """        if isinstance(obj, np.ndarray):            if obj.flags['C_CONTIGUOUS']:                obj_data = obj.data            else:                cont_obj = np.ascontiguousarray(obj)                assert(cont_obj.flags['C_CONTIGUOUS'])                obj_data = cont_obj.data            data_b64 = base64.b64encode(obj_data)            return dict(__ndarray__=data_b64,                        dtype=str(obj.dtype),                        shape=obj.shape)        # Let the base class default method raise the TypeError        super(NumpyEncoder, self).default(obj)def json_numpy_obj_hook(dct):    """Decodes a previously encoded numpy ndarray with proper shape and dtype.    :param dct: (dict) json encoded ndarray    :return: (ndarray) if input was an encoded ndarray    """    if isinstance(dct, dict) and '__ndarray__' in dct:        data = base64.b64decode(dct['__ndarray__'])        return np.frombuffer(data, dct['dtype']).reshape(dct['shape'])    return dctexpected = np.arange(100, dtype=np.float)dumped = json.dumps(expected, cls=NumpyEncoder)result = json.loads(dumped, object_hook=json_numpy_obj_hook)# None of the following assertions will be broken.assert result.dtype == expected.dtype, "Wrong Type"assert result.shape == expected.shape, "Wrong Shape"assert np.allclose(expected, result), "Wrong Values"


I'd use simplejson.dumps(somearray.tolist()) as the most convenient approach (if I was still using simplejson at all, which implies being stuck with Python 2.5 or earlier; 2.6 and later have a standard library module json which works the same way, so of course I'd use that if the Python release in use supported it;-).

In a quest for greater efficiency, you could subclass json.JSONEncoder (in json; I don't know if the older simplejson already offered such customization possibilities) and, in the default method, special-case instances of numpy.array by turning them into list or tuples "just in time". I kind of doubt you'd gain enough by such an approach, in terms of performance, to justify the effort, though.


I found this json subclass code for serializing one-dimensional numpy arrays within a dictionary. I tried it and it works for me.

class NumpyAwareJSONEncoder(json.JSONEncoder):    def default(self, obj):        if isinstance(obj, numpy.ndarray) and obj.ndim == 1:            return obj.tolist()        return json.JSONEncoder.default(self, obj)

My dictionary is 'results'. Here's how I write to the file "data.json":

j=json.dumps(results,cls=NumpyAwareJSONEncoder)f=open("data.json","w")f.write(j)f.close()