def map_coordinate_to_name(coordinate): '''Maps coordinate to identifier string representation. Parameters ---------- coordinate: Tuple[int] zero-based row, column position of a given well within the plate Returns ------- str identifier string representation of a well Examples -------- >>> Well.map_coordinate_to_name((0, 1)) "A02" ''' row_index, col_index = coordinate[0], coordinate[1] row_name = utils.map_number_to_letter(row_index + 1) return '%s%.2d' % (row_name, col_index + 1)
def read(self, microscope_metadata_files, microscope_image_filenames): '''Reads metadata from "mlf" and "mrf" metadata files in case they are provided. Parameters ---------- microscope_metadata_files: List[str] absolute path to microscope metadata files microscope_image_filenames: List[str] names of the corresponding microscope image files Returns ------- bioformats.omexml.OMEXML OMEXML image metadata ''' microscope_image_filenames = natsorted(microscope_image_filenames) metadata = bioformats.OMEXML(XML_DECLARATION) if len(microscope_metadata_files) == 0: logger.warn('no microscope metadata files found') return None elif len(microscope_metadata_files) != 2: logger.warn('expected two microscope metadata files') return None for f in microscope_metadata_files: if f.endswith('mlf'): mlf_filename = f elif f.endswith('mrf'): mrf_filename = f mrf_tree = etree.parse(mrf_filename) mrf_root = mrf_tree.getroot() mrf_ns = mrf_root.nsmap['bts'] # Obtain the positional information for each image acquisition site # from the ".mlf" file: mlf_tree = etree.parse(mlf_filename) mlf_root = mlf_tree.getroot() record_elements = mlf_root.xpath('.//bts:MeasurementRecord', namespaces=mlf_root.nsmap) mlf_ns = mlf_root.nsmap['bts'] metadata.image_count = len([ e for e in record_elements if e.attrib['{%s}Type' % mlf_ns] != 'ERR' ]) lookup = defaultdict(list) for e in record_elements: # Translate positional information into well identifier string well_row = utils.map_number_to_letter( int(e.attrib['{%s}Row' % mlf_ns])) well_col = int(e.attrib['{%s}Column' % mlf_ns]) well_id = '%s%.2d' % (well_row, well_col) if e.attrib['{%s}Type' % mlf_ns] == 'ERR': field_index = int(e.attrib['{%s}FieldIndex' % mlf_ns]) logger.error( 'erroneous acquisition - no channel and z-position ' 'information available at well %s field %d' % (well_id, field_index)) continue # This microscope stores each plane in a separate file. Therefore, # we can use the filename to match images. name = e.text index = microscope_image_filenames.index(name) img = metadata.image(index) img.AcquisitionDate = e.attrib['{%s}Time' % mlf_ns] # Image files always contain only a single plane img.Pixels.SizeT = 1 img.Pixels.SizeC = 1 img.Pixels.SizeZ = 1 img.Pixels.plane_count = 1 # A name has to be set as a flag for the handler to update # the metadata img.Name = name # Make channel name consistent with how it is encoded in the image # file name to ensure that the result is the same, independent of # whether it was obtained from the metadata or the image file name. img.Pixels.Channel(0).Name = e.attrib['{%s}Ch' % mlf_ns] img.Pixels.Plane(0).PositionX = float(e.attrib['{%s}X' % mlf_ns]) img.Pixels.Plane(0).PositionY = float(e.attrib['{%s}Y' % mlf_ns]) img.Pixels.Plane(0).PositionZ = float(e.attrib['{%s}Z' % mlf_ns]) img.Pixels.Plane(0).TheZ = int(e.attrib['{%s}ZIndex' % mlf_ns]) img.Pixels.Plane(0).TheT = int(e.attrib['{%s}TimelineIndex' % mlf_ns]) idx = microscope_image_filenames.index(img.Name) lookup[well_id].append(idx) # Obtain the general experiment information and well plate format # specifications from the ".mrf" file: name = mrf_root.attrib['{%s}Title' % mrf_ns] plate = metadata.PlatesDucktype(metadata.root_node).newPlate(name=name) plate.RowNamingConvention = 'letter' plate.ColumnNamingConvention = 'number' plate.Rows = mrf_root.attrib['{%s}RowCount' % mrf_ns] plate.Columns = mrf_root.attrib['{%s}ColumnCount' % mrf_ns] wells = lookup.keys() for w in set(wells): # Create a *Well* element for each imaged well in the plate row = utils.map_letter_to_number(w[0]) - 1 col = int(w[1:]) - 1 well = metadata.WellsDucktype(plate).new(row=row, column=col) well_samples = metadata.WellSampleDucktype(well.node) for i, ref in enumerate(lookup[w]): # Create a *WellSample* element for each acquisition site well_samples.new(index=i) well_samples[i].ImageRef = ref return metadata
def read(self, microscope_metadata_files, microscope_image_filenames): '''Reads metadata from "mlf" and "mrf" metadata files in case they are provided. Parameters ---------- microscope_metadata_files: List[str] absolute path to microscope metadata files microscope_image_filenames: List[str] names of the corresponding microscope image files Returns ------- bioformats.omexml.OMEXML OMEXML image metadata ''' microscope_image_filenames = natsorted(microscope_image_filenames) metadata = bioformats.OMEXML(XML_DECLARATION) if len(microscope_metadata_files) == 0: logger.warn('no microscope metadata files found') return None elif len(microscope_metadata_files) != 2: logger.warn('expected two microscope metadata files') return None for f in microscope_metadata_files: if f.endswith('mlf'): mlf_filename = f elif f.endswith('mrf'): mrf_filename = f mrf_tree = etree.parse(mrf_filename) mrf_root = mrf_tree.getroot() mrf_ns = mrf_root.nsmap['bts'] # Obtain the positional information for each image acquisition site # from the ".mlf" file: mlf_tree = etree.parse(mlf_filename) mlf_root = mlf_tree.getroot() record_elements = mlf_root.xpath( './/bts:MeasurementRecord', namespaces=mlf_root.nsmap ) mlf_ns = mlf_root.nsmap['bts'] metadata.image_count = len([ e for e in record_elements if e.attrib['{%s}Type' % mlf_ns] != 'ERR' ]) lookup = defaultdict(list) for e in record_elements: # Translate positional information into well identifier string well_row = utils.map_number_to_letter( int(e.attrib['{%s}Row' % mlf_ns])) well_col = int(e.attrib['{%s}Column' % mlf_ns]) well_id = '%s%.2d' % (well_row, well_col) if e.attrib['{%s}Type' % mlf_ns] == 'ERR': field_index = int(e.attrib['{%s}FieldIndex' % mlf_ns]) logger.error( 'erroneous acquisition - no channel and z-position ' 'information available at well %s field %d' % (well_id, field_index) ) continue # This microscope stores each plane in a separate file. Therefore, # we can use the filename to match images. name = e.text # Check for .tif to .png/.jpg conversion if microscope_image_filenames[0].endswith('.png'): name = name.replace('.tif','.png') elif microscope_image_filenames[0].endswith('.jpg'): name = name.replace('.tif','.jpg') index = microscope_image_filenames.index(name) img = metadata.image(index) img.AcquisitionDate = e.attrib['{%s}Time' % mlf_ns] # Image files always contain only a single plane img.Pixels.SizeT = 1 img.Pixels.SizeC = 1 img.Pixels.SizeZ = 1 img.Pixels.plane_count = 1 # A name has to be set as a flag for the handler to update # the metadata img.Name = name # Make channel name consistent with how it is encoded in the image # file name to ensure that the result is the same, independent of # whether it was obtained from the metadata or the image file name. img.Pixels.Channel(0).Name = e.attrib['{%s}Ch' % mlf_ns] img.Pixels.Plane(0).PositionX = float(e.attrib['{%s}X' % mlf_ns]) img.Pixels.Plane(0).PositionY = float(e.attrib['{%s}Y' % mlf_ns]) img.Pixels.Plane(0).PositionZ = float(e.attrib['{%s}Z' % mlf_ns]) img.Pixels.Plane(0).TheZ = int(e.attrib['{%s}ZIndex' % mlf_ns]) img.Pixels.Plane(0).TheT = int(e.attrib['{%s}TimelineIndex' % mlf_ns]) idx = microscope_image_filenames.index(img.Name) lookup[well_id].append(idx) # Obtain the general experiment information and well plate format # specifications from the ".mrf" file: name = mrf_root.attrib['{%s}Title' % mrf_ns] plate = metadata.PlatesDucktype(metadata.root_node).newPlate(name=name) plate.RowNamingConvention = 'letter' plate.ColumnNamingConvention = 'number' plate.Rows = mrf_root.attrib['{%s}RowCount' % mrf_ns] plate.Columns = mrf_root.attrib['{%s}ColumnCount' % mrf_ns] wells = lookup.keys() for w in set(wells): # Create a *Well* element for each imaged well in the plate row = utils.map_letter_to_number(w[0]) - 1 col = int(w[1:]) - 1 well = metadata.WellsDucktype(plate).new(row=row, column=col) well_samples = metadata.WellSampleDucktype(well.node) for i, ref in enumerate(lookup[w]): # Create a *WellSample* element for each acquisition site well_samples.new(index=i) well_samples[i].ImageRef = ref return metadata