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

Conversion from swc to nml with custom types #67

Open
njhulst opened this issue Feb 11, 2021 · 14 comments
Open

Conversion from swc to nml with custom types #67

njhulst opened this issue Feb 11, 2021 · 14 comments

Comments

@njhulst
Copy link

njhulst commented Feb 11, 2021

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
Copy link
Member

Have a look here:

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("custom-n");
newSeg.getSection().addToGroup(c3ColourGroup);
break;
default:
newSeg.getSection().addToGroup("undefined");
break;

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
Copy link
Author

njhulst commented Feb 11, 2021

Great, that helps, thank you!

@njhulst njhulst closed this as completed Feb 11, 2021
@njhulst njhulst reopened this Feb 11, 2021
@njhulst
Copy link
Author

njhulst commented Feb 11, 2021

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
Copy link
Member

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
Copy link
Author

njhulst commented Feb 17, 2021

That makes sense, thanks!

@pgleeson
Copy link
Member

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
Copy link

MRIO commented Feb 25, 2021

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
Copy link
Member

@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
Copy link
Author

njhulst commented Mar 9, 2021

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
Copy link

@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
Copy link

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

@HussainAther
Copy link

HussainAther commented Jun 14, 2024

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
Copy link

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
Copy link

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:

NeuroML/pyNeuroML#89

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants