Source code for specparam.io.models

"""File I/O for model objects.

Notes
-----
Model loader function import model objects locally to prevent circular imports.
"""

import io

from specparam.io.files import save_json
from specparam.io.utils import create_file_path
from specparam.utils.select import dict_select_keys
from specparam.utils.convert import dict_array_to_lst
from specparam.modutils.docs import (docs_get_section, replace_docstring_sections,
                                     docs_replace_param)

###################################################################################################
###################################################################################################

[docs]def save_model(model, file_name, file_path=None, append=False, save_results=False, save_settings=False, save_data=False, save_base=None): """Save out data, results and/or settings from a model object into a JSON file. Parameters ---------- model : SpectralModel Object to save data from. file_name : str or FileObject File to save data to. file_path : Path or str, optional Path to directory to save to. If None, saves to current directory. append : bool, optional, default: False Whether to append to an existing file, if available. This option is only valid (and only used) if 'file_name' is a str. save_results : bool, optional Whether to save out model fit results. save_settings : bool, optional Whether to save out settings. save_data : bool, optional Whether to save out input data. save_base : bool, optional Whether to save out base data. Can be set to False to remove redundant information when saving from multiple models. Raises ------ ValueError If the save file is not understood. """ # 'Flatten' the model object by extracting relevant attributes to a dictionary obj_dict = {**model.data.__dict__, **model.algorithm.settings.values} # Convert modes object to their saveable string name obj_dict['aperiodic_mode'] = model.modes.aperiodic.name obj_dict['periodic_mode'] = model.modes.periodic.name mode_labels = ['aperiodic_mode', 'periodic_mode'] # Add bands information to saveable information obj_dict['bands'] = dict(model.results.bands.bands) \ if not model.results.bands._n_bands else model.results.bands._n_bands bands_label = ['bands'] if model.results.bands else [] # Add parameter results to information to saveable information res_dict = model.results.params.asdict() obj_dict = {**obj_dict, **res_dict} results_labels = list(res_dict.keys()) # Add metrics to information to saveable information obj_dict['metrics'] = model.results.metrics.results # Convert all arrays to list for JSON serialization obj_dict = dict_array_to_lst(obj_dict) # Check for saving out base information / check if base only if save_base is None: save_base = save_results or save_data base_only = (not save_settings and not save_results and not save_data) # Set and select which variables to keep. Use a set to drop any potential overlap # Note that results also saves frequency information to be able to recreate freq vector keep = set(\ (mode_labels + bands_label if save_base else []) + \ (model.data._meta_fields if save_base or base_only else []) + \ (results_labels + ['metrics'] if save_results else []) + \ (model.algorithm.settings.names if save_settings else []) + \ (model.data._fields if save_data else [])) obj_dict = dict_select_keys(obj_dict, keep) # Save out to json file save_json(obj_dict, file_name, file_path, append)
[docs]def save_group(group, file_name, file_path=None, append=False, save_results=False, save_settings=False, save_data=False): """Save out results and/or settings from group object. Saves out to a JSON file. Parameters ---------- group : SpectralGroupModel Object to save data from. file_name : str or FileObject File to save data to. file_path : Path or str, optional Path to directory to load from. If None, saves to current directory. append : bool, optional, default: False Whether to append to an existing file, if available. This option is only valid (and only used) if 'file_name' is a str. save_results : bool, optional Whether to save out model fit results. save_settings : bool, optional Whether to save out settings. save_data : bool, optional Whether to save out power spectra data. Raises ------ ValueError If the data or save file specified are not understood. """ if not save_results and not save_settings and not save_data: raise ValueError("No data specified for saving.") # Save to string specified file, specifying whether to append or not if isinstance(file_name, str): full_path = create_file_path(file_name, file_path, 'json') with open(full_path, 'a' if append else 'w') as f_obj: _save_group(group, f_obj, save_results, save_settings, save_data) # Save to file-object specified file elif isinstance(file_name, io.IOBase): _save_group(group, file_name, save_results, save_settings, save_data) else: raise ValueError("Save file not understood.")
@replace_docstring_sections(\ docs_replace_param(docs_get_section(\ save_group.__doc__, 'Parameters'), 'group', 'time : SpectralTimeModel\n Object to save data from.')) def save_time(time, file_name, file_path=None, append=False, save_results=False, save_settings=False, save_data=False): """Save out results and/or settings from time object. Saves out to a JSON file. Parameters ---------- % copied in from save_group function. """ save_group(time, file_name, file_path, append, save_results, save_settings, save_data)
[docs]def save_event(event, file_name, file_path=None, append=False, save_results=False, save_settings=False, save_data=False): """Save out results and/or settings from event object. Saves out to a JSON file. Parameters ---------- event : SpectralTimeEventModel Object to save data from. file_name : str or FileObject File to save data to. file_path : str, optional Path to directory to load from. If None, saves to current directory. append : bool, optional, default: False Whether to append to an existing file, if available. This option is only valid (and only used) if 'file_name' is a str. save_results : bool, optional Whether to save out model fit results. save_settings : bool, optional Whether to save out settings. save_data : bool, optional Whether to save out power spectra data. Raises ------ ValueError If the data or save file specified are not understood. """ fg = event.get_group(None, None, 'group') if save_settings and not save_results and not save_data: fg.save(file_name, file_path, append=append, save_settings=save_settings) else: ndigits = len(str(len(event.results))) for ind, gres in enumerate(event.results.event_group_results): fg.results.group_results = gres if save_data: fg.data.power_spectra = event.data.spectrograms[ind, :, :].T fg.save(file_name + '_{:0{ndigits}d}'.format(ind, ndigits=ndigits), file_path=file_path, append=append, save_results=save_results, save_settings=save_settings, save_data=save_data)
[docs]def load_model(file_name, file_path=None, regenerate=True): """Load a SpectralModel object from file. Parameters ---------- file_name : str File to load the data from. file_path : Path or str, optional Path to directory to load from. If None, loads from current directory. regenerate : bool, optional, default: True Whether to regenerate the model fit from the loaded data, if data is available. Returns ------- model : SpectralModel Loaded model object with data from file. """ from specparam import SpectralModel model = SpectralModel() model.load(file_name, file_path, regenerate) return model
[docs]def load_group(file_name, file_path=None): """Load a SpectralGroupModel object from file. Parameters ---------- file_name : str File(s) to load data from. file_path : Path or str, optional Path to directory to load from. If None, loads from current directory. Returns ------- group : SpectralGroupModel Loaded model object with data from file. """ from specparam import SpectralGroupModel group = SpectralGroupModel() group.load(file_name, file_path) return group
[docs]def load_time(file_name, file_path=None): """Load a SpectralTimeModel object from file. Parameters ---------- file_name : str File(s) to load data from. file_path : Path or str, optional Path to directory to load from. If None, loads from current directory. Returns ------- time : SpectralTimeModel Loaded model object with data from file. """ from specparam import SpectralTimeModel time = SpectralTimeModel() time.load(file_name, file_path) return time
[docs]def load_event(file_name, file_path=None): """Load a SpectralTimeEventModel object from file. Parameters ---------- file_name : str File(s) to load data from. file_path : Path or str, optional Path to directory to load from. If None, loads from current directory. Returns ------- event : SpectralTimeEventModel Loaded model object with data from file. """ from specparam import SpectralTimeEventModel event = SpectralTimeEventModel() event.load(file_name, file_path) return event
def _save_group(group, f_obj, save_results, save_settings, save_data): """Helper function for saving a group object - saves data given a file object. Parameters ---------- group : SpectralGroupModel Object to save data from. f_obj : FileObject File object to save data to. save_results : bool Whether to save out model fit results. save_settings : bool Whether to save out settings. save_data : bool Whether to save out power spectra data. """ # Since there is a single set of object settings, save them out once, at the top if save_settings: save_model(group, file_name=f_obj, file_path=None, append=False, save_settings=save_settings, save_base=save_results or save_data) else: save_model(group, file_name=f_obj, file_path=None, append=False, save_base=True) # For results & data, loop across all data and/or models, and save each out to a new line if save_results or save_data: for ind in range(len(group.results.group_results)): model = group.get_model(ind, regenerate=False) save_model(model, file_name=f_obj, file_path=None, append=False, save_results=save_results, save_data=save_data, save_base=False)