# -*- coding: utf-8 -*-
"""
This module implements Configuration Class for NeuroChaT software.
@author: Md Nurul Islam; islammn at tcd dot ie
"""
import os.path
import logging
from collections import OrderedDict as oDict
import yaml
# default parameters by analaysis type
from neurochat.nc_defaults import ANALYSES, PARAMETERS
_MAPPING_TAG = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
def __dict_representer(dumper, data):
return dumper.represent_mapping(_MAPPING_TAG, data.items())
def __dict_constructor(loader, node):
return oDict(loader.construct_pairs(node))
yaml.add_representer(oDict, __dict_representer)
yaml.add_constructor(_MAPPING_TAG, __dict_constructor)
[docs]class Configuration(object):
"""
The Configuration object is the placeholder for all NeuroChaT settings.
The object consists of specification of data and analysis along with
the parameters for each analysis type.
It also facilitates saving these setting to a .ncfg file
and retriving them from the .ncfg file.
The .ncfg file is a YAML-formatted file.
Attributes
----------
filename: str
Full file name of the configuration storage (.ncfg)
format: str
Recording system or format of the data file
analysis_mode: str
Mode of analysis in NeuroChaT.
Options are 'Single Unit', 'Single Session' and 'Listed Units'
mode_id: int
Numeric ID of modes in NeuroChaT
Respectively 0, 1, and 2 for the three modes
graphic_format: str
File format for output graphics. Options are 'PDF' or 'Postscript'
unit_no: int
Unit number to be analyzed. Used in 'Single Unit' mode
spatial_file: str
Full file of the spatial dataset
spike_file: str
Full file of the spike dataset
lfp_file: str
Full file of the lfp dataset
nwb_file: str
Full file of the NWB format dataset
excel_dir: str
Full file of the Excel list of unit.
Used only in 'Listed Units' mode
analyses: dict
Dictionary of analysis methods as key and
their selection as boolean values
parameters: dict
(key: value) pairs of parameter names and their values
special_analysis: dict
A dict indicating a menu analysis method.
"""
def __init__(self, filename=[]):
"""
See also Configuration.
Parameters
----------
filename : str
Full file name of the configuration storage (.ncfg)
"""
self.filename = filename
self.format = 'Axona'
self.analysis_mode = 'Single Unit'
self.mode_id = 0
self.graphic_format = 'pdf'
self.valid_graphics = {'PDF': 'pdf', 'Postscript': 'ps'}
self.unit_no = 0
self.cell_type = ''
self.spike_file = ''
self.spatial_file = ''
self.lfp_file = ''
self.nwb_file = ''
self.excel_file = ''
self.data_directory = ''
self.config_directory = ''
self.analyses = {}
self.parameters = {}
self.special_analysis = {}
for k, v in PARAMETERS.items(): # setting the default parameters
self.parameters.update(v)
for k, v in ANALYSES.items(): # setting the default analyses
self.analyses.update({k: v})
self.options = oDict()
self.mode_dict = oDict([('Single Unit', 0),
('Single Session', 1),
('Listed Units', 2)])
[docs] def set_special_analysis(self, in_dict={}):
"""
Set special analysis to the input dictionary.
Parameters
----------
in_dict: dict
Dictionary to set special analysis to.
Returns
-------
None
"""
self.special_analysis = in_dict
[docs] def get_special_analysis(self):
"""
Get the special analysis dictionary.
Parameters
----------
None
Returns
-------
dict
Dictionary of special analyses.
"""
return self.special_analysis
[docs] def set_param(self, name=None, value=None):
"""
Set the value of a parameter.
Parameters
----------
name : str
Name of the parameter
value : any
Value of the parameter
Returns
-------
None
"""
if isinstance(name, str):
self.parameters[name] = value
else:
logging.error('Parameter name and/or value is inappropriate')
[docs] def get_params(self, name=None):
"""
Get the value of parameter.
If a list of parameter names are provided,
then a list of values are returned.
Parameters
----------
name : str or list of str
Name of the parameter(s)
Returns
-------
params
Parameter value(s)
"""
if isinstance(name, list):
params = {}
not_found = []
for pname in name:
if pname in self.parameters.keys():
params[pname] = self.parameters[pname]
else:
not_found.append(pname)
if not_found:
logging.warning(
'Following parameters not found- ' + ','.join(not_found))
return params
elif isinstance(name, str):
if name in self.parameters.keys():
return self.parameters[name]
else:
logging.error(name + ' is not found in parameter list')
[docs] def get_params_by_analysis(self, analysis=None):
"""
Return the parameters and their values for a given analysis.
Parameters
----------
analysis : str
Name of the analysis
Returns
-------
params : dict
Dictionary of parameters and their values
"""
if analysis in PARAMETERS.keys():
# get default params first
params = PARAMETERS[analysis]
# Update from set parameter
params.update(self.get_params(list(params.keys())))
return params
else:
logging.error(
'Specific analysis is not found in defaults PARAMETERS!')
[docs] def set_analysis(self, name=None, value=None):
"""
Set the selection of an analysis.
Parameters
----------
name : str
Name of the analysis
value : bool
Boolean value to indicate analysis selection
Returns
-------
None
"""
if name == 'all' and isinstance(value, bool):
for name in self.analyses.keys():
self.analyses[name] = value
elif isinstance(name, str) and isinstance(value, bool):
self.analyses[name] = value
elif isinstance(name, list) and isinstance(value, bool):
for n in name:
if isinstance(n, str):
self.analyses[n] = value
else:
logging.error('Analysis name and/or value is inappropriate')
[docs] def get_analysis(self, name=None):
"""
Return the selection of an analysis.
If name is 'all', selection values for all the analyses are returned.
Parameters
----------
name : str
Name of the analysis.
Enter 'all' for returning values for all the analyses
Returns
-------
bool
True if selected, False if not.
"""
if name == 'all':
return self.analyses.values()
elif name in self.analyses.keys():
return self.analyses[name]
else:
logging.error(name + ' is not found in parameter list')
[docs] def get_param_list(self):
"""
Return the list of all parameters.
Parameters
----------
None
Returns
-------
list
List of parameter names
"""
return list(self.parameters.keys())
[docs] def get_analysis_list(self):
"""
Return a list of analyses.
Parameters
----------
None
Returns
-------
list
List of analysis names.
"""
return list(self.analyses.keys())
[docs] def set_analysis_mode(self, analysis_mode=None):
"""
Set the mode of analysis.
Parameters
----------
analysis_mode : str
Mode of the analysis
Returns
-------
None
"""
if analysis_mode in self.mode_dict.keys():
self.analysis_mode = analysis_mode
self.mode_id = self.mode_dict[analysis_mode]
elif analysis_mode in self.mode_dict.values():
self.mode_id = analysis_mode
for key, val in self.mode_dict.items():
if val == analysis_mode:
self.analysis_mode = key
else:
logging.error('No/Invalid analysis mode!')
[docs] def get_analysis_mode(self):
"""
Return the mode of analysis and mode ID.
Parameters
----------
None
Returns
-------
(str, int)
Analysis mode set, ID of analysis mode
"""
return self.analysis_mode, self.mode_id
[docs] def get_all_modes(self):
"""
Return the analysis modes in NeuroChaT.
Parameters
----------
None
Returns
-------
dict
Modes and their IDs
"""
return self.mode_dict
[docs] def set_unit_no(self, unit_no=None):
"""
Set the unit no to analyse in 'Single Unit' analysis.
Parameters
----------
unit_no : int
Unit number the user is intending to analyse
Returns
-------
None
"""
if isinstance(unit_no, int):
self.unit_no = unit_no
[docs] def get_unit_no(self):
"""
Return the unit number that is already set.
Parameters
----------
None
Returns
-------
str
Unit number
"""
return self.unit_no
[docs] def set_cell_type(self, cell_type=None):
"""
Set the type of cell to analyse.
Parameters
----------
cell_type : str
Cell type of interest
Returns
-------
None
"""
self.cell_type = cell_type
[docs] def get_cell_type(self):
"""
Return the type of cell set to analyse.
Parameters
----------
None
Returns
-------
str
Cell type set for analyses
"""
return self.cell_type
[docs] def set_spike_file(self, spike_file=None):
"""
Set filename of the spike data.
Parameters
----------
spike_file : str
Filename of the spike data
Returns
-------
None
"""
if isinstance(spike_file, str):
self.spike_file = spike_file
[docs] def get_spike_file(self):
"""
Return the filename of the spike data.
Parameters
----------
None
Returns
-------
str
Filename of spike data
"""
return self.spike_file
[docs] def set_spatial_file(self, spatial_file=None):
"""
Set filename of the spatial data.
Parameters
----------
spatial_file : str
Filename of the spatial data
Returns
-------
None
"""
if isinstance(spatial_file, str):
self.spatial_file = spatial_file
[docs] def get_spatial_file(self):
"""
Return the filename of the spatial data.
Parameters
----------
None
Returns
-------
str
Filename of the spatial data
"""
return self.spatial_file
[docs] def set_lfp_file(self, lfp_file=None):
"""
Set filename of the lfp data.
Parameters
----------
lfp_file : str
Filename of the lfp data
Returns
-------
None
"""
if isinstance(lfp_file, str):
self.lfp_file = lfp_file
[docs] def get_lfp_file(self):
"""
Return the filename of the lfp data.
Parameters
----------
None
Returns
-------
str
Filename of the lfp data
"""
return self.lfp_file
[docs] def set_nwb_file(self, nwb_file=None):
"""
Set filename of the HDF5 data.
Parameters
----------
nwb_file : str
Filename of the HDF5 data
Returns
-------
None
"""
if isinstance(nwb_file, str):
self.nwb_file = nwb_file
[docs] def get_nwb_file(self):
"""
Return the filename of the HDF5 data.
Parameters
----------
None
Returns
-------
str
Filename of the HDF5 data
"""
return self.nwb_file
[docs] def get_excel_file(self):
"""
Return the filename of the Excel list.
Parameters
----------
None
Returns
-------
str
Filename of the Excel list
"""
return self.excel_file
[docs] def set_excel_file(self, excel_file=None):
"""
Set filename of the Excel list.
Parameters
----------
excel_file : str
Filename of the Excel list
Returns
-------
None
"""
if excel_file:
self.excel_file = excel_file
else:
logging.error('Invalid/No excel filename specified')
[docs] def set_data_dir(self, directory=None):
"""
Set the data directory.
Parameters
----------
directory : str
Data directory
Returns
-------
None
"""
if os.path.exists(directory):
self.data_directory = directory
else:
logging.error('Invalid/No directory specified')
[docs] def get_data_dir(self):
"""
Return the data directory.
Parameters
----------
None
Returns
-------
str
Data directory
"""
return self.data_directory
[docs] def set_config_dir(self, directory=None):
"""
Set the directory of configuration file.
Parameters
----------
directory : str
Directory of configuration file
Returns
-------
None
"""
if os.path.exists(directory):
self.config_directory = directory
else:
logging.error('Invalid/No directory specified')
[docs] def get_config_dir(self):
"""
Return the directory of configuration file.
Parameters
----------
None
Returns
-------
str
Name of the configuration file
"""
return self.config_directory
[docs] def set_config_file(self, filename):
"""
Set the name of the configuration file.
Parameters
----------
directory : str
Name of configuration file
Returns
-------
None
"""
self.filename = filename
[docs] def get_config_file(self):
"""
Return the name of the configuration file.
Parameters
----------
None
Returns
-------
str
Name of configuration file
"""
return self.filename
[docs] def save_config(self, filename=None):
"""
Export the configuration data to .ncfg file.
Parameters
----------
filename : str
Name of the configuration file
Returns
-------
None
"""
if filename:
self.set_config_file(filename)
if not self.filename:
logging.warning('No/invalid filename')
else:
self._save()
[docs] def load_config(self, filename=None):
"""
Import the configuration data from a .ncfg file.
Parameters
----------
filename: str
Name of the configuration file
Returns
-------
None
"""
if filename:
self.set_config_file(filename)
if not self.filename:
logging.warning('No/Invalid filename')
else:
self._load()
def _save(self):
"""Save configuration data to the specified .ncfg(YAML) file."""
try:
with open(self.filename, 'w') as f:
settings = oDict([('format', self.format),
('analysis_mode', self.analysis_mode),
('mode_id', self.mode_id),
('graphic_format', self.graphic_format),
('unit_no', self.unit_no),
('lfp_file', self.lfp_file),
('cell_type', self.cell_type),
('spike_file', self.spike_file),
('spatial_file', self.spatial_file),
('nwb_file', self.nwb_file),
('excel_file', self.excel_file),
('data_directory', self.data_directory)])
cfgData = oDict([('settings', settings),
('analyses', self.analyses),
('parameters', self.parameters)])
yaml.dump(cfgData, f, default_flow_style=False)
except Exception:
logging.error(
'Configuration cannot be saved in the specified file!')
def _load(self):
"""Load configuration data from the .ncfg(YAML) file."""
with open(self.filename, 'r') as f:
cfgData = yaml.load(f, Loader=yaml.FullLoader)
settings = cfgData.get('settings')
for key, val in settings.items():
self.__setattr__(key, val)
self.analyses = cfgData.get('analyses')
self.parameters = cfgData.get('parameters')