"""File input/output for localization data in SMAP files."""from__future__importannotationsimportloggingimportosfromcollections.abcimportMappingfromtypingimportTYPE_CHECKING,AnyifTYPE_CHECKING:from_typeshedimportSupportsRead,SupportsWriteimportpandasaspdimportlocan.constantsfromlocan.dataimportmetadata_pb2fromlocan.data.locdataimportLocDatafromlocan.dependenciesimportHAS_DEPENDENCY,needs_packagefromlocan.locan_io.locdata.utilitiesimport(convert_property_names,convert_property_types,)ifHAS_DEPENDENCY["h5py"]:importh5py__all__:list[str]=["load_SMAP_header","load_SMAP_file","save_SMAP_csv"]logger=logging.getLogger(__name__)@needs_package("h5py")def_read_SMAP_header(file:Mapping[str,Any])->list[str]:""" Identify column names from a SMAP single-molecule localization file. Parameters ---------- file HDF5 file object. Returns ------- list[str] A list of valid dataset property keys as derived from the identifiers. """# list identifiersidentifiers=list(file["saveloc"]["loc"].keys())column_keys=convert_property_names(properties=identifiers,property_mapping=locan.constants.SMAP_KEYS)returncolumn_keys
[docs]@needs_package("h5py")defload_SMAP_header(path:str|os.PathLike[Any]|SupportsRead[Any],)->list[str]:""" Identify column names from a SMAP single-molecule localization file. Parameters ---------- path File path for a file to load. Returns ------- list[str] A list of valid dataset property keys as derived from the identifiers. """withh5py.File(path,"r")asfile:return_read_SMAP_header(file)
[docs]@needs_package("h5py")defload_SMAP_file(path:str|os.PathLike[Any]|SupportsRead[Any],nrows:int|None=None,convert:bool=True,)->LocData:""" Load data from a SMAP single-molecule localization file. Parameters ---------- path File path for a file to load. nrows The number of localizations to load from file. None means that all available rows are loaded. convert If True convert types by applying type specifications in locan.constants.PROPERTY_KEYS. Returns ------- LocData A new instance of LocData with all localizations. """withh5py.File(path,"r")asfile:columns=_read_SMAP_header(file)iffile["saveloc"]["loc"]["frame"].shape==(0,):# empty filelogger.warning("File does not contain any data.")locdata=LocData()else:# file not emptydata={}forkey,valueinfile["saveloc"]["loc"].items():ifvalue.shapeisnotNone:ifkeyinlocan.constants.SMAP_KEYS:data[locan.constants.SMAP_KEYS[key]]=list(value[0][:nrows])else:data[key]=list(value[0][:nrows])dataframe=pd.DataFrame(data)ifconvert:dataframe=convert_property_types(dataframe,types=locan.constants.PROPERTY_KEYS)locdata=LocData.from_dataframe(dataframe=dataframe)locdata.meta.source=metadata_pb2.EXPERIMENTlocdata.meta.state=metadata_pb2.RAWlocdata.meta.file.type=metadata_pb2.SMAPlocdata.meta.file.path=str(path)forproperty_insorted(list(set(columns).intersection({"position_x","position_y","position_z"}))):locdata.meta.localization_properties.add(name=property_,unit="nm",type="float")dellocdata.meta.history[:]locdata.meta.history.add(name="load_SMAP_file",parameter=f"path={path}, nrows={nrows}")returnlocdata
[docs]defsave_SMAP_csv(locdata:LocData,path:str|os.PathLike[Any]|SupportsWrite[Any],)->None:""" Save LocData to SMAP-readable csv-file. In the csv-file file format we store only localization data with SMAP-readable column names. Parameters ---------- locdata The LocData object to be saved. path File path including file name to save to. """# get data from locdata objectdataframe=locdata.data# create reverse mapping to columnsinv_map={v:kfork,vinlocan.constants.SMAP_KEYS.items()}# rename columnsdataframe=dataframe.rename(index=str,columns=inv_map,inplace=False)valid_smap_columns=[keyforkeyindataframe.columnsifkeyinlocan.constants.SMAP_KEYS]# write to csvdataframe[valid_smap_columns].to_csv(path,float_format="%.10g",index=False)# type: ignore[arg-type]