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

Wrong logical connection points for cell imported from neurolucida file #2973

Open
TorgeW opened this issue Jul 10, 2024 · 6 comments · May be fixed by #2981
Open

Wrong logical connection points for cell imported from neurolucida file #2973

TorgeW opened this issue Jul 10, 2024 · 6 comments · May be fixed by #2981
Assignees
Labels

Comments

@TorgeW
Copy link

TorgeW commented Jul 10, 2024

Context

Its common that define_shape needs to be called when working with and editing cells imported from an neurolucida file.
define_shape will also be called before the visualization in NEURON.

Overview of the issue

When importing a cell from a neurolucida file (.asc) that contains a some described by a contour, the center of this contour will be used as the logical connection point for the connected processes (connected at 0.5). When calling define_shape after importing, the processes will be moved since the soma section center is at a different location then the contour center.
I fixed this for myself by changing the logical connection points after importing to the center of the soma section.

Expected result/behavior

After importing a cell from a neurolucida file, define_shape should not change the cell in any way.

NEURON setup

  • Version: 8.2.4
  • Installation method: pip
  • OS + Version: Ubuntu 22.04.4
  • Compiler + Version: gcc 11.4.0

Minimal working example - MWE

  • python script:
from neuron import h

class Cell:
    pass

cell = Cell()
h.load_file("stdrun.hoc")
h.load_file("import3d.hoc")
nl = h.Import3d_Neurolucida3()
nl.quiet = 1
nl.input('test.asc')
import_neuron = h.Import3d_GUI(nl, 0)
import_neuron.instantiate(cell)

for s in cell.axon:
    for i in range(s.n3d()):
        print(i, s, s.x3d(i), s.y3d(i), s.z3d(i))

h.define_shape()
print('------------------')
for s in cell.axon:
    for i in range(s.n3d()):
        print(i, s, s.x3d(i), s.y3d(i), s.z3d(i))
  • asc file:
("CellBody"
  (Color Red)
  (CellBody)
  (3.80077 3.41923 0 0)  ; 1, 1
  (3.81077 1.71923 0 0)  ; 1, 2
  (6.30077 -1.15077 0 0)  ; 1, 3
  (5.79077 -3.76077 0 0)  ; 1, 4
  (2.48077 -6.86077 0 0)  ; 1, 5
  (-0.849229 -8.24077 0 0)  ; 1, 6
  (-4.37923 -7.22077 0 0)  ; 1, 7
  (-5.62923 -4.94077 0 0)  ; 1, 8
  (-5.19923 -0.95077 0 0)  ; 1, 9
  (-3.06923 4.74923 0 0)  ; 1, 10
  (-1.70923 6.51923 0 0)  ; 1, 11
  (-2.10923 7.95923 0 0)  ; 1, 12
  (0.760771 8.75923 0 0)  ; 1, 13
);

( (Color Blue)
  (Axon)
  (-1.10012 -6.51191 1.75185 1.33)
  (-1.39509 -8.25791 2.22157 1.33)
  (-2.03149 -16.6016 2.41259 0.66)
);
  • script output:
0 <__main__.Cell object at 0x7ff4c6e7ef10>.axon[0] -1.100119948387146 -6.5119099617004395 1.7518500089645386
1 <__main__.Cell object at 0x7ff4c6e7ef10>.axon[0] -1.3950899839401245 -8.257909774780273 2.2215700149536133
2 <__main__.Cell object at 0x7ff4c6e7ef10>.axon[0] -2.0314900875091553 -16.601600646972656 2.4125900268554688
------------------
0 <__main__.Cell object at 0x7ff4c6e7ef10>.axon[0] -1.2292762994766235 -5.1274309158325195 1.7518500089645386
1 <__main__.Cell object at 0x7ff4c6e7ef10>.axon[0] -1.524246335029602 -6.8734307289123535 2.2215700149536133
2 <__main__.Cell object at 0x7ff4c6e7ef10>.axon[0] -2.160646438598633 -15.217121124267578 2.4125900268554688
@nrnhines
Copy link
Member

nrnhines commented Jul 11, 2024

No fix yet, but it seems worthwhile to document some of my diagnostic results so far which more closely isolate the underlying puzzle to me. I.e. why does the logical connection point change (with define_shape) when the soma 3d points do not change. Note that the logical connection point should always track the location of the parent connection (3-d location of center of parent segment). The distance between logical connection point and first 3-d point of a section should be invariant. Thus, when one moves the root section (usually soma) that moves the rest of the tree a corresponding amount (and updates the logical connection point to keep the invariant).

Anyway, what I observe is that the soma 3d points are exactly the same before and after define_shape. Also, of course, that means the average and center of the soma points are the same. However the logical connection point starts out wrong and after define_shape gets updated to be the same as the soma center point.

The observations are:
before diam_shape

average  [-0.5143091442684332, 0.224248896752085, 0.0, 7.583558775129772]
center  [-0.5143091678619385, 0.22424888610839844, 0.0, 2.4370133876800537]
logcon  (1.0, [-0.3851528465747833, -1.1602301597595215, 0.0])

after diam_shape

average  [-0.5143091442684332, 0.224248896752085, 0.0, 7.583558775129772]
center  [-0.5143091678619385, 0.22424888610839844, 0.0, 2.4370133876800537]
logcon  (1.0, [-0.5143091678619385, 0.22424888610839844, 0.0])

Note that the code for those calculations is

def logcon(s):
    lcf = tuple([h.ref(0.) for _ in range(3)])
    lc = h.pt3dstyle(1, *lcf, sec=s)
    return lc, [ref[0] for ref in lcf]

printed by print("logcon ", logcon(cell.axon[0])) and

def vec3d(s):
    vecs =[[] for _ in range(4)] # x, y ,z, d
    for i, f in enumerate([h.x3d, h.y3d, h.z3d, h.diam3d]):
        for j in range(s.n3d()):
            vecs[i].append(f(j))
    return vecs

def paverage():
    soma3d = vec3d(cell.soma[0])
    print("average ", [sum(vec)/len(vec) for vec in soma3d])
    print("center ", [(vec[0] + vec[-1])/2.0 for vec in soma3d])

@nrnhines
Copy link
Member

The problem is that the center of the original soma neurolucida contour is not the same as the center of the processed contour that ends up becoming the linear chain of 3d soma points. The former is

-0.385153	-1.16023	0

and looks like (Note the tip of the green line)
image

and the latter is (see the green dot on the screenshot)

-0.5143091678619385, 0.22424888610839844, 0.0

image

@nrnhines
Copy link
Member

I'm wondering if the least disruptive fix is to construct the processed soma (defined by the h.soma[0] 3-d points) so that the processed soma has the same center as the original neurolucida contour.

@TorgeW
Copy link
Author

TorgeW commented Jul 11, 2024

What would be the issue with updating the style (logical connection points) after the soma section (points) is created from the counter with the real section center?

Setting the processed soma center to the same center as the original neurolucida contour would not work. You would need to translate the full cell then, which would be especially bad because the coordinates from the file wouldnt match the loaded point coordinates anymore, which isnt a problem inn itself but would throw people off for sure.

If you are talking about changing the way the contour is turned into the section, to more closely match the contour shape, that would work I guess if one finds a way to preserve the center in that process, although it would change the soma shape, which is a change that would effect anyone using neurolucida files. While correcting the logical connection points is only noticed when using define shape in combination with neurolucida files.

@nrnhines
Copy link
Member

nrnhines commented Jul 13, 2024

Let me know if you agree with the fix embodied in #2981

@TorgeW
Copy link
Author

TorgeW commented Jul 14, 2024

Looks good to me as far as I understand it.

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