From 1880684f33c220c502283dba88a458739df9174e Mon Sep 17 00:00:00 2001 From: Alessandra Trapani <55453048+alessandratrapani@users.noreply.github.com> Date: Mon, 5 Feb 2024 18:14:06 +0100 Subject: [PATCH] Change quantitative properties to add units to name (#6) * add new spec (not working for the stimulated_rois) * tests not working * fix testing * define what is required * improve tutorial * add explaination for stimulus table * add testing for power,frequency and pulse_width as 1D arrays * set defaults for power,frequency and pulse_width * add schema diagram * remove unnecessary imports * add targeted_rois (required) and segmented_rois (optional) * remove unnecessary imports * remove old schema * update schema * minor fixes * add elements to __all__ to count as used * add exception to ruff * remove space * adjust to proper sentences * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Update spec/ndx-patterned-ogen.extensions.yaml Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> * Improve readability of doc strings * targeted_rois defined as table region * add example for slm model and filter_description * split SLM in 2 device SLM2D and SLM3D * split OgenPattern in 2D and 3D * update tutorial and schema * minor fixes * update schema * set sweeep_size and sweep_mask as datasets * set SpiralScanning and TemporalFocusing properties as datasets * set effector as dataset * set spatial_resolution as dataset * set all LightSource properties as datasets except "model" * update tutorial * set segmented_rois default * change required:false to quantity:'?' for dataset * remove unnecessary class definition * add unit, shape and dims * update tutorial and mock_fun accordingly * minor fixes * Apply suggestions from code review * add unit measure in the name of the attribute --------- Co-authored-by: Cody Baker <51133164+CodyCBakerPhD@users.noreply.github.com> --- spec/ndx-patterned-ogen.extensions.yaml | 134 ++++-- src/pynwb/ndx_patterned_ogen/__init__.py | 20 +- .../ndx_patterned_ogen/patterned_ogen.py | 347 +------------- src/pynwb/tests/mock/patternedogen.py | 62 +-- src/pynwb/tests/test_patternedogen.py | 3 +- tutorial_patterned_ogen.ipynb | 429 ++++++++++++++++-- 6 files changed, 538 insertions(+), 457 deletions(-) diff --git a/spec/ndx-patterned-ogen.extensions.yaml b/spec/ndx-patterned-ogen.extensions.yaml index c604e88..6138530 100644 --- a/spec/ndx-patterned-ogen.extensions.yaml +++ b/spec/ndx-patterned-ogen.extensions.yaml @@ -6,22 +6,34 @@ groups: - name: description dtype: text doc: Description of the scanning or scanless method for shaping optogenetic light. Examples include diffraction limited points, 3D shot, disks, etc. - required: false - - name: sweep_size + - name: sweep_size_in_um dtype: numeric doc: - Size of the scanning sweep pattern in micrometers. If a scalar is provided, the sweep pattern is + Size of the scanning sweep pattern (default in micrometers). If a scalar is provided, the sweep pattern is assumed to be a circle (for 2D patterns) with diameter 'sweep_size'. If 'sweep_size' is a two dimensional array, the the sweep pattern is assumed to be a rectangle, with dimensions [width, height]. required: false + dims: + - diameter + - width, height + shape: + - - 1 + - - 2 + datasets: - name: sweep_mask dtype: numeric doc: Scanning sweep pattern designated using a mask of size [width, height] for 2D stimulation, where for a given pixel a value of 1 indicates stimulation, and a value of 0 indicates no stimulation. - required: false + quantity: "?" + dims: + - num_rows + - num_cols + shape: + - + - - neurodata_type_def: OptogeneticStimulus3DPattern neurodata_type_inc: LabMetaData doc: Container to store the information about a generic 3D stimulus pattern (spatial information). @@ -29,58 +41,68 @@ groups: - name: description dtype: text doc: Description of the scanning or scanless method for shaping optogenetic light. Examples include diffraction limited points, 3D shot, disks, etc. - required: false - - name: sweep_size + - name: sweep_size_in_um dtype: numeric doc: - Size of the scanning sweep pattern in micrometers. If a scalar is provided, the sweep pattern is + Size of the scanning sweep pattern (default in micrometers). If a scalar is provided, the sweep pattern is assumed to be a cylinder (for 3D patterns), with diameter 'sweep_size'. If 'sweep_size' is a three dimensional array, the the sweep pattern is assumed to be a cuboid, with dimensions [width, height, depth]. required: false + dims: + - diameter + - width, height, depth + shape: + - - 1 + - - 3 + datasets: - name: sweep_mask dtype: numeric doc: Scanning sweep pattern designated using a mask of size [width,height, depth] for 3D stimulation, where for a given pixel a value of 1 indicates stimulation, and a value of 0 indicates no stimulation. - required: false + quantity: "?" + dims: + - num_rows + - num_cols + - num_planes + shape: + - + - + - - neurodata_type_def: SpiralScanning neurodata_type_inc: LabMetaData doc: Container to store the parameters defining a spiral scanning pattern. attributes: - - name: diameter + - name: diameter_in_um dtype: numeric doc: Spiral diameter (in micrometers). - required: true - name: number_of_revolutions dtype: numeric doc: Number of turns within a spiral. - required: true + - name: height_in_um + dtype: numeric + doc: Spiral height of each sweep (in micrometers). + required: false - name: description dtype: text doc: Describe any additional details about the pattern. required: false - - name: height - dtype: numeric - doc: Spiral height of each sweep (in micrometers). - required: false - neurodata_type_def: TemporalFocusing neurodata_type_inc: LabMetaData doc: Container to store the parameters defining a temporal focusing beam-shaping. attributes: - - name: lateral_point_spread_function + - name: lateral_point_spread_function_in_um dtype: text doc: Estimated lateral spatial profile or point spread function, expressed as mean [um] ± s.d [um]. - required: true - - name: axial_point_spread_function + - name: axial_point_spread_function_in_um dtype: text doc: Estimated axial spatial profile or point spread function, expressed as mean [um] ± s.d [um]. - required: true - name: description dtype: text doc: Describe any additional details about the pattern. @@ -92,12 +114,10 @@ groups: - name: effector dtype: text doc: Light-activated effector protein expressed by the targeted cell (e.g., ChR2). - required: true links: - name: light_source - target_type: LightSource + target_type: Device doc: Light source used to apply photostimulation. - required: true - name: spatial_light_modulator target_type: Device doc: Spatial light modulator used to generate photostimulation pattern. @@ -110,10 +130,14 @@ groups: dtype: text doc: The model specification of the spatial light modulator (e.g. 'X15213 series', from Hamamatsu). required: false - - name: spatial_resolution + - name: spatial_resolution_in_px dtype: numeric doc: Resolution of spatial light modulator (in pixels), formatted as [width, height]. required: false + dims: + - width, height + shape: + - 2 - neurodata_type_def: SpatialLightModulator3D neurodata_type_inc: Device doc: 3D spatial light modulator used in the experiment. @@ -122,46 +146,49 @@ groups: dtype: text doc: The model specification of the spatial light modulator (e.g. 'NeuraLight 3D Ultra', from Bruker). required: false - - name: spatial_resolution + - name: spatial_resolution_in_px dtype: numeric doc: Resolution of spatial light modulator (in pixels), formatted as [width, height, depth]. required: false + dims: + - width, height, depth + shape: + - 3 - neurodata_type_def: LightSource neurodata_type_inc: Device doc: Light source used in the experiment. attributes: - - name: stimulation_wavelength + - name: stimulation_wavelength_in_nm dtype: numeric doc: Excitation wavelength of stimulation light (nanometers). - required: true - - name: model - dtype: text - doc: Model of light source device. - required: false - name: filter_description dtype: text doc: Filter used to obtain the excitation wavelength of stimulation light, e.g. 'Short pass at 1040 nm'. required: false - - name: peak_power + - name: peak_power_in_W dtype: numeric doc: Incident power of stimulation device (in Watts). required: false - - name: peak_pulse_energy + - name: peak_pulse_energy_in_J dtype: numeric doc: If device is pulsed light source, pulse energy (in Joules). required: false - - name: intensity + - name: intensity_in_W_per_m2 dtype: numeric doc: Intensity of the excitation in W/m^2, if known. required: false - - name: exposure_time + - name: exposure_time_in_s dtype: numeric doc: Exposure time of the sample (in sec). required: false - - name: pulse_rate + - name: pulse_rate_in_Hz dtype: numeric doc: If device is pulsed light source, pulse rate (in Hz) used for stimulation. required: false + - name: model + dtype: text + doc: Model of light source device. + required: false - neurodata_type_def: OptogeneticStimulusTarget neurodata_type_inc: LabMetaData doc: Container to store the targated rois in a photostimulation experiment. @@ -169,58 +196,83 @@ groups: - name: targeted_rois neurodata_type_inc: DynamicTableRegion doc: A table region referencing a PlaneSegmentation object storing targeted ROIs. - required: true - name: segmented_rois neurodata_type_inc: DynamicTableRegion doc: A table region referencing a PlaneSegmentation object storing segmented ROIs that receive photostimulation. - required: false + quantity: "?" - neurodata_type_def: PatternedOptogeneticStimulusTable neurodata_type_inc: TimeIntervals doc: Table to hold all patterned optogenetic stimulus onsets. - quantity: "?" datasets: - name: power neurodata_type_inc: VectorData doc: Power (in Watts) defined as a scalar. All rois in target receive the same photostimulation power. quantity: "?" + attributes: + - name: unit + value: Watts + doc: Unit of measure of power, fixed to Watts. + dtype: text - name: power_per_roi neurodata_type_inc: VectorData doc: Power (in Watts) defined as an array. Each power value refers to each roi in target. quantity: "?" + attributes: + - name: unit + value: Watts + doc: Unit of measure of power, fixed to Watts. + dtype: text - name: targets neurodata_type_inc: VectorData dtype: target_type: OptogeneticStimulusTarget reftype: object doc: Targeted rois for the stimulus onset. - required: true - name: stimulus_pattern neurodata_type_inc: VectorData dtype: target_type: LabMetaData reftype: object doc: Link to the stimulus pattern. - required: true - name: stimulus_site neurodata_type_inc: VectorData dtype: target_type: PatternedOptogeneticStimulusSite reftype: object doc: Link to the stimulus site. - required: true - name: frequency neurodata_type_inc: VectorData doc: Frequency (in Hz) defined as a scalar. All rois in target receive the photostimulation at the same frequency. quantity: "?" + attributes: + - name: unit + value: Hertz + doc: Unit of measure of frequency, fixed to Hertz. + dtype: text - name: frequency_per_roi neurodata_type_inc: VectorData doc: Frequency (in Hz) defined as an array. Each frequency value refers to each roi in target. quantity: "?" + attributes: + - name: unit + value: Hertz + doc: Unit of measure of frequency, fixed to Hertz. + dtype: text - name: pulse_width neurodata_type_inc: VectorData doc: Pulse Width (in sec/phase) defined as a scalar. All rois in target receive the photostimulation with the same pulse width. quantity: "?" + attributes: + - name: unit + value: seconds/phase + doc: Unit of measure of power, fixed to seconds per phase. + dtype: text - name: pulse_width_per_roi neurodata_type_inc: VectorData doc: Pulse Width (in sec/phase) defined as an array. Each pulse width value refers to each roi in target. quantity: "?" + attributes: + - name: unit + value: seconds/phase + doc: Unit of measure of power, fixed to seconds per phase. + dtype: text diff --git a/src/pynwb/ndx_patterned_ogen/__init__.py b/src/pynwb/ndx_patterned_ogen/__init__.py index 44fa0ef..b9eee51 100644 --- a/src/pynwb/ndx_patterned_ogen/__init__.py +++ b/src/pynwb/ndx_patterned_ogen/__init__.py @@ -1,5 +1,5 @@ import os -from pynwb import load_namespaces +from pynwb import load_namespaces, get_class try: from importlib.resources import files @@ -14,22 +14,24 @@ # If that path does not exist, we are likely running in editable mode. Use the local path instead if not os.path.exists(__spec_path): __spec_path = __location_of_this_file.parent.parent.parent / "spec" / "ndx-patterned-ogen.namespace.yaml" + +load_namespaces(str(__spec_path)) + +SpatialLightModulator2D = get_class('SpatialLightModulator2D', 'ndx-patterned-ogen') +SpatialLightModulator3D = get_class('SpatialLightModulator3D', 'ndx-patterned-ogen') +LightSource = get_class('LightSource', 'ndx-patterned-ogen') +OptogeneticStimulus2DPattern = get_class('OptogeneticStimulus2DPattern', 'ndx-patterned-ogen') +OptogeneticStimulus3DPattern = get_class('OptogeneticStimulus3DPattern', 'ndx-patterned-ogen') +SpiralScanning = get_class('SpiralScanning', 'ndx-patterned-ogen') +TemporalFocusing = get_class('TemporalFocusing', 'ndx-patterned-ogen') # Load the namespace -load_namespaces(str(__spec_path)) from .patterned_ogen import ( - SpatialLightModulator3D, - SpatialLightModulator2D, - LightSource, PatternedOptogeneticStimulusSite, PatternedOptogeneticStimulusTable, - OptogeneticStimulus2DPattern, - OptogeneticStimulus3DPattern, OptogeneticStimulusSite, OptogeneticStimulusTarget, - SpiralScanning, - TemporalFocusing, ) __all__ = [ diff --git a/src/pynwb/ndx_patterned_ogen/patterned_ogen.py b/src/pynwb/ndx_patterned_ogen/patterned_ogen.py index 74195c8..946967a 100644 --- a/src/pynwb/ndx_patterned_ogen/patterned_ogen.py +++ b/src/pynwb/ndx_patterned_ogen/patterned_ogen.py @@ -10,147 +10,6 @@ namespace = "ndx-patterned-ogen" -@register_class("SpatialLightModulator3D", namespace) -class SpatialLightModulator3D(Device): - """ - Spatial light modulator used in the experiment. - """ - - __nwbfields__ = ("model", "spatial_resolution") - - @docval( - {"name": "name", "type": str, "doc": "Name of SpatialLightModulator3D object."}, - *get_docval(Device.__init__, "description", "manufacturer"), - { - "name": "model", - "type": str, - "doc": "The model specification of the spatial light modulator (e.g. 'NeuraLight 3D Ultra', from Bruker).", - }, - { - "name": "spatial_resolution", - "type": Iterable, - "doc": "Resolution of spatial light modulator (in pixels), formatted as [width, height, depth].", - "default": None, - "shape": (3,), - }, - ) - def __init__(self, **kwargs): - keys_to_set = ("model", "spatial_resolution") - args_to_set = popargs_to_dict(keys_to_set, kwargs) - super().__init__(**kwargs) - for key, val in args_to_set.items(): - setattr(self, key, val) - - -@register_class("SpatialLightModulator2D", namespace) -class SpatialLightModulator2D(Device): - """ - Spatial light modulator used in the experiment. - """ - - __nwbfields__ = ("model", "spatial_resolution") - - @docval( - {"name": "name", "type": str, "doc": "Name of SpatialLightModulator3D object. "}, - *get_docval(Device.__init__, "description", "manufacturer"), - { - "name": "model", - "type": str, - "doc": "The model specification of the spatial light modulator (e.g. 'X15213 series', from Hamamatsu).", - }, - { - "name": "spatial_resolution", - "type": Iterable, - "doc": "Resolution of spatial light modulator (in pixels), formatted as [width, height].", - "default": None, - "shape": (2,), - }, - ) - def __init__(self, **kwargs): - keys_to_set = ("model", "spatial_resolution") - args_to_set = popargs_to_dict(keys_to_set, kwargs) - super().__init__(**kwargs) - for key, val in args_to_set.items(): - setattr(self, key, val) - - -@register_class("LightSource", namespace) -class LightSource(Device): - """ - Light source used in the experiment. - """ - - __nwbfields__ = ( - "model", - "stimulation_wavelength", - "peak_power", - "filter_descriptionpeak_pulse_energy", - "intensity", - "pulse_rate", - "exposure_time", - ) - - @docval( - {"name": "name", "type": str, "doc": "Name of LightSource object."}, - *get_docval(Device.__init__, "description", "manufacturer"), - {"name": "model", "type": str, "doc": "Model of light source device."}, - { - "name": "stimulation_wavelength", - "type": (int, float), - "doc": "Excitation wavelength of stimulation light (nanometers).", - "default": None, - }, - { - "name": "peak_power", - "type": (int, float), - "doc": "Incident power of stimulation device (in Watts).", - "default": None, - }, - { - "name": "filter_description", - "type": str, - "doc": ( - "Filter used to obtain the excitation wavelength of stimulation light, e.g. 'Short pass at 1040 nm'." - ), - "default": None, - }, - { - "name": "peak_pulse_energy", - "type": (int, float), - "doc": "If device is pulsed light source, pulse energy (in Joules).", - "default": None, - }, - { - "name": "intensity", - "type": (int, float), - "doc": "Intensity of the excitation in W/m^2, if known.", - "default": None, - }, - { - "name": "pulse_rate", - "type": (int, float), - "doc": "If device is pulsed light source, pulse rate (in Hz) used for stimulation.", - "default": None, - }, - {"name": "exposure_time", "type": (int, float), "doc": "Exposure time of the sample (in sec)", "default": None}, - ) - def __init__(self, **kwargs): - keys_to_set = ( - "model", - "stimulation_wavelength", - "peak_power", - "filter_description", - "peak_pulse_energy", - "intensity", - "pulse_rate", - "exposure_time", - ) - args_to_set = popargs_to_dict(keys_to_set, kwargs) - super().__init__(**kwargs) - for key, val in args_to_set.items(): - setattr(self, key, val) - - @register_class("PatternedOptogeneticStimulusSite", namespace) class PatternedOptogeneticStimulusSite(OptogeneticStimulusSite): """ @@ -169,10 +28,10 @@ class PatternedOptogeneticStimulusSite(OptogeneticStimulusSite): }, { "name": "spatial_light_modulator", - "type": (SpatialLightModulator3D, SpatialLightModulator2D), + "type": Device, "doc": "Spatial light modulator used to generate photostimulation pattern.", }, - {"name": "light_source", "type": LightSource, "doc": "Light source used to apply photostimulation."}, + {"name": "light_source", "type": Device, "doc": "Light source used to apply photostimulation."}, ) def __init__(self, **kwargs): keys_to_set = ("effector", "spatial_light_modulator", "light_source") @@ -181,13 +40,11 @@ def __init__(self, **kwargs): for key, val in args_to_set.items(): setattr(self, key, val) - @docval( - { - "name": "spatial_light_modulator", - "type": (SpatialLightModulator3D, SpatialLightModulator2D), - "doc": "Spatial light modulator used to generate photostimulation pattern. ", - } - ) + @docval({ + "name": "spatial_light_modulator", + "type": Device, + "doc": "Spatial light modulator used to generate photostimulation pattern. ", + }) def add_spatial_light_modulator(self, spatial_light_modulator): """ Add a spatial light modulator to the photostimulation method. @@ -197,7 +54,7 @@ def add_spatial_light_modulator(self, spatial_light_modulator): else: self.spatial_light_modulator = spatial_light_modulator - @docval({"name": "light_source", "type": LightSource, "doc": "Light source used to apply photostimulation."}) + @docval({"name": "light_source", "type": Device, "doc": "Light source used to apply photostimulation."}) def add_light_source(self, light_source): """ Add a light source to the photostimulation method. @@ -245,182 +102,6 @@ def __init__(self, **kwargs): setattr(self, key, val) -@register_class("OptogeneticStimulus2DPattern", namespace) -class OptogeneticStimulus2DPattern(LabMetaData): - """ - Container to store the information about a generic 2D stimulus pattern (spatial information). - """ - - __nwbfields__ = ("description", "sweep_size", "sweep_mask") - - @docval( - *get_docval(LabMetaData.__init__, "name"), - { - "name": "description", - "type": str, - "doc": ( - "Description of the scanning or scanless method for shaping optogenetic light. Examples include" - " diffraction limited points, 3D shot, disks, etc." - ), - }, - { - "name": "sweep_size", - "type": (int, float, Iterable), - "doc": ( - "Size of the scanning sweep pattern in micrometers. If a scalar is provided, the sweep pattern is" - " assumed to be a circle (for 2D patterns) with diameter 'sweep_size'." - " If 'sweep_size' is a two dimensional array, the the sweep pattern is assumed to be a" - " rectangle, with dimensions [width, height]." - ), - "default": None, - }, - { - "name": "sweep_mask", - "type": Iterable, - "doc": ( - "Scanning sweep pattern designated using a mask of size [width, height] for 2D stimulation," - " where for a given pixel a value of 1 indicates stimulation, and a" - " value of 0 indicates no stimulation." - ), - "default": None, - }, - ) - def __init__(self, **kwargs): - keys_to_set = ("description", "sweep_size", "sweep_mask") - args_to_set = popargs_to_dict(keys_to_set, kwargs) - super().__init__(**kwargs) - for key, val in args_to_set.items(): - setattr(self, key, val) - - -@register_class("OptogeneticStimulus3DPattern", namespace) -class OptogeneticStimulus3DPattern(LabMetaData): - """ - Container to store the information about a generic 3D stimulus pattern (spatial information). - """ - - __nwbfields__ = ("description", "sweep_size", "sweep_mask") - - @docval( - *get_docval(LabMetaData.__init__, "name"), - { - "name": "description", - "type": str, - "doc": ( - "Description of the scanning or scanless method for shaping optogenetic light. Examples include" - " diffraction limited points, 3D shot, disks, etc." - ), - }, - { - "name": "sweep_size", - "type": (int, float, Iterable), - "doc": ( - "Size of the scanning sweep pattern in micrometers. If a scalar is provided, the sweep pattern is" - " assumed to be a cylinder (for 3D patterns), with diameter 'sweep_size'." - " If 'sweep_size' is a three dimensional array, the the sweep pattern is assumed to be a" - " cuboid, with dimensions [width, height, depth]." - ), - "default": None, - }, - { - "name": "sweep_mask", - "type": Iterable, - "doc": ( - "Scanning sweep pattern designated using a mask of size [width, height, depth] for 3D stimulation," - " where for a given pixel a value of 1 indicates stimulation, and a" - " value of 0 indicates no stimulation." - ), - "default": None, - }, - ) - def __init__(self, **kwargs): - keys_to_set = ("description", "sweep_size", "sweep_mask") - args_to_set = popargs_to_dict(keys_to_set, kwargs) - super().__init__(**kwargs) - for key, val in args_to_set.items(): - setattr(self, key, val) - - -@register_class("TemporalFocusing", namespace) -class TemporalFocusing(LabMetaData): - """ - Container to store the parameters defining a temporal focusing beam-shaping - """ - - __nwbfields__ = ("description", "lateral_point_spread_function", "axial_point_spread_function") - - @docval( - *get_docval(LabMetaData.__init__, "name"), - { - "name": "description", - "type": str, - "doc": "Describe any additional details about the pattern.", - "default": None, - }, - { - "name": "lateral_point_spread_function", - "type": str, - "doc": "Estimated lateral spatial profile or point spread function, expressed as mean [um] ± s.d [um].", - "default": None, - }, - { - "name": "axial_point_spread_function", - "type": str, - "doc": "Estimated axial spatial profile or point spread function, expressed as mean [um] ± s.d [um]", - "default": None, - }, - ) - def __init__(self, **kwargs): - keys_to_set = ("description", "lateral_point_spread_function", "axial_point_spread_function") - args_to_set = popargs_to_dict(keys_to_set, kwargs) - super().__init__(**kwargs) - for key, val in args_to_set.items(): - setattr(self, key, val) - - -@register_class("SpiralScanning", namespace) -class SpiralScanning(LabMetaData): - """ - Container to store the parameters defining a spiral scanning pattern. - """ - - __nwbfields__ = ("description", "diameter", "height", "number_of_revolutions") - - @docval( - *get_docval(LabMetaData.__init__, "name"), - { - "name": "description", - "type": str, - "doc": "Describe any additional details about the pattern.", - "default": None, - }, - { - "name": "diameter", - "type": (int, float), - "doc": "Spiral diameter (in micrometers).", - "default": None, - }, - { - "name": "height", - "type": (int, float), - "doc": "Spiral height of each sweep (in micrometers).", - "default": None, - }, - { - "name": "number_of_revolutions", - "type": int, - "doc": "Number of turns within a spiral.", - "default": None, - }, - ) - def __init__(self, **kwargs): - keys_to_set = ("description", "diameter", "height", "number_of_revolutions") - args_to_set = popargs_to_dict(keys_to_set, kwargs) - super().__init__(**kwargs) - for key, val in args_to_set.items(): - setattr(self, key, val) - - @register_class("PatternedOptogeneticStimulusTable", namespace) class PatternedOptogeneticStimulusTable(TimeIntervals): """ @@ -429,8 +110,8 @@ class PatternedOptogeneticStimulusTable(TimeIntervals): __fields__ = () __columns__ = ( - {"name": "start_time", "description": "Start time of stimulation, in seconds", "required": True}, - {"name": "stop_time", "description": "Stop time of stimulation, in seconds", "required": True}, + {"name": "start_time", "description": "Start time of stimulation, in seconds"}, + {"name": "stop_time", "description": "Stop time of stimulation, in seconds"}, { "name": "power", "description": ( @@ -471,16 +152,14 @@ class PatternedOptogeneticStimulusTable(TimeIntervals): ), "required": False, }, - {"name": "targets", "description": "Targeted rois for the stimulus onset.", "required": True}, + {"name": "targets", "description": "Targeted rois for the stimulus onset."}, { "name": "stimulus_pattern", "description": "Link to the stimulus pattern.", - "required": True, }, { "name": "stimulus_site", "description": "Link to the stimulus site.", - "required": True, }, ) @@ -492,7 +171,7 @@ def check_if_argument_is_not_scalar(cls, colset, field_name): f"{field_name} should be defined as scalar. Use '{field_name}_per_roi' to store photostimulation" f" at different {field_name}, for each rois in target." ) - + @classmethod def check_length_rois_properties(cls, colset, field_name): for row in range(len(colset[field_name])): @@ -602,7 +281,7 @@ def __init__(self, **kwargs): { "name": "stimulus_pattern", "doc": "Link to the stimulus pattern.", - "type": (OptogeneticStimulus3DPattern, OptogeneticStimulus2DPattern, TemporalFocusing, SpiralScanning), + "type": LabMetaData, }, { "name": "stimulus_site", diff --git a/src/pynwb/tests/mock/patternedogen.py b/src/pynwb/tests/mock/patternedogen.py index 1281360..04a8784 100644 --- a/src/pynwb/tests/mock/patternedogen.py +++ b/src/pynwb/tests/mock/patternedogen.py @@ -26,7 +26,7 @@ def mock_OptogeneticStimulus2DPattern( name: Optional[str] = None, description: str = "Generic description for optogenetic stimulus 2D pattern", - sweep_size: float = 5, # um + sweep_size_in_um: list = [5], # um sweep_mask=np.zeros((10, 10)), nwbfile: Optional[NWBFile] = None, ) -> OptogeneticStimulus2DPattern: @@ -34,7 +34,7 @@ def mock_OptogeneticStimulus2DPattern( name=name or name_generator("OptogeneticStimulus2DPattern"), description=description, sweep_mask=sweep_mask, - sweep_size=sweep_size, + sweep_size_in_um=sweep_size_in_um, ) nwbfile.add_lab_meta_data(stimulus_pattern) return stimulus_pattern @@ -43,7 +43,7 @@ def mock_OptogeneticStimulus2DPattern( def mock_OptogeneticStimulus3DPattern( name: Optional[str] = None, description: str = "Generic description for optogenetic stimulus 3D pattern", - sweep_size: float = 5, # um + sweep_size_in_um: list = [5], # um sweep_mask=np.zeros((10, 10, 2)), nwbfile: Optional[NWBFile] = None, ) -> OptogeneticStimulus3DPattern: @@ -51,7 +51,7 @@ def mock_OptogeneticStimulus3DPattern( name=name or name_generator("OptogeneticStimulus3DPattern"), description=description, sweep_mask=sweep_mask, - sweep_size=sweep_size, + sweep_size_in_um=sweep_size_in_um, ) nwbfile.add_lab_meta_data(stimulus_pattern) return stimulus_pattern @@ -60,15 +60,15 @@ def mock_OptogeneticStimulus3DPattern( def mock_TemporalFocusing( name: Optional[str] = None, description: str = "Generic description for optogenetic stimulus pattern", - lateral_point_spread_function: str = "9e-6 m ± 0.7e-6 m", - axial_point_spread_function: str = "32e-6 m ± 1.6e-6 m", + lateral_point_spread_function_in_um: str = "9e-6 m ± 0.7e-6 m", + axial_point_spread_function_in_um: str = "32e-6 m ± 1.6e-6 m", nwbfile: Optional[NWBFile] = None, ) -> TemporalFocusing: stimulus_pattern_temporal_focusing = TemporalFocusing( name=name or name_generator("TemporalFocusing"), description=description, - lateral_point_spread_function=lateral_point_spread_function, - axial_point_spread_function=axial_point_spread_function, + lateral_point_spread_function_in_um=lateral_point_spread_function_in_um, + axial_point_spread_function_in_um=axial_point_spread_function_in_um, ) nwbfile.add_lab_meta_data(stimulus_pattern_temporal_focusing) return stimulus_pattern_temporal_focusing @@ -77,16 +77,16 @@ def mock_TemporalFocusing( def mock_SpiralScanning( name: Optional[str] = None, description: str = "Generic description for optogenetic stimulus pattern", - diameter: float = 15e-6, # diameter of a single spiral - height: float = 10e-6, # height of a single spira (if 3D pattern) + diameter_in_um: float = 15e-6, # diameter_in_um of a single spiral + height_in_um: float = 10e-6, # height_in_um of a single spira (if 3D pattern) number_of_revolutions: float = 5, # number of revolution of a single spira nwbfile: Optional[NWBFile] = None, ) -> SpiralScanning: stimulus_pattern_spiral_scanning = SpiralScanning( name=name or name_generator("SpiralScanning"), description=description, - diameter=diameter, - height=height, + diameter_in_um=diameter_in_um, + height_in_um=height_in_um, number_of_revolutions=number_of_revolutions, ) nwbfile.add_lab_meta_data(stimulus_pattern_spiral_scanning) @@ -97,28 +97,28 @@ def mock_LightSource( name: Optional[str] = None, manufacturer: Optional[str] = None, model: Optional[str] = "laser model", - stimulation_wavelength: float = 1035.0, # nm + stimulation_wavelength_in_nm: float = 1035.0, # nm description: str = "Generic description for the laser", - peak_power: float = 0.70, # the peak power of stimulation in Watts + peak_power_in_W: float = 0.70, # the peak power of stimulation in Watts filter_description: str = "Short pass at 1040 nm", - peak_pulse_energy: float = 0.70, - intensity: float = 0.005, # the intensity of excitation in W/mm^2 - exposure_time: float = 2.51e-13, # the exposure time of the sample in seconds - pulse_rate: float = 2.0e6, # the pulse rate of the laser is in Hz + peak_pulse_energy_in_J: float = 0.70, + intensity_in_W_per_m2: float = 0.005, # the intensity of excitation in W/mm^2 + exposure_time_in_s: float = 2.51e-13, # the exposure time of the sample in seconds + pulse_rate_in_Hz: float = 2.0e6, # the pulse rate of the laser is in Hz nwbfile: Optional[NWBFile] = None, ) -> LightSource: light_source = LightSource( name=name or name_generator("LightSource"), manufacturer=manufacturer, model=model, - stimulation_wavelength=stimulation_wavelength, + stimulation_wavelength_in_nm=stimulation_wavelength_in_nm, filter_description=filter_description, description=description, - peak_pulse_energy=peak_pulse_energy, - peak_power=peak_power, - intensity=intensity, - exposure_time=exposure_time, - pulse_rate=pulse_rate, + peak_pulse_energy_in_J=peak_pulse_energy_in_J, + peak_power_in_W=peak_power_in_W, + intensity_in_W_per_m2=intensity_in_W_per_m2, + exposure_time_in_s=exposure_time_in_s, + pulse_rate_in_Hz=pulse_rate_in_Hz, ) nwbfile.add_device(light_source) return light_source @@ -129,7 +129,7 @@ def mock_SpatialLightModulator2D( description: str = "Generic description for the spatial light modulator device", model: str = "Generic model for the spatial light modulator device", manufacturer: Optional[str] = None, - spatial_resolution: list = [100, 100], + spatial_resolution_in_px: list = [100, 100], nwbfile: Optional[NWBFile] = None, ) -> SpatialLightModulator2D: spatial_light_modulator = SpatialLightModulator2D( @@ -137,7 +137,7 @@ def mock_SpatialLightModulator2D( description=description, model=model, manufacturer=manufacturer, - spatial_resolution=spatial_resolution, + spatial_resolution_in_px=spatial_resolution_in_px, ) nwbfile.add_device(spatial_light_modulator) return spatial_light_modulator @@ -148,7 +148,7 @@ def mock_SpatialLightModulator3D( description: str = "Generic description for the spatial light modulator device", model: str = "Generic model for the spatial light modulator device", manufacturer: Optional[str] = None, - spatial_resolution: list = [100, 100, 100], + spatial_resolution_in_px: list = [100, 100, 100], nwbfile: Optional[NWBFile] = None, ) -> SpatialLightModulator3D: spatial_light_modulator = SpatialLightModulator3D( @@ -156,7 +156,7 @@ def mock_SpatialLightModulator3D( description=description, model=model, manufacturer=manufacturer, - spatial_resolution=spatial_resolution, + spatial_resolution_in_px=spatial_resolution_in_px, ) nwbfile.add_device(spatial_light_modulator) return spatial_light_modulator @@ -225,9 +225,9 @@ def mock_PatternedOptogeneticStimulusTable( description: str = "no description", start_time: list = [0.0, 0.1, 0.2], stop_time: list = [0.7, 0.8, 0.9], - power: list = [700.0, 800.0, 900.0], - frequency: list = [7.0, 8.0, 9.0], - pulse_width: list = [0.1, 0.1, 0.1], + power: list = [0.7, 0.8, 0.9], + frequency: list = [20.0, 10.0, 5.0], + pulse_width: list = [0.01, 0.02, 0.05], stimulus_pattern: list = [None, None, None], targets: list = [None, None, None], stimulus_site: list = [None, None, None], diff --git a/src/pynwb/tests/test_patternedogen.py b/src/pynwb/tests/test_patternedogen.py index ec0b7b5..a8853dc 100644 --- a/src/pynwb/tests/test_patternedogen.py +++ b/src/pynwb/tests/test_patternedogen.py @@ -1,5 +1,4 @@ -"""Unit and integration tests for the PatternedOptogeneticStimulusTable extension neurodata type. -""" +"""Unit and integration tests for the PatternedOptogeneticStimulusTable extension neurodata type.""" import numpy as np from hdmf.common.table import VectorData diff --git a/tutorial_patterned_ogen.ipynb b/tutorial_patterned_ogen.ipynb index afed8a9..72689af 100644 --- a/tutorial_patterned_ogen.ipynb +++ b/tutorial_patterned_ogen.ipynb @@ -22,7 +22,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -61,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -70,7 +70,7 @@ " name=\"SpatialLightModulator2D\",\n", " description=\"Generic description for the slm\",\n", " manufacturer=\"slm manufacturer\",\n", - " spatial_resolution=[512, 512],\n", + " spatial_resolution_in_px=[512, 512],\n", ")\n", "nwbfile.add_device(spatial_light_modulator)\n", "\n", @@ -79,13 +79,13 @@ " name=\"Laser\",\n", " model=\"laser model\",\n", " manufacturer=\"laser manufacturer\",\n", - " stimulation_wavelength=1035.0, # nm\n", + " stimulation_wavelength_in_nm=1035.0, # nm\n", " filter_description=\"Short pass at 1040 nm\",\n", " description=\"Generic description for the laser\",\n", - " peak_power=70e-3, # the peak power of stimulation in Watts\n", - " intensity=0.005, # the intensity of excitation in W/mm^2\n", - " exposure_time=2.51e-13, # the exposure time of the sample in seconds\n", - " pulse_rate=1 / 2.51e-13, # the pulse rate of the laser is in Hz\n", + " peak_power_in_W=70e-3, # the peak power of stimulation in Watts\n", + " intensity_in_W_per_m2=0.005, # the intensity of excitation in W/mm^2\n", + " exposure_time_in_s=2.51e-13, # the exposure time of the sample in seconds\n", + " pulse_rate_in_Hz=1 / 2.51e-13, # the pulse rate of the laser is in Hz\n", ")\n", "nwbfile.add_device(light_source)\n", "\n", @@ -108,9 +108,86 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + "

PatternedOptogeneticStimulusSite

device
description: My two-photon microscope
manufacturer: The best microscope manufacturer
description: Scanning
excitation_lambda: 600.0
location: VISrl
effector: ChR2
spatial_light_modulator
description: Generic description for the slm
manufacturer: slm manufacturer
spatial_resolution_in_px
0: 512
1: 512
light_source
description: Generic description for the laser
manufacturer: laser manufacturer
stimulation_wavelength_in_nm: 1035.0
filter_description: Short pass at 1040 nm
peak_power_in_W: 0.07
intensity_in_W_per_m2: 0.005
exposure_time_in_s: 2.51e-13
pulse_rate_in_Hz: 3984063745019.9204
model: laser model
" + ], + "text/plain": [ + "PatternedOptogeneticStimulusSite ndx_patterned_ogen.patterned_ogen.PatternedOptogeneticStimulusSite at 0x140319671366000\n", + "Fields:\n", + " description: Scanning\n", + " device: 2P_microscope pynwb.device.Device at 0x140321045509376\n", + "Fields:\n", + " description: My two-photon microscope\n", + " manufacturer: The best microscope manufacturer\n", + "\n", + " effector: ChR2\n", + " excitation_lambda: 600.0\n", + " light_source: Laser abc.LightSource at 0x140319685390176\n", + "Fields:\n", + " description: Generic description for the laser\n", + " exposure_time_in_s: 2.51e-13\n", + " filter_description: Short pass at 1040 nm\n", + " intensity_in_W_per_m2: 0.005\n", + " manufacturer: laser manufacturer\n", + " model: laser model\n", + " peak_power_in_W: 0.07\n", + " pulse_rate_in_Hz: 3984063745019.9204\n", + " stimulation_wavelength_in_nm: 1035.0\n", + "\n", + " location: VISrl\n", + " spatial_light_modulator: SpatialLightModulator2D abc.SpatialLightModulator2D at 0x140321045509664\n", + "Fields:\n", + " description: Generic description for the slm\n", + " manufacturer: slm manufacturer\n", + " spatial_resolution_in_px: [512 512]\n" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# metadata for the stimulus methods\n", "site = PatternedOptogeneticStimulusSite(\n", @@ -140,9 +217,83 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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DAb1+9//3usxAAAJzvMzoLffflv79u3T/v371djYqL179+oPf/iD9u7d2+P+69atUygUii2tra1ejwQASECO6/HlaQUFBVq7dq0qKipi6zZu3Ki//OUv+vTTT/u9fzgclt/v93Ik9IMrFIG7w7dh9ywUCik7O7vX7Z6fAd24cUMpKd0fNjU1VdFo1OtDAQCSmOfvAZWVlWnTpk0qLCxUcXGxPvroI7388stavny514cCACQxz1+Cu3btmmpqalRbW6uOjg4FAgEtXrxY69evV3p6er/35yW4ocdLcMDd4SW4nvX3EpznAbpbBGjoJdivAJB0CFDPhvw9IAAABoIAAQBMECAAgAkCBAAw4fll2Eg+8X4DlYscYI2LBBITZ0AAABMECABgggABAEwQIACACQIEADBBgAAAJggQAMAEAQIAmCBAAAATBAgAYIIAAQBMECAAgAkCBAAwQYAAACYIEADABAECAJggQAAAEwQIAGCCAAEATBAgAIAJAgQAMEGAAAAmCBAAwAQBAgCYIEAAABMECABgggABAEwQIACACQIEADBBgAAAJgYdoOPHj6usrEyBQECO4+jgwYPdtruuq/Xr12vcuHHKyMhQaWmpLl686NW8AIBhYtAB6uzs1LRp07R9+/Yet2/dulWvvvqqdu7cqdOnTyszM1Pz5s3TzZs373pYAMAw4t4FSW5tbW3sdjQadfPz892XXnoptu7rr792fT6fe+DAgQE9ZigUciWxDKMFsGb9HBipSygU6vP/i6fvAbW0tKitrU2lpaWxdX6/XzNnztTJkyd7vE8kElE4HO62AACGP08D1NbWJknKy8vrtj4vLy+27buCwaD8fn9sKSgo8HIkAECCMr8Kbt26dQqFQrGltbXVeiQAwBDwNED5+fmSpPb29m7r29vbY9u+y+fzKTs7u9sCABj+PA1QUVGR8vPzVVdXF1sXDod1+vRpzZo1y8tDAQCSXNpg73D9+nVdunQpdrulpUVNTU3KyclRYWGhKisrtXHjRk2aNElFRUWqqalRIBDQwoULvZwbAJDsBns5Y319fY+X25WXl7uu+99LsWtqaty8vDzX5/O5c+fOdZubmwf8+FyGPfwWwJr1c2CkLv1dhu38//+chBEOh+X3+63HgIcS7FcMI5DjONYjjEihUKjP9/XNr4IDAIxMBAgAYIIAAQBMECAAgIlB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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + "

TemporalFocusing

lateral_point_spread_function_in_um: 9 um ± 0.7 um
axial_point_spread_function_in_um: 32 um ± 1.6 um
description: scanless beam pattern
" + ], + "text/plain": [ + "TemporalFocusing abc.TemporalFocusing at 0x140319659264384\n", + "Fields:\n", + " axial_point_spread_function_in_um: 32 um ± 1.6 um\n", + " description: scanless beam pattern\n", + " lateral_point_spread_function_in_um: 9 um ± 0.7 um" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# metadata for a generic stimulus pattern\n", "import numpy as np\n", @@ -175,12 +326,12 @@ " raise ValueError(\"Invalid sweep_size_in_pizels. Should be a scalar or a 2-element array.\")\n", " return image_mask\n", "\n", - "sweep_size=8 \n", - "circular_image_mask_np = generate_image_mask_np(width=sweep_size*2, height=sweep_size*2, sweep_size_in_pizels=sweep_size) # assuming 1 pixel=1 um\n", + "sweep_size=[8] \n", + "circular_image_mask_np = generate_image_mask_np(width=sweep_size[0]*2, height=sweep_size[0]*2, sweep_size_in_pizels=sweep_size[0]) # assuming 1 pixel=1 um\n", "generic_circular_pattern = OptogeneticStimulus2DPattern(\n", " name=\"CircularOptogeneticStimulusPattern\",\n", " description=\"circular pattern\",\n", - " sweep_size=sweep_size, # um\n", + " sweep_size_in_um=sweep_size, # um\n", " # sweep_mask=circular_image_mask_np,\n", ")\n", "nwbfile.add_lab_meta_data(generic_circular_pattern)\n", @@ -194,7 +345,7 @@ "generic_rectangular_pattern = OptogeneticStimulus2DPattern(\n", " name=\"RectangularOptogeneticStimulusPattern\",\n", " description=\"rectangular pattern\",\n", - " sweep_size=sweep_size, # um\n", + " sweep_size_in_um=sweep_size, # um\n", " sweep_mask=rectangular_image_mask_np,\n", ")\n", "nwbfile.add_lab_meta_data(generic_rectangular_pattern)\n", @@ -206,8 +357,8 @@ "# metadata for spiral scanning pattern\n", "spiral_scanning = SpiralScanning(\n", " name=\"SpiralScanning\",\n", - " diameter=15, # um\n", - " height=10, # um\n", + " diameter_in_um=15, # um\n", + " height_in_um=10, # um\n", " number_of_revolutions=5,\n", " description=\"scanning beam pattern\",\n", ")\n", @@ -217,8 +368,8 @@ "temporal_focusing = TemporalFocusing(\n", " name=\"TemporalFocusing\",\n", " description=\"scanless beam pattern\",\n", - " lateral_point_spread_function=\"9 um ± 0.7 um\",\n", - " axial_point_spread_function=\"32 um ± 1.6 um\",\n", + " lateral_point_spread_function_in_um=\"9 um ± 0.7 um\",\n", + " axial_point_spread_function_in_um=\"32 um ± 1.6 um\",\n", ")\n", "nwbfile.add_lab_meta_data(temporal_focusing)" ] @@ -235,7 +386,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -271,7 +422,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -315,7 +466,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -362,9 +513,90 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + "

