Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved SWC I/O #72

Merged
merged 3 commits into from
Nov 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/user/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ script which should provide a convenient multiplatform experience, made even
easier by the automatic install scripts available on most platforms.

**NB** if you run against some bugs after the installation, please first have
a look at the `Known errors`_ section, in case it is not already listed there.
a look at the "Known errors" section, in case it is not already listed there.


.. contents:: :depth: 2
Expand Down
2 changes: 1 addition & 1 deletion src/growth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ int main(int argc, char **argv)
growth::SkelNeurite axon, dendrites, nodes, growth_cones, somas;
std::vector<growth::stype> gid = {0};
// growth::get_skeleton(axon, dendrites, nodes, growth_cones, somas, gid);
growth::get_swc_("myswc", gid, 10);
growth::get_swc_("myswc", gid, 10, false);

return 0;
}
19 changes: 19 additions & 0 deletions src/io/Swc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ namespace growth

typedef std::array<std::vector<double>, 3> PointsArray;


Swc::Swc()
{}

/**
* @brief Create a file with neuron in SWC format
*
Expand All @@ -50,6 +54,21 @@ Swc::Swc(std::string output_file, unsigned int resolution)
swc_file_ << "#sample element_ID X Y Z radius parent\n";
}

Swc::Swc(Swc&& rhs) :
resolution_(std::move(rhs.resolution_))
{
swc_file_.swap(rhs.swc_file_);
}


Swc& Swc::operator=(Swc &&rhs)
{
resolution_ = rhs.resolution_;
swc_file_.swap(rhs.swc_file_);

return *this;
}


void Swc::close_file() { swc_file_.close(); }

Expand Down
3 changes: 3 additions & 0 deletions src/io/Swc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ class Swc
unsigned int resolution_;

public:
Swc();
Swc(std::string output_file, unsigned int resolution);
Swc(Swc&& rhs);
Swc& operator=(Swc &&rhs);
void to_swc(const Neuron *, stype gid);
void close_file();
~Swc();
Expand Down
29 changes: 25 additions & 4 deletions src/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -914,19 +914,40 @@ void get_distances_(stype gid, const std::string &neurite_name, stype node,


void get_swc_(std::string output_file, std::vector<stype> gids,
unsigned int resolution)
unsigned int resolution, bool split)
{
std::sort(gids.begin(), gids.end());
Swc swc(output_file, resolution);
Swc swc;

if (not split)
{
Swc tmp(output_file + ".swc", resolution);
swc = std::move(tmp);
}

for (const auto &neuron_gid : gids)
{
if (split)
{
Swc tmp(output_file + "_" + std::to_string(neuron_gid) + ".swc",
resolution);
swc = std::move(tmp);
}

const NeuronPtr neuron = kernel().neuron_manager.get_neuron(neuron_gid);
// @todo: pass non default arguments

swc.to_swc(neuron.get(), neuron_gid);

if (split)
{
swc.close_file();
}
}

swc.close_file();
if (not split)
{
swc.close_file();
}
}


Expand Down
2 changes: 1 addition & 1 deletion src/module.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ void get_skeleton_(SkelNeurite &axon, SkelNeurite &dendrites,


void get_swc_(std::string output_file, std::vector<stype> gids,
unsigned int resolution);
unsigned int resolution, bool split);


statusMap get_kernel_status_();
Expand Down
2 changes: 1 addition & 1 deletion src/pymodule/dense/_pygrowth.pxd.in
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ cdef extern from "../module.hpp" namespace "growth":
double &dist_to_soma) except +

cdef void get_swc_(string output_file,
vector[stype] gids, unsigned int resolution) except +
vector[stype] gids, unsigned int resolution, bool split) except +

cdef statusMap get_status_(stype gid) except +

Expand Down
12 changes: 10 additions & 2 deletions src/pymodule/dense/_pygrowth.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2029,7 +2029,7 @@ def _get_parent_and_soma_distances(neuron, neurite, node, segment):
return distance_to_parent, distance_to_soma


def _neuron_to_swc(filename, gid=None, resolution=10):
def _neuron_to_swc(filename, gid=None, resolution=10, split=False):
'''
Save neurons to SWC file.

Expand All @@ -2042,18 +2042,26 @@ def _neuron_to_swc(filename, gid=None, resolution=10):
resolution : int, optional (default: 10)
Coarse-graining factor of the structure: only one point every
`resolution` will be kept.
split : bool
Split neurons among files if there are more than one neuron.
'''
filename = filename[:-4] if filename.endswith(".swc") else filename

cdef:
string cfname = _to_bytes(filename)
vector[stype] gids

if gid is None:
gids = get_neurons_()
elif isinstance(gid, int):
gids = vector[stype](1, <stype>gid)
else:
for n in gid:
gids.push_back(<stype>n)
get_swc_(cfname, gids, resolution)

split *= (gids.size() > 1)

get_swc_(cfname, gids, resolution, split)


def _get_tree(neuron, neurite):
Expand Down
108 changes: 63 additions & 45 deletions src/pymodule/dense/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,32 @@ def __init__(self, gid, **kwargs):
Optional arguments used when loading neurons that do not exist
in the simulator.
'''
kwargs = kwargs.copy()

self._axon = None
self._dendrites = {}
self.__gid = int(gid)

self._in_simulator = True
self._in_simulator = kwargs.get("in_simulator", True)

if "in_simulator" in kwargs:
del kwargs["in_simulator"]

# check if object exists
try:
_pg.get_object_type(gid)
self._in_simulator *= True
except RuntimeError:
# object does not exist, use kwargs for some information
self._in_simulator = False

if not self._in_simulator:
# object does not exist, use kwargs for some information
for k, v in kwargs.items():
setattr(self, k, v)

if "axon" not in kwargs:
self._axon = None

# necessary for initial setting of attributes due to __setattr__
self.__initialized = True

Expand Down Expand Up @@ -960,15 +970,15 @@ class Population(list):

@classmethod
def from_swc(cls, population, info=None):
if info is not None:
ensemble = cls(info=population['info'])
else:
ensemble = cls(info=population['info'])
ensemble._add_swc_population(population['neurons'])
ensemble = cls(info=info)

ensemble._add_swc_population(population)
ensemble.sort()
ensemble._idx = {} # converter from gid to idx

for i, n in enumerate(ensemble):
ensemble._idx[int(n)] = i

return ensemble

@classmethod
Expand Down Expand Up @@ -1072,7 +1082,14 @@ def size(self):
return len(self)

def append(self, val):
super(Population, self).append(val)
super().append(val)
self.sort()
self._idx = {} # converter from gid to idx
for i, n in enumerate(self):
self._idx[int(n)] = i

def extend(self, values):
super().extend(values)
self.sort()
self._idx = {} # converter from gid to idx
for i, n in enumerate(self):
Expand Down Expand Up @@ -1128,45 +1145,46 @@ def _add_structure_population(self, structure):

def _add_swc_population(self, neurons):
'''
add population
Build population from SWC files
'''
from .io.data_swc import GetSWCStructure as _get_swc_struct

for neuron in neurons:
gid = neurons[neuron]['gid']
axon, dendrites = _get_swc_struct(neuron=neurons[neuron]['data'])
try:
position = self.info["neurons"][str(
neurons[neuron]['gid'])]['position']
except KeyError:
_warn.warn("Cannot retrieve `position` from info.json file "
"setting default position to [0, 0].")
position = [0, 0]
try:
soma_radius = self.info["neurons"][str(
neurons[neuron]['gid'])]['soma_radius']
except KeyError:
_warn.warn("Cannot retrieve `soma_radius` from info.json file "
"setting default radius to 8.")
soma_radius = 8.

super(Population, self).append(
Neuron(gid, position=position, soma_radius=soma_radius))

if isinstance(axon, list):
self[gid].axon = Neurite([Branch(ax) for ax in axon],
neurite_type="axon", name="axon")
else:
raise Exception("Axon is expected to be a list of segments.")
if dendrites is not None:
if isinstance(dendrites, list):
# add neurons first
self.extend((
Neuron(gid, position=neuron["position"],
soma_radius=neuron["soma_radius"],
in_simulator=False)
for gid, neuron in neurons.items()
))

# then add neurites
for gid, neuron in neurons.items():
if neuron["axon"] is not None:
axon = neuron["axon"][0]
self[gid]._axon = Neurite(
[Branch((ax["xy"], None, None, ax["diameter"]),
parent=ax["parent_id"], node_id=ax["first_id"])
for ax in axon], neurite_type="axon", name="axon")

if neuron["basal"] is not None:
for i, basal in enumerate(neuron["basal"]):
dendrite = Neurite(
[Branch(dend) for dend in dendrites],
neurite_type="dendrite", name="dendrite")
self[gid].dendrites[str(dendrite)] = dendrite
else:
raise Exception(
"Dendrites are expected to be a list of segments.")
[Branch((dend["xy"], None, None, dend["diameter"]),
parent=dend["parent_id"],
node_id=dend["first_id"])
for dend in basal],
neurite_type="dendrite", name="dendrite_{}".format(i))

self[gid]._dendrites[str(dendrite)] = dendrite

if neuron["apical"] is not None:
for j, apical in enumerate(neuron["apical"]):
dendrite = Neurite(
[Branch((dend["xy"], None, None, dend["diameter"]),
parent=dend["parent_id"],
node_id=dend["first_id"])
for dend in apical], neurite_type="dendrite",
name="dendrite_{}".format(i + j))

self[gid]._dendrites[str(dendrite)] = dendrite

def get_properties(self, property_name=None, level=None, neurite=None):
'''
Expand Down
5 changes: 4 additions & 1 deletion src/pymodule/dense/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
# along with DeNSE. If not, see <http://www.gnu.org/licenses/>.


""" IO functions """
"""
IO functions
============
"""

import hashlib
import json
Expand Down
6 changes: 5 additions & 1 deletion src/pymodule/dense/io/dataIO.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def save_to_neuroml(filename, gid=None, resolution=10):
'''
Save the morphology of each neuron to a single NeuroML file.

NeuroML is an XML (Extensible Markup Language) based model description
NeuroML is an XML (eXtensible Markup Language) based model description
language that aims to provide a common data format for defining and
exchanging models in computational neuroscience. It is focused on
biophysical and anatomical detailed models.
Expand All @@ -94,6 +94,10 @@ def save_to_neuroml(filename, gid=None, resolution=10):
resolution : int, optional (default: 10)
Subsampling coefficient for points on a neurite (sample on point every
`resolution`).

See also
--------
:func:`~dense.io.save_to_swc`
'''
import neuroml
import neuroml.writers as writers
Expand Down
Loading