Skip to content

Commit 9950c14

Browse files
committed
latest changes (a bit of a mess)
1 parent 9877b65 commit 9950c14

File tree

2 files changed

+359
-66
lines changed

2 files changed

+359
-66
lines changed

needles2/probe_model.py

Lines changed: 147 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
from brainbox.numerical import ismember
33
from oneibl.one import ONE
44
from ibllib.pipes import histology
5-
from ibllib.atlas import AllenAtlas
5+
from ibllib.atlas import AllenAtlas, atlas
66
from ibllib.ephys.neuropixel import TIP_SIZE_UM, SITES_COORDINATES
77
from ibllib.pipes.ephys_alignment import EphysAlignment
88
import time
9+
from scipy.signal import fftconvolve
10+
from ibllib.dsp import fcn_cosine
911

1012
PROV_2_VAL = {
1113
'Resolved': 90,
@@ -28,7 +30,11 @@ def __init__(self, one=None, ba=None):
2830
'Ephys aligned histology track': {},
2931
'Resolved': {},
3032
'Best': {}}
33+
self.ins = {}
3134

35+
# for histology get the insertions and compute the trajectory from them. Means only one
36+
# long query to alyx and use xyz picks for channels and coverage lower down. More complicated
37+
# but will speed things up
3238
self.get_traj_for_provenance(provenance='Histology track', django=['x__isnull,False'])
3339
self.get_traj_for_provenance(provenance='Ephys aligned histology track')
3440
self.get_traj_for_provenance(provenance='Ephys aligned histology track',
@@ -38,13 +44,15 @@ def __init__(self, one=None, ba=None):
3844
self.find_traj_is_best(provenance='Ephys aligned histology track')
3945
self.traj['Resolved']['is_best'] = np.arange(len(self.traj['Resolved']['traj']))
4046

47+
self.get_insertions_with_xyz()
48+
4149
@staticmethod
4250
def get_traj_info(traj):
4351
return traj['probe_insertion'], traj['x'], traj['y']
4452

4553
def get_traj_for_provenance(self, provenance='Histology track', django=None,
4654
prov_dict=None):
47-
55+
start = time.time()
4856
if django is None:
4957
django = []
5058

@@ -62,6 +70,19 @@ def get_traj_for_provenance(self, provenance='Histology track', django=None,
6270
self.traj[prov_dict]['ins'] = np.array(ins_ids)
6371
self.traj[prov_dict]['x'] = np.array(x)
6472
self.traj[prov_dict]['y'] = np.array(y)
73+
end = time.time()
74+
print(end-start)
75+
76+
def get_insertions_with_xyz(self):
77+
start = time.time()
78+
django_str = 'session__project__name__icontains,ibl_neuropixel_brainwide_01,' \
79+
'json__has_key,xyz_picks'
80+
self.ins['insertions'] = self.one.alyx.rest('insertions', 'list', django=django_str)
81+
self.ins['ids'] = np.array([ins['id'] for ins in self.ins['insertions']])
82+
83+
end = time.time()
84+
print(end-start)
85+
6586

6687
def compute_best_for_provenance(self, provenance='Histology track'):
6788
val = PROV_2_VAL[provenance]
@@ -114,39 +135,13 @@ def find_traj_is_best(self, provenance='Histology track'):
114135
self.traj[provenance]['is_best'] = (self.traj[provenance]['is_best']
115136
[np.where(np.invert(isin))[0]])
116137

117-
def get_channels(self, provenance):
118-
119-
depths = SITES_COORDINATES[:, 1]
120-
start = time.time()
121-
122-
# Need to account for case when no insertions for planned and micro can skip the insertions
123-
insertions = []
124-
step = 150
125-
for i in range(np.ceil(self.traj[provenance]['ins'].shape[0] / step).astype(np.int)):
126-
insertions += self.one.alyx.rest(
127-
'insertions', 'list', django=f"id__in,{list(self.traj[provenance]['ins'][i * step:(i + 1) * step])}")
128-
129-
ins_id = np.ravel([np.where(ins['id'] == self.traj[provenance]['ins'])
130-
for ins in insertions])
131-
132-
end = time.time()
133-
print(end-start)
138+
def get_all_channels(self, provenance):
134139

140+
depths = SITES_COORDINATES[:, 1]
135141
start1 = time.time()
136-
for iT, (traj, ins) in enumerate(zip(self.traj[provenance]['traj'][ins_id], insertions)):
142+
for iT, traj in enumerate(self.traj[provenance]['traj']):
137143
try:
138-
xyz_picks = np.array(ins['json']['xyz_picks']) / 1e6
139-
if traj['provenance'] == 'Histology track':
140-
xyz_picks = xyz_picks[np.argsort(xyz_picks[:, 2]), :]
141-
xyz_channels = histology.interpolate_along_track(xyz_picks, (depths + TIP_SIZE_UM) / 1e6)
142-
else:
143-
align_key = ins['json']['extended_qc']['alignment_stored']
144-
feature = traj['json'][align_key][0]
145-
track = traj['json'][align_key][1]
146-
ephysalign = EphysAlignment(xyz_picks, depths, track_prev=track,
147-
feature_prev=feature,
148-
brain_atlas=self.ba, speedy=True)
149-
xyz_channels = ephysalign.get_channel_locations(feature, track)
144+
xyz_channels = xyz_channels = self.get_channels(traj, depths)
150145

151146
if iT == 0:
152147
all_channels = xyz_channels
@@ -158,23 +153,80 @@ def get_channels(self, provenance):
158153

159154
end = time.time()
160155
print(end-start1)
156+
iii = self.ba.bc.xyz2i(all_channels)
157+
keep_idx = np.setdiff1d(np.arange(all_channels.shape[0]), np.unique(np.where(iii < 0)[0]))
158+
return all_channels[keep_idx, :]
159+
160+
def compute_coverage(self, all_channels):
161+
162+
start = time.time()
163+
cvol = np.zeros(self.ba.image.shape, dtype=np.float)
164+
val, counts = np.unique(self.ba._lookup(all_channels), return_counts=True)
165+
cvol[np.unravel_index(val, cvol.shape)] = counts
166+
167+
DIST_FCN = np.array([100, 150]) / 1e6
168+
dx = self.ba.bc.dx
169+
template = np.arange(- np.max(DIST_FCN) - dx, np.max(DIST_FCN) + 2 * dx, dx) ** 2
170+
kernel = sum(np.meshgrid(template, template, template))
171+
kernel = 1 - fcn_cosine(DIST_FCN)(np.sqrt(kernel))
172+
#
173+
cvol = fftconvolve(cvol, kernel)
174+
end = time.time()
175+
print(end-start)
176+
177+
return cvol
178+
179+
def add_coverage(self, x, y, depth=4000, theta=10, phi=180):
180+
traj = {'x': x,
181+
'y': y,
182+
'z': 0.0,
183+
'phi': phi,
184+
'theta': theta,
185+
'depth': depth,
186+
'provenance': 'Planned'}
187+
188+
cov = histology.coverage([traj], self.ba)
189+
return cov, traj
190+
191+
192+
def get_channels(self, traj, depths = None):
193+
if depths is None:
194+
depths = SITES_COORDINATES[:, 1]
195+
if traj['provenance'] == 'Planned' or traj['provenance'] == 'Micro-manipulator':
196+
ins = atlas.Insertion.from_dict(traj)
197+
# Deepest coordinate first
198+
xyz = np.c_[ins.tip, ins.entry].T
199+
xyz_channels = histology.interpolate_along_track(xyz, (depths +
200+
TIP_SIZE_UM) / 1e6)
201+
else:
202+
ins_idx = np.where(traj['probe_insertion'] == self.ins['ids'])[0][0]
203+
xyz = np.array(self.ins['insertions'][ins_idx]['json']['xyz_picks']) / 1e6
204+
if traj['provenance'] == 'Histology track':
205+
xyz = xyz[np.argsort(xyz[:, 2]), :]
206+
xyz_channels = histology.interpolate_along_track(xyz, (depths +
207+
TIP_SIZE_UM) / 1e6)
208+
else:
209+
align_key = (self.ins['insertions'][ins_idx]['json']['extended_qc']
210+
['alignment_stored'])
211+
feature = traj['json'][align_key][0]
212+
track = traj['json'][align_key][1]
213+
ephysalign = EphysAlignment(xyz, depths, track_prev=track,
214+
feature_prev=feature,
215+
brain_atlas=self.ba, speedy=True)
216+
xyz_channels = ephysalign.get_channel_locations(feature, track)
217+
218+
return xyz_channels
219+
220+
def get_brain_regions(self, traj):
221+
depths = SITES_COORDINATES[:, 1]
222+
xyz_channels = self.get_channels(traj, depths)
223+
(region, region_label,
224+
region_colour, _) = EphysAlignment.get_histology_regions(xyz_channels, depths,
225+
brain_atlas=self.ba)
226+
return region, region_label, region_colour
227+
161228

162-
return all_channels
163229

164-
from scipy.signal import fftconvolve
165-
cvol = np.zeros(ba.image.shape, dtype=np.float)
166-
val, counts = np.unique(ba._lookup(all_channels), return_counts=True)
167-
cvol[np.unravel_index(val, cvol.shape)] = counts
168-
#
169-
from ibllib.dsp import fcn_cosine
170-
DIST_FCN = np.array([100, 150]) / 1e6
171-
dx = ba.bc.dx
172-
template = np.arange(- np.max(DIST_FCN) - dx, np.max(DIST_FCN) + 2 * dx, dx) ** 2
173-
kernel = sum(np.meshgrid(template, template, template))
174-
kernel = 1 - fcn_cosine(DIST_FCN)(np.sqrt(kernel))
175-
#
176-
cvol = fftconvolve(cvol, kernel)
177-
#
178230
#
179231
# cvol[np.unravel_index(ba._lookup(all_channels), cvol.shape)] = 1
180232

@@ -188,4 +240,51 @@ def get_channels(self, provenance):
188240
# plt.add(actor)
189241
# plt.show()
190242

191-
243+
#from vedo import *
244+
#from ibllib.atlas import AllenAtlas
245+
#ba = AllenAtlas()
246+
#import numpy as np
247+
#import vtk
248+
#la = ba.label
249+
#la[la != 0] = 1
250+
#vol2 = Volume(la).alpha([0, 0, 0.5])
251+
#vol = Volume(ba.image).alpha([0, 0, 0.8]).c('bone').pickable(False)
252+
##vol = Volume(ba.image).c('bone').pickable(False)
253+
#
254+
#plane = vtk.vtkPlane()
255+
#clipping_planes = vtk.vtkPlaneCollection()
256+
#clipping_planes.AddItem(plane)
257+
#vol2.mapper().SetClippingPlanes(clipping_planes)
258+
##
259+
#plane.SetOrigin(vol.center() + np.array([0, -100, 0]))
260+
#plane.SetNormal(0.5, 0.866, 0)
261+
##
262+
#sl = vol.slicePlane(origin=vol.center() + np.array([0, 100, 50]), normal=(0.5, 0.866, 0))
263+
#s2 = vol.slicePlane(origin=vol.center(), normal=(0.5, 0.866, 0))
264+
#s3 = vol.slicePlane(origin=vol.center() + np.array([0, -100, -50]), normal=(0.5, 0.866, 0)) # this is 30 degree in coronal
265+
##s3 = vol.slicePlane(origin=vol.center(), normal=(0.5, 0, 0.866)) # this is 30 degree in coronal
266+
#
267+
#sl.cmap('Purples_r').lighting('off').addScalarBar(title='Slice', c='w')
268+
#s2.cmap('Blues_r').lighting('off')
269+
#s3.cmap('Greens_r').lighting('off')
270+
#plt = show(vol, vol2, sl, s2, s3, __doc__, axes=9, bg='k', bg2='bb', interactive=False)
271+
#
272+
#interactive()
273+
#
274+
#from vedo.utils import versor
275+
#
276+
#
277+
#from vedo import *
278+
#
279+
#vol = Volume(dataurl+'embryo.slc').alpha([0,0,0.5]).c('k')
280+
#
281+
#slices = []
282+
#for i in range(4):
283+
# sl = vol.slicePlane(origin=[150,150,i*50+50], normal=(-1,0,1))
284+
# slices.append(sl)
285+
#
286+
#amap = [0, 1, 1, 1, 1] # hide low value points giving them alpha 0
287+
#mslices = merge(slices) # merge all slices into a single Mesh
288+
#mslices.cmap('hot_r', alpha=amap).lighting('off').addScalarBar3D()
289+
#
290+
#show(vol, mslices, __doc__, axes=1)

0 commit comments

Comments
 (0)