NeuralEnsemble / neuroConstruct

neuroConstruct: biophysically detailed neuronal modelling in 3D
http://www.neuroconstruct.org
GNU General Public License v2.0
48 stars 24 forks source link

Conversion from swc to nml with custom types #67

Open njhulst opened 3 years ago

njhulst commented 3 years ago

Hi there,

I want to assign different parameter values to different regions of the dendrites and therefore want to split my dendrites into two groups: proximal dendrites and distal dendrites. I used type 8 to indicate proximal dendrites and type 7 to indicate distal dendrites in my swc file. Now if I use neuroConstruct to convert my swc file to an nml file, it seems to go wrong, as the nml file contains segment groups that I cannot identify as the ones I made. For example I have 17 nodes with ID 8 in my swc file, but the nml file contains no segment group that contain 17 nodes. Also, it creates a dendrite group, even though I did not make a dendrite group (none of the nodes has ID 3). My questions:

Am I allowed to split dendrites like this or is it invalid in neuroML? If it is allowed, what might be going wrong here?

Both files can be found at: https://github.com/njhulst/IO-temperature-dependence/tree/master/Morphology

pgleeson commented 3 years ago

Have a look here: https://github.com/NeuralEnsemble/neuroConstruct/blob/d94b86afbc88e1ccafcfc0558649d3d194aa8bb6/src/ucl/physiol/neuroconstruct/cell/converters/SWCMorphReader.java#L451-L488

Only point types 0-7 are defined for the neuroConstruct import. Not sure if this is a limitation in the spec itself (documentation on SWC is limited), but if you can use just these values (i.e. not 8) then hopefully what comes out will be closer to what you need...

njhulst commented 3 years ago

Great, that helps, thank you!

njhulst commented 3 years ago

Actually, my segment groups are still not as I would expect. I have custom-1 and custom-2 now, but everything in custom-1 is also in custom-2. And custom-1 is still larger than 17 nodes.

pgleeson commented 3 years ago

So the problem is a bit of a tricky one... the nC import of SWC breaks the list of points into unbranched Sections which are the list of points between where the dendrites split. This is required since these sections are what get mapped to the NEURON sections and the 3D points are added with the pt3d() functions in Neuron, and it's solved with the cable equation in Neuron.

The problem is that some of the points in your swc inside a single unbranched section are 5 and some are 6, e.g. (from neuroConstruct, View cell in 3D and press Cell Info):

Screenshot 2021-02-15 at 16 35 35

so the sections get added to both groups, and so the exported NML has the segments in both segmentGroups

The possible solutions: 1) Change your definitions so the points which are in the proximal groups switch to being in distal group only at branch points 2) Update the swc importer java file to be clever enough to automatically split the section when it sees that it's a new type 3) (long overdue...) Make a pure python reader for SWC that can generate NML2 and is easily extensible (e.g. in here)

njhulst commented 3 years ago

That makes sense, thanks!

pgleeson commented 3 years ago

So FYI for these options: 1) You would need to do this 2) I would probably need to, but it's not on the todo list for now... 3) You could certainly start this off if you felt like it and would be very useful in the longer term if you continue to use SWC & NeuroML...

MRIO commented 3 years ago

Yes indeed, likely useful in the long term, especially if we want to handle the 'continuous cable' directive in a way that allows for heterogeneous channel expression across different simulators. Thanks for your pointer above!

pgleeson commented 3 years ago

@njhulst Ok. If you do plan to go the SWC->NML route via Python (option 3), please do consider making a general purpose one that can go in the pyNeuroML repo. It will be much more useful in the long run for others in the community, rather than the Java/neuroConstruct implementation.

njhulst commented 3 years ago

It is work in progress at the moment, another student has started working on it. We will indeed try and make it general purpose!

sanjayankur31 commented 2 years ago

@MRIO @njhulst : would you have access to any code that's been written for this? It's on my TODO list to complete this task, so any existing code would be useful to start from. Cheers

sanjayankur31 commented 2 years ago

i ran into this repo, which seems to be a start: https://github.com/WardDPeeters/Morphologies

HussainAther commented 5 months ago

Has this ever been addressed? Perhaps we could look at enhancing the "SWCMorphReader.java" for handling custom types better.

private void addGroups(Segment newSeg, int sectionType) {
    switch (sectionType) {
        case 0:
            break;
        case 1:
            newSeg.getSection().addToGroup(Section.SOMA_GROUP);
            newSeg.getSection().addToGroup(somaColourGroup);
            break;
        case 2:
            newSeg.getSection().addToGroup(Section.AXONAL_GROUP);
            newSeg.getSection().addToGroup(axonColourGroup);
            break;
        case 3:
            newSeg.getSection().addToGroup(Section.DENDRITIC_GROUP);
            newSeg.getSection().addToGroup(dendColourGroup);
            break;
        case 4:
            newSeg.getSection().addToGroup("apical_dendrite");
            newSeg.getSection().addToGroup(dendApicalColourGroup);
            break;
        case 5:
            newSeg.getSection().addToGroup("custom-1");
            newSeg.getSection().addToGroup(c1ColourGroup);
            break;
        case 6:
            newSeg.getSection().addToGroup("custom-2");
            newSeg.getSection().addToGroup(c2ColourGroup);
            break;
        case 7:
            newSeg.getSection().addToGroup("proximal_dendrite");
            newSeg.getSection().addToGroup(proximalDendColourGroup);
            break;
        case 8:
            newSeg.getSection().addToGroup("distal_dendrite");
            newSeg.getSection().addToGroup(distalDendColourGroup);
            break;
        default:
            newSeg.getSection().addToGroup("undefined");
            break;
    }
}
HussainAther commented 5 months ago

Alternatively you could create a file "swc_to_nml.py" :

import neuroml
from neuroml import Segment, SegmentGroup, Morphology, Cell
import neuroml.writers as writers

def parse_swc(file_path):
    with open(file_path, 'r') as file:
        lines = file.readlines()

    segments = []
    for line in lines:
        if not line.startswith('#'):
            parts = line.strip().split()
            if len(parts) == 7:
                id, type, x, y, z, radius, parent = map(float, parts)
                segment = Segment(
                    id=int(id),
                    parent=int(parent) if int(parent) != -1 else None,
                    proximal=None,
                    distal=None,
                    name=f"type_{int(type)}",
                    group=f"custom_{int(type)}" if int(type) > 3 else None
                )
                segments.append(segment)

    return segments

def create_neuroml(segments, output_path):
    cell = Cell(id="swc_cell")
    morphology = Morphology(id="morph")
    cell.morphology = morphology

    for segment in segments:
        morphology.segments.append(segment)

    doc = neuroml.NeuroMLDocument(id="swc_to_nml")
    doc.cells.append(cell)

    writers.NeuroMLWriter.write(doc, output_path)
    print(f"NeuroML file written to {output_path}")

if __name__ == "__main__":
    swc_file = "path/to/your/input.swc"
    nml_file = "path/to/your/output.nml"
    segments = parse_swc(swc_file)
    create_neuroml(segments, nml_file)
sanjayankur31 commented 5 months ago

Hi @HussainAther , thanks for your note. We currently have a GSoC intern working on writing a SWC to NML converter and adding it to PyNeuroML. One can follow the progress here and in the PyNeuroML repo:

https://github.com/NeuroML/pyNeuroML/issues/89