Hologram3 (OptogeneticStimulusTarget)

targeted_rois
description: targeted rois
table
description: Table for storing the targeted roi centroids, defined by a one-pixel mask
imaging_plane
optical_channel
0
description: an optical channel
emission_lambda: 500.0
description: a very interesting part of the brain
device
description: My two-photon microscope
manufacturer: The best microscope manufacturer
excitation_lambda: 600.0
imaging_rate: 30.0
indicator: GFP
location: V1
conversion: 1.0
unit: meters
table\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
pixel_mask
id
0[[0, 0, 0]]
1[[1, 1, 0]]
2[[2, 2, 0]]
3[[3, 3, 0]]

... and 41 more rows.

" + ], + "text/plain": [ + "Hologram3 ndx_patterned_ogen.patterned_ogen.OptogeneticStimulusTarget at 0x140321045763696\n", + "Fields:\n", + " targeted_rois: targeted_rois " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "hologram_1 = OptogeneticStimulusTarget(\n", " name=\"Hologram1\", segmented_rois=segmented_rois_1, targeted_rois=targeted_rois_1\n", @@ -396,9 +628,134 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + " \n", + " \n", + "

PatternedOptogeneticStimulusTable

description: Patterned stimulus
table\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
start_timestop_timepowerfrequencypulse_widthtargetsstimulus_patternstimulus_site
id
00.01.00.0720.00.1Hologram1 ndx_patterned_ogen.patterned_ogen.OptogeneticStimulusTarget at 0x140319653226032\\nFields:\\n segmented_rois: segmented_rois <class 'hdmf.common.table.DynamicTableRegion'>\\n targeted_rois: targeted_rois <class 'hdmf.common.table.DynamicTableRegion'>\\nTemporalFocusing abc.TemporalFocusing at 0x140319659264384\\nFields:\\n axial_point_spread_function_in_um: 32 um ± 1.6 um\\n description: scanless beam pattern\\n lateral_point_spread_function_in_um: 9 um ± 0.7 um\\nPatternedOptogeneticStimulusSite ndx_patterned_ogen.patterned_ogen.PatternedOptogeneticStimulusSite at 0x140319671366000\\nFields:\\n description: Scanning\\n device: 2P_microscope pynwb.device.Device at 0x140321045509376\\nFields:\\n description: My two-photon microscope\\n manufacturer: The best microscope manufacturer\\n\\n effector: ChR2\\n excitation_lambda: 600.0\\n light_source: Laser abc.LightSource at 0x140319685390176\\nFields:\\n description: Generic description for the laser\\n exposure_time_in_s: 2.51e-13\\n filter_description: Short pass at 1040 nm\\n intensity_in_W_per_m2: 0.005\\n manufacturer: laser manufacturer\\n model: laser model\\n peak_power_in_W: 0.07\\n pulse_rate_in_Hz: 3984063745019.9204\\n stimulation_wavelength_in_nm: 1035.0\\n\\n location: VISrl\\n spatial_light_modulator: SpatialLightModulator2D abc.SpatialLightModulator2D at 0x140321045509664\\nFields:\\n description: Generic description for the slm\\n manufacturer: slm manufacturer\\n spatial_resolution_in_px: [512 512]\\n\\n
10.51.00.0520.00.1Hologram2 ndx_patterned_ogen.patterned_ogen.OptogeneticStimulusTarget at 0x140321045763456\\nFields:\\n segmented_rois: segmented_rois <class 'hdmf.common.table.DynamicTableRegion'>\\n targeted_rois: targeted_rois <class 'hdmf.common.table.DynamicTableRegion'>\\nSpiralScanning abc.SpiralScanning at 0x140319654796544\\nFields:\\n description: scanning beam pattern\\n diameter_in_um: 15\\n height_in_um: 10\\n number_of_revolutions: 5\\nPatternedOptogeneticStimulusSite ndx_patterned_ogen.patterned_ogen.PatternedOptogeneticStimulusSite at 0x140319671366000\\nFields:\\n description: Scanning\\n device: 2P_microscope pynwb.device.Device at 0x140321045509376\\nFields:\\n description: My two-photon microscope\\n manufacturer: The best microscope manufacturer\\n\\n effector: ChR2\\n excitation_lambda: 600.0\\n light_source: Laser abc.LightSource at 0x140319685390176\\nFields:\\n description: Generic description for the laser\\n exposure_time_in_s: 2.51e-13\\n filter_description: Short pass at 1040 nm\\n intensity_in_W_per_m2: 0.005\\n manufacturer: laser manufacturer\\n model: laser model\\n peak_power_in_W: 0.07\\n pulse_rate_in_Hz: 3984063745019.9204\\n stimulation_wavelength_in_nm: 1035.0\\n\\n location: VISrl\\n spatial_light_modulator: SpatialLightModulator2D abc.SpatialLightModulator2D at 0x140321045509664\\nFields:\\n description: Generic description for the slm\\n manufacturer: slm manufacturer\\n spatial_resolution_in_px: [512 512]\\n\\n
20.81.70.0420.00.1Hologram3 ndx_patterned_ogen.patterned_ogen.OptogeneticStimulusTarget at 0x140321045763696\\nFields:\\n targeted_rois: targeted_rois <class 'hdmf.common.table.DynamicTableRegion'>\\nCircularOptogeneticStimulusPattern abc.OptogeneticStimulus2DPattern at 0x140319671364608\\nFields:\\n description: circular pattern\\n sweep_size_in_um: [8]\\nPatternedOptogeneticStimulusSite ndx_patterned_ogen.patterned_ogen.PatternedOptogeneticStimulusSite at 0x140319671366000\\nFields:\\n description: Scanning\\n device: 2P_microscope pynwb.device.Device at 0x140321045509376\\nFields:\\n description: My two-photon microscope\\n manufacturer: The best microscope manufacturer\\n\\n effector: ChR2\\n excitation_lambda: 600.0\\n light_source: Laser abc.LightSource at 0x140319685390176\\nFields:\\n description: Generic description for the laser\\n exposure_time_in_s: 2.51e-13\\n filter_description: Short pass at 1040 nm\\n intensity_in_W_per_m2: 0.005\\n manufacturer: laser manufacturer\\n model: laser model\\n peak_power_in_W: 0.07\\n pulse_rate_in_Hz: 3984063745019.9204\\n stimulation_wavelength_in_nm: 1035.0\\n\\n location: VISrl\\n spatial_light_modulator: SpatialLightModulator2D abc.SpatialLightModulator2D at 0x140321045509664\\nFields:\\n description: Generic description for the slm\\n manufacturer: slm manufacturer\\n spatial_resolution_in_px: [512 512]\\n\\n
" + ], + "text/plain": [ + "PatternedOptogeneticStimulusTable ndx_patterned_ogen.patterned_ogen.PatternedOptogeneticStimulusTable at 0x140319655133744\n", + "Fields:\n", + " colnames: ['start_time' 'stop_time' 'power' 'frequency' 'pulse_width' 'targets'\n", + " 'stimulus_pattern' 'stimulus_site']\n", + " columns: (\n", + " start_time ,\n", + " stop_time ,\n", + " power ,\n", + " frequency ,\n", + " pulse_width ,\n", + " targets ,\n", + " stimulus_pattern ,\n", + " stimulus_site \n", + " )\n", + " description: Patterned stimulus\n", + " id: id " + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "stimulus_table = PatternedOptogeneticStimulusTable(\n", " name=\"PatternedOptogeneticStimulusTable\", description=\"Patterned stimulus\"\n", @@ -408,7 +765,7 @@ " stop_time=1.0,\n", " power=70e-3,\n", " frequency=20.0,\n", - " pulse_width=0.1,\n", + " pulse_width=0.01,\n", " stimulus_pattern=temporal_focusing,\n", " targets=nwbfile.lab_meta_data[\"Hologram1\"],\n", " stimulus_site=site,\n", @@ -417,6 +774,8 @@ " start_time=0.5,\n", " stop_time=1.0,\n", " power=50e-3,\n", + " frequency=20.0,\n", + " pulse_width=0.01,\n", " stimulus_pattern=spiral_scanning,\n", " targets=hologram_2,\n", " stimulus_site=site,\n", @@ -426,25 +785,15 @@ " stop_time=1.7,\n", " power=40e-3,\n", " frequency=20.0,\n", - " pulse_width=0.1,\n", + " pulse_width=0.01,\n", " stimulus_pattern=generic_circular_pattern,\n", " targets=hologram_3,\n", " stimulus_site=site,\n", ")\n", - "# TODO add working example for `power`,`frequency` and `pulse_width` as 1D arrays\n", "\n", "nwbfile.add_time_intervals(stimulus_table)" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hologram_3.add_segmented_rois(segmented_rois_3)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -454,7 +803,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [