petersaj / neuropixels_trajectory_explorer

Neuropixels trajectory explorer with the Allen CCF mouse atlas
GNU General Public License v3.0
68 stars 25 forks source link

The .mat save file no longer gives area name for each channel #24

Closed ngrujic closed 3 months ago

ngrujic commented 3 months ago

Hi, the old version used to give me a brain region per probe channel, but this seems to have been removed?

I now only have the coordinates for each area in the probe_positions.mat file.

This was super useful to not have to do additional coding but just plug in during analysis

petersaj commented 3 months ago

Right that was removed a while ago, it has the disadvantage that you need some code when loading to assign channel to region, but it has advantages, e.g.

Good that you asked though, I see that somehow a previous change was lost which I've now built back in:

It now saves area border locations as distance from tip of the shank (probe_areas{probe #}.tip_distance = [area start, area end]), with negative numbers being off/past the shank, and positive numbers being towards the headstage. i.e. an area with tip_distance = [-2,1.5] means the borders of that area are from 2mm down past the probe tip to 1.5mm up from the probe tip.

This was important because distance of channel from tip is easy to get from the kilosort channel map, but distance from insertion point is arbitrary and not related to anything absolute on the probe.

So if you wanted to use the NTE areas at face value, you can assign channels to areas with something like this in Matlab:

%  Load channel positions from Kilosort output
channel_positions = readNPY("(kilosort output path)\channel_positions.npy");

% Assign each channel to area by position bins
probe_number = 1;
[area_bins_sorted,area_bins_sort_idx] = sort(probe_areas{probe_number}.tip_distance(:,1));
channel_area_bin = discretize(channel_positions(:,2)/1000,area_bins_sorted);

% Grab area acronym for each channel 
channel_area = cell(size(channel_positions,1),1);
channel_area(~isnan(channel_area_bin)) = probe_areas{1}.acronym(area_bins_sort_idx(channel_area_bin(~isnan(channel_area_bin))));

All that being said - I would take the saved NTE areas with a massive grain of salt. These areas are always a rough estimate, and always at least a little wrong, so ideally they would only be used as quick/preliminary analysis and histology would be used in any real analysis.

I could potentially save which channels each area likely corresponds to, although I'm having trouble finding where master Neuropixels channel maps are stored (looks like there isn't a standard, but Kilosort/SpikeInterface save their own versions). I'm not sure many people would use this feature though (and it would be completely wrong with selectable channels).

Let me know if all this makes sense or if you've got ideas for this.

ngrujic commented 3 months ago

Hey, thanks for the comprehensive reply. Indeed, I only use the NTE output for a general idea of unit locations while I'm running acute experiments on a mouse before doing histology.

I have implemented already a similar code as what you suggest, it really wasn't much trouble, just was slightly more convenient before, but as you said ultimately unnecessary.

However, would be quite a useful thing potentially after cross-referencing with histology rather than inputting areas manually. Not sure what people do once they get the trajectory of the probe from histology to assign units to areas with high channel npx recordings, but I was planning to replicate the brain slice trajectory in NTE and use the output.

petersaj commented 3 months ago

Ah that's an interesting approach to use the NTE to pull out histology areas. I have a different toolbox for doing that: https://github.com/petersaj/AP_histology, this goes from histology directly to the CCF without needing to go through the NTE first. Might be easier to do something like that, since it takes out the middleman application.

I'll close this issue for now, but feel free to let me know if you have other ideas or questions.

Tevin-yue commented 3 weeks ago

Hi, it is a wonderful function in fact. One more problem with the saved .mat file is that the nested structure seems hard for Python to read, whether using scipy or h5py. Is it possible to save it with h5py or a higher version? (loadmat cannot parse the complex nested structure, for example, the cell of the table). Another question, can you give more information about the probe tip consideration, specifically the triangular tip to the first channel (175 µm)? How does the NTE deal with that?

petersaj commented 2 weeks ago

Unfortunately I'm not versed enough in Python to add a more Python-friendly save format, it sounds like it would need a restructuring since Python can't read Matlab tables, so I don't think I'd be able to add that any time soon.

For the probe tip relative to channels: the NTE doesn't give any channel-specific information, it only gives the areas along the probe relative to the probe tip. It also saves them in this format, so any assignment of areas to channels would be done with the channel Y-positions. That being said: error between your actual and estimated trajectories is likely big enough that assigning areas to channels just based on the estimated trajectory won't be accurate.