labdata 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {labdata-0.1.0 → labdata-0.1.1}/PKG-INFO +1 -1
- {labdata-0.1.0 → labdata-0.1.1}/labdata/__init__.py +1 -1
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/segmentation.py +212 -116
- labdata-0.1.1/labdata/dashboard/sorting.py +207 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata.egg-info/PKG-INFO +1 -1
- labdata-0.1.0/labdata/dashboard/sorting.py +0 -102
- {labdata-0.1.0 → labdata-0.1.1}/LICENSE +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/README.md +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/cli.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/__init__.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/caiman.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/ec2.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/ephys.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/pose.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/schedulers.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/singularity.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/suite2p.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/compute/utils.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/copy.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/__init__.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/compute.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/console.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/decisiontask.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/explorer/__init__.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/explorer/cellsegmentation.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/explorer/spikesorting.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/index.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/notes.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/procedures.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/dashboard/video.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/export.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/rules/__init__.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/rules/ephys.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/rules/imaging.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/rules/utils.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/s3.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/__init__.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/ephys.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/general.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/histology.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/onephoton.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/procedures.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/tasks.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/twophoton.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/utils.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/schema/video.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/stacks.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/utils.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata/widgets.py +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata.egg-info/SOURCES.txt +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata.egg-info/dependency_links.txt +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata.egg-info/entry_points.txt +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata.egg-info/requires.txt +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/labdata.egg-info/top_level.txt +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/pyproject.toml +0 -0
- {labdata-0.1.0 → labdata-0.1.1}/setup.cfg +0 -0
|
@@ -42,6 +42,18 @@ def segmentation_tab(schema=None):
|
|
|
42
42
|
df['parameter_set_num'] = df['parameter_set_num'].astype(str)
|
|
43
43
|
return df
|
|
44
44
|
|
|
45
|
+
@st.cache_data
|
|
46
|
+
def get_all_sessions():
|
|
47
|
+
rows = (schema.CellSegmentation * schema.Session * schema.CellSegmentationParams).fetch(
|
|
48
|
+
'subject_name', 'session_name', 'dataset_name', 'parameter_set_num',
|
|
49
|
+
'algorithm_name', 'algorithm_version', 'n_rois', 'session_datetime',
|
|
50
|
+
as_dict=True)
|
|
51
|
+
if not rows:
|
|
52
|
+
return pd.DataFrame()
|
|
53
|
+
df = pd.DataFrame(rows)
|
|
54
|
+
df['parameter_set_num'] = df['parameter_set_num'].astype(str)
|
|
55
|
+
return df.sort_values(['subject_name', 'session_datetime']).reset_index(drop=True)
|
|
56
|
+
|
|
45
57
|
@st.cache_data
|
|
46
58
|
def get_sessions(subject_name):
|
|
47
59
|
rows = (schema.CellSegmentation * schema.Session * schema.CellSegmentationParams
|
|
@@ -70,6 +82,42 @@ def segmentation_tab(schema=None):
|
|
|
70
82
|
del r['proj_im']
|
|
71
83
|
return rows
|
|
72
84
|
|
|
85
|
+
@st.cache_data
|
|
86
|
+
def get_roi_color_proj(subject_name, session_name, dataset_name, parameter_set_num,
|
|
87
|
+
sel_method, selected_only):
|
|
88
|
+
from labdata.stacks import roi_color_projection
|
|
89
|
+
key = dict(subject_name=subject_name, session_name=session_name,
|
|
90
|
+
dataset_name=dataset_name, parameter_set_num=parameter_set_num)
|
|
91
|
+
plane_rows = (schema.CellSegmentation.Plane & key).fetch(
|
|
92
|
+
'plane_num', 'dims', as_dict=True)
|
|
93
|
+
results = []
|
|
94
|
+
for plane in plane_rows:
|
|
95
|
+
pnum = plane['plane_num']
|
|
96
|
+
if plane['dims'] is None:
|
|
97
|
+
continue
|
|
98
|
+
plane_key = dict(key, plane_num=pnum)
|
|
99
|
+
roi_table = schema.CellSegmentation.ROI & plane_key
|
|
100
|
+
roi_nums = list(roi_table.fetch('roi_num'))
|
|
101
|
+
if not roi_nums:
|
|
102
|
+
continue
|
|
103
|
+
if selected_only:
|
|
104
|
+
sel_rois = set(
|
|
105
|
+
(schema.CellSegmentation.Selection
|
|
106
|
+
& dict(plane_key, selection_method=sel_method, selection=1)
|
|
107
|
+
).fetch('roi_num'))
|
|
108
|
+
cell_indices = [i for i, rn in enumerate(roi_nums) if rn in sel_rois]
|
|
109
|
+
else:
|
|
110
|
+
cell_indices = list(range(len(roi_nums)))
|
|
111
|
+
if not cell_indices:
|
|
112
|
+
continue
|
|
113
|
+
all_masks = roi_table.get_roi_sparse_masks()
|
|
114
|
+
masks = [all_masks[i] for i in cell_indices]
|
|
115
|
+
rgb = roi_color_projection(masks)
|
|
116
|
+
h, w = rgb.shape[:2]
|
|
117
|
+
results.append(dict(plane_num=pnum, proj_name='roi color',
|
|
118
|
+
url=_to_base64(rgb), h=h, w=w))
|
|
119
|
+
return results
|
|
120
|
+
|
|
73
121
|
@st.cache_data
|
|
74
122
|
def get_selection_methods(subject_name, session_name, dataset_name, parameter_set_num):
|
|
75
123
|
key = dict(subject_name=subject_name, session_name=session_name,
|
|
@@ -109,6 +157,18 @@ def segmentation_tab(schema=None):
|
|
|
109
157
|
db_label=db_label))
|
|
110
158
|
return centers
|
|
111
159
|
|
|
160
|
+
@st.cache_data
|
|
161
|
+
def get_frame_rate(subject_name, session_name, dataset_name):
|
|
162
|
+
key = dict(subject_name=subject_name, session_name=session_name,
|
|
163
|
+
dataset_name=dataset_name)
|
|
164
|
+
for table in (schema.TwoPhoton, schema.Miniscope):
|
|
165
|
+
try:
|
|
166
|
+
frame_rate, n_frames = (table & key).fetch1('frame_rate', 'n_frames')
|
|
167
|
+
return float(frame_rate), int(n_frames)
|
|
168
|
+
except Exception:
|
|
169
|
+
pass
|
|
170
|
+
return 1.0, 0
|
|
171
|
+
|
|
112
172
|
@st.cache_data
|
|
113
173
|
def get_traces(subject_name, session_name, dataset_name, parameter_set_num,
|
|
114
174
|
roi_keys, trace_type):
|
|
@@ -127,7 +187,7 @@ def segmentation_tab(schema=None):
|
|
|
127
187
|
data = (schema.CellSegmentation.RawTraces & roi_key).fetch1('f_trace')
|
|
128
188
|
else:
|
|
129
189
|
data = (schema.CellSegmentation.Deconvolved & roi_key).fetch1('deconv')
|
|
130
|
-
data = np.asarray(data, dtype=float)
|
|
190
|
+
data = np.asarray(data, dtype=float)
|
|
131
191
|
for t, v in enumerate(data):
|
|
132
192
|
traces.append({'t': t, 'value': float(v), 'roi': label})
|
|
133
193
|
except Exception:
|
|
@@ -146,13 +206,8 @@ def segmentation_tab(schema=None):
|
|
|
146
206
|
|
|
147
207
|
# sessions per subject for each parameter_set_num
|
|
148
208
|
counts_df = get_session_counts()
|
|
149
|
-
bar_param_filter = st.session_state.get('seg_bar_param_filter')
|
|
150
209
|
|
|
151
210
|
if not counts_df.empty:
|
|
152
|
-
if st.session_state.pop('seg_bar_clear_pending', False):
|
|
153
|
-
st.session_state.pop('seg_bar_param_filter', None)
|
|
154
|
-
bar_param_filter = None
|
|
155
|
-
|
|
156
211
|
_colors = ['#000000', '#d62728', '#1f77b4', '#ff7f0e', '#2ca02c',
|
|
157
212
|
'#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22']
|
|
158
213
|
param_sets = sorted(counts_df['parameter_set_num'].unique().tolist())
|
|
@@ -179,17 +234,60 @@ def segmentation_tab(schema=None):
|
|
|
179
234
|
pts = (bar_event.selection or {}).get('bar_sel', [])
|
|
180
235
|
if pts and pts[0].get('subject_name'):
|
|
181
236
|
clicked_subject = pts[0]['subject_name']
|
|
182
|
-
clicked_param = str(pts[0].get('parameter_set_num', ''))
|
|
183
237
|
if clicked_subject in subjects:
|
|
184
238
|
st.session_state['seg_subject'] = clicked_subject
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
239
|
+
subj_df = get_all_sessions()
|
|
240
|
+
subj_df = subj_df[subj_df['subject_name'] == clicked_subject]
|
|
241
|
+
if not subj_df.empty:
|
|
242
|
+
first = subj_df.sort_values('session_datetime', ascending=False).iloc[0]
|
|
243
|
+
st.session_state['seg_scatter_sel_key'] = (
|
|
244
|
+
f"{first['session_name']}|{first['dataset_name']}")
|
|
245
|
+
|
|
246
|
+
# All-sessions scatter: animals on Y, dates on X, color by parameter_set_num
|
|
247
|
+
all_sessions_df = get_all_sessions()
|
|
248
|
+
if not all_sessions_df.empty:
|
|
249
|
+
scatter_all_df = all_sessions_df.copy()
|
|
250
|
+
|
|
251
|
+
param_sets_all = sorted(scatter_all_df['parameter_set_num'].unique().tolist())
|
|
252
|
+
_colors = ['#000000', '#d62728', '#1f77b4', '#ff7f0e', '#2ca02c',
|
|
253
|
+
'#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22']
|
|
254
|
+
all_color_scale = alt.Scale(
|
|
255
|
+
domain=param_sets_all,
|
|
256
|
+
range=[_colors[i % len(_colors)] for i in range(len(param_sets_all))])
|
|
257
|
+
|
|
258
|
+
all_scatter_click = alt.selection_point(
|
|
259
|
+
fields=['session_name', 'dataset_name', 'subject_name'], name='all_sess_click')
|
|
260
|
+
n_subjects = scatter_all_df['subject_name'].nunique()
|
|
261
|
+
all_scatter_chart = (
|
|
262
|
+
alt.Chart(scatter_all_df).mark_circle(size=80, opacity=0.7).encode(
|
|
263
|
+
x=alt.X('session_datetime:T', title='Date',
|
|
264
|
+
axis=alt.Axis(tickCount='month', format='%b %Y', labelAngle=-45)),
|
|
265
|
+
y=alt.Y('subject_name:N', title='Subject name', sort='ascending'),
|
|
266
|
+
yOffset=alt.YOffset('jitter:Q', scale=alt.Scale(range=[-12, 12])),
|
|
267
|
+
color=alt.Color('parameter_set_num:N', scale=all_color_scale,
|
|
268
|
+
title='Param set'),
|
|
269
|
+
opacity=alt.condition(all_scatter_click, alt.value(0.9), alt.value(0.35)),
|
|
270
|
+
tooltip=['subject_name:N', 'session_name:N', 'dataset_name:N',
|
|
271
|
+
'parameter_set_num:N',
|
|
272
|
+
alt.Tooltip('session_datetime:T', format='%Y-%m-%d'),
|
|
273
|
+
'n_rois:Q'],
|
|
274
|
+
).transform_calculate(jitter='random() - 0.5')
|
|
275
|
+
.add_params(all_scatter_click)
|
|
276
|
+
.properties(height=max(150, 60 * n_subjects + 60))
|
|
277
|
+
)
|
|
278
|
+
all_scatter_event = st.altair_chart(
|
|
279
|
+
all_scatter_chart, width='stretch', on_select='rerun',
|
|
280
|
+
key='seg_all_scatter')
|
|
281
|
+
|
|
282
|
+
all_pts = (all_scatter_event.selection or {}).get('all_sess_click', [])
|
|
283
|
+
if all_pts and all_pts[0].get('subject_name'):
|
|
284
|
+
clicked_subject = all_pts[0]['subject_name']
|
|
285
|
+
clicked_sname = all_pts[0].get('session_name', '')
|
|
286
|
+
clicked_dname = all_pts[0].get('dataset_name', '')
|
|
287
|
+
if clicked_subject in subjects:
|
|
288
|
+
st.session_state['seg_subject'] = clicked_subject
|
|
289
|
+
if clicked_sname:
|
|
290
|
+
st.session_state['seg_scatter_sel_key'] = f"{clicked_sname}|{clicked_dname}"
|
|
193
291
|
|
|
194
292
|
subject = st.selectbox('Subject', subjects, index=None, key='seg_subject')
|
|
195
293
|
if not subject:
|
|
@@ -200,54 +298,21 @@ def segmentation_tab(schema=None):
|
|
|
200
298
|
st.write('No segmentation sessions found for this subject.')
|
|
201
299
|
return
|
|
202
300
|
|
|
203
|
-
# Apply bar param filter when active
|
|
204
|
-
if bar_param_filter is not None:
|
|
205
|
-
filtered = sessions[
|
|
206
|
-
sessions['parameter_set_num'].astype(str) == str(bar_param_filter)]
|
|
207
|
-
if not filtered.empty:
|
|
208
|
-
sessions = filtered.reset_index(drop=True)
|
|
209
|
-
|
|
210
|
-
# Clear scatter sticky selection when subject changes
|
|
211
|
-
if st.session_state.get('seg_scatter_subject') != subject:
|
|
212
|
-
st.session_state['seg_scatter_subject'] = subject
|
|
213
|
-
st.session_state.pop('seg_scatter_sel_key', None)
|
|
214
|
-
|
|
215
|
-
_colors = ['#000000', '#d62728', '#1f77b4', '#ff7f0e', '#2ca02c',
|
|
216
|
-
'#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22']
|
|
217
|
-
scatter_df = sessions.copy()
|
|
218
|
-
scatter_df['parameter_set_num'] = scatter_df['parameter_set_num'].astype(str)
|
|
219
|
-
param_sets_s = sorted(scatter_df['parameter_set_num'].unique().tolist())
|
|
220
|
-
sess_color_scale = alt.Scale(
|
|
221
|
-
domain=param_sets_s,
|
|
222
|
-
range=[_colors[i % len(_colors)] for i in range(len(param_sets_s))])
|
|
223
|
-
|
|
224
|
-
scatter_click = alt.selection_point(
|
|
225
|
-
fields=['session_name', 'dataset_name'], name='sess_click')
|
|
226
|
-
scatter_chart = (
|
|
227
|
-
alt.Chart(scatter_df).mark_circle(size=120).encode(
|
|
228
|
-
x=alt.X('session_datetime:T', title='Date'),
|
|
229
|
-
y=alt.Y('parameter_set_num:N', title='Param set'),
|
|
230
|
-
color=alt.Color('parameter_set_num:N', scale=sess_color_scale,
|
|
231
|
-
title='Param set'),
|
|
232
|
-
opacity=alt.condition(scatter_click, alt.value(1.0), alt.value(0.4)),
|
|
233
|
-
tooltip=['session_name:N', 'dataset_name:N', 'parameter_set_num:N',
|
|
234
|
-
alt.Tooltip('session_datetime:T', format='%Y-%m-%d'),
|
|
235
|
-
'n_rois:Q'],
|
|
236
|
-
).add_params(scatter_click).properties(height=150)
|
|
237
|
-
)
|
|
238
|
-
scatter_event = st.altair_chart(scatter_chart, width='stretch', on_select='rerun',
|
|
239
|
-
key='seg_scatter_timeline')
|
|
240
301
|
|
|
241
|
-
|
|
302
|
+
# Resolve scatter selection before rendering the table so we can pre-select the row
|
|
303
|
+
stored = st.session_state.get('seg_scatter_sel_key', '')
|
|
242
304
|
scatter_sel_idx = None
|
|
243
|
-
if
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
(sessions['dataset_name'] == dname)]
|
|
305
|
+
if stored:
|
|
306
|
+
parts = stored.split('|', 1)
|
|
307
|
+
matches = sessions[(sessions['session_name'] == parts[0]) &
|
|
308
|
+
(sessions['dataset_name'] == parts[1])]
|
|
248
309
|
if not matches.empty:
|
|
249
310
|
scatter_sel_idx = int(matches.index[0])
|
|
250
|
-
|
|
311
|
+
|
|
312
|
+
# Pre-select the table row only when the scatter key is freshly set
|
|
313
|
+
if scatter_sel_idx is not None and stored != st.session_state.get('seg_scatter_applied_key'):
|
|
314
|
+
st.session_state['seg_sessions_table'] = {'selection': {'rows': [scatter_sel_idx], 'columns': []}}
|
|
315
|
+
st.session_state['seg_scatter_applied_key'] = stored
|
|
251
316
|
|
|
252
317
|
event_sess = st.dataframe(
|
|
253
318
|
sessions, hide_index=True, width='stretch',
|
|
@@ -260,14 +325,7 @@ def segmentation_tab(schema=None):
|
|
|
260
325
|
elif scatter_sel_idx is not None:
|
|
261
326
|
sel_idx_final = scatter_sel_idx
|
|
262
327
|
else:
|
|
263
|
-
|
|
264
|
-
if stored:
|
|
265
|
-
parts = stored.split('|', 1)
|
|
266
|
-
matches = sessions[(sessions['session_name'] == parts[0]) &
|
|
267
|
-
(sessions['dataset_name'] == parts[1])]
|
|
268
|
-
sel_idx_final = int(matches.index[0]) if not matches.empty else None
|
|
269
|
-
else:
|
|
270
|
-
sel_idx_final = None
|
|
328
|
+
sel_idx_final = None
|
|
271
329
|
|
|
272
330
|
if sel_idx_final is None:
|
|
273
331
|
return
|
|
@@ -282,6 +340,7 @@ def segmentation_tab(schema=None):
|
|
|
282
340
|
if st.session_state.get('seg_current_key') != seg_key_id:
|
|
283
341
|
st.session_state['seg_current_key'] = seg_key_id
|
|
284
342
|
st.session_state['seg_picked_rois'] = []
|
|
343
|
+
st.session_state.pop('seg_selection_editor', None)
|
|
285
344
|
for k in list(st.session_state.keys()):
|
|
286
345
|
if k.startswith('seg_last_click_'):
|
|
287
346
|
del st.session_state[k]
|
|
@@ -291,9 +350,6 @@ def segmentation_tab(schema=None):
|
|
|
291
350
|
with st.spinner('Loading projections…'):
|
|
292
351
|
projections = get_projections(
|
|
293
352
|
subject, row['session_name'], row['dataset_name'], param_set)
|
|
294
|
-
if not projections:
|
|
295
|
-
st.write('No projections found for this session.')
|
|
296
|
-
return
|
|
297
353
|
|
|
298
354
|
# ROI display controls
|
|
299
355
|
methods = get_selection_methods(
|
|
@@ -302,14 +358,14 @@ def segmentation_tab(schema=None):
|
|
|
302
358
|
if 'seg_sel_method_pending' in st.session_state:
|
|
303
359
|
st.session_state['seg_sel_method'] = st.session_state.pop('seg_sel_method_pending')
|
|
304
360
|
|
|
305
|
-
cA, cB, cC = st.columns([1, 1, 2])
|
|
306
|
-
show_rois
|
|
307
|
-
show_mode
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
sel_method
|
|
311
|
-
|
|
312
|
-
|
|
361
|
+
cA, cB, cC, cD = st.columns([1, 1, 1, 2])
|
|
362
|
+
show_rois = cA.toggle('Show ROI centers', value=True, key='seg_show_rois')
|
|
363
|
+
show_mode = cB.radio('ROIs to show', ['All', 'Selected'], horizontal=True,
|
|
364
|
+
key='seg_show_mode', label_visibility='collapsed')
|
|
365
|
+
show_traces = cC.toggle('Show traces', value=True, key='seg_show_traces')
|
|
366
|
+
sel_method = cD.selectbox('Selection method', methods, key='seg_sel_method',
|
|
367
|
+
label_visibility='collapsed',
|
|
368
|
+
disabled=not show_rois)
|
|
313
369
|
|
|
314
370
|
# Duplicate / delete selection methods
|
|
315
371
|
_, _, dC = st.columns([1, 1, 2])
|
|
@@ -335,6 +391,7 @@ def segmentation_tab(schema=None):
|
|
|
335
391
|
[{**r, 'selection_method': nm} for r in src_rows])
|
|
336
392
|
get_selection_methods.clear()
|
|
337
393
|
get_roi_data.clear()
|
|
394
|
+
get_roi_color_proj.clear()
|
|
338
395
|
st.session_state['seg_sel_method_pending'] = nm
|
|
339
396
|
st.rerun()
|
|
340
397
|
except Exception as exc:
|
|
@@ -355,6 +412,7 @@ def segmentation_tab(schema=None):
|
|
|
355
412
|
schema.dj.config['safemode'] = True # re-enable
|
|
356
413
|
get_selection_methods.clear()
|
|
357
414
|
get_roi_data.clear()
|
|
415
|
+
get_roi_color_proj.clear()
|
|
358
416
|
st.session_state.pop('seg_del_confirm', None)
|
|
359
417
|
st.rerun()
|
|
360
418
|
except Exception as exc:
|
|
@@ -367,6 +425,13 @@ def segmentation_tab(schema=None):
|
|
|
367
425
|
centers = get_roi_data(
|
|
368
426
|
subject, row['session_name'], row['dataset_name'], param_set, sel_method)
|
|
369
427
|
|
|
428
|
+
with st.spinner('Loading ROI color projection…'):
|
|
429
|
+
roi_color_projs = get_roi_color_proj(
|
|
430
|
+
subject, row['session_name'], row['dataset_name'], param_set, sel_method,
|
|
431
|
+
selected_only=(show_mode == 'Selected'))
|
|
432
|
+
|
|
433
|
+
all_projections = roi_color_projs + list(projections)
|
|
434
|
+
|
|
370
435
|
picked: list = st.session_state['seg_picked_rois']
|
|
371
436
|
|
|
372
437
|
color_domain = ['cell', 'not cell', 'unclassified', 'picked']
|
|
@@ -374,13 +439,18 @@ def segmentation_tab(schema=None):
|
|
|
374
439
|
size_domain = ['cell', 'not cell', 'unclassified', 'picked']
|
|
375
440
|
size_range = [80, 80, 60, 160]
|
|
376
441
|
|
|
377
|
-
# projection tabs
|
|
378
|
-
|
|
442
|
+
# projection tabs — 'roi color' first (default), then others sorted
|
|
443
|
+
_other_names = sorted(set(r['proj_name'] for r in projections))
|
|
444
|
+
proj_names = (['roi color'] if roi_color_projs else []) + _other_names
|
|
445
|
+
if not proj_names:
|
|
446
|
+
st.write('No projections found for this session.')
|
|
447
|
+
return
|
|
448
|
+
|
|
379
449
|
proj_tabs = st.tabs(proj_names)
|
|
380
450
|
|
|
381
451
|
for tab, pname in zip(proj_tabs, proj_names):
|
|
382
452
|
with tab:
|
|
383
|
-
plane_imgs = sorted([r for r in
|
|
453
|
+
plane_imgs = sorted([r for r in all_projections if r['proj_name'] == pname],
|
|
384
454
|
key=lambda r: r['plane_num'])
|
|
385
455
|
cols = st.columns(max(1, len(plane_imgs)))
|
|
386
456
|
for col, r in zip(cols, plane_imgs):
|
|
@@ -444,9 +514,10 @@ def segmentation_tab(schema=None):
|
|
|
444
514
|
else:
|
|
445
515
|
display = img_layer
|
|
446
516
|
|
|
517
|
+
display = display.properties(width=350, height=350, title=f'Plane {pnum}').interactive()
|
|
518
|
+
|
|
447
519
|
event = col.altair_chart(
|
|
448
|
-
display
|
|
449
|
-
title=f'Plane {pnum}').interactive(),
|
|
520
|
+
display,
|
|
450
521
|
on_select='rerun',
|
|
451
522
|
key=f'seg_scatter_{pname}_{pnum}',
|
|
452
523
|
width='content',
|
|
@@ -464,23 +535,26 @@ def segmentation_tab(schema=None):
|
|
|
464
535
|
entry = {'plane_num': int(pnum_click), 'roi_num': int(roi_num)}
|
|
465
536
|
if entry in picked:
|
|
466
537
|
picked.remove(entry)
|
|
467
|
-
|
|
538
|
+
else:
|
|
468
539
|
picked.append(entry)
|
|
469
540
|
st.session_state['seg_picked_rois'] = picked
|
|
470
541
|
get_traces.clear()
|
|
471
542
|
|
|
472
|
-
# traces
|
|
543
|
+
# traces
|
|
473
544
|
if not picked:
|
|
474
|
-
st.caption(
|
|
545
|
+
st.caption('Click ROI dots on the projection to select traces.')
|
|
475
546
|
return
|
|
476
547
|
|
|
477
548
|
st.divider()
|
|
478
549
|
|
|
550
|
+
plot_picked = picked[-MAX_PICKED:]
|
|
551
|
+
|
|
479
552
|
hA, hB = st.columns([3, 1])
|
|
480
|
-
hA.write(f'**
|
|
481
|
-
+ ' '.join(f'plane {p["plane_num"]}, roi {p["roi_num"]}' for p in
|
|
553
|
+
hA.write(f'**ROIs** (plotting last {len(plot_picked)} of {len(picked)} selected): '
|
|
554
|
+
+ ' '.join(f'plane {p["plane_num"]}, roi {p["roi_num"]}' for p in plot_picked))
|
|
482
555
|
if hB.button('Clear all', key='seg_clear_picked'):
|
|
483
556
|
st.session_state['seg_picked_rois'] = []
|
|
557
|
+
st.session_state.pop('seg_selection_editor', None)
|
|
484
558
|
get_traces.clear()
|
|
485
559
|
st.rerun()
|
|
486
560
|
|
|
@@ -493,39 +567,60 @@ def segmentation_tab(schema=None):
|
|
|
493
567
|
st.rerun()
|
|
494
568
|
|
|
495
569
|
trace_type = st.radio('Trace', ['dff', 'F', 'deconv'],
|
|
496
|
-
horizontal=True, key='seg_trace_type'
|
|
570
|
+
horizontal=True, key='seg_trace_type',
|
|
571
|
+
disabled=not show_traces)
|
|
497
572
|
|
|
498
|
-
roi_keys = tuple((p['plane_num'], p['roi_num']) for p in
|
|
573
|
+
roi_keys = tuple((p['plane_num'], p['roi_num']) for p in plot_picked)
|
|
499
574
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
575
|
+
if show_traces:
|
|
576
|
+
with st.spinner('Loading traces…'):
|
|
577
|
+
traces_df = get_traces(subject, row['session_name'], row['dataset_name'],
|
|
578
|
+
param_set, roi_keys, trace_type)
|
|
503
579
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
.
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
580
|
+
if traces_df.empty:
|
|
581
|
+
st.write(f'No `{trace_type}` traces found for the selected ROIs.')
|
|
582
|
+
else:
|
|
583
|
+
frame_rate, _ = get_frame_rate(subject, row['session_name'], row['dataset_name'])
|
|
584
|
+
traces_df = traces_df.copy()
|
|
585
|
+
traces_df['t_sec'] = traces_df['t'] / frame_rate
|
|
586
|
+
|
|
587
|
+
window_s = 300.0
|
|
588
|
+
total_s = float(traces_df['t_sec'].max())
|
|
589
|
+
if total_s > window_s:
|
|
590
|
+
max_start = round(total_s - window_s, 2)
|
|
591
|
+
_lc, _sc = st.columns([1, 11])
|
|
592
|
+
_lc.markdown('**Time (s)**')
|
|
593
|
+
t_start = _sc.slider('Time (s)', 0.0, max_start, 0.0, step=30.0,
|
|
594
|
+
key='seg_trace_window', label_visibility='collapsed')
|
|
595
|
+
else:
|
|
596
|
+
t_start = 0.0
|
|
597
|
+
t_end = t_start + window_s
|
|
598
|
+
|
|
599
|
+
view_df = traces_df[
|
|
600
|
+
(traces_df['t_sec'] >= t_start) & (traces_df['t_sec'] <= t_end)]
|
|
601
|
+
trace_chart = (
|
|
602
|
+
alt.Chart(view_df)
|
|
603
|
+
.mark_line(strokeWidth=1.2)
|
|
604
|
+
.encode(
|
|
605
|
+
x=alt.X('t_sec:Q', title='Time (s)',
|
|
606
|
+
scale=alt.Scale(domain=[t_start, t_end]),
|
|
607
|
+
axis=alt.Axis(tickCount=5, tickSize=5, grid=False)),
|
|
608
|
+
y=alt.Y('value:Q', title=trace_type,
|
|
609
|
+
axis=alt.Axis(tickCount=5, tickSize=5, grid=False)),
|
|
610
|
+
color=alt.Color('roi:N', title='ROI',
|
|
611
|
+
scale=alt.Scale(
|
|
612
|
+
range=['#000000', '#d62728', '#1f77b4', '#ff7f0e',
|
|
613
|
+
'#2ca02c', '#9467bd', '#8c564b', '#e377c2',
|
|
614
|
+
'#7f7f7f', '#bcbd22'])),
|
|
615
|
+
tooltip=['roi:N', alt.Tooltip('t_sec:Q', title='Time (s)', format='.2f'),
|
|
616
|
+
alt.Tooltip('value:Q', format='.4f')],
|
|
617
|
+
)
|
|
618
|
+
.properties(height=220)
|
|
521
619
|
)
|
|
522
|
-
.
|
|
523
|
-
.add_params(zoom_x)
|
|
524
|
-
)
|
|
525
|
-
st.altair_chart(trace_chart, width='stretch')
|
|
620
|
+
st.altair_chart(trace_chart, width='stretch')
|
|
526
621
|
|
|
527
622
|
# classification editor
|
|
528
|
-
st.write('**
|
|
623
|
+
st.write('**ROI classification**')
|
|
529
624
|
sel_rows = []
|
|
530
625
|
for p in picked:
|
|
531
626
|
roi_key = dict(seg_key, plane_num=p['plane_num'], roi_num=p['roi_num'])
|
|
@@ -558,7 +653,8 @@ def segmentation_tab(schema=None):
|
|
|
558
653
|
except Exception as exc:
|
|
559
654
|
st.error(f'Error updating plane {erow["plane"]} roi {erow["roi"]}: {exc}')
|
|
560
655
|
if changed:
|
|
561
|
-
get_roi_data.clear()
|
|
562
656
|
st.success(f'Updated {changed} ROI classification(s).')
|
|
657
|
+
get_roi_data.clear()
|
|
658
|
+
get_roi_color_proj.clear()
|
|
563
659
|
st.rerun()
|
|
564
660
|
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import streamlit as st
|
|
3
|
+
import numpy as np
|
|
4
|
+
import altair as alt
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
colors = ['#1f77b4',
|
|
8
|
+
'#ff7f0e',
|
|
9
|
+
'#d62728',
|
|
10
|
+
'#2ca02c',
|
|
11
|
+
'#9467bd',
|
|
12
|
+
'#8c564b',
|
|
13
|
+
'#e377c2',
|
|
14
|
+
'#7f7f7f',
|
|
15
|
+
'#bcbd22']
|
|
16
|
+
|
|
17
|
+
def sorting_tab(schema=None):
|
|
18
|
+
|
|
19
|
+
@st.cache_data
|
|
20
|
+
def get_all_sorting_sessions():
|
|
21
|
+
rows = (schema.SpikeSorting * schema.Session).fetch(
|
|
22
|
+
'subject_name', 'session_name', 'dataset_name',
|
|
23
|
+
'parameter_set_num', 'session_datetime', as_dict=True)
|
|
24
|
+
if not rows:
|
|
25
|
+
return pd.DataFrame()
|
|
26
|
+
df = pd.DataFrame(rows).drop_duplicates(
|
|
27
|
+
subset=['subject_name', 'session_name', 'dataset_name', 'parameter_set_num'])
|
|
28
|
+
df['parameter_set_num'] = df['parameter_set_num'].astype(str)
|
|
29
|
+
return df.sort_values(['subject_name', 'session_datetime']).reset_index(drop=True)
|
|
30
|
+
|
|
31
|
+
@st.cache_data
|
|
32
|
+
def get_session_counts():
|
|
33
|
+
rows = (schema.Subject * schema.SpikeSortingParams).aggr(
|
|
34
|
+
schema.SpikeSorting,
|
|
35
|
+
n_sessions='count(session_name)'
|
|
36
|
+
).fetch(as_dict=True)
|
|
37
|
+
if not rows:
|
|
38
|
+
return pd.DataFrame()
|
|
39
|
+
df = pd.DataFrame(rows)
|
|
40
|
+
df = df[df['n_sessions'] > 0].reset_index(drop=True)
|
|
41
|
+
df['parameter_set_num'] = df['parameter_set_num'].astype(str)
|
|
42
|
+
return df
|
|
43
|
+
|
|
44
|
+
pars = schema.SpikeSortingParams().fetch(format='frame')[['algorithm_name', 'parameters_dict']]
|
|
45
|
+
pars.insert(0, 'Select', False)
|
|
46
|
+
edited_df = st.data_editor(pars.sort_index(),
|
|
47
|
+
hide_index=False,
|
|
48
|
+
disabled=['parameter_set_num',
|
|
49
|
+
'algorithm_name',
|
|
50
|
+
'parameters_dict'])
|
|
51
|
+
sessions = schema.SpikeSorting().fetch(format='frame').reset_index()
|
|
52
|
+
par_sets = edited_df[edited_df.Select == 1].reset_index()
|
|
53
|
+
from functools import partial
|
|
54
|
+
st.button('Update unit counts',
|
|
55
|
+
on_click=partial(schema.UnitCount.populate, display_progress=True))
|
|
56
|
+
|
|
57
|
+
# histogram: session counts per subject
|
|
58
|
+
counts_df = get_session_counts()
|
|
59
|
+
if not counts_df.empty:
|
|
60
|
+
# filter to selected param sets if any are chosen
|
|
61
|
+
if len(par_sets):
|
|
62
|
+
selected_params = par_sets.parameter_set_num.astype(str).tolist()
|
|
63
|
+
counts_filt = counts_df[counts_df['parameter_set_num'].isin(selected_params)]
|
|
64
|
+
else:
|
|
65
|
+
counts_filt = counts_df
|
|
66
|
+
|
|
67
|
+
if not counts_filt.empty:
|
|
68
|
+
param_sets_h = sorted(counts_filt['parameter_set_num'].unique().tolist())
|
|
69
|
+
bar_color_scale = alt.Scale(
|
|
70
|
+
domain=param_sets_h,
|
|
71
|
+
range=[colors[i % len(colors)] for i in range(len(param_sets_h))])
|
|
72
|
+
|
|
73
|
+
bar_sel = alt.selection_point(
|
|
74
|
+
fields=['subject_name', 'parameter_set_num'], name='bar_sel')
|
|
75
|
+
bar_chart = (
|
|
76
|
+
alt.Chart(counts_filt).mark_bar().encode(
|
|
77
|
+
x=alt.X('subject_name:N', sort='ascending', title='Subject'),
|
|
78
|
+
xOffset=alt.XOffset('parameter_set_num:N', title='Param set'),
|
|
79
|
+
y=alt.Y('n_sessions:Q', title='# sessions'),
|
|
80
|
+
color=alt.Color('parameter_set_num:N', title='Param set',
|
|
81
|
+
scale=bar_color_scale),
|
|
82
|
+
opacity=alt.condition(bar_sel, alt.value(1.0), alt.value(0.4)),
|
|
83
|
+
tooltip=['subject_name:N', 'parameter_set_num:N', 'n_sessions:Q'],
|
|
84
|
+
).add_params(bar_sel).properties(height=200)
|
|
85
|
+
)
|
|
86
|
+
bar_event = st.altair_chart(bar_chart, width='stretch', on_select='rerun',
|
|
87
|
+
key='srt_sessions_bar')
|
|
88
|
+
|
|
89
|
+
bar_pts = (bar_event.selection or {}).get('bar_sel', [])
|
|
90
|
+
if bar_pts and bar_pts[0].get('subject_name'):
|
|
91
|
+
clicked_subj = bar_pts[0]['subject_name']
|
|
92
|
+
current = list(st.session_state.get('srt_subjects', []))
|
|
93
|
+
if clicked_subj not in current:
|
|
94
|
+
current.append(clicked_subj)
|
|
95
|
+
st.session_state['srt_subjects'] = current
|
|
96
|
+
|
|
97
|
+
# all-sessions scatter
|
|
98
|
+
all_sessions_df = get_all_sorting_sessions()
|
|
99
|
+
if not all_sessions_df.empty:
|
|
100
|
+
scatter_df = all_sessions_df.copy()
|
|
101
|
+
if len(par_sets):
|
|
102
|
+
selected_params = par_sets.parameter_set_num.astype(str).tolist()
|
|
103
|
+
flt = scatter_df[scatter_df['parameter_set_num'].isin(selected_params)]
|
|
104
|
+
if not flt.empty:
|
|
105
|
+
scatter_df = flt.reset_index(drop=True)
|
|
106
|
+
|
|
107
|
+
param_sets_s = sorted(scatter_df['parameter_set_num'].unique().tolist())
|
|
108
|
+
scat_color_scale = alt.Scale(
|
|
109
|
+
domain=param_sets_s,
|
|
110
|
+
range=[colors[i % len(colors)] for i in range(len(param_sets_s))])
|
|
111
|
+
|
|
112
|
+
n_subjects = scatter_df['subject_name'].nunique()
|
|
113
|
+
scat_sel = alt.selection_point(
|
|
114
|
+
fields=['subject_name', 'session_name', 'dataset_name'], name='srt_scat_sel')
|
|
115
|
+
scat_chart = (
|
|
116
|
+
alt.Chart(scatter_df).mark_circle(size=80, opacity=0.7).encode(
|
|
117
|
+
x=alt.X('session_datetime:T', title='Date',
|
|
118
|
+
axis=alt.Axis(tickCount='month', format='%b %Y', labelAngle=-45)),
|
|
119
|
+
y=alt.Y('subject_name:N', title='Subject name', sort='ascending'),
|
|
120
|
+
yOffset=alt.YOffset('jitter:Q', scale=alt.Scale(range=[-12, 12])),
|
|
121
|
+
color=alt.Color('parameter_set_num:N', scale=scat_color_scale,
|
|
122
|
+
title='Param set'),
|
|
123
|
+
opacity=alt.condition(scat_sel, alt.value(0.9), alt.value(0.35)),
|
|
124
|
+
tooltip=['subject_name:N', 'session_name:N', 'parameter_set_num:N',
|
|
125
|
+
alt.Tooltip('session_datetime:T', format='%Y-%m-%d')],
|
|
126
|
+
).transform_calculate(jitter='random() - 0.5')
|
|
127
|
+
.add_params(scat_sel)
|
|
128
|
+
.properties(height=max(150, 60 * n_subjects + 60))
|
|
129
|
+
)
|
|
130
|
+
scat_event = st.altair_chart(scat_chart, width='stretch', on_select='rerun',
|
|
131
|
+
key='srt_sessions_scatter')
|
|
132
|
+
|
|
133
|
+
scat_pts = (scat_event.selection or {}).get('srt_scat_sel', [])
|
|
134
|
+
if scat_pts and scat_pts[0].get('subject_name'):
|
|
135
|
+
clicked_subj = scat_pts[0]['subject_name']
|
|
136
|
+
current = list(st.session_state.get('srt_subjects', []))
|
|
137
|
+
if clicked_subj not in current:
|
|
138
|
+
current.append(clicked_subj)
|
|
139
|
+
st.session_state['srt_subjects'] = current
|
|
140
|
+
|
|
141
|
+
# subject/unit-count
|
|
142
|
+
selected_subjects = []
|
|
143
|
+
if len(par_sets):
|
|
144
|
+
sess = []
|
|
145
|
+
for p in par_sets.parameter_set_num.values:
|
|
146
|
+
sess.append(sessions[sessions.parameter_set_num == p])
|
|
147
|
+
sess = pd.concat(sess)
|
|
148
|
+
subjects = np.unique(sess.subject_name.values)
|
|
149
|
+
|
|
150
|
+
sesdict = []
|
|
151
|
+
for p in par_sets.parameter_set_num.values:
|
|
152
|
+
for subj in subjects:
|
|
153
|
+
sub = sessions[(sessions.subject_name == subj) &
|
|
154
|
+
(sessions.parameter_set_num == p)]
|
|
155
|
+
sesdict.append({'subject_name': subj,
|
|
156
|
+
'number_of_sessions': len(sub),
|
|
157
|
+
'parameter_set_num': p,
|
|
158
|
+
'number_of_probes': len(np.unique(sub.probe_num.values))})
|
|
159
|
+
sesdict = pd.DataFrame(sesdict)
|
|
160
|
+
if not len(sesdict):
|
|
161
|
+
return
|
|
162
|
+
|
|
163
|
+
selected_subjects = st.multiselect('Select subject:', subjects,
|
|
164
|
+
key='srt_subjects')
|
|
165
|
+
|
|
166
|
+
criteria_ids = schema.UnitCountCriteria().fetch(as_dict=True)
|
|
167
|
+
if not len(criteria_ids):
|
|
168
|
+
st.write('Add a UnitCountCriteria to the table: example '
|
|
169
|
+
'"isi_contamination < 0.1 & amplitude_cutoff < 0.1 & '
|
|
170
|
+
'spike_duration > 0.1 & spike_amplitude > 50 & presence_ratio > 0.6"')
|
|
171
|
+
return
|
|
172
|
+
selection = st.selectbox('Unit count criteria:',
|
|
173
|
+
[f'[{c["unit_criteria_id"]}] -> {c["sua_criteria"]}'
|
|
174
|
+
for c in criteria_ids])
|
|
175
|
+
if '->' in selection:
|
|
176
|
+
unit_criteria = int(int(selection.split('->')[0].strip(' []')))
|
|
177
|
+
else:
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
@st.cache_data
|
|
181
|
+
def get_unit_counts(s, p, unit_criteria):
|
|
182
|
+
return pd.DataFrame(
|
|
183
|
+
schema.UnitCount() * schema.Session() * schema.EphysRecording.ProbeSetting()
|
|
184
|
+
& dict(subject_name=s, parameter_set_num=p, unit_criteria_id=unit_criteria))
|
|
185
|
+
|
|
186
|
+
if len(selected_subjects):
|
|
187
|
+
units = []
|
|
188
|
+
for p in par_sets.parameter_set_num.values:
|
|
189
|
+
for s in selected_subjects:
|
|
190
|
+
units.append(get_unit_counts(s, p, unit_criteria))
|
|
191
|
+
if not len(units):
|
|
192
|
+
return
|
|
193
|
+
unit_counts = pd.concat(units).set_index('subject_name')
|
|
194
|
+
N = len(colors)
|
|
195
|
+
cc = np.array([colors[0] for c in np.arange(len(unit_counts.probe_id.values))])
|
|
196
|
+
for i, p in enumerate(np.unique(unit_counts.probe_id)):
|
|
197
|
+
idx = np.where(unit_counts.probe_id.values == p)[0]
|
|
198
|
+
cc[idx] = colors[np.mod(i, N)]
|
|
199
|
+
unit_counts['probe_color'] = cc
|
|
200
|
+
st.scatter_chart(unit_counts,
|
|
201
|
+
x='session_datetime', y='all',
|
|
202
|
+
x_label='Session date', y_label='Number of units',
|
|
203
|
+
color='probe_color', size=30)
|
|
204
|
+
st.scatter_chart(unit_counts,
|
|
205
|
+
x='session_datetime', y='sua',
|
|
206
|
+
x_label='Session date', y_label='Number of single units',
|
|
207
|
+
color='probe_color', size=30)
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import streamlit as st
|
|
3
|
-
import numpy as np
|
|
4
|
-
|
|
5
|
-
colors = ['#1f77b4',
|
|
6
|
-
'#ff7f0e',
|
|
7
|
-
'#d62728',
|
|
8
|
-
'#2ca02c',
|
|
9
|
-
'#9467bd',
|
|
10
|
-
'#8c564b',
|
|
11
|
-
'#e377c2',
|
|
12
|
-
'#7f7f7f',
|
|
13
|
-
'#bcbd22']
|
|
14
|
-
|
|
15
|
-
def sorting_tab(schema = None):
|
|
16
|
-
pars = schema.SpikeSortingParams().fetch(format='frame')[['algorithm_name','parameters_dict']]
|
|
17
|
-
pars.insert(0, "Select", False)
|
|
18
|
-
edited_df = st.data_editor(pars.sort_index(),
|
|
19
|
-
hide_index=False,
|
|
20
|
-
disabled = ['parameter_set_num',
|
|
21
|
-
'algorithm_name',
|
|
22
|
-
'parameters_dict'])
|
|
23
|
-
sessions = schema.SpikeSorting().fetch(format = 'frame').reset_index()
|
|
24
|
-
par_sets = edited_df[edited_df.Select == 1].reset_index()
|
|
25
|
-
from functools import partial
|
|
26
|
-
st.button('Update unit counts',on_click = partial(schema.UnitCount.populate,display_progress = True))
|
|
27
|
-
|
|
28
|
-
selected_subjects = []
|
|
29
|
-
if len(par_sets):
|
|
30
|
-
sess = []
|
|
31
|
-
for p in par_sets.parameter_set_num.values:
|
|
32
|
-
sess.append(sessions[sessions.parameter_set_num == p])
|
|
33
|
-
sess = pd.concat(sess)
|
|
34
|
-
subjects = np.unique(sess.subject_name.values)
|
|
35
|
-
sesdict = []
|
|
36
|
-
for p in par_sets.parameter_set_num.values:
|
|
37
|
-
for subj in subjects:
|
|
38
|
-
sub = sessions[(sessions.subject_name == subj) & (sessions.parameter_set_num == p)]
|
|
39
|
-
sesdict.append({'subject_name' : subj,
|
|
40
|
-
'number_of_sessions': len(sub),
|
|
41
|
-
'parameter_set_num': p,
|
|
42
|
-
'number_of_probes':len(np.unique(sub.probe_num.values))})
|
|
43
|
-
sesdict = pd.DataFrame(sesdict)
|
|
44
|
-
if not len(sesdict):
|
|
45
|
-
return
|
|
46
|
-
# st.bar_chart(sesdict.set_index('subject_name'),y='number_of_sessions')
|
|
47
|
-
import altair as alt
|
|
48
|
-
ch = (alt.Chart(sesdict).mark_bar().encode(
|
|
49
|
-
y = 'subject_name:N', #alt.Y(,type = 'nominal'),
|
|
50
|
-
x = 'number_of_sessions:Q',#alt.X(,type = 'quantitative'),
|
|
51
|
-
color='parameter_set_num:N').configure_axis(labelLimit=3000))#alt.Color('color',type = 'nominal')))
|
|
52
|
-
st.altair_chart(ch,width="stretch")
|
|
53
|
-
selected_subjects = st.multiselect('Select subject:',subjects)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
criteria_ids = schema.UnitCountCriteria().fetch(as_dict = True)
|
|
58
|
-
if not len(criteria_ids):
|
|
59
|
-
st.write('Add a UnitCountCriteria to the table: example "isi_contamination < 0.1 & amplitude_cutoff < 0.1 & spike_duration > 0.1 & spike_amplitude > 50 & presence_ratio > 0.6"')
|
|
60
|
-
return
|
|
61
|
-
selection = st.selectbox('Unit count criteria:',
|
|
62
|
-
[f'[{c["unit_criteria_id"]}] -> {c["sua_criteria"]}' for c in criteria_ids])
|
|
63
|
-
if '->' in selection:
|
|
64
|
-
unit_criteria = int(int(selection.split('->')[0].strip(' []')))
|
|
65
|
-
else:
|
|
66
|
-
return
|
|
67
|
-
@st.cache_data
|
|
68
|
-
def get_unit_counts(s,p,unit_criteria):
|
|
69
|
-
return pd.DataFrame(schema.UnitCount()*schema.Session()*schema.EphysRecording.ProbeSetting() & dict(
|
|
70
|
-
subject_name = s,
|
|
71
|
-
parameter_set_num = p,
|
|
72
|
-
unit_criteria_id = unit_criteria))
|
|
73
|
-
|
|
74
|
-
if len(selected_subjects):
|
|
75
|
-
units = []
|
|
76
|
-
for p in par_sets.parameter_set_num.values:
|
|
77
|
-
for s in selected_subjects:
|
|
78
|
-
units.append(get_unit_counts(s,p,unit_criteria))
|
|
79
|
-
if not len(units):
|
|
80
|
-
return
|
|
81
|
-
unit_counts = pd.concat(units).set_index('subject_name')
|
|
82
|
-
# make the probe color
|
|
83
|
-
N = len(colors)
|
|
84
|
-
cc = np.array([colors[0] for c in np.arange(len(unit_counts.probe_id.values))])
|
|
85
|
-
for i,p in enumerate(np.unique(unit_counts.probe_id)):
|
|
86
|
-
idx = np.where(unit_counts.probe_id.values == p)[0]
|
|
87
|
-
cc[idx] = colors[np.mod(i,N)]
|
|
88
|
-
unit_counts['probe_color'] = cc
|
|
89
|
-
st.scatter_chart(unit_counts,
|
|
90
|
-
x = 'session_datetime',
|
|
91
|
-
y = 'all',
|
|
92
|
-
x_label = 'Session date',
|
|
93
|
-
y_label = 'Number of units',
|
|
94
|
-
color = 'probe_color',
|
|
95
|
-
size = 30)
|
|
96
|
-
st.scatter_chart(unit_counts,
|
|
97
|
-
x = 'session_datetime',
|
|
98
|
-
y = 'sua',
|
|
99
|
-
x_label = 'Session date',
|
|
100
|
-
y_label = 'Number of single units',
|
|
101
|
-
color = 'probe_color',
|
|
102
|
-
size = 30)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|