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.
@@ -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
+ """
@@ -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
+