labdata 0.0.25__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.0.25 → labdata-0.1.1}/PKG-INFO +1 -1
- labdata-0.1.1/labdata/__init__.py +11 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/cli.py +4 -0
- labdata-0.1.1/labdata/dashboard/console.py +166 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/decisiontask.py +11 -12
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/index.py +8 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/segmentation.py +308 -62
- labdata-0.1.1/labdata/dashboard/sorting.py +207 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/utils.py +42 -3
- {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/PKG-INFO +1 -1
- {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/SOURCES.txt +1 -0
- labdata-0.0.25/labdata/__init__.py +0 -16
- labdata-0.0.25/labdata/dashboard/sorting.py +0 -102
- {labdata-0.0.25 → labdata-0.1.1}/LICENSE +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/README.md +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/__init__.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/caiman.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/ec2.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/ephys.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/pose.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/schedulers.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/singularity.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/suite2p.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/utils.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/copy.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/__init__.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/compute.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/explorer/__init__.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/explorer/cellsegmentation.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/explorer/spikesorting.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/notes.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/procedures.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/video.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/export.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/__init__.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/ephys.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/imaging.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/utils.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/s3.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/__init__.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/ephys.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/general.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/histology.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/onephoton.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/procedures.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/tasks.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/twophoton.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/utils.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/video.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/stacks.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata/widgets.py +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/dependency_links.txt +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/entry_points.txt +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/requires.txt +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/top_level.txt +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/pyproject.toml +0 -0
- {labdata-0.0.25 → labdata-0.1.1}/setup.cfg +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
VERSION = "0.1.1"
|
|
2
|
+
|
|
3
|
+
from .utils import *
|
|
4
|
+
from .copy import copy_to_upload_server
|
|
5
|
+
from .s3 import copy_to_s3
|
|
6
|
+
|
|
7
|
+
_default_project = (prefs.get('database', {}) or {}).get('database.project', None)
|
|
8
|
+
plugins = load_plugins(project=_default_project)
|
|
9
|
+
for _name, _mod in plugins.items():
|
|
10
|
+
globals()[_name] = _mod
|
|
11
|
+
|
|
@@ -60,6 +60,8 @@ Server commands (don't run on experimental computers):
|
|
|
60
60
|
parser.add_argument('--spike-sorting' ,action = 'store_true', default = False)
|
|
61
61
|
parser.add_argument('--cell-segmentation' ,action = 'store_true', default = False)
|
|
62
62
|
parser.add_argument('--debug' ,action = 'store_true', default = False, help = 'To debug the dash (dashboard) errors.')
|
|
63
|
+
parser.add_argument('--console', action = 'store_true', default = False,
|
|
64
|
+
help = 'Include the IPython console tab in the dashboard.')
|
|
63
65
|
project = _get_project()
|
|
64
66
|
parser.add_argument('-p','--project',
|
|
65
67
|
default = project,
|
|
@@ -91,6 +93,8 @@ Server commands (don't run on experimental computers):
|
|
|
91
93
|
command = f'streamlit run {str(main_webpage_path)}'
|
|
92
94
|
if not args.project is None:
|
|
93
95
|
command += f' project={args.project}'
|
|
96
|
+
if args.console:
|
|
97
|
+
command += ' console=1'
|
|
94
98
|
sub.run(command.split(' '))
|
|
95
99
|
|
|
96
100
|
def subjects(self):
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import streamlit as st
|
|
2
|
+
import base64
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _execute_silent(kc, code):
|
|
6
|
+
"""Fire-and-forget execution (used for kernel init)."""
|
|
7
|
+
kc.execute(code, silent=True)
|
|
8
|
+
while True:
|
|
9
|
+
try:
|
|
10
|
+
msg = kc.get_iopub_msg(timeout=60)
|
|
11
|
+
except Exception:
|
|
12
|
+
break
|
|
13
|
+
if (msg['msg_type'] == 'status' and
|
|
14
|
+
msg['content'].get('execution_state') == 'idle'):
|
|
15
|
+
break
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _execute(kc, code):
|
|
19
|
+
"""Execute code and collect text outputs, inline images, and errors."""
|
|
20
|
+
kc.execute(code)
|
|
21
|
+
outputs = [] # list of (kind, text) kind in ('stream','result')
|
|
22
|
+
images = [] # list of base-64 PNG strings
|
|
23
|
+
error = None
|
|
24
|
+
while True:
|
|
25
|
+
try:
|
|
26
|
+
msg = kc.get_iopub_msg(timeout=60)
|
|
27
|
+
except Exception:
|
|
28
|
+
break
|
|
29
|
+
mtype = msg['msg_type']
|
|
30
|
+
content = msg['content']
|
|
31
|
+
if mtype == 'stream':
|
|
32
|
+
outputs.append(('stream', content['text']))
|
|
33
|
+
elif mtype in ('execute_result', 'display_data'):
|
|
34
|
+
img = content['data'].get('image/png')
|
|
35
|
+
if img:
|
|
36
|
+
images.append(img)
|
|
37
|
+
else:
|
|
38
|
+
text = content['data'].get('text/plain', '')
|
|
39
|
+
if text:
|
|
40
|
+
outputs.append(('result', text))
|
|
41
|
+
elif mtype == 'error':
|
|
42
|
+
error = '\n'.join(content['traceback'])
|
|
43
|
+
elif mtype == 'status' and content.get('execution_state') == 'idle':
|
|
44
|
+
break
|
|
45
|
+
return outputs, images, error
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _start_kernel(project_name):
|
|
49
|
+
import jupyter_client
|
|
50
|
+
km = jupyter_client.KernelManager(kernel_name='python3')
|
|
51
|
+
km.start_kernel()
|
|
52
|
+
kc = km.client()
|
|
53
|
+
kc.start_channels()
|
|
54
|
+
kc.wait_for_ready(timeout=60)
|
|
55
|
+
|
|
56
|
+
# Configure matplotlib for inline PNG output, then preload labdata
|
|
57
|
+
init_lines = [
|
|
58
|
+
"import matplotlib",
|
|
59
|
+
"matplotlib.use('Agg')",
|
|
60
|
+
"import pylab as plt",
|
|
61
|
+
"%matplotlib inline",
|
|
62
|
+
]
|
|
63
|
+
if project_name:
|
|
64
|
+
init_lines += [
|
|
65
|
+
"import os",
|
|
66
|
+
f"os.environ['LABDATA_DATABASE_PROJECT'] = {project_name!r}",
|
|
67
|
+
]
|
|
68
|
+
init_lines += [
|
|
69
|
+
"from labdata import *",
|
|
70
|
+
"from labdata.schema import *",
|
|
71
|
+
]
|
|
72
|
+
_execute_silent(kc, '\n'.join(init_lines))
|
|
73
|
+
|
|
74
|
+
st.session_state['_console_km'] = km
|
|
75
|
+
st.session_state['_console_kc'] = kc
|
|
76
|
+
st.session_state['_console_hist'] = []
|
|
77
|
+
st.session_state['_console_n'] = 0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _shutdown_kernel():
|
|
81
|
+
km = st.session_state.pop('_console_km', None)
|
|
82
|
+
st.session_state.pop('_console_kc', None)
|
|
83
|
+
st.session_state.pop('_console_hist', None)
|
|
84
|
+
st.session_state.pop('_console_n', None)
|
|
85
|
+
if km is not None:
|
|
86
|
+
try:
|
|
87
|
+
km.shutdown_kernel(now=True)
|
|
88
|
+
except Exception:
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def console_tab(schema=None):
|
|
93
|
+
project_name = getattr(schema, 'schema_project', None) if schema else None
|
|
94
|
+
|
|
95
|
+
# kernel status bar
|
|
96
|
+
alive = '_console_km' in st.session_state
|
|
97
|
+
status_col, btn_col = st.columns([4, 1])
|
|
98
|
+
with status_col:
|
|
99
|
+
if alive:
|
|
100
|
+
st.success("Kernel running • `from labdata import *` and `from labdata.schema import *` pre-loaded")
|
|
101
|
+
else:
|
|
102
|
+
st.info("Kernel not started. Click **Start kernel** to launch an IPython kernel.")
|
|
103
|
+
with btn_col:
|
|
104
|
+
if not alive:
|
|
105
|
+
if st.button("Start kernel", type="primary", use_container_width=True):
|
|
106
|
+
with st.spinner("Starting IPython kernel…"):
|
|
107
|
+
_start_kernel(project_name)
|
|
108
|
+
st.rerun()
|
|
109
|
+
else:
|
|
110
|
+
if st.button("Restart kernel", type="secondary", use_container_width=True):
|
|
111
|
+
_shutdown_kernel()
|
|
112
|
+
with st.spinner("Restarting…"):
|
|
113
|
+
_start_kernel(project_name)
|
|
114
|
+
st.rerun()
|
|
115
|
+
|
|
116
|
+
if not alive:
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
kc = st.session_state['_console_kc']
|
|
120
|
+
history = st.session_state['_console_hist']
|
|
121
|
+
|
|
122
|
+
# cell history
|
|
123
|
+
for entry in history:
|
|
124
|
+
n = entry['n']
|
|
125
|
+
st.code(f"In [{n}]:\n{entry['input']}", language='python')
|
|
126
|
+
for kind, text in entry['outputs']:
|
|
127
|
+
if kind == 'result':
|
|
128
|
+
st.text(f"Out [{n}]: {text.rstrip()}")
|
|
129
|
+
else:
|
|
130
|
+
st.text(text.rstrip())
|
|
131
|
+
for b64 in entry['images']:
|
|
132
|
+
st.image(base64.b64decode(b64))
|
|
133
|
+
if entry['error']:
|
|
134
|
+
st.error(entry['error'])
|
|
135
|
+
|
|
136
|
+
if history:
|
|
137
|
+
st.divider()
|
|
138
|
+
|
|
139
|
+
# input area
|
|
140
|
+
code = st.text_area(
|
|
141
|
+
"code_input",
|
|
142
|
+
height=130,
|
|
143
|
+
placeholder="Python / IPython code — plots are displayed inline",
|
|
144
|
+
label_visibility='collapsed',
|
|
145
|
+
key='_console_code',
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
run_col, clear_col, _ = st.columns([1, 1, 6])
|
|
149
|
+
with run_col:
|
|
150
|
+
run_pressed = st.button("▶ Run", type="primary", use_container_width=True)
|
|
151
|
+
with clear_col:
|
|
152
|
+
if st.button("Clear", use_container_width=True):
|
|
153
|
+
st.session_state['_console_hist'] = []
|
|
154
|
+
st.session_state['_console_n'] = 0
|
|
155
|
+
st.rerun()
|
|
156
|
+
|
|
157
|
+
if run_pressed and code.strip():
|
|
158
|
+
with st.spinner("Running…"):
|
|
159
|
+
outputs, images, error = _execute(kc, code)
|
|
160
|
+
n = st.session_state['_console_n'] + 1
|
|
161
|
+
st.session_state['_console_n'] = n
|
|
162
|
+
history.append(dict(n=n, input=code,
|
|
163
|
+
outputs=outputs, images=images, error=error))
|
|
164
|
+
st.rerun()
|
|
165
|
+
|
|
166
|
+
|
|
@@ -125,11 +125,11 @@ def decisionmaking_tab(schema = None):
|
|
|
125
125
|
point_selector = alt.selection_point(on="click")
|
|
126
126
|
chart = alt.Chart(summarysource).mark_rect().encode(
|
|
127
127
|
x=alt.X('session_datetime:T',timeUnit = 'yearmonthdate',
|
|
128
|
-
scale=alt.Scale(nice={'interval': 'day', 'step': 1})).axis(labelAngle=45,format='%Y-%m-%d').title('Date'),
|
|
128
|
+
scale=alt.Scale(nice={'interval': 'day', 'step': 1})).axis(labelAngle=45,format='%Y-%m-%d').title('Date'),
|
|
129
129
|
y=alt.Y('subject_name:O').title('Subject name'),
|
|
130
130
|
color=alt.Color('performance_easy:Q',
|
|
131
131
|
scale=alt.Scale(scheme='spectral', reverse=True, domain=[0.5,1], clamp=True)).title('Perf easy'),
|
|
132
|
-
tooltip = ['subject_name','session_name','session_datetime','performance_easy','performance','n_trials']
|
|
132
|
+
tooltip = ['subject_name:N','session_name:N','session_datetime:T','performance_easy:Q','performance:Q','n_trials:Q']
|
|
133
133
|
|
|
134
134
|
).properties(width=1000, title ='Behavioral performance').add_params(point_selector)
|
|
135
135
|
event_data = st.altair_chart(chart.interactive(), on_select='rerun')
|
|
@@ -204,11 +204,11 @@ def decisionmaking_tab(schema = None):
|
|
|
204
204
|
x_enc = alt.X('session_datetime:T', axis=axis).title('Session date')
|
|
205
205
|
perf_chart = (
|
|
206
206
|
alt.Chart(trialset).mark_line(color=black).encode(x=x_enc, y=alt.Y('performance_easy:Q', axis=axis).title('Performance')).properties(width=1000) +
|
|
207
|
-
alt.Chart(trialset).mark_point(color=black).encode(x=x_enc, y=alt.Y('performance_easy:Q'), tooltip=['session_name','session_datetime','performance_easy','performance']) +
|
|
207
|
+
alt.Chart(trialset).mark_point(color=black).encode(x=x_enc, y=alt.Y('performance_easy:Q'), tooltip=['session_name:N','session_datetime:T','performance_easy:Q','performance:Q']) +
|
|
208
208
|
alt.Chart(perf_val).mark_text(align='left', dx=6, dy=100, color=black).encode(x=x_enc, y=alt.Y('performance_easy:Q'), text=alt.value('easy')) +
|
|
209
209
|
alt.Chart(trialset).mark_line(color=orange).encode(x=x_enc, y=alt.Y('performance:Q', axis=axis)) +
|
|
210
210
|
alt.Chart(trialset).mark_point(color=orange).encode(x=x_enc, y=alt.Y('performance:Q'),
|
|
211
|
-
tooltip=['session_name','session_datetime','performance_easy','performance']) +
|
|
211
|
+
tooltip=['session_name:N','session_datetime:T','performance_easy:Q','performance:Q']) +
|
|
212
212
|
alt.Chart(perf_val).mark_text(align='left', dx=6, dy=100, color=orange).encode(x=x_enc, y=alt.Y('performance:Q'), text=alt.value('all trials'))
|
|
213
213
|
)
|
|
214
214
|
ruler_df = pd.DataFrame({'t': [selected_dt]})
|
|
@@ -320,12 +320,11 @@ def decisionmaking_tab(schema = None):
|
|
|
320
320
|
st.caption(f"*{n['notetaker']} — {pd.Timestamp(n['note_datetime']).strftime('%Y-%m-%d %H:%M')}*")
|
|
321
321
|
st.write(n['notes'])
|
|
322
322
|
|
|
323
|
-
def line_point_plot(data,x,y,tooltip,color):
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
tooltip=tooltip)
|
|
323
|
+
def line_point_plot(data, x, y, tooltip, color):
|
|
324
|
+
if data is None or not len(data):
|
|
325
|
+
return alt.Chart(pd.DataFrame()).mark_point()
|
|
326
|
+
scatter = alt.Chart(data).mark_point(color=color).encode(
|
|
327
|
+
x=x, y=y, tooltip=tooltip)
|
|
328
328
|
line = alt.Chart(data).mark_line(color=color).encode(
|
|
329
|
-
x=x,
|
|
330
|
-
|
|
331
|
-
return scatter+line
|
|
329
|
+
x=x, y=y).properties(width=1000)
|
|
330
|
+
return scatter + line
|
|
@@ -196,9 +196,13 @@ def load_schema(project):
|
|
|
196
196
|
return load_project_schema(project)
|
|
197
197
|
|
|
198
198
|
project = None
|
|
199
|
+
show_console = False
|
|
199
200
|
for k in sys.argv:
|
|
200
201
|
if 'project=' in k:
|
|
201
202
|
project = k.replace('project=','')
|
|
203
|
+
if k == 'console=1':
|
|
204
|
+
from console import console_tab
|
|
205
|
+
show_console = True
|
|
202
206
|
with st.spinner(f'Connecting to {"project " + project if project else "database"}…'):
|
|
203
207
|
schema = load_schema(project)
|
|
204
208
|
|
|
@@ -213,11 +217,15 @@ page_names_to_funcs = {
|
|
|
213
217
|
"**Compute/Upload**": partial(compute_tab, schema = schema),
|
|
214
218
|
}
|
|
215
219
|
|
|
220
|
+
if show_console:
|
|
221
|
+
page_names_to_funcs["**Console**"] = partial(console_tab, schema=schema)
|
|
222
|
+
|
|
216
223
|
from labdata import plugins
|
|
217
224
|
for p in plugins.keys():
|
|
218
225
|
if hasattr(plugins[p],'dashboard_function'):
|
|
219
226
|
page_names_to_funcs[plugins[p].dashboard_name] = partial(plugins[p].dashboard_function, schema = schema)
|
|
220
227
|
|
|
228
|
+
|
|
221
229
|
tab_name = st.sidebar.radio(
|
|
222
230
|
"``labdata dashboard``",
|
|
223
231
|
page_names_to_funcs.keys())
|