labdata 0.0.3__py3-none-any.whl
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/__init__.py +17 -0
- labdata/cli.py +499 -0
- labdata/compute/__init__.py +27 -0
- labdata/compute/ec2.py +198 -0
- labdata/compute/ephys.py +469 -0
- labdata/compute/pose.py +281 -0
- labdata/compute/schedulers.py +194 -0
- labdata/compute/singularity.py +95 -0
- labdata/compute/utils.py +561 -0
- labdata/copy.py +351 -0
- labdata/rules/__init__.py +78 -0
- labdata/rules/ephys.py +188 -0
- labdata/rules/imaging.py +618 -0
- labdata/rules/utils.py +290 -0
- labdata/s3.py +317 -0
- labdata/schema/__init__.py +24 -0
- labdata/schema/ephys.py +547 -0
- labdata/schema/general.py +647 -0
- labdata/schema/histology.py +309 -0
- labdata/schema/onephoton.py +93 -0
- labdata/schema/procedures.py +102 -0
- labdata/schema/tasks.py +66 -0
- labdata/schema/twophoton.py +142 -0
- labdata/schema/utils.py +25 -0
- labdata/schema/video.py +243 -0
- labdata/stacks.py +182 -0
- labdata/utils.py +598 -0
- labdata/widgets.py +412 -0
- labdata-0.0.3.dist-info/METADATA +42 -0
- labdata-0.0.3.dist-info/RECORD +36 -0
- labdata-0.0.3.dist-info/WHEEL +5 -0
- labdata-0.0.3.dist-info/entry_points.txt +2 -0
- labdata-0.0.3.dist-info/licenses/LICENSE +674 -0
- labdata-0.0.3.dist-info/top_level.txt +2 -0
- labdata_frontend/Home.py +39 -0
- labdata_frontend/__init__.py +0 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
from .general import *
|
|
2
|
+
|
|
3
|
+
@dataschema
|
|
4
|
+
class Atlas(dj.Manual):
|
|
5
|
+
definition = '''
|
|
6
|
+
atlas_id : varchar(12)
|
|
7
|
+
---
|
|
8
|
+
atlas_description = NULL: varchar(156)
|
|
9
|
+
atlas_url = NULL: varchar(156)
|
|
10
|
+
atlas_citation = NULL: varchar(156)
|
|
11
|
+
'''
|
|
12
|
+
class Region(dj.Part):
|
|
13
|
+
definition = '''
|
|
14
|
+
-> master
|
|
15
|
+
region_acronym : varchar(12)
|
|
16
|
+
---
|
|
17
|
+
region_name: varchar(256)
|
|
18
|
+
region_id: int
|
|
19
|
+
region_atlas_id: int
|
|
20
|
+
region_level: int
|
|
21
|
+
region_graph_depth = NULL: int
|
|
22
|
+
region_graph_order = NULL: int
|
|
23
|
+
structure_id_path: varchar(80)
|
|
24
|
+
color_hex = NULL: char(8)
|
|
25
|
+
'''
|
|
26
|
+
|
|
27
|
+
@dataschema
|
|
28
|
+
class FixedBrain(dj.Imported):
|
|
29
|
+
'''Whole brain histology or fixed tissue.
|
|
30
|
+
The class provides methods for:
|
|
31
|
+
- Loading brain image data via get() method
|
|
32
|
+
- Viewing brain data in napari via napari_open() method
|
|
33
|
+
|
|
34
|
+
Definition
|
|
35
|
+
----------
|
|
36
|
+
file_path : str
|
|
37
|
+
Path to the brain imaging data file
|
|
38
|
+
num_channels : int
|
|
39
|
+
Number of imaging channels
|
|
40
|
+
width : int
|
|
41
|
+
Image width in pixels
|
|
42
|
+
height : int
|
|
43
|
+
Image height in pixels
|
|
44
|
+
um_per_pixel : array
|
|
45
|
+
Microns per pixel resolution in each dimension
|
|
46
|
+
hardware : str
|
|
47
|
+
Imaging hardware/microscope used
|
|
48
|
+
'''
|
|
49
|
+
definition = '''
|
|
50
|
+
-> Dataset
|
|
51
|
+
---
|
|
52
|
+
-> [nullable] File
|
|
53
|
+
num_channels = NULL : smallint
|
|
54
|
+
width = NULL : int
|
|
55
|
+
height = NULL : int
|
|
56
|
+
um_per_pixel = NULL : blob
|
|
57
|
+
hardware = NULL : varchar(56)
|
|
58
|
+
'''
|
|
59
|
+
def get(self):
|
|
60
|
+
'''Get the brain imaging data.
|
|
61
|
+
|
|
62
|
+
Returns
|
|
63
|
+
-------
|
|
64
|
+
array or list
|
|
65
|
+
If single brain, returns array containing brain data.
|
|
66
|
+
If multiple brains, returns list of arrays.
|
|
67
|
+
'''
|
|
68
|
+
brains = []
|
|
69
|
+
for s in self:
|
|
70
|
+
brains.append(open_zarr((File() & s).get()[0]))
|
|
71
|
+
if len(brains)==1:
|
|
72
|
+
return brains[0] # like fetch1
|
|
73
|
+
return brains
|
|
74
|
+
|
|
75
|
+
def napari_open(self, **kwargs):
|
|
76
|
+
'''Open brain data in napari viewer.
|
|
77
|
+
|
|
78
|
+
Opens the brain imaging data in a napari viewer window for visualization.
|
|
79
|
+
Only one brain can be opened at a time.
|
|
80
|
+
|
|
81
|
+
Pass channel_axis = 1 to open with color
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
napari.Viewer
|
|
85
|
+
The napari viewer instance displaying the brain data
|
|
86
|
+
|
|
87
|
+
Raises
|
|
88
|
+
------
|
|
89
|
+
AssertionError
|
|
90
|
+
If more than one brain is selected
|
|
91
|
+
'''
|
|
92
|
+
assert len(self) == 1, 'Open only one brain at a time.'
|
|
93
|
+
from labdata.stacks import napari_open
|
|
94
|
+
napari_open(self.get(),**kwargs)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@analysisschema
|
|
98
|
+
class FixedBrainTransformParameters(dj.Manual):
|
|
99
|
+
'''Table for storing manual transformation parameters for fixed brain images.
|
|
100
|
+
|
|
101
|
+
The parameters are used by FixedBrainTransform to generate transformed versions
|
|
102
|
+
of the original brain images for analysis and visualization.
|
|
103
|
+
|
|
104
|
+
Definition
|
|
105
|
+
----------
|
|
106
|
+
transform_id : int
|
|
107
|
+
ID for this set of transform parameters (default 0)
|
|
108
|
+
downsample : array-like
|
|
109
|
+
Downsampling factors for [T,C,X,Y] dimensions
|
|
110
|
+
rotate : array-like
|
|
111
|
+
[Z,Y,X] rotation angles and [flipx,flipy] boolean flags
|
|
112
|
+
crop : array-like
|
|
113
|
+
Crop ranges [[start,end,step], ...] for each dimension
|
|
114
|
+
transpose : array-like
|
|
115
|
+
Order to transpose dimensions, e.g. [2,1,3,0]
|
|
116
|
+
cast : str
|
|
117
|
+
Data type to cast output to (e.g. 'uint16')
|
|
118
|
+
'''
|
|
119
|
+
definition = '''
|
|
120
|
+
-> FixedBrain
|
|
121
|
+
transform_id = 0 : smallint
|
|
122
|
+
---
|
|
123
|
+
downsample = NULL : blob # [T, C, X, Y]
|
|
124
|
+
rotate = NULL : blob # [Z, Y, X, flipx, flipy]
|
|
125
|
+
crop = NULL : blob # [[START,END,STEP],None,None,None] what to crop
|
|
126
|
+
transpose = NULL : blob # [2,1,3,0] order to transpose so it is a coronal section
|
|
127
|
+
cast = NULL : varchar(8) # datatype of the downsampled data
|
|
128
|
+
'''
|
|
129
|
+
|
|
130
|
+
@analysisschema
|
|
131
|
+
class FixedBrainTransform(dj.Computed):
|
|
132
|
+
'''Table for storing transformed fixed brain images.
|
|
133
|
+
|
|
134
|
+
This class computes and stores transformed versions of fixed brain images based on
|
|
135
|
+
parameters from FixedBrainTransformParameters.
|
|
136
|
+
|
|
137
|
+
The transformed images are stored as TIFF files in the analysis storage location.
|
|
138
|
+
|
|
139
|
+
Definition
|
|
140
|
+
----------
|
|
141
|
+
file_path : str
|
|
142
|
+
Path to the transformed TIFF file in analysis storage
|
|
143
|
+
storage : str
|
|
144
|
+
Storage location name (default: 'analysis')
|
|
145
|
+
um_per_pixel : array-like
|
|
146
|
+
Resolution in microns per pixel for each dimension
|
|
147
|
+
shape : array-like
|
|
148
|
+
Shape of the transformed stack [T,C,X,Y]
|
|
149
|
+
hemisphere : str
|
|
150
|
+
Which hemisphere is included ('left', 'right', or 'both')
|
|
151
|
+
|
|
152
|
+
Methods
|
|
153
|
+
-------
|
|
154
|
+
transform(key)
|
|
155
|
+
Apply transformations specified in parameters to generate transformed stack
|
|
156
|
+
|
|
157
|
+
Returns
|
|
158
|
+
-------
|
|
159
|
+
ndarray
|
|
160
|
+
The transformed image stack
|
|
161
|
+
|
|
162
|
+
get()
|
|
163
|
+
Load and return the transformed image stack(s)
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
list
|
|
168
|
+
List of transformed image stacks as numpy arrays
|
|
169
|
+
'''
|
|
170
|
+
definition = '''
|
|
171
|
+
-> FixedBrain
|
|
172
|
+
-> FixedBrainTransformParameters
|
|
173
|
+
---
|
|
174
|
+
-> AnalysisFile
|
|
175
|
+
um_per_pixel = NULL : blob
|
|
176
|
+
shape = NULL : blob
|
|
177
|
+
hemisphere = NULL : varchar(5) # left, right, both
|
|
178
|
+
'''
|
|
179
|
+
|
|
180
|
+
def transform(self,key):
|
|
181
|
+
'''Transform fixed brain image according to parameters.
|
|
182
|
+
|
|
183
|
+
Applies transformations specified in FixedBrainTransformParameters to generate
|
|
184
|
+
a transformed stack. If the transform has already been computed, loads and
|
|
185
|
+
returns the existing transformed stack from storage.
|
|
186
|
+
|
|
187
|
+
Transformation order:
|
|
188
|
+
1. Downsample if specified
|
|
189
|
+
2. Rotate if specified
|
|
190
|
+
3. Crop if specified
|
|
191
|
+
4. Transpose dimensions if specified
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
----------
|
|
195
|
+
key : dict
|
|
196
|
+
Primary key specifying which FixedBrainTransformParameters to use
|
|
197
|
+
|
|
198
|
+
Returns
|
|
199
|
+
-------
|
|
200
|
+
ndarray
|
|
201
|
+
The transformed image stack. Shape depends on transformation parameters.
|
|
202
|
+
|
|
203
|
+
'''
|
|
204
|
+
if len(self & key):
|
|
205
|
+
key = (self & key).fetch1()
|
|
206
|
+
print(f'Transform has been computed. Fetching from {key["file_path"]}.')
|
|
207
|
+
apath = (AnalysisFile() & key).get()[0]
|
|
208
|
+
|
|
209
|
+
from tifffile import imread
|
|
210
|
+
stack = imread(apath)
|
|
211
|
+
return stack
|
|
212
|
+
stack = (FixedBrain() & key).get()
|
|
213
|
+
params = (FixedBrainTransformParameters() & key).fetch1()
|
|
214
|
+
from labdata.stacks import rotate_stack,downsample_stack
|
|
215
|
+
if not params['downsample'] is None:
|
|
216
|
+
stack = downsample_stack(stack,params['downsample'])
|
|
217
|
+
if not params['rotate'] is None:
|
|
218
|
+
stack = rotate_stack(stack,*params['rotate'])
|
|
219
|
+
if not params['crop'] is None:
|
|
220
|
+
A,B,C,D = params['crop']
|
|
221
|
+
if A is None:
|
|
222
|
+
A = [0,stack.shape[0],1]
|
|
223
|
+
if B is None:
|
|
224
|
+
B = [0,stack.shape[1],1]
|
|
225
|
+
if C is None:
|
|
226
|
+
C = [0,stack.shape[2],1]
|
|
227
|
+
if D is None:
|
|
228
|
+
D = [0,stack.shape[3],1]
|
|
229
|
+
stack = stack[A[0]:A[1]:A[2],
|
|
230
|
+
B[0]:B[1]:B[2],
|
|
231
|
+
C[0]:C[1]:C[2],
|
|
232
|
+
D[0]:D[1]:D[2],]
|
|
233
|
+
if not params['transpose'] is None:
|
|
234
|
+
stack = stack.transpose(params['transpose'])
|
|
235
|
+
return stack
|
|
236
|
+
|
|
237
|
+
def get(self):
|
|
238
|
+
'''Load the transformed brain stacks.
|
|
239
|
+
|
|
240
|
+
Returns
|
|
241
|
+
-------
|
|
242
|
+
ndarray or list
|
|
243
|
+
If only one stack exists, returns a single ndarray.
|
|
244
|
+
If multiple stacks exist, returns a list of ndarrays.
|
|
245
|
+
'''
|
|
246
|
+
brains = []
|
|
247
|
+
from tifffile import imread
|
|
248
|
+
for s in self:
|
|
249
|
+
brains.append(imread((AnalysisFile() & s).get()[0]))
|
|
250
|
+
if len(brains)==1:
|
|
251
|
+
return brains[0] # like fetch1
|
|
252
|
+
return brains
|
|
253
|
+
|
|
254
|
+
def make(self,k):
|
|
255
|
+
par = (FixedBrainTransformParameters() & k).fetch1()
|
|
256
|
+
origpar = (FixedBrain() & k).fetch1()
|
|
257
|
+
|
|
258
|
+
downsample_par = np.array(par['downsample'])[np.array([0,2,3])]
|
|
259
|
+
stack = self.transform(k)
|
|
260
|
+
um_per_pixel = list(origpar['um_per_pixel']/downsample_par)
|
|
261
|
+
|
|
262
|
+
folder_path = (((Path(prefs['local_paths'][0])
|
|
263
|
+
/k['subject_name']))
|
|
264
|
+
/k['session_name'])/f'brain_transform_{k["transform_id"]}'
|
|
265
|
+
filepath = folder_path/f'stack_{um_per_pixel[0]}um.ome.tif'
|
|
266
|
+
folder_path.mkdir(exist_ok=True)
|
|
267
|
+
from tifffile import imwrite # saving in tiff so it is easier to read
|
|
268
|
+
imwrite(filepath,stack,
|
|
269
|
+
imagej = True,
|
|
270
|
+
metadata={'axes': 'ZCYX'},
|
|
271
|
+
compression ='zlib',
|
|
272
|
+
compressionargs = {'level': 6})
|
|
273
|
+
added = AnalysisFile().upload_files([filepath],dict(subject_name = k['subject_name'],
|
|
274
|
+
session_name = k['session_name'],
|
|
275
|
+
dataset_name = f'brain_transform_{k["transform_id"]}'))[0]
|
|
276
|
+
|
|
277
|
+
to_add = dict(k,
|
|
278
|
+
um_per_pixel = um_per_pixel,
|
|
279
|
+
shape = stack.shape,
|
|
280
|
+
**added)
|
|
281
|
+
self.insert1(to_add)
|
|
282
|
+
# save to tiff and upload to the analysis bucket
|
|
283
|
+
|
|
284
|
+
@analysisschema
|
|
285
|
+
class FixedBrainTransformAnnotation(dj.Manual):
|
|
286
|
+
'''Table for storing manual annotations of brain locations.
|
|
287
|
+
|
|
288
|
+
This table stores manually annotated points in transformed brain volumes, such as:
|
|
289
|
+
- Probe tracks
|
|
290
|
+
- Injection sites
|
|
291
|
+
- Anatomical landmarks
|
|
292
|
+
- Region boundaries
|
|
293
|
+
|
|
294
|
+
Each annotation consists of:
|
|
295
|
+
- annotation_name: Description of what is being annotated
|
|
296
|
+
- annotation_type: Category of annotation (e.g. 'probe_track', 'injection')
|
|
297
|
+
- xyz: Array of x,y,z coordinates marking the annotation location
|
|
298
|
+
|
|
299
|
+
The coordinates are in pixels relative to the transformed brain volume.
|
|
300
|
+
'''
|
|
301
|
+
definition = '''
|
|
302
|
+
-> FixedBrainTransform
|
|
303
|
+
annotation_id : int
|
|
304
|
+
---
|
|
305
|
+
annotation_name : varchar(36)
|
|
306
|
+
annotation_type : varchar(36)
|
|
307
|
+
xyz : blob
|
|
308
|
+
'''
|
|
309
|
+
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from .general import *
|
|
2
|
+
from .procedures import *
|
|
3
|
+
from .histology import *
|
|
4
|
+
|
|
5
|
+
@dataschema
|
|
6
|
+
class Widefield(dj.Imported):
|
|
7
|
+
'''Table for widefield one-photon imaging data.
|
|
8
|
+
|
|
9
|
+
This table stores metadata about widefield imaging recordings including:
|
|
10
|
+
- Frame dimensions and counts
|
|
11
|
+
- Frame rate
|
|
12
|
+
- Optical parameters (magnification, objective, pixel scale)
|
|
13
|
+
- Reference to raw data file
|
|
14
|
+
- Imaging software details
|
|
15
|
+
|
|
16
|
+
The table includes a Part table for storing different projections of the data
|
|
17
|
+
(mean, std, var, max).
|
|
18
|
+
'''
|
|
19
|
+
definition = '''
|
|
20
|
+
-> Dataset
|
|
21
|
+
---
|
|
22
|
+
n_channels : smallint # number of channels
|
|
23
|
+
n_frames : int # duration of the recording
|
|
24
|
+
width : int # width of each frame
|
|
25
|
+
height : int # height of each frame
|
|
26
|
+
frame_rate : double # frame rate
|
|
27
|
+
-> File # path to the stack
|
|
28
|
+
magnification = NULL : double # magnification
|
|
29
|
+
objective_angle = NULL : double # angle
|
|
30
|
+
objective = NULL : varchar(32) # objective
|
|
31
|
+
um_per_pixel = NULL : blob # XY scale conversion factors
|
|
32
|
+
imaging_software : varchar(32) # software and version
|
|
33
|
+
'''
|
|
34
|
+
|
|
35
|
+
def open(self):
|
|
36
|
+
'''Opens the widefield imaging data file.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
zarr.Array
|
|
41
|
+
The opened zarr array containing the widefield imaging data.
|
|
42
|
+
Data is stored in a compressed zarr format with dimensions:
|
|
43
|
+
[frames, channels, height, width]
|
|
44
|
+
'''
|
|
45
|
+
if len(self) != 1:
|
|
46
|
+
raise(ValueError(f'Select only one dataset {self.proj().fetch(as_dict = True)}.'))
|
|
47
|
+
fname = (File() & (Widefield & self.proj()) & 'file_path LIKE "%.zarr.zip"').get()[0]
|
|
48
|
+
return open_zarr(fname)
|
|
49
|
+
|
|
50
|
+
class Projection(dj.Part):
|
|
51
|
+
'''Part table for storing projections of widefield imaging data.
|
|
52
|
+
|
|
53
|
+
This table stores projections (mean, std, var, max) of the
|
|
54
|
+
widefield imaging data.
|
|
55
|
+
|
|
56
|
+
Attributes
|
|
57
|
+
----------
|
|
58
|
+
proj_name : enum
|
|
59
|
+
Type of projection ('mean', 'std', 'var', 'max')
|
|
60
|
+
proj : longblob
|
|
61
|
+
The projection data array
|
|
62
|
+
'''
|
|
63
|
+
definition = '''
|
|
64
|
+
-> master
|
|
65
|
+
proj_name : enum('mean','std','var','max')
|
|
66
|
+
---
|
|
67
|
+
proj : longblob
|
|
68
|
+
'''
|
|
69
|
+
|
|
70
|
+
@dataschema
|
|
71
|
+
class Miniscope(dj.Imported):
|
|
72
|
+
definition = '''
|
|
73
|
+
-> Dataset
|
|
74
|
+
---
|
|
75
|
+
n_channels : smallint # number of channels
|
|
76
|
+
n_frames : int # duration of the recording
|
|
77
|
+
width : int # width of each frame
|
|
78
|
+
height : int # height of each frame
|
|
79
|
+
frame_rate : double # frame rate
|
|
80
|
+
-> File # path to the stack
|
|
81
|
+
device = NULL : varchar(32) # miniscope device
|
|
82
|
+
power = NULL : blob # power used per channel
|
|
83
|
+
lens_tuning : int # EWL tuning (focus)
|
|
84
|
+
sensor_gain = NULL : int # gain of the imaging sensor
|
|
85
|
+
um_per_pixel = NULL : blob # XY scale conversion factors
|
|
86
|
+
-> [nullable] Atlas.Region # target region (or the center of the imaging plane)
|
|
87
|
+
'''
|
|
88
|
+
def open(self):
|
|
89
|
+
if len(self) != 1:
|
|
90
|
+
raise(ValueError(f'Select only one dataset {self.proj().fetch(as_dict = True)}.'))
|
|
91
|
+
fname = (File() & self).get()[0]
|
|
92
|
+
return open_zarr(fname)
|
|
93
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from .general import *
|
|
2
|
+
|
|
3
|
+
@dataschema
|
|
4
|
+
class Weighing(dj.Manual):
|
|
5
|
+
'''Table for tracking subject weights.
|
|
6
|
+
|
|
7
|
+
This table stores weight measurements for experimental subjects. Each entry includes:
|
|
8
|
+
- Subject
|
|
9
|
+
- Date and time of weighing
|
|
10
|
+
- Weight in grams
|
|
11
|
+
|
|
12
|
+
'''
|
|
13
|
+
definition = """
|
|
14
|
+
-> Subject
|
|
15
|
+
weighing_datetime : datetime
|
|
16
|
+
---
|
|
17
|
+
weight : float # (g)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@dataschema
|
|
21
|
+
class ProcedureType(dj.Lookup):
|
|
22
|
+
'''Table defining types of experimental procedures.
|
|
23
|
+
|
|
24
|
+
This lookup table enumerates the different types of experimental procedures, including:
|
|
25
|
+
- Surgical procedures (surgery, implants, craniotomy)
|
|
26
|
+
- Behavioral procedures (handling, training)
|
|
27
|
+
- Other manipulations (injections)
|
|
28
|
+
|
|
29
|
+
The procedure types are used by the Procedure table to categorize and track all
|
|
30
|
+
procedures performed.
|
|
31
|
+
'''
|
|
32
|
+
definition = """
|
|
33
|
+
procedure_type : varchar(52) # Defines procedures that are not an experimental session
|
|
34
|
+
"""
|
|
35
|
+
contents = zip(['surgery',
|
|
36
|
+
'chronic implant',
|
|
37
|
+
'chronic explant',
|
|
38
|
+
'injection',
|
|
39
|
+
'window implant',
|
|
40
|
+
'window replacement',
|
|
41
|
+
'handling',
|
|
42
|
+
'training',
|
|
43
|
+
'craniotomy'])
|
|
44
|
+
|
|
45
|
+
@dataschema
|
|
46
|
+
class Procedure(dj.Manual):
|
|
47
|
+
'''Table for tracking experimental procedures performed on subjects.
|
|
48
|
+
|
|
49
|
+
Each procedure entry includes:
|
|
50
|
+
- Subject
|
|
51
|
+
- ProcedureType
|
|
52
|
+
- Date and time
|
|
53
|
+
- Lab member who performed it
|
|
54
|
+
- Optional metadata: weight, and notes
|
|
55
|
+
'''
|
|
56
|
+
definition = """
|
|
57
|
+
-> Subject
|
|
58
|
+
-> ProcedureType
|
|
59
|
+
procedure_datetime : datetime
|
|
60
|
+
---
|
|
61
|
+
-> LabMember
|
|
62
|
+
procedure_metadata = NULL : longblob
|
|
63
|
+
-> [nullable] Weighing
|
|
64
|
+
-> [nullable] Note
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
@dataschema
|
|
68
|
+
class Watering(dj.Manual):
|
|
69
|
+
'''Table for tracking water administration to subjects.
|
|
70
|
+
|
|
71
|
+
This table records water consumed, including:
|
|
72
|
+
- Subject receiving water
|
|
73
|
+
- Date and time
|
|
74
|
+
- Volume of water, in microliters
|
|
75
|
+
|
|
76
|
+
'''
|
|
77
|
+
definition = """
|
|
78
|
+
-> Subject
|
|
79
|
+
watering_datetime : datetime
|
|
80
|
+
---
|
|
81
|
+
water_volume : float # (uL)
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
@dataschema
|
|
85
|
+
class WaterRestriction(dj.Manual):
|
|
86
|
+
definition = """
|
|
87
|
+
-> Subject
|
|
88
|
+
water_restriction_start_date : date
|
|
89
|
+
---
|
|
90
|
+
-> LabMember
|
|
91
|
+
water_restriction_end_date : date
|
|
92
|
+
-> Weighing
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
@dataschema
|
|
96
|
+
class Death(dj.Manual):
|
|
97
|
+
definition = """
|
|
98
|
+
-> Subject
|
|
99
|
+
---
|
|
100
|
+
death_date : datetime # death date
|
|
101
|
+
-> [nullable] Note
|
|
102
|
+
"""
|
labdata/schema/tasks.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from .general import *
|
|
2
|
+
from .procedures import Watering
|
|
3
|
+
@analysisschema
|
|
4
|
+
class DecisionTask(dj.Imported): # imported because if comes from data but there is no 'make'
|
|
5
|
+
'''Table for behavioral decision task data.
|
|
6
|
+
|
|
7
|
+
This table serves as a general schema for decision-making behavioral tasks,
|
|
8
|
+
abstracting common features that can be inherited by specific task tables
|
|
9
|
+
defined in plugins. Each entry includes:
|
|
10
|
+
- Total trial counts (assisted, self-performed, initiated, with choice)
|
|
11
|
+
- Performance metrics (rewarded, punished trials)
|
|
12
|
+
- Optional reference to water intake during session
|
|
13
|
+
|
|
14
|
+
The table includes a Part table (TrialSet) that stores detailed sets of trials within a session,
|
|
15
|
+
dependent on the modality or condition and includes including:
|
|
16
|
+
- Trial conditions and modalities
|
|
17
|
+
- Performance metrics per condition
|
|
18
|
+
- Timing data (initiation times, reaction times)
|
|
19
|
+
- Response and subject feedback values
|
|
20
|
+
- Stimulus parameters (intensity, block)
|
|
21
|
+
|
|
22
|
+
This data can be used to compute:
|
|
23
|
+
- Psychometric curves
|
|
24
|
+
- Learning curves
|
|
25
|
+
- Reaction time distributions
|
|
26
|
+
- Choice biases and strategies
|
|
27
|
+
- ...
|
|
28
|
+
|
|
29
|
+
The schema is designed to be flexible and is meant to be populated by specific task tables (defined as plugins)
|
|
30
|
+
while maintaining a consistent interface for analysis and visualization.
|
|
31
|
+
'''
|
|
32
|
+
definition = '''
|
|
33
|
+
-> Dataset
|
|
34
|
+
---
|
|
35
|
+
n_total_trials : int # number of trials in the session
|
|
36
|
+
n_total_assisted = NULL : int # number of assisted trials in the session
|
|
37
|
+
n_total_performed = NULL : int # number of self-performed trials
|
|
38
|
+
n_total_initiated = NULL : int # number of initiated trials
|
|
39
|
+
n_total_with_choice = NULL : int # number of self-initiated with choice
|
|
40
|
+
n_total_rewarded = NULL : int # number of rewarded trials
|
|
41
|
+
n_total_punished = NULL : int # number of punished trials
|
|
42
|
+
-> [nullable] Watering # water intake during the session (ml)
|
|
43
|
+
'''
|
|
44
|
+
|
|
45
|
+
class TrialSet(dj.Part):
|
|
46
|
+
definition = '''
|
|
47
|
+
-> master
|
|
48
|
+
trialset_description : varchar(54) # e.g. trial modality, unique condition
|
|
49
|
+
---
|
|
50
|
+
n_trials : int # total number of trials
|
|
51
|
+
n_performed : int # number of self-performed trials
|
|
52
|
+
n_with_choice : int # number of self-initiated trials with choice
|
|
53
|
+
n_correct : int # number of correct trials
|
|
54
|
+
performance_easy = NULL : float # performance on easy trials
|
|
55
|
+
performance = NULL : float # performance on all trials
|
|
56
|
+
trial_num : longblob # trial number because TrialSets can be intertwined
|
|
57
|
+
initiation_times = NULL : longblob # time between trial start and stim onset
|
|
58
|
+
assisted = NULL : longblob # wether the trial was assisted
|
|
59
|
+
response_values = NULL : longblob # left=1;no response=0; right=-1
|
|
60
|
+
correct_values = NULL : longblob # correct = 1; no_response = NaN; wrong = 0
|
|
61
|
+
intensity_values = NULL : longblob # value of the stim (left-right)
|
|
62
|
+
reaction_times = NULL : longblob # between onset of the response period and reporting
|
|
63
|
+
block_values = NULL : longblob # block number for each trial
|
|
64
|
+
'''
|
|
65
|
+
|
|
66
|
+
|