You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							77 lines
						
					
					
						
							2.5 KiB
						
					
					
				
			
		
		
	
	
							77 lines
						
					
					
						
							2.5 KiB
						
					
					
				| """ Sensospot Data Parser | |
|  | |
| Parsing the numerical output from Sensovations Sensospot image analysis. | |
| """ | |
| 
 | |
| from pathlib import Path | |
| from collections import namedtuple | |
| 
 | |
| import numpy | |
| from defusedxml import ElementTree | |
| 
 | |
| from .columns import ( | |
|     META_DATA_EXPOSURE_ID, | |
|     META_DATA_PARAMETERS_TIME, | |
|     META_DATA_PARAMETERS_CHANNEL, | |
| ) | |
| from .utils import apply_map | |
| 
 | |
| ExposureInfo = namedtuple("ExposureInfo", ["channel", "time"]) | |
| 
 | |
| 
 | |
| def _search_measurement_params_file(folder): | |
|     """ searches for a exposure settings file in a folder """ | |
|     folder_path = Path(folder) | |
|     params_folder = folder_path / "Parameters" | |
|     if not params_folder.is_dir(): | |
|         return None | |
|     param_files = list(params_folder.glob("**/*.svexp")) | |
|     if len(param_files) == 1: | |
|         return param_files[0] | |
|     else: | |
|         return None | |
| 
 | |
| 
 | |
| def _parse_measurement_params(params_file): | |
|     """ parses the cannel informations from a settings file """ | |
|     file_path = Path(params_file) | |
|     with file_path.open("r") as file_handle: | |
|         tree = ElementTree.parse(file_handle) | |
|     result = {} | |
|     for child in tree.find("Channels"): | |
|         # child.tag == "ChannelConfig1" | |
|         exposure = int(child.tag[-1]) | |
|         channel_description = child.attrib["Description"] | |
|         # channel_description == "[Cy3|Cy5] Green" | |
|         channel = channel_description.rsplit(" ", 1)[-1] | |
|         time = float(child.attrib["ExposureTimeMs"]) | |
|         result[exposure] = ExposureInfo(channel.lower(), time) | |
|     return result | |
| 
 | |
| 
 | |
| def get_measurement_params(folder): | |
|     """ returns measurement parameters """ | |
|     params_file = _search_measurement_params_file(folder) | |
|     if params_file is not None: | |
|         return _parse_measurement_params(params_file) | |
|     return None | |
| 
 | |
| 
 | |
| def _add_measurement_params(data_frame, params): | |
|     """ adds measurement parameters to a data frame """ | |
|     columns=[META_DATA_PARAMETERS_CHANNEL, META_DATA_PARAMETERS_TIME] | |
|     map = {k: dict(zip(columns, v)) for k, v in params.items()} | |
|     return apply_map(data_frame, map, META_DATA_EXPOSURE_ID) | |
| 
 | |
| 
 | |
| def add_optional_measurement_parameters(data_frame, folder): | |
|     """ adds measurement params to the data frame, if they could be parsed """ | |
|     params = get_measurement_params(folder) | |
|     if params: | |
|         available_exposures = set(data_frame[META_DATA_EXPOSURE_ID].unique()) | |
|         if available_exposures == set(params.keys()): | |
|             return _add_measurement_params(data_frame, params) | |
|     else: | |
|         data_frame[META_DATA_PARAMETERS_CHANNEL] = numpy.nan | |
|         data_frame[META_DATA_PARAMETERS_TIME] = numpy.nan | |
|     return data_frame
 | |
| 
 |