Source code for navis.io.json_io
# This script is part of navis (http://www.github.com/navis-org/navis).
# Copyright (C) 2018 Philipp Schlegel
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
import json
import pandas as pd
import numpy as np
from pathlib import Path
from .. import config, core
# Set up logging
logger = config.get_logger(__name__)
__all__ = ['write_json', 'read_json']
[docs]
def write_json(x: 'core.NeuronObject', filepath, **kwargs) -> str:
"""Save neuron(s) to json-formatted file.
Nodes and connectors are serialised using pandas' ``to_json()``. Most
other items in the neuron's __dict__ are serialised using
``json.dumps()``. Properties not serialised: `.graph`, `.igraph`.
Parameters
----------
x : TreeNeuron | NeuronList
Neuron(s) to save.
filepath : str, optional
File to save data to. If `None` will return a json-formatted
string.
**kwargs
Parameters passed to ``json.dumps()`` and
``pandas.DataFrame.to_json()``.
Returns
-------
str
Only if ``filepath=None``.
See Also
--------
:func:`~navis.read_json`
Read json back into navis neurons.
"""
if not isinstance(x, (core.TreeNeuron, core.NeuronList)):
raise TypeError(f'Unable to convert data of type "{type(x)}"')
if isinstance(x, core.BaseNeuron):
x = core.NeuronList([x])
data = []
for n in x:
this_data = {'id': n.id}
for k, v in n.__dict__.items():
if not isinstance(k, str):
continue
if k.startswith('_') and k not in ['_nodes', '_connectors']:
continue
if isinstance(v, pd.DataFrame):
this_data[k] = v.to_json()
elif isinstance(v, np.ndarray):
this_data[k] = v.tolist()
else:
this_data[k] = v
data.append(this_data)
if not isinstance(filepath, type(None)):
with open(filepath, 'w') as f:
json.dump(data, f, **kwargs)
else:
return json.dumps(data, **kwargs)
[docs]
def read_json(s: str, **kwargs) -> 'core.NeuronList':
"""Load neuron from JSON (file or string).
Parameters
----------
s : str
Either filepath or JSON-formatted string.
**kwargs
Parameters passed to ``json.loads()`` and
``pandas.DataFrame.read_json()``.
Returns
-------
:class:`~navis.NeuronList`
See Also
--------
:func:`~navis.neuron2json`
Turn neuron into json.
Examples
--------
>>> import navis
>>> n = navis.example_neurons(1)
>>> js = navis.write_json(n, filepath=None)
>>> n2 = navis.read_json(js)
"""
if not isinstance(s, (str, Path)):
raise TypeError(f'Expected str, got "{type(s)}"')
# Try except is necessary because Path() throws a hissy fit if it is given
# a long ass json string as filepath
try:
is_file = Path(s).is_file()
except OSError:
is_file = False
except BaseException:
raise
if is_file:
with open(Path(s), 'r') as f:
data = json.load(f, **kwargs)
else:
data = json.loads(s, **kwargs)
nl = core.NeuronList([])
for n in data:
cn = core.TreeNeuron(None)
if '_nodes' in n:
try:
cn._nodes = pd.read_json(n['_nodes'])
except ValueError:
cn._nodes = None
if '_connectors' in n:
try:
cn._connectors = pd.read_json(n['_connectors'])
except ValueError:
cn._connectors = None
for key in n:
if key in ['_nodes', '_connectors']:
continue
setattr(cn, key, n[key])
nl += cn
return nl