labdata 0.1.7__tar.gz → 0.1.8__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.7 → labdata-0.1.8}/PKG-INFO +1 -1
- labdata-0.1.8/labdata/__init__.py +15 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/cli.py +5 -2
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/utils.py +2 -1
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/decisiontask.py +87 -3
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/index.py +20 -1
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/segmentation.py +4 -3
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/sorting.py +211 -127
- labdata-0.1.8/labdata/dashboard/video.py +554 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/onephoton.py +2 -2
- {labdata-0.1.7 → labdata-0.1.8}/labdata.egg-info/PKG-INFO +1 -1
- labdata-0.1.7/labdata/__init__.py +0 -11
- labdata-0.1.7/labdata/dashboard/video.py +0 -119
- {labdata-0.1.7 → labdata-0.1.8}/LICENSE +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/README.md +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/__init__.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/caiman.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/ec2.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/ephys.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/pose.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/schedulers.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/singularity.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/compute/suite2p.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/copy.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/__init__.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/admin.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/compute.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/console.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/explorer/__init__.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/explorer/cellsegmentation.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/explorer/spikesorting.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/notes.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/procedures.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/dashboard/schema_graph.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/export.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/rules/__init__.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/rules/ephys.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/rules/imaging.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/rules/utils.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/s3.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/__init__.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/ephys.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/general.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/histology.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/procedures.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/tasks.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/twophoton.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/utils.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/schema/video.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/stacks.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/utils.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata/widgets.py +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata.egg-info/SOURCES.txt +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata.egg-info/dependency_links.txt +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata.egg-info/entry_points.txt +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata.egg-info/requires.txt +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/labdata.egg-info/top_level.txt +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/pyproject.toml +0 -0
- {labdata-0.1.7 → labdata-0.1.8}/setup.cfg +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
VERSION = "0.1.8"
|
|
2
|
+
|
|
3
|
+
from .utils import *
|
|
4
|
+
from .copy import copy_to_upload_server
|
|
5
|
+
from .s3 import copy_to_s3
|
|
6
|
+
|
|
7
|
+
_project = (prefs.get('database', {}) or {}).get('database.project', None)
|
|
8
|
+
if 'LABDATA_DATABASE_PROJECT' in os.environ.keys():
|
|
9
|
+
if len(os.environ['LABDATA_DATABASE_PROJECT']):
|
|
10
|
+
_project = os.environ['LABDATA_DATABASE_PROJECT']
|
|
11
|
+
|
|
12
|
+
plugins = load_plugins(project=_project)
|
|
13
|
+
for _name, _mod in plugins.items():
|
|
14
|
+
globals()[_name] = _mod
|
|
15
|
+
|
|
@@ -91,15 +91,18 @@ Server commands (don't run on experimental computers):
|
|
|
91
91
|
open_browser = True)
|
|
92
92
|
else:
|
|
93
93
|
import subprocess as sub
|
|
94
|
+
import os
|
|
94
95
|
main_webpage_path = Path(__file__).parent / 'dashboard' / 'index.py'
|
|
95
|
-
command = f'streamlit run {str(main_webpage_path)}'
|
|
96
|
+
command = f'streamlit run --server.showEmailPrompt=False --browser.gatherUsageStats=False {str(main_webpage_path)}'
|
|
97
|
+
if 'LABDATA_VERBOSE' in os.environ.keys():
|
|
98
|
+
print(f'Running streamlit dashboard: {command}')
|
|
96
99
|
if not args.project is None:
|
|
97
100
|
command += f' project={args.project}'
|
|
98
101
|
if args.console:
|
|
99
102
|
command += ' console=1'
|
|
100
103
|
if args.admin:
|
|
101
104
|
command += ' admin=1'
|
|
102
|
-
sub.run(command
|
|
105
|
+
sub.run(command,shell=True)
|
|
103
106
|
|
|
104
107
|
def subjects(self):
|
|
105
108
|
parser = argparse.ArgumentParser(
|
|
@@ -279,7 +279,8 @@ class BaseCompute():
|
|
|
279
279
|
self.dataset_key = None
|
|
280
280
|
self.is_container = False
|
|
281
281
|
if allow_s3 is None:
|
|
282
|
-
|
|
282
|
+
allow_s3 = prefs['allow_s3_download']
|
|
283
|
+
self.allow_s3 = allow_s3
|
|
283
284
|
if 'LABDATA_CONTAINER' in os.environ.keys():
|
|
284
285
|
# then it is running inside a container
|
|
285
286
|
self.is_container = True
|
|
@@ -105,7 +105,8 @@ def decisionmaking_tab(schema = None):
|
|
|
105
105
|
date_str = end_date.strftime('%Y-%m-%d')
|
|
106
106
|
date_filter = (f'session_datetime > (DATE("{date_str}") - INTERVAL 3 MONTH) '
|
|
107
107
|
f'AND DATE(session_datetime) <= "{date_str}"')
|
|
108
|
-
summarysource = pd.DataFrame((schema.Session*schema.DecisionTask.TrialSet()
|
|
108
|
+
summarysource = pd.DataFrame((schema.Session * schema.DecisionTask.TrialSet() * schema.Subject() & keys
|
|
109
|
+
& 'trialset_description NOT LIKE "%opto%"'
|
|
109
110
|
& date_filter).fetch())
|
|
110
111
|
if not len(summarysource):
|
|
111
112
|
return []
|
|
@@ -113,14 +114,66 @@ def decisionmaking_tab(schema = None):
|
|
|
113
114
|
lambda x: x.strftime("%y-%m-%d"))
|
|
114
115
|
return summarysource
|
|
115
116
|
|
|
116
|
-
|
|
117
|
+
@st.cache_data
|
|
118
|
+
def get_session_setups(selected_indices, end_date):
|
|
119
|
+
keys = [dict(subject_name=i) for i in selected_indices]
|
|
120
|
+
date_str = end_date.strftime('%Y-%m-%d')
|
|
121
|
+
date_filter = (f'session_datetime > (DATE("{date_str}") - INTERVAL 3 MONTH) '
|
|
122
|
+
f'AND DATE(session_datetime) <= "{date_str}"')
|
|
123
|
+
try:
|
|
124
|
+
df = pd.DataFrame(
|
|
125
|
+
(schema.Session() * schema.Dataset() & keys & date_filter).fetch(
|
|
126
|
+
'subject_name', 'session_name', 'setup_name', as_dict=True)
|
|
127
|
+
)
|
|
128
|
+
if len(df):
|
|
129
|
+
return (df.dropna(subset=['setup_name'])
|
|
130
|
+
.drop_duplicates(['subject_name', 'session_name'])
|
|
131
|
+
[['subject_name', 'session_name', 'setup_name']])
|
|
132
|
+
except Exception:
|
|
133
|
+
pass
|
|
134
|
+
return pd.DataFrame(columns=['subject_name', 'session_name', 'setup_name'])
|
|
135
|
+
|
|
136
|
+
@st.cache_data
|
|
137
|
+
def get_sort_data(subject_names):
|
|
138
|
+
keys = [dict(subject_name=s) for s in subject_names]
|
|
139
|
+
try:
|
|
140
|
+
subjects_df = pd.DataFrame(
|
|
141
|
+
(schema.Subject() & keys).fetch('subject_name', 'subject_dob', 'strain_name', as_dict=True)
|
|
142
|
+
)
|
|
143
|
+
except Exception:
|
|
144
|
+
subjects_df = pd.DataFrame({'subject_name': list(subject_names)})
|
|
145
|
+
try:
|
|
146
|
+
last_setups = pd.DataFrame(
|
|
147
|
+
(schema.Session() * schema.Dataset() & keys).fetch(
|
|
148
|
+
'subject_name', 'session_datetime', 'setup_name', as_dict=True)
|
|
149
|
+
)
|
|
150
|
+
if len(last_setups):
|
|
151
|
+
last_setups = (last_setups.sort_values('session_datetime')
|
|
152
|
+
.drop_duplicates('subject_name', keep='last')
|
|
153
|
+
[['subject_name', 'setup_name']])
|
|
154
|
+
subjects_df = subjects_df.merge(last_setups, on='subject_name', how='left')
|
|
155
|
+
else:
|
|
156
|
+
subjects_df['setup_name'] = None
|
|
157
|
+
except Exception:
|
|
158
|
+
subjects_df['setup_name'] = None
|
|
159
|
+
return subjects_df
|
|
160
|
+
|
|
161
|
+
ctrl_col, date_col, sort_col, _ = st.columns([1, 2, 2, 5])
|
|
117
162
|
with ctrl_col:
|
|
118
163
|
if st.button('Refresh', icon=':material/refresh:'):
|
|
119
164
|
get_max_date.clear()
|
|
120
165
|
get_subjects_last_ran.clear()
|
|
121
166
|
get_summary_data.clear()
|
|
167
|
+
get_sort_data.clear()
|
|
168
|
+
get_session_setups.clear()
|
|
122
169
|
with date_col:
|
|
123
170
|
end_date = st.date_input('End date', value=get_max_date(), label_visibility='collapsed')
|
|
171
|
+
with sort_col:
|
|
172
|
+
lbl, sel = st.columns([1, 2])
|
|
173
|
+
lbl.markdown('Sort by')
|
|
174
|
+
with sel:
|
|
175
|
+
sort_by = st.selectbox('Sort by', ['Name', 'Age', 'Strain', 'Last setup'],
|
|
176
|
+
label_visibility='collapsed')
|
|
124
177
|
|
|
125
178
|
if end_date is None:
|
|
126
179
|
return
|
|
@@ -137,6 +190,33 @@ def decisionmaking_tab(schema = None):
|
|
|
137
190
|
st.write('Could not find sessions for the specified dates..')
|
|
138
191
|
return
|
|
139
192
|
|
|
193
|
+
# Merge per-session setup into summary
|
|
194
|
+
setup_df = get_session_setups(tuple(selected_indices), end_date)
|
|
195
|
+
if len(setup_df):
|
|
196
|
+
summarysource = summarysource.merge(setup_df, on=['subject_name', 'session_name'], how='left')
|
|
197
|
+
|
|
198
|
+
# Compute Y-axis sort order
|
|
199
|
+
if sort_by == 'Last setup' and 'setup_name' in summarysource.columns:
|
|
200
|
+
last_setup = (summarysource[['subject_name', 'session_datetime', 'setup_name']]
|
|
201
|
+
.dropna(subset=['setup_name'])
|
|
202
|
+
.sort_values('session_datetime')
|
|
203
|
+
.drop_duplicates('subject_name', keep='last'))
|
|
204
|
+
ordered = last_setup.sort_values('setup_name')['subject_name'].tolist()
|
|
205
|
+
sort_order = ordered + [s for s in selected_indices if s not in ordered]
|
|
206
|
+
else:
|
|
207
|
+
sort_field_map = {
|
|
208
|
+
'Name': ('subject_name', True),
|
|
209
|
+
'Age': ('subject_dob', True),
|
|
210
|
+
'Strain': ('strain_name', True),
|
|
211
|
+
}
|
|
212
|
+
sort_field, ascending = sort_field_map.get(sort_by, ('subject_name', True))
|
|
213
|
+
sort_df = get_sort_data(tuple(selected_indices))
|
|
214
|
+
if sort_field in sort_df.columns:
|
|
215
|
+
sort_order = (sort_df[sort_df['subject_name'].isin(selected_indices)]
|
|
216
|
+
.sort_values(sort_field, ascending=ascending)['subject_name'].tolist())
|
|
217
|
+
else:
|
|
218
|
+
sort_order = sorted(selected_indices)
|
|
219
|
+
|
|
140
220
|
# Build heatmap chart
|
|
141
221
|
has_perf = 'performance_easy' in summarysource.columns and 'performance' in summarysource.columns
|
|
142
222
|
point_selector = alt.selection_point(on="click")
|
|
@@ -144,6 +224,10 @@ def decisionmaking_tab(schema = None):
|
|
|
144
224
|
scale=alt.Scale(scheme='spectral', reverse=True, domain=[0.5,1], clamp=True)).title('Perf easy')
|
|
145
225
|
if has_perf else alt.value('#4477AA'))
|
|
146
226
|
tooltip_fields = ['subject_name:N', 'session_name:N', 'session_datetime:T']
|
|
227
|
+
if 'strain_name' in summarysource.columns:
|
|
228
|
+
tooltip_fields.append('strain_name:N')
|
|
229
|
+
if 'setup_name' in summarysource.columns:
|
|
230
|
+
tooltip_fields.append('setup_name:N')
|
|
147
231
|
if has_perf:
|
|
148
232
|
tooltip_fields += ['performance_easy:Q', 'performance:Q']
|
|
149
233
|
if 'n_trials' in summarysource.columns:
|
|
@@ -151,7 +235,7 @@ def decisionmaking_tab(schema = None):
|
|
|
151
235
|
chart = alt.Chart(summarysource).mark_rect().encode(
|
|
152
236
|
x=alt.X('session_datetime:T', timeUnit='yearmonthdate',
|
|
153
237
|
scale=alt.Scale(nice={'interval': 'day', 'step': 1})).axis(labelAngle=45, format='%Y-%m-%d').title('Date'),
|
|
154
|
-
y=alt.Y('subject_name:O').title('Subject name'),
|
|
238
|
+
y=alt.Y('subject_name:O', sort=sort_order).title('Subject name'),
|
|
155
239
|
color=color_enc,
|
|
156
240
|
tooltip=tooltip_fields,
|
|
157
241
|
).properties(title='Behavioral performance').add_params(point_selector)
|
|
@@ -289,4 +289,23 @@ tab_name = st.sidebar.radio(
|
|
|
289
289
|
index=_tab_options.index(_tab_default),
|
|
290
290
|
key='sidebar_tab')
|
|
291
291
|
|
|
292
|
-
|
|
292
|
+
try:
|
|
293
|
+
page_names_to_funcs[tab_name]()
|
|
294
|
+
except Exception as _e:
|
|
295
|
+
import pymysql, datajoint as dj
|
|
296
|
+
def _is_mysql_err(exc):
|
|
297
|
+
return isinstance(exc, pymysql.err.Error) or (
|
|
298
|
+
hasattr(exc, '__cause__') and isinstance(exc.__cause__, pymysql.err.Error))
|
|
299
|
+
if _is_mysql_err(_e):
|
|
300
|
+
try:
|
|
301
|
+
conn = dj.conn()
|
|
302
|
+
if conn._conn is not None:
|
|
303
|
+
try:
|
|
304
|
+
conn._conn.close()
|
|
305
|
+
except Exception:
|
|
306
|
+
pass
|
|
307
|
+
conn.connect()
|
|
308
|
+
except Exception:
|
|
309
|
+
pass
|
|
310
|
+
st.rerun()
|
|
311
|
+
raise
|
|
@@ -584,6 +584,7 @@ def segmentation_tab(schema=None):
|
|
|
584
584
|
return cell_list.index(tup)
|
|
585
585
|
return -1
|
|
586
586
|
|
|
587
|
+
_btn_clicked = False
|
|
587
588
|
nav_prev, nav_next, *_ = st.columns([1, 1, 6])
|
|
588
589
|
if nav_prev.button('**p**rev cell', key='seg_prev_cell', disabled=not cell_list):
|
|
589
590
|
idx = _nav_cursor()
|
|
@@ -591,14 +592,14 @@ def segmentation_tab(schema=None):
|
|
|
591
592
|
pn, rn = cell_list[idx]
|
|
592
593
|
st.session_state['seg_picked_rois'] = [{'plane_num': pn, 'roi_num': rn}]
|
|
593
594
|
get_traces.clear()
|
|
594
|
-
|
|
595
|
+
_btn_clicked = True
|
|
595
596
|
if nav_next.button('**n**ext cell', key='seg_next_cell', disabled=not cell_list):
|
|
596
597
|
idx = _nav_cursor()
|
|
597
598
|
idx = (idx + 1) % len(cell_list)
|
|
598
599
|
pn, rn = cell_list[idx]
|
|
599
600
|
st.session_state['seg_picked_rois'] = [{'plane_num': pn, 'roi_num': rn}]
|
|
600
601
|
get_traces.clear()
|
|
601
|
-
|
|
602
|
+
_btn_clicked = True
|
|
602
603
|
|
|
603
604
|
# Keyboard: w or p/s or n = prev/next cell, d/a = time forward/back
|
|
604
605
|
_kb_html = """
|
|
@@ -714,7 +715,7 @@ def segmentation_tab(schema=None):
|
|
|
714
715
|
width='content',
|
|
715
716
|
)
|
|
716
717
|
|
|
717
|
-
if scatter is not None:
|
|
718
|
+
if scatter is not None and not _btn_clicked:
|
|
718
719
|
click_key = f'seg_last_click_{pname}_{pnum}'
|
|
719
720
|
current_click = (event.selection or {}).get('roi_click', [])
|
|
720
721
|
if current_click and current_click != st.session_state.get(click_key, []):
|