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.
Files changed (57) hide show
  1. {labdata-0.0.25 → labdata-0.1.1}/PKG-INFO +1 -1
  2. labdata-0.1.1/labdata/__init__.py +11 -0
  3. {labdata-0.0.25 → labdata-0.1.1}/labdata/cli.py +4 -0
  4. labdata-0.1.1/labdata/dashboard/console.py +166 -0
  5. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/decisiontask.py +11 -12
  6. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/index.py +8 -0
  7. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/segmentation.py +308 -62
  8. labdata-0.1.1/labdata/dashboard/sorting.py +207 -0
  9. {labdata-0.0.25 → labdata-0.1.1}/labdata/utils.py +42 -3
  10. {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/PKG-INFO +1 -1
  11. {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/SOURCES.txt +1 -0
  12. labdata-0.0.25/labdata/__init__.py +0 -16
  13. labdata-0.0.25/labdata/dashboard/sorting.py +0 -102
  14. {labdata-0.0.25 → labdata-0.1.1}/LICENSE +0 -0
  15. {labdata-0.0.25 → labdata-0.1.1}/README.md +0 -0
  16. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/__init__.py +0 -0
  17. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/caiman.py +0 -0
  18. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/ec2.py +0 -0
  19. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/ephys.py +0 -0
  20. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/pose.py +0 -0
  21. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/schedulers.py +0 -0
  22. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/singularity.py +0 -0
  23. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/suite2p.py +0 -0
  24. {labdata-0.0.25 → labdata-0.1.1}/labdata/compute/utils.py +0 -0
  25. {labdata-0.0.25 → labdata-0.1.1}/labdata/copy.py +0 -0
  26. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/__init__.py +0 -0
  27. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/compute.py +0 -0
  28. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/explorer/__init__.py +0 -0
  29. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/explorer/cellsegmentation.py +0 -0
  30. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/explorer/spikesorting.py +0 -0
  31. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/notes.py +0 -0
  32. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/procedures.py +0 -0
  33. {labdata-0.0.25 → labdata-0.1.1}/labdata/dashboard/video.py +0 -0
  34. {labdata-0.0.25 → labdata-0.1.1}/labdata/export.py +0 -0
  35. {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/__init__.py +0 -0
  36. {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/ephys.py +0 -0
  37. {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/imaging.py +0 -0
  38. {labdata-0.0.25 → labdata-0.1.1}/labdata/rules/utils.py +0 -0
  39. {labdata-0.0.25 → labdata-0.1.1}/labdata/s3.py +0 -0
  40. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/__init__.py +0 -0
  41. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/ephys.py +0 -0
  42. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/general.py +0 -0
  43. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/histology.py +0 -0
  44. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/onephoton.py +0 -0
  45. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/procedures.py +0 -0
  46. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/tasks.py +0 -0
  47. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/twophoton.py +0 -0
  48. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/utils.py +0 -0
  49. {labdata-0.0.25 → labdata-0.1.1}/labdata/schema/video.py +0 -0
  50. {labdata-0.0.25 → labdata-0.1.1}/labdata/stacks.py +0 -0
  51. {labdata-0.0.25 → labdata-0.1.1}/labdata/widgets.py +0 -0
  52. {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/dependency_links.txt +0 -0
  53. {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/entry_points.txt +0 -0
  54. {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/requires.txt +0 -0
  55. {labdata-0.0.25 → labdata-0.1.1}/labdata.egg-info/top_level.txt +0 -0
  56. {labdata-0.0.25 → labdata-0.1.1}/pyproject.toml +0 -0
  57. {labdata-0.0.25 → labdata-0.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labdata
3
- Version: 0.0.25
3
+ Version: 0.1.1
4
4
  Summary: Package to manage data in experimental neuroscience labs
5
5
  Author-email: Joao Couto <jpcouto@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/jcouto/labdata
@@ -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
- scatter = alt.Chart(data).mark_point(color = color).encode(
325
- x=x,
326
- y=y,
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
- y=y,).properties(width=1000)
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())