diff --git a/doc/api.rst b/doc/api.rst index 609f75240..f33a4432e 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -31,14 +31,25 @@ FOOOFGroup Object FOOOFGroup -FOOOF Object Functions ----------------------- +Bands +----- + +.. currentmodule:: fooof.bands + +.. autosummary:: + :toctree: generated/ + + Bands + +FOOOF Functions +--------------- .. currentmodule:: fooof.funcs .. autosummary:: :toctree: generated/ + average_fg combine_fooofs fit_fooof_group_3d @@ -51,16 +62,20 @@ Analysis Functions :toctree: generated/ get_band_peak + get_band_peak_fm + get_band_peak_fg get_band_peak_group get_highest_peak -Synth Code ----------- +Sim Code +-------- + +Code & utilities for simulating power spectra. Generating Power Spectra ~~~~~~~~~~~~~~~~~~~~~~~~ -.. currentmodule:: fooof.synth.gen +.. currentmodule:: fooof.sim.gen .. autosummary:: :toctree: generated/ @@ -72,7 +87,7 @@ Generating Power Spectra Parameter Management ~~~~~~~~~~~~~~~~~~~~ -.. currentmodule:: fooof.synth.params +.. currentmodule:: fooof.sim.params .. autosummary:: :toctree: generated/ @@ -80,19 +95,20 @@ Parameter Management Stepper param_iter param_sampler + update_sim_ap_params Transforming Power Spectra ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. currentmodule:: fooof.synth.transform +.. currentmodule:: fooof.sim.transform .. autosummary:: :toctree: generated/ translate_spectrum - translate_syn_spectrum + translate_sim_spectrum rotate_spectrum - rotate_syn_spectrum + rotate_sim_spectrum compute_rotation_offset Plotting Functions @@ -117,7 +133,5 @@ Utility Functions :toctree: generated/ trim_spectrum - get_settings - get_data_info - compare_settings - compare_data_info + get_info + compare_info diff --git a/examples/plot_fit_fooof_3d.py b/examples/plot_fit_fooof_3d.py index 75a05215a..19d8c20ff 100644 --- a/examples/plot_fit_fooof_3d.py +++ b/examples/plot_fit_fooof_3d.py @@ -12,12 +12,12 @@ # FOOOF imports from fooof import FOOOFGroup from fooof.funcs import fit_fooof_group_3d, combine_fooofs -from fooof.synth.gen import gen_group_power_spectra -from fooof.synth.params import param_sampler +from fooof.sim.gen import gen_group_power_spectra +from fooof.sim.params import param_sampler ################################################################################################### -# Settings for creating synthetic data +# Settings for creating simulated data n_spectra = 10 freq_range = [3, 40] ap_opts = param_sampler([[0, 1.0], [0, 1.5], [0, 2]]) @@ -25,7 +25,7 @@ ################################################################################################### -# Generate some synthetic power spectra, and organize into a 3D matrix +# Generate some simulated power spectra, and organize into a 3D matrix spectra = [] for ind in range(3): fs, ps, _ = gen_group_power_spectra(n_spectra, freq_range, ap_opts, gauss_opts) diff --git a/examples/plot_plots.py b/examples/plot_plots.py index 76fc869a8..5dba0ea38 100644 --- a/examples/plot_plots.py +++ b/examples/plot_plots.py @@ -13,10 +13,10 @@ ################################################################################################### -# Create a couple synthetic power spectra to explore plotting with +# Create a couple simulated power spectra to explore plotting with # Here we create two spectra, with different aperiodic components # but each with the same oscillations (a theta, alpha & beta) -from fooof.synth.gen import gen_group_power_spectra +from fooof.sim.gen import gen_group_power_spectra fs, ps, _ = gen_group_power_spectra(2, [3, 40], [[0.75, 1.5], [0.25, 1]], [6, 0.2, 1, 10, 0.3, 1, 25, 0.15, 3]) ps1, ps2 = ps diff --git a/examples/plot_synth_params.py b/examples/plot_sim_params.py similarity index 81% rename from examples/plot_synth_params.py rename to examples/plot_sim_params.py index 9b27efaff..fa8fb579d 100644 --- a/examples/plot_synth_params.py +++ b/examples/plot_sim_params.py @@ -1,27 +1,27 @@ """ -Synthetic Parameters +Simulated Parameters ==================== -Manage parameters for creating synthetic power spectra. +Manage parameters for creating simulated power spectra. """ ################################################################################################### # Import fooof functions for creating spectra and managing parameters -from fooof.synth.params import param_sampler, param_iter, Stepper -from fooof.synth.gen import gen_power_spectrum, gen_group_power_spectra +from fooof.sim.params import param_sampler, param_iter, Stepper +from fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra # Import some fooof plotting functions from fooof.plts.spectra import plot_spectrum, plot_spectra ################################################################################################### -# SynParams +# SimParams # ~~~~~~~~~ # -# When you synthesize multiple power spectra, FOOOF uses `SynParams` objects to +# When you simulate multiple power spectra, FOOOF uses `SimParams` objects to # keep track of the parameters used for each power spectrum. # -# SynParams objects are named tuples with the following fields: +# SimParams objects are named tuples with the following fields: # - `aperiodic_params` # - `gaussian_params` # - `nlv` @@ -29,7 +29,7 @@ ################################################################################################### -# Set up settings for synthesizing a group of power spectra +# Set up settings for simulating a group of power spectra n_spectra = 2 freq_range = [3, 40] ap_params = [[0.5, 1], [1, 1.5]] @@ -38,19 +38,19 @@ ################################################################################################### -# Synthesize a group of power spectra -fs, ps, syn_params = gen_group_power_spectra(n_spectra, freq_range, ap_params, gauss_params, nlv) +# Simulate a group of power spectra +fs, ps, sim_params = gen_group_power_spectra(n_spectra, freq_range, ap_params, gauss_params, nlv) ################################################################################################### -# Print out the SynParams objects that track the parameters used to create power spectra -for syn_param in syn_params: - print(syn_param) +# Print out the SimParams objects that track the parameters used to create power spectra +for sim_param in sim_params: + print(sim_param) ################################################################################################### -# You can also use a SynParams object to regenerate a particular power spectrum -cur_params = syn_params[0] +# You can also use a SimParams object to regenerate a particular power spectrum +cur_params = sim_params[0] fs, ps = gen_power_spectrum(freq_range, *cur_params) ################################################################################################### @@ -83,7 +83,7 @@ ################################################################################################### # Generate some power spectra, using the param samplers -fs, ps, syn_params = gen_group_power_spectra(10, [3, 40], ap_opts, gauss_opts) +fs, ps, sim_params = gen_group_power_spectra(10, [3, 40], ap_opts, gauss_opts) ################################################################################################### @@ -113,7 +113,7 @@ ################################################################################################### # Generate some power spectra, using param iter -fs, ps, syn_params = gen_group_power_spectra(len(cf_steps), [3, 40], ap_params, gauss_params) +fs, ps, sim_params = gen_group_power_spectra(len(cf_steps), [3, 40], ap_params, gauss_params) ################################################################################################### diff --git a/examples/plot_synthetic_power_spectra.py b/examples/plot_simulated_power_spectra.py similarity index 80% rename from examples/plot_synthetic_power_spectra.py rename to examples/plot_simulated_power_spectra.py index 3d942cdda..16df38181 100644 --- a/examples/plot_synthetic_power_spectra.py +++ b/examples/plot_simulated_power_spectra.py @@ -1,55 +1,55 @@ """ -Creating Synthetic Power Spectra +Creating Simulated Power Spectra ================================ -Use FOOOF to create synthetic power spectra. +Use FOOOF to create simulated power spectra. """ ################################################################################################### -# Import fooof functions for creating synthetic power spectra -from fooof.synth.gen import gen_power_spectrum, gen_group_power_spectra +# Import fooof functions for creating simulated power spectra +from fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra # Import some fooof plotting functions from fooof.plts.spectra import plot_spectrum, plot_spectra ################################################################################################### -# Creating Synthetic Power Spectra +# Creating Simulated Power Spectra # -------------------------------- # -# FOOOF has utilities to create synthetic power spectra, whereby spectra +# FOOOF has utilities to create simulated power spectra, whereby spectra # are simulated with an aperiodic component with overlying peaks, # using specified parameters. # -# The :func:`gen_power_spectrum` function can be used to synthesize a power +# The :func:`gen_power_spectrum` function can be used to simulate a power # spectrum with specified parameters. # -# Note that all FOOOF functions that synthesize power spectra take in +# Note that all FOOOF functions that simulate power spectra take in # gaussian parameters, not the modified peak parameters. # ################################################################################################### -# Settings for creating a synthetic power spectrum +# Settings for creating a simulated power spectrum freq_range = [3, 40] # The frequency range to simulate aperiodic_params = [1, 1] # Parameters defining the aperiodic component gaussian_params = [10, 0.3, 1] # Parameters for any periodic components ################################################################################################### -# Generate a synthetic power spectrum +# Generate a simulated power spectrum fs, ps = gen_power_spectrum(freq_range, aperiodic_params, gaussian_params) ################################################################################################### -# Plot the synthetic power spectrum +# Plot the simulated power spectrum plot_spectrum(fs, ps, log_freqs=True, log_powers=False) ################################################################################################### # Simulating With Different Parameters # ------------------------------------ # -# Power spectra can be synthesized with any desired parameters for the FOOOF power spectra model. +# Power spectra can be simulated with any desired parameters for the FOOOF power spectra model. # # The aperiodic mode for the simulated power spectrum is inferred from the parameters provided. # If two parameters are provided, this is interpreted as [offset, exponent] for simulating @@ -67,19 +67,19 @@ ################################################################################################### -# Set up new settings for creating a different synthetic power spectrum +# Set up new settings for creating a different simulated power spectrum freq_range = [1, 60] aperiodic_params = [1, 500, 2] # Specify three values as [offset, knee, exponent] gaussian_params = [9, 0.4, 1, 24, 0.2, 3] # Add peaks - can also be [[9, 0.4, 1], [24, 0.2, 3]] nlv = 0.01 # The amount of noise to add to the spectrum freq_res = 0.25 # Specific the frequency resolution to simulate -# Generate the new synthetic power spectrum +# Generate the new simulated power spectrum fs, ps = gen_power_spectrum(freq_range, aperiodic_params, gaussian_params, nlv, freq_res) ################################################################################################### -# Plot the new synthetic power spectrum +# Plot the new simulated power spectrum plot_spectrum(fs, ps, log_powers=True) ################################################################################################### @@ -100,7 +100,7 @@ ################################################################################################### -# Create some new settings for synthesizing a group of power spectra +# Create some new settings for simulating a group of power spectra n_spectra = 2 freq_range = [3, 40] ap_params = [[0.5, 1], [1, 1.5]] @@ -109,8 +109,8 @@ ################################################################################################### -# Synthesize a group of power spectra -fs, ps, syn_params = gen_group_power_spectra(n_spectra, freq_range, ap_params, gauss_params, nlv) +# Simulate a group of power spectra +fs, ps, sim_params = gen_group_power_spectra(n_spectra, freq_range, ap_params, gauss_params, nlv) ################################################################################################### @@ -119,8 +119,8 @@ ################################################################################################### # -# Note that when you simulate a group of power spectra, FOOOF returns SynParam objects that +# Note that when you simulate a group of power spectra, FOOOF returns SimParam objects that # keep track of the simulations. This, and other utilties to manage parameters and provide -# parameter definitions for synthesizing groups of power spectra are covered in the -# `Synthetic Parameters` example. +# parameter definitions for simulating groups of power spectra are covered in the +# `Simulated Parameters` example. # diff --git a/examples/plot_transforms.py b/examples/plot_transforms.py index 760cabe62..a80197c81 100644 --- a/examples/plot_transforms.py +++ b/examples/plot_transforms.py @@ -8,14 +8,14 @@ ################################################################################################### # Imports -from fooof.synth.gen import gen_power_spectrum -from fooof.synth.transform import rotate_spectrum +from fooof.sim.gen import gen_power_spectrum +from fooof.sim.transform import rotate_spectrum from fooof.plts.spectra import plot_spectra ################################################################################################### -# Generate a synthetic power spectrum +# Generate a simulated power spectrum fs, ps = gen_power_spectrum([3, 40], [1, 1], [10, 0.5, 1]) ################################################################################################### diff --git a/fooof/analysis.py b/fooof/analysis.py index a6f5c6a3d..aeea68f95 100644 --- a/fooof/analysis.py +++ b/fooof/analysis.py @@ -29,7 +29,7 @@ def get_band_peak_fm(fm, band, ret_one=True, attribute='peak_params'): return get_band_peak(getattr(fm, attribute + '_'), band, ret_one) -def get_band_peaks_fg(fg, band, attribute='peak_params'): +def get_band_peak_fg(fg, band, attribute='peak_params'): """Extract peaks from a band of interest from a FOOOF object. Parameters @@ -47,10 +47,10 @@ def get_band_peaks_fg(fg, band, attribute='peak_params'): Peak data. Each row is a peak, as [CF, Amp, BW]. """ - return get_band_peaks_group(fg.get_all_data(attribute), band, len(fg)) + return get_band_peak_group(fg.get_params(attribute), band, len(fg)) -def get_band_peaks_group(peak_params, band, n_fits): +def get_band_peak_group(peak_params, band, n_fits): """Extracts peaks within a given band of interest. Parameters diff --git a/fooof/core/info.py b/fooof/core/info.py index 5aea7fe97..756226fbc 100644 --- a/fooof/core/info.py +++ b/fooof/core/info.py @@ -1,7 +1,10 @@ """Internal functions to manage info related to FOOOF objects.""" -def get_obj_desc(): - """Get dictionary specifying FOOOF object names and kind of attributes. +################################################################################################### +################################################################################################### + +def get_description(): + """Get dictionary specifying FOOOF attributes, and what kind of data they store. Returns ------- @@ -9,24 +12,23 @@ def get_obj_desc(): Mapping of FOOOF object attributes, and what kind of data they are. """ - attributes = {'results' : ['aperiodic_params_', 'peak_params_', - 'r_squared_', 'error_', - '_gaussian_params'], + attributes = {'results' : ['aperiodic_params_', 'gaussian_params_', 'peak_params_', + 'r_squared_', 'error_'], 'settings' : ['peak_width_limits', 'max_n_peaks', 'min_peak_height', 'peak_threshold', 'aperiodic_mode'], 'data' : ['power_spectrum', 'freq_range', 'freq_res'], - 'data_info' : ['freq_range', 'freq_res'], + 'meta_data' : ['freq_range', 'freq_res'], 'arrays' : ['freqs', 'power_spectrum', 'aperiodic_params_', - 'peak_params_', '_gaussian_params'], + 'peak_params_', 'gaussian_params_'], 'model_components' : ['_spectrum_flat', '_spectrum_peak_rm', '_ap_fit', '_peak_fit']} return attributes -def get_data_indices(aperiodic_mode): - """Get a dictionary mapping the column labels to indices in FOOOF data (FOOOFResults). +def get_indices(aperiodic_mode): + """Get a dictionary mapping indices of FOOOF params to column labels. Parameters ---------- @@ -36,7 +38,7 @@ def get_data_indices(aperiodic_mode): Returns ------- indices : dict - Mapping for data columns to the column indices in which they appear. + Mapping of the column indices for the FOOOF model fit params. """ indices = { diff --git a/fooof/core/io.py b/fooof/core/io.py index 417b707ce..f6f991170 100644 --- a/fooof/core/io.py +++ b/fooof/core/io.py @@ -5,7 +5,7 @@ import json from json import JSONDecodeError -from fooof.core.info import get_obj_desc +from fooof.core.info import get_description from fooof.core.utils import dict_array_to_lst, dict_select_keys, dict_lst_to_array ################################################################################################### @@ -89,8 +89,8 @@ def save_fm(fm, file_name, file_path=None, append=False, # 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 - attributes = get_obj_desc() - keep = set((attributes['results'] + attributes['data_info'] if save_results else []) + \ + attributes = get_description() + keep = set((attributes['results'] + attributes['meta_data'] if save_results else []) + \ (attributes['settings'] if save_settings else []) + \ (attributes['data'] if save_data else [])) obj_dict = dict_select_keys(obj_dict, keep) @@ -183,7 +183,7 @@ def load_json(file_name, file_path): dat = json.loads(file_name.readline()) # Get dictionary of available attributes, and convert specified lists back into arrays - dat = dict_lst_to_array(dat, get_obj_desc()['arrays']) + dat = dict_lst_to_array(dat, get_description()['arrays']) return dat diff --git a/fooof/core/modutils.py b/fooof/core/modutils.py index 424dbce59..88a1772b9 100644 --- a/fooof/core/modutils.py +++ b/fooof/core/modutils.py @@ -122,13 +122,17 @@ def wrapper(func): return wrapper -def copy_doc_class(source, section=None, att_add=''): +def copy_doc_class(source, section='Attributes', add=''): """Copy method docstring from class, to another class, adding extra info (decorator). Parameters ---------- source : cls Source class to copy docstring from. + section : str, optional, default: 'Attributes' + Name of the section within the dostring to add to. + add : str, optional + Text to append to specified section of the docstring. Returns ------- @@ -138,7 +142,7 @@ def copy_doc_class(source, section=None, att_add=''): def wrapper(func): - func.__doc__ = docs_append_to_section(source.__doc__, 'Attributes', att_add) + func.__doc__ = docs_append_to_section(source.__doc__, section, add) return func diff --git a/fooof/core/reports.py b/fooof/core/reports.py index 6b5fd664b..dd2bed43b 100644 --- a/fooof/core/reports.py +++ b/fooof/core/reports.py @@ -1,11 +1,9 @@ """Generate reports from FOOOF and FOOOF derivative objects.""" -import os - from fooof.core.io import fname, fpath from fooof.core.modutils import safe_import, check_dependency -from fooof.core.strings import gen_settings_str, gen_results_str_fm, gen_results_str_fg -from fooof.plts.fg import plot_fg_bg, plot_fg_gf, plot_fg_peak_cens +from fooof.core.strings import gen_settings_str, gen_results_fm_str, gen_results_fg_str +from fooof.plts.fg import plot_fg_ap, plot_fg_gf, plot_fg_peak_cens plt = safe_import('.pyplot', 'matplotlib') gridspec = safe_import('.gridspec', 'matplotlib') @@ -37,7 +35,7 @@ def save_report_fm(fm, file_name, file_path=None, plt_log=False): # First - text results ax0 = plt.subplot(grid[0]) - results_str = gen_results_str_fm(fm) + results_str = gen_results_fm_str(fm) ax0.text(0.5, 0.7, results_str, font, ha='center', va='center') ax0.set_frame_on(False) ax0.set_xticks([]) @@ -82,7 +80,7 @@ def save_report_fg(fg, file_name, file_path=None): # First / top: text results ax0 = plt.subplot(gs[0, :]) - results_str = gen_results_str_fg(fg) + results_str = gen_results_fg_str(fg) ax0.text(0.5, 0.7, results_str, font, ha='center', va='center') ax0.set_frame_on(False) ax0.set_xticks([]) @@ -90,7 +88,7 @@ def save_report_fg(fg, file_name, file_path=None): # Aperiodic parameters plot ax1 = plt.subplot(gs[1, 0]) - plot_fg_bg(fg, ax1) + plot_fg_ap(fg, ax1) # Goodness of fit plot ax2 = plt.subplot(gs[1, 1]) diff --git a/fooof/core/strings.py b/fooof/core/strings.py index 0d151dfc9..418d815f4 100644 --- a/fooof/core/strings.py +++ b/fooof/core/strings.py @@ -14,7 +14,7 @@ ################################################################################################### ################################################################################################### -def gen_wid_warn_str(freq_res, bwl): +def gen_width_warning_str(freq_res, bwl): """Generate a string representation of warning about peak width limits. Parameters @@ -29,7 +29,7 @@ def gen_wid_warn_str(freq_res, bwl): '', 'FOOOF WARNING: Lower-bound peak width limit is < or ~= the frequency resolution: ' + \ '{:1.2f} <= {:1.2f}'.format(freq_res, bwl), - '\tLower bounds below frequency-resolution have no effect (effective lower bound is freq-res)', + '\tLower bounds below frequency-resolution have no effect (effective lower bound is the frequency resolution).', '\tToo low a limit may lead to overfitting noise as small bandwidth peaks.', '\tWe recommend a lower bound of approximately 2x the frequency resolution.', '' @@ -98,7 +98,7 @@ def gen_settings_str(f_obj, description=False, concise=False): return output -def gen_results_str_fm(fm, concise=False): +def gen_results_fm_str(fm, concise=False): """Generate a string representation of model fit results. Parameters @@ -163,7 +163,7 @@ def gen_results_str_fm(fm, concise=False): return output -def gen_results_str_fg(fg, concise=False): +def gen_results_fg_str(fg, concise=False): """Generate a string representation of group fit results. Parameters @@ -183,15 +183,15 @@ def gen_results_str_fg(fg, concise=False): raise ValueError('Model fit has not been run - can not proceed.') # Extract all the relevant data for printing - n_peaks = len(fg.get_all_data('peak_params')) - r2s = fg.get_all_data('r_squared') - errors = fg.get_all_data('error') + n_peaks = len(fg.get_params('peak_params')) + r2s = fg.get_params('r_squared') + errors = fg.get_params('error') if fg.aperiodic_mode == 'knee': - kns = fg.get_all_data('aperiodic_params', 1) - sls = fg.get_all_data('aperiodic_params', 2) + kns = fg.get_params('aperiodic_params', 1) + sls = fg.get_params('aperiodic_params', 2) else: kns = np.array([0]) - sls = fg.get_all_data('aperiodic_params', 1) + sls = fg.get_params('aperiodic_params', 1) # Check if there are any power spectra that failed to fit n_failed = sum(np.isnan(sls)) diff --git a/fooof/core/utils.py b/fooof/core/utils.py index abd285547..742f4d22c 100644 --- a/fooof/core/utils.py +++ b/fooof/core/utils.py @@ -151,8 +151,8 @@ def check_flat(lst): Returns ------- - list - A '1D' list, which is a flattened version of the input. + lst: list + A flat (1d) list, which is a flattened version of the input. Notes ----- diff --git a/fooof/data.py b/fooof/data.py index 80a258f0c..b970fba7e 100644 --- a/fooof/data.py +++ b/fooof/data.py @@ -26,9 +26,9 @@ """ -FOOOFDataInfo = namedtuple('FOOOFDataInfo', ['freq_range', 'freq_res']) +FOOOFMetaData = namedtuple('FOOOFMetaData', ['freq_range', 'freq_res']) -FOOOFDataInfo.__doc__ = """\ +FOOOFMetaData.__doc__ = """\ Data related information for a FOOOF object. Attributes @@ -62,10 +62,10 @@ """ -SynParams = namedtuple('SynParams', ['aperiodic_params', 'gaussian_params', 'nlv']) +SimParams = namedtuple('SimParams', ['aperiodic_params', 'gaussian_params', 'nlv']) -SynParams.__doc__ = """\ -Stores parameters used to synthesize a single power spectra. +SimParams.__doc__ = """\ +Stores parameters used to simulate a single power spectra. Attributes ---------- diff --git a/fooof/fit.py b/fooof/fit.py index cf0a35a69..823a784cc 100644 --- a/fooof/fit.py +++ b/fooof/fit.py @@ -11,9 +11,6 @@ Flattened power spectrum (aperiodic component removed). _spectrum_peak_rm : 1d array Power spectrum with peaks removed (not flattened). -_gaussian_params : 2d array - Parameters that define the gaussian fit(s). - Each row is a gaussian, as [mean, height, standard deviation]. _ap_fit : 1d array Values of the aperiodic fit. _peak_fit : 1d array @@ -42,19 +39,20 @@ from fooof.core.reports import save_report_fm from fooof.core.funcs import gaussian_function, get_ap_func, infer_ap_func from fooof.core.utils import group_three, check_array_dim -from fooof.core.info import get_obj_desc +from fooof.core.info import get_description, get_indices from fooof.core.modutils import copy_doc_func_to_method -from fooof.core.strings import gen_settings_str, gen_results_str_fm, gen_issue_str, gen_wid_warn_str +from fooof.core.strings import (gen_settings_str, gen_results_fm_str, + gen_issue_str, gen_width_warning_str) from fooof.plts.fm import plot_fm from fooof.utils import trim_spectrum -from fooof.data import FOOOFResults, FOOOFSettings, FOOOFDataInfo -from fooof.synth.gen import gen_freqs, gen_aperiodic, gen_peaks +from fooof.data import FOOOFResults, FOOOFSettings, FOOOFMetaData +from fooof.sim.gen import gen_freqs, gen_aperiodic, gen_peaks ################################################################################################### ################################################################################################### -class FOOOF(object): +class FOOOF(): """Model the physiological power spectrum as a combination of aperiodic and periodic components. WARNING: FOOOF expects frequency and power values in linear space. @@ -94,6 +92,9 @@ class FOOOF(object): The knee parameter is only included if aperiodic component is fit with a knee. peak_params_ : 2d array Fitted parameter values for the peaks. Each row is a peak, as [CF, PW, BW]. + gaussian_params : 2d array + Parameters that define the gaussian fit(s). + Each row is a gaussian, as [mean, height, standard deviation]. r_squared_ : float R-squared of the fit between the input power spectrum and the full model fit. error_ : float @@ -110,6 +111,10 @@ class FOOOF(object): procedure, or a median filter smoothing on the FFT output before running FOOOF. - Where possible and appropriate, use longer time segments for power spectrum calculation to get smoother power spectra, as this will give better FOOOF fits. + - The gaussian params are those that define the gaussian of the fit, where as the peak + params are a modified version, in which the CF of the peak is the mean of the gaussian, + the PW of the peak is the height of the gaussian over and above the aperiodic component, + and the BW of the peak, is 2*std of the gaussian (as 'two sided' bandwidth). """ def __init__(self, peak_width_limits=(0.5, 12.0), max_n_peaks=np.inf, min_peak_height=0.0, @@ -202,10 +207,10 @@ def _reset_data_results(self, clear_freqs=True, clear_spectrum=True, clear_resul if clear_results: self.aperiodic_params_ = None + self.gaussian_params_ = None self.peak_params_ = None self.r_squared_ = None self.error_ = None - self._gaussian_params = None self.fooofed_spectrum_ = None @@ -251,23 +256,23 @@ def add_settings(self, fooof_settings): A FOOOF data object containing the settings for a FOOOF model. """ - for setting in get_obj_desc()['settings']: + for setting in get_description()['settings']: setattr(self, setting, getattr(fooof_settings, setting)) self._check_loaded_settings(fooof_settings._asdict()) - def add_data_info(self, fooof_data_info): - """Add data information into object from a FOOOFDataInfo object. + def add_meta_data(self, fooof_meta_data): + """Add data information into object from a FOOOFMetaData object. Parameters ---------- - fooof_data_info : FOOOFDataInfo - A FOOOF data object containing information about the data. + fooof_meta_data : FOOOFMetaData + A FOOOF meta data object containing meta data information. """ - for data_info in get_obj_desc()['data_info']: - setattr(self, data_info, getattr(fooof_data_info, data_info)) + for meta_dat in get_description()['meta_data']: + setattr(self, meta_dat, getattr(fooof_meta_data, meta_dat)) self._regenerate_freqs() @@ -282,10 +287,10 @@ def add_results(self, fooof_result): """ self.aperiodic_params_ = fooof_result.aperiodic_params + self.gaussian_params_ = fooof_result.gaussian_params self.peak_params_ = fooof_result.peak_params self.r_squared_ = fooof_result.r_squared self.error_ = fooof_result.error - self._gaussian_params = fooof_result.gaussian_params self._check_loaded_results(fooof_result._asdict()) @@ -360,11 +365,11 @@ def fit(self, freqs=None, power_spectrum=None, freq_range=None): self._spectrum_flat = self.power_spectrum - self._ap_fit # Find peaks, and fit them with gaussians - self._gaussian_params = self._fit_peaks(np.copy(self._spectrum_flat)) + self.gaussian_params_ = self._fit_peaks(np.copy(self._spectrum_flat)) # Calculate the peak fit # Note: if no peaks are found, this creates a flat (all zero) peak fit. - self._peak_fit = gen_peaks(self.freqs, np.ndarray.flatten(self._gaussian_params)) + self._peak_fit = gen_peaks(self.freqs, np.ndarray.flatten(self.gaussian_params_)) # Create peak-removed (but not flattened) power spectrum. self._spectrum_peak_rm = self.power_spectrum - self._peak_fit @@ -378,7 +383,7 @@ def fit(self, freqs=None, power_spectrum=None, freq_range=None): self.fooofed_spectrum_ = self._peak_fit + self._ap_fit # Convert gaussian definitions to peak parameters - self.peak_params_ = self._create_peak_params(self._gaussian_params) + self.peak_params_ = self._create_peak_params(self.gaussian_params_) # Calculate R^2 and error of the model fit. self._calc_r_squared() @@ -419,7 +424,7 @@ def print_results(self, concise=False): Whether to print the report in a concise mode, or not. """ - print(gen_results_str_fm(self, concise)) + print(gen_results_fm_str(self, concise)) @staticmethod @@ -444,23 +449,70 @@ def get_settings(self): Object containing the settings from the current FOOOF object. """ - return FOOOFSettings(**{key : getattr(self, key) for key in get_obj_desc()['settings']}) + return FOOOFSettings(**{key : getattr(self, key) for key in get_description()['settings']}) - def get_data_info(self): + def get_meta_data(self): """Return data information from the FOOOF object. Returns ------- - FOOOFDataInfo - Object containing information about the data from the current FOOOF object. + FOOOFMetaData + Object containing meta data from the current FOOOF object. """ - return FOOOFDataInfo(**{key : getattr(self, key) for key in get_obj_desc()['data_info']}) + return FOOOFMetaData(**{key : getattr(self, key) for key in get_description()['meta_data']}) + + + def get_params(self, name, col=None): + """Return model fit parameters for specified feature(s). + + Parameters + ---------- + name : {'aperiodic_params', 'peak_params', 'gaussian_params', 'error', 'r_squared'} + Name of the data field to extract. + col : {'CF', 'PW', 'BW', 'offset', 'knee', 'exponent'} or int, optional + Column name / index to extract from selected data, if requested. + Only used for name of {'aperiodic_params', 'peak_params', 'gaussian_params'}. + + Returns + ------- + out : float or 1d array + Requested data. + + Notes + ----- + For further description of the data you can extract, check the FOOOFResults documentation. + + If there is no data on periodic features, this method will return NaN. + """ + + if self.aperiodic_params_ is None: + raise RuntimeError('No model fit data is available to extract - can not proceed.') + + # If col specified as string, get mapping back to integer + if isinstance(col, str): + col = get_indices(self.aperiodic_mode)[col] + + # Extract the request data field from object + out = getattr(self, name + '_') + + # Periodic values can be empty arrays - if so replace with NaN array + if isinstance(out, np.ndarray) and out.size == 0: + out = np.array([np.nan, np.nan, np.nan]) + + # Select out a specific column, if requested + if col is not None: + + # Extract column, & if result is a single value in an array, unpack from array + out = out[col] if out.ndim == 1 else out[:, col] + out = out[0] if isinstance(out, np.ndarray) and out.size == 1 else out + + return out def get_results(self): - """Return model fit parameters and goodness of fit metrics. + """Return model fit parameters and goodness of fit metrics in a FOOOFResults object. Returns ------- @@ -468,7 +520,8 @@ def get_results(self): Object containing the FOOOF model fit results from the current FOOOF object. """ - return FOOOFResults(**{key.strip('_') : getattr(self, key) for key in get_obj_desc()['results']}) + return FOOOFResults(**{key.strip('_') : getattr(self, key) \ + for key in get_description()['results']}) @copy_doc_func_to_method(plot_fm) @@ -531,7 +584,7 @@ def _check_width_limits(self): # Check peak width limits against frequency resolution; warn if too close. if 1.5 * self.freq_res >= self.peak_width_limits[0]: - print(gen_wid_warn_str(self.freq_res, self.peak_width_limits[0])) + print(gen_width_warning_str(self.freq_res, self.peak_width_limits[0])) def _simple_ap_fit(self, freqs, power_spectrum): @@ -629,8 +682,9 @@ def _fit_peaks(self, flat_iter): # Initialize matrix of guess parameters for gaussian fitting. guess = np.empty([0, 3]) - # Find peak: Loop through, finding a candidate peak, and fitting with a guass gaussian. - # Stopping procedure based on either # of peaks, or the relative or absolute height thresholds. + # Find peak: Loop through, finding a candidate peak, and fitting with a guess gaussian. + # Stopping procedure based on either the limit on # of peaks, + # or the relative or absolute height thresholds. while len(guess) < self.max_n_peaks: # Find candidate peak - the maximum point of the flattened spectrum. @@ -652,18 +706,19 @@ def _fit_peaks(self, flat_iter): # Data-driven first guess at standard deviation # Find half height index on each side of the center frequency. half_height = 0.5 * max_height - le_ind = next((x for x in range(max_ind - 1, 0, -1) if flat_iter[x] <= half_height), None) - ri_ind = next((x for x in range(max_ind + 1, len(flat_iter), 1) - if flat_iter[x] <= half_height), None) + le_ind = next((val for val in range(max_ind - 1, 0, -1) + if flat_iter[val] <= half_height), None) + ri_ind = next((val for val in range(max_ind + 1, len(flat_iter), 1) + if flat_iter[val] <= half_height), None) # Keep bandwidth estimation from the shortest side. # We grab shortest to avoid estimating very large std from overalapping peaks. # Grab the shortest side, ignoring a side if the half max was not found. # Note: will fail if both le & ri ind's end up as None (probably shouldn't happen). - shortest_side = min([abs(ind - max_ind) for ind in [le_ind, ri_ind] if ind is not None]) + short_side = min([abs(ind - max_ind) for ind in [le_ind, ri_ind] if ind is not None]) # Estimate std from FWHM. Calculate FWHM, converting to Hz, get guess std from FWHM - fwhm = shortest_side * 2 * self.freq_res + fwhm = short_side * 2 * self.freq_res guess_std = fwhm / (2 * np.sqrt(2 * np.log(2))) # Check that guess std isn't outside preset std limits; restrict if so. @@ -709,21 +764,26 @@ def _fit_peak_guess(self, guess): Parameters for gaussian fits to peaks, as gaussian parameters. """ - # Set the bounds for center frequency, enforce positive height value, and set bandwidth limits. - # Note that 'guess' is in terms of gaussian standard deviation, so +/- BW is 2 * the guess_gauss_std. + # Set the bounds for CF, enforce positive height value, and set bandwidth limits. + # Note that 'guess' is in terms of gaussian std, so +/- BW is 2 * the guess_gauss_std. # This set of list comprehensions is a way to end up with bounds in the form: - # ((cf_low_bound_peak1, height_low_bound_peak1, bw_low_bound_peak1, *repeated for n_peak*), - # (cf_high_bound_peak1, height_high_bound_peak1, bw_high_bound_peak, *repeated for n_peak*)) + # ((cf_low_peak1, height_low_peak1, bw_low_peak1, *repeated for n_peaks*), + # (cf_high_peak1, height_high_peak1, bw_high_peak, *repeated for n_peaks*)) + # ^where each value sets the bound on the specified parameter. lo_bound = [[peak[0] - 2 * self._cf_bound * peak[2], 0, self._gauss_std_limits[0]] for peak in guess] hi_bound = [[peak[0] + 2 * self._cf_bound * peak[2], np.inf, self._gauss_std_limits[1]] for peak in guess] - # Check that CF bounds are within frequency range, and, if not, updates them to be restricted to frequency range. - lo_bound = [bound if bound[0] > self.freq_range[0] else [self.freq_range[0], *bound[1:]] for bound in lo_bound] - hi_bound = [bound if bound[0] < self.freq_range[1] else [self.freq_range[1], *bound[1:]] for bound in hi_bound] + # Check that CF bounds are within frequency range + # If they are not, update them to be restricted to frequency range. + lo_bound = [bound if bound[0] > self.freq_range[0] else \ + [self.freq_range[0], *bound[1:]] for bound in lo_bound] + hi_bound = [bound if bound[0] < self.freq_range[1] else \ + [self.freq_range[1], *bound[1:]] for bound in hi_bound] - # Unpacks the embedded lists into flat tuples, which is what the fit function requires as input. + # Unpacks the embedded lists into flat tuples + # This is what the fit function requires as input. gaus_param_bounds = (tuple([item for sublist in lo_bound for item in sublist]), tuple([item for sublist in hi_bound for item in sublist])) @@ -807,7 +867,7 @@ def _drop_peak_cf(self, guess): (np.abs(np.subtract(cf_params, self.freq_range[1])) > bw_params) # Drop peaks that fail the center frequency edge criterion - guess = np.array([d for (d, keep) in zip(guess, keep_peak) if keep]) + guess = np.array([gu for (gu, keep) in zip(guess, keep_peak) if keep]) return guess @@ -838,9 +898,8 @@ def _drop_peak_overlap(self, guess): bounds = [[peak[0] - peak[2] * self._gauss_overlap_thresh, peak[0], peak[0] + peak[2] * self._gauss_overlap_thresh] for peak in guess] - drop_inds = [] - # Loop through peak bounds, comparing current bound to that of next peak + drop_inds = [] for ind, b_0 in enumerate(bounds[:-1]): b_1 = bounds[ind + 1] @@ -851,8 +910,8 @@ def _drop_peak_overlap(self, guess): drop_inds.append([ind, ind + 1][np.argmin([guess[ind][1], guess[ind + 1][1]])]) # Drop any peaks guesses that overlap too much, based on threshold. - keep_peak = [True if j not in drop_inds else False for j in range(len(guess))] - guess = np.array([d for (d, keep) in zip(guess, keep_peak) if keep]) + keep_peak = [not ind in drop_inds for ind in range(len(guess))] + guess = np.array([gu for (gu, keep) in zip(guess, keep_peak) if keep]) return guess @@ -969,9 +1028,9 @@ def _check_loaded_results(self, data): # If results loaded, check dimensions of peak parameters # This fixes an issue where they end up the wrong shape if they are empty (no peaks) - if set(get_obj_desc()['results']).issubset(set(data.keys())): + if set(get_description()['results']).issubset(set(data.keys())): self.peak_params_ = check_array_dim(self.peak_params_) - self._gaussian_params = check_array_dim(self._gaussian_params) + self.gaussian_params_ = check_array_dim(self.gaussian_params_) def _check_loaded_settings(self, data): @@ -985,10 +1044,10 @@ def _check_loaded_settings(self, data): # If settings not loaded from file, clear from object, so that default # settings, which are potentially wrong for loaded data, aren't kept - if not set(get_obj_desc()['settings']).issubset(set(data.keys())): + if not set(get_description()['settings']).issubset(set(data.keys())): # Reset all public settings to None - for setting in get_obj_desc()['settings']: + for setting in get_description()['settings']: setattr(self, setting, None) # Infer whether knee fitting was used, if aperiodic params have been loaded @@ -1010,5 +1069,5 @@ def _regenerate_model(self): """Regenerate model fit from parameters.""" self._ap_fit = gen_aperiodic(self.freqs, self.aperiodic_params_) - self._peak_fit = gen_peaks(self.freqs, np.ndarray.flatten(self._gaussian_params)) + self._peak_fit = gen_peaks(self.freqs, np.ndarray.flatten(self.gaussian_params_)) self.fooofed_spectrum_ = self._peak_fit + self._ap_fit diff --git a/fooof/funcs.py b/fooof/funcs.py index 661ca51fa..fdb833bb4 100644 --- a/fooof/funcs.py +++ b/fooof/funcs.py @@ -5,8 +5,7 @@ from fooof import FOOOF, FOOOFGroup from fooof.data import FOOOFResults from fooof.utils import compare_info -from fooof.synth.gen import gen_freqs -from fooof.analysis import get_band_peaks_fg +from fooof.analysis import get_band_peak_fg ################################################################################################### ################################################################################################### @@ -39,22 +38,22 @@ def average_fg(fg, bands, avg_method='mean'): elif avg_method == 'median': avg_func = np.nanmedian - ap_params = avg_func(fg.get_all_data('aperiodic_params'), 0) + ap_params = avg_func(fg.get_params('aperiodic_params'), 0) - peak_params = np.array([avg_func(get_band_peaks_fg(fg, band, 'peak_params'), 0) \ + peak_params = np.array([avg_func(get_band_peak_fg(fg, band, 'peak_params'), 0) \ for label, band in bands]) - gaussian_params = np.array([avg_func(get_band_peaks_fg(fg, band, 'gaussian_params'), 0) \ + gaussian_params = np.array([avg_func(get_band_peak_fg(fg, band, 'gaussian_params'), 0) \ for label, band in bands]) - r2 = avg_func(fg.get_all_data('r_squared')) - error = avg_func(fg.get_all_data('error')) + r2 = avg_func(fg.get_params('r_squared')) + error = avg_func(fg.get_params('error')) results = FOOOFResults(ap_params, peak_params, r2, error, gaussian_params) # Create the new FOOOF object, with settings, data info & results fm = FOOOF() fm.add_settings(fg.get_settings()) - fm.add_data_info(fg.get_data_info()) + fm.add_meta_data(fg.get_meta_data()) fm.add_results(results) return fm @@ -75,8 +74,8 @@ def combine_fooofs(fooofs): """ # Compare settings - if not compare_info(fooofs, 'settings') or not compare_info(fooofs, 'data_info'): - raise ValueError("These objects have incompatible settings or data," \ + if not compare_info(fooofs, 'settings') or not compare_info(fooofs, 'meta_data'): + raise ValueError("These objects have incompatible settings or meta data," \ "and so cannot be combined.") # Initialize FOOOFGroup object, with settings derived from input objects @@ -103,7 +102,7 @@ def combine_fooofs(fooofs): fg.power_spectra = temp_power_spectra # Add data information information - fg.add_data_info(fooofs[0].get_data_info()) + fg.add_meta_data(fooofs[0].get_meta_data()) return fg diff --git a/fooof/group.py b/fooof/group.py index 5cd139bdf..87a69a9c4 100644 --- a/fooof/group.py +++ b/fooof/group.py @@ -14,9 +14,9 @@ from fooof import FOOOF from fooof.plts.fg import plot_fg from fooof.core.reports import save_report_fg -from fooof.core.strings import gen_results_str_fg +from fooof.core.strings import gen_results_fg_str from fooof.core.io import save_fg, load_jsonlines -from fooof.core.info import get_data_indices +from fooof.core.info import get_indices from fooof.core.modutils import copy_doc_func_to_method, copy_doc_class, safe_import ################################################################################################### @@ -59,7 +59,8 @@ def __getitem__(self, index): return self.group_results[index] - def _reset_data_results(self, clear_freqs=True, clear_spectrum=True, clear_results=True, clear_spectra=True): + def _reset_data_results(self, clear_freqs=True, clear_spectrum=True, + clear_results=True, clear_spectra=True): """Set (or reset) data & results attributes to empty. Parameters @@ -171,7 +172,8 @@ def fit(self, freqs=None, power_spectra=None, freq_range=None, n_jobs=1): # Run linearly if n_jobs == 1: self._reset_group_results(len(self.power_spectra)) - for ind, power_spectrum in _progress(enumerate(self.power_spectra), self.verbose, len(self)): + for ind, power_spectrum in \ + _progress(enumerate(self.power_spectra), self.verbose, len(self)): self._fit(power_spectrum=power_spectrum) self.group_results[ind] = self._get_results() @@ -193,12 +195,12 @@ def get_results(self): return self.group_results - def get_all_data(self, name, col=None): - """Return all data for a specified attribute across the group. + def get_params(self, name, col=None): + """Return model fit parameters for specified feature(s). Parameters ---------- - name : {'aperiodic_params', 'peak_params', 'error', 'r_squared', 'gaussian_params'} + name : {'aperiodic_params', 'peak_params', 'gaussian_params', 'error', 'r_squared'} Name of the data field to extract across the group. col : {'CF', 'PW', 'BW', 'offset', 'knee', 'exponent'} or int, optional Column name / index to extract from selected data, if requested. @@ -212,17 +214,19 @@ def get_all_data(self, name, col=None): Notes ----- For further description of the data you can extract, check the FOOOFResults documentation. - For example `print(fg[0].__doc__)` """ + if not self.group_results: + raise RuntimeError('No model fit data is available to extract - can not proceed.') + # If col specified as string, get mapping back to integer if isinstance(col, str): - col = get_data_indices(self.aperiodic_mode)[col] + col = get_indices(self.aperiodic_mode)[col] # Pull out the requested data field from the group data # As a special case, peak_params are pulled out in a way that appends # an extra column, indicating from which FOOOF run each peak comes from - if name == 'peak_params' or name == 'gaussian_params': + if name in ('peak_params', 'gaussian_params'): out = np.array([np.insert(getattr(data, name), 3, index, axis=1) for index, data in enumerate(self.group_results)]) # This updates index to grab selected column, and the last colum @@ -272,7 +276,8 @@ def load(self, file_name='FOOOFGroup_results', file_path=None): file_name : str, optional File from which to load data. file_path : str, optional - Path to directory from which to load from. If not provided, loads from current directory. + Path to directory from which to load from. + If not provided, loads from current directory. """ # Clear results so as not to have possible prior results interfere @@ -318,7 +323,7 @@ def get_fooof(self, ind, regenerate=False): fm.add_data(self.freqs, np.power(10, self.power_spectra[ind])) # If no power spectrum data available, copy over data information & regenerate freqs else: - fm.add_data_info(self.get_data_info()) + fm.add_meta_data(self.get_meta_data()) # Add results for specified power spectrum, regenerating full fit if requested fm.add_results(self.group_results[ind]) @@ -337,7 +342,7 @@ def print_results(self, concise=False): Whether to print the report in a concise mode, or not. """ - print(gen_results_str_fg(self, concise)) + print(gen_results_fg_str(self, concise)) def _fit(self, *args, **kwargs): diff --git a/fooof/plts/fg.py b/fooof/plts/fg.py index 0f7c0e156..b68781e42 100644 --- a/fooof/plts/fg.py +++ b/fooof/plts/fg.py @@ -5,8 +5,6 @@ This file contains plotting functions that take as input a FOOOFGroup() object. """ -import os - from fooof.core.io import fname, fpath from fooof.core.modutils import safe_import, check_dependency from fooof.plts.templates import plot_scatter_1, plot_scatter_2, plot_hist @@ -41,7 +39,7 @@ def plot_fg(fg, save_fig=False, file_name='FOOOF_group_fit', file_path=None): # Aperiodic parameters plot ax0 = plt.subplot(gs[0, 0]) - plot_fg_bg(fg, ax0) + plot_fg_ap(fg, ax0) # Goodness of fit plot ax1 = plt.subplot(gs[0, 1]) @@ -56,7 +54,7 @@ def plot_fg(fg, save_fig=False, file_name='FOOOF_group_fit', file_path=None): @check_dependency(plt, 'matplotlib') -def plot_fg_bg(fg, ax=None): +def plot_fg_ap(fg, ax=None): """Plot aperiodic fit parameters, in a scatter plot. Parameters @@ -68,11 +66,11 @@ def plot_fg_bg(fg, ax=None): """ if fg.aperiodic_mode == 'knee': - plot_scatter_2(fg.get_all_data('aperiodic_params', 1), 'Knee', - fg.get_all_data('aperiodic_params', 2), 'Exponent', + plot_scatter_2(fg.get_params('aperiodic_params', 1), 'Knee', + fg.get_params('aperiodic_params', 2), 'Exponent', 'Aperiodic Fit', ax=ax) else: - plot_scatter_1(fg.get_all_data('aperiodic_params', 1), 'Exponent', + plot_scatter_1(fg.get_params('aperiodic_params', 1), 'Exponent', 'Aperiodic Fit', ax=ax) @@ -88,8 +86,8 @@ def plot_fg_gf(fg, ax=None): Figure axes upon which to plot. """ - plot_scatter_2(fg.get_all_data('error'), 'Error', - fg.get_all_data('r_squared'), 'R^2', 'Goodness of Fit', ax=ax) + plot_scatter_2(fg.get_params('error'), 'Error', + fg.get_params('r_squared'), 'R^2', 'Goodness of Fit', ax=ax) @check_dependency(plt, 'matplotlib') @@ -104,5 +102,5 @@ def plot_fg_peak_cens(fg, ax=None): Figure axes upon which to plot. """ - plot_hist(fg.get_all_data('peak_params', 0)[:, 0], 'Center Frequency', + plot_hist(fg.get_params('peak_params', 0)[:, 0], 'Center Frequency', 'Peaks - Center Frequencies', x_lims=fg.freq_range, ax=ax) diff --git a/fooof/plts/fm.py b/fooof/plts/fm.py index 320dd084b..6c6bfa8b5 100644 --- a/fooof/plts/fm.py +++ b/fooof/plts/fm.py @@ -5,7 +5,6 @@ This file contains plotting functions that take as input a FOOOF() object. """ -import os import numpy as np from fooof.plts.utils import check_ax @@ -75,7 +74,7 @@ def plot_peak_iter(fm): """ flatspec = fm._spectrum_flat - n_gauss = fm._gaussian_params.shape[0] + n_gauss = fm.gaussian_params_.shape[0] ylims = [min(flatspec) - 0.1 * np.abs(min(flatspec)), max(flatspec) + 0.1 * max(flatspec)] for ind in range(n_gauss + 1): @@ -97,7 +96,7 @@ def plot_peak_iter(fm): if ind < n_gauss: - gauss = gaussian_function(fm.freqs, *fm._gaussian_params[ind, :]) + gauss = gaussian_function(fm.freqs, *fm.gaussian_params_[ind, :]) plot_spectrum(fm.freqs, gauss, label='Gaussian Fit', linestyle=':', linewidth=2.0, ax=ax) diff --git a/fooof/plts/settings.py b/fooof/plts/settings.py index 63e23664f..b6e84d564 100644 --- a/fooof/plts/settings.py +++ b/fooof/plts/settings.py @@ -8,4 +8,4 @@ DEFAULT_FIGSIZE = (12, 10) # Levels for scaling alpha with the number of points in scatter plots -ALPHA_LEVELS = OrderedDict({0 : 0.50, 100 : 0.40, 500 : 0.25, 1000 : 0.10}) \ No newline at end of file +ALPHA_LEVELS = OrderedDict({0 : 0.50, 100 : 0.40, 500 : 0.25, 1000 : 0.10}) diff --git a/fooof/synth/__init__.py b/fooof/sim/__init__.py similarity index 100% rename from fooof/synth/__init__.py rename to fooof/sim/__init__.py diff --git a/fooof/synth/gen.py b/fooof/sim/gen.py similarity index 92% rename from fooof/synth/gen.py rename to fooof/sim/gen.py index 414d7a723..e7515d407 100644 --- a/fooof/synth/gen.py +++ b/fooof/sim/gen.py @@ -1,10 +1,10 @@ -"""Synthesis functions for generating model components and synthetic power spectra.""" +"""Functions for generating model components and simulated power spectra.""" import numpy as np from fooof.core.utils import group_three, check_iter, check_flat from fooof.core.funcs import gaussian_function, get_ap_func, infer_ap_func -from fooof.synth.params import SynParams +from fooof.sim.params import SimParams ################################################################################################### ################################################################################################### @@ -34,7 +34,7 @@ def gen_freqs(freq_range, freq_res): def gen_power_spectrum(freq_range, aperiodic_params, gaussian_params, nlv=0.005, freq_res=0.5): - """Generate a synthetic power spectrum. + """Generate a simualted power spectrum. Parameters ---------- @@ -47,7 +47,7 @@ def gen_power_spectrum(freq_range, aperiodic_params, gaussian_params, nlv=0.005, nlv : float, optional, default: 0.005 Noise level to add to generated power spectrum. freq_res : float, optional, default: 0.5 - Frequency resolution for the synthetic power spectra. + Frequency resolution for the simulated power spectrum. Returns ------- @@ -94,7 +94,7 @@ def gen_power_spectrum(freq_range, aperiodic_params, gaussian_params, nlv=0.005, def gen_group_power_spectra(n_spectra, freq_range, aperiodic_params, gaussian_params, nlvs=0.005, freq_res=0.5): - """Generate a group of synthetic power spectra. + """Generate a group of simulated power spectra. Parameters ---------- @@ -110,7 +110,7 @@ def gen_group_power_spectra(n_spectra, freq_range, aperiodic_params, nlvs : float or list of float or generator, optional, default: 0.005 Noise level to add to generated power spectrum. freq_res : float, optional, default: 0.5 - Frequency resolution for the synthetic power spectra. + Frequency resolution for the simulated power spectra. Returns ------- @@ -118,7 +118,7 @@ def gen_group_power_spectra(n_spectra, freq_range, aperiodic_params, Frequency values (linear). powers : 2d array Matrix of power values (linear), as [n_power_spectra, n_freqs]. - syn_params : list of SynParams + sim_params : list of SimParams Definitions of parameters used for each spectrum. Has length of n_spectra. Notes @@ -154,26 +154,26 @@ def gen_group_power_spectra(n_spectra, freq_range, aperiodic_params, >>> ap_opts = param_sampler([[0, 1.0], [0, 1.5], [0, 2]]) >>> gauss_opts = param_sampler([[], [10, 1, 1], [10, 1, 1, 20, 2, 1]]) - >>> freqs, psds, syn_params = gen_group_power_spectra(10, [1, 50], ap_opts, gauss_opts) + >>> freqs, psds, sim_params = gen_group_power_spectra(10, [1, 50], ap_opts, gauss_opts) """ # Initialize things freqs = gen_freqs(freq_range, freq_res) powers = np.zeros([n_spectra, len(freqs)]) - syn_params = [None] * n_spectra + sim_params = [None] * n_spectra # Check if inputs are generators, if not, make them into repeat generators aperiodic_params = check_iter(aperiodic_params, n_spectra) gaussian_params = check_iter(gaussian_params, n_spectra) nlvs = check_iter(nlvs, n_spectra) - # Synthesize power spectra + # Simulate power spectra for ind, bgp, gp, nlv in zip(range(n_spectra), aperiodic_params, gaussian_params, nlvs): - syn_params[ind] = SynParams(bgp.copy(), sorted(group_three(gp)), nlv) + sim_params[ind] = SimParams(bgp.copy(), sorted(group_three(gp)), nlv) powers[ind, :] = gen_power_vals(freqs, bgp, gp, nlv) - return freqs, powers, syn_params + return freqs, powers, sim_params def gen_aperiodic(freqs, aperiodic_params, aperiodic_mode=None): diff --git a/fooof/synth/params.py b/fooof/sim/params.py similarity index 82% rename from fooof/synth/params.py rename to fooof/sim/params.py index 47ceb386b..0bf62dc55 100644 --- a/fooof/synth/params.py +++ b/fooof/sim/params.py @@ -1,21 +1,21 @@ -"""Classes & functions for managing parameter choices for synthesizing power spectra.""" +"""Classes & functions for managing parameter choices for simulating power spectra.""" import numpy as np from fooof.core.funcs import infer_ap_func from fooof.core.utils import check_flat -from fooof.core.info import get_data_indices -from fooof.data import SynParams +from fooof.core.info import get_indices +from fooof.data import SimParams ################################################################################################### ################################################################################################### -def update_syn_ap_params(syn_params, delta, field=None): - """Update the aperiodic parameter definition in a SynParams object. +def update_sim_ap_params(sim_params, delta, field=None): + """Update the aperiodic parameter definition in a SimParams object. Parameters ---------- - syn_params : SynParams object + sim_params : SimParams object Object storing the current parameter definitions. delta : float or list Value(s) by which to update the parameters. @@ -24,16 +24,16 @@ def update_syn_ap_params(syn_params, delta, field=None): Returns ------- - new_syn_params : SynParams object + new_sim_params : SimParams object Updated object storing the new parameter definitions. Notes ----- - SynParams is a `namedtuple`, which is immutable. - Therefore, this function constructs and returns a new `SynParams` object. + SimParams is a `namedtuple`, which is immutable. + Therefore, this function constructs and returns a new `SimParams` object. """ - ap_params = syn_params.aperiodic_params.copy() + ap_params = sim_params.aperiodic_params.copy() if not field: if not len(ap_params) == len(delta): @@ -45,12 +45,12 @@ def update_syn_ap_params(syn_params, delta, field=None): delta = list([delta]) if not isinstance(delta, list) else delta for cur_field, cur_delta in zip(field, delta): - dat_ind = get_data_indices(infer_ap_func(syn_params.aperiodic_params))[cur_field] + dat_ind = get_indices(infer_ap_func(sim_params.aperiodic_params))[cur_field] ap_params[dat_ind] = ap_params[dat_ind] + cur_delta - new_syn_params = SynParams(ap_params, *syn_params[1:]) + new_sim_params = SimParams(ap_params, *sim_params[1:]) - return new_syn_params + return new_sim_params class Stepper(): @@ -115,9 +115,9 @@ def param_iter(params): Parameters ---------- params : list of floats and Stepper - Parameters over which to iterate in which the - Stepper object defines iterated parameter and its range and, - floats are other parameters that will be held constant. + Parameters over which to iterate, including a Stepper object. + The Stepper defines the iterated parameter and its range. + Floats define the other parameters, that will be held constant. Yields ------ @@ -139,12 +139,13 @@ def param_iter(params): iter_ind = 0 num_iters = 0 for cur_ind, param in enumerate(params): + if isinstance(param, Stepper): num_iters += 1 iter_ind = cur_ind if num_iters > 1: - raise ValueError("Iteration is only supported on one parameter") + raise ValueError("Iteration is only supported across one parameter at a time.") # Generate and yield next set of parameters gen = params[iter_ind] diff --git a/fooof/synth/transform.py b/fooof/sim/transform.py similarity index 86% rename from fooof/synth/transform.py rename to fooof/sim/transform.py index b51e18ece..135263008 100644 --- a/fooof/synth/transform.py +++ b/fooof/sim/transform.py @@ -2,7 +2,7 @@ import numpy as np -from fooof.synth.params import update_syn_ap_params +from fooof.sim.params import update_sim_ap_params ################################################################################################### ################################################################################################### @@ -66,8 +66,8 @@ def translate_spectrum(power_spectrum, delta_offset): return translated_spectrum -def rotate_syn_spectrum(freqs, power_spectrum, delta_exponent, f_rotation, syn_params): - """Rotate a power spectrum about a frequency point, changing the power law exponent. +def rotate_sim_spectrum(freqs, power_spectrum, delta_exponent, f_rotation, sim_params): + """Rotate a simulated power spectrum, updating that SimParams object. Parameters ---------- @@ -81,14 +81,14 @@ def rotate_syn_spectrum(freqs, power_spectrum, delta_exponent, f_rotation, syn_p Negative is counterclockwise rotation (flatten). f_rotation : float Frequency value, in Hz, about which rotation is applied, at which power is unchanged. - syn_params : SynParams object + sim_params : SimParams object Object storing the current parameter definitions. Returns ------- rotated_spectrum : 1d array Rotated power spectrum. - new_syn_params : SynParams object + new_sim_params : SimParams object Updated object storing the new parameter definitions. Notes @@ -103,13 +103,13 @@ def rotate_syn_spectrum(freqs, power_spectrum, delta_exponent, f_rotation, syn_p rotated_spectrum = rotate_spectrum(freqs, power_spectrum, delta_exponent, f_rotation) delta_offset = compute_rotation_offset(delta_exponent, f_rotation) - new_syn_params = update_syn_ap_params(syn_params, [delta_offset, delta_exponent]) + new_sim_params = update_sim_ap_params(sim_params, [delta_offset, delta_exponent]) - return rotated_spectrum, new_syn_params + return rotated_spectrum, new_sim_params -def translate_syn_spectrum(power_spectrum, delta_offset, syn_params): - """Translate a spectrum, changing the offset value. +def translate_sim_spectrum(power_spectrum, delta_offset, sim_params): + """Translate a simulated spectrum, updating that SimParams object. Parameters ---------- @@ -119,21 +119,21 @@ def translate_syn_spectrum(power_spectrum, delta_offset, syn_params): Amount to change the offset by. Positive is an upwards translation. Negative is a downwards translation. - syn_params : SynParams object + sim_params : SimParams object Object storing the current parameter definitions. Returns ------- translated_spectrum : 1d array Translated power spectrum. - new_syn_params : SynParams object + new_sim_params : SimParams object Updated object storing the new parameter definitions. """ translated_spectrum = translate_spectrum(power_spectrum, delta_offset) - new_syn_params = update_syn_ap_params(syn_params, delta_offset, 'offset') + new_sim_params = update_sim_ap_params(sim_params, delta_offset, 'offset') - return translated_spectrum, new_syn_params + return translated_spectrum, new_sim_params def compute_rotation_offset(delta_exponent, f_rotation): diff --git a/fooof/tests/test_analysis.py b/fooof/tests/test_analysis.py index 4d9e28ca2..cfcb60aec 100644 --- a/fooof/tests/test_analysis.py +++ b/fooof/tests/test_analysis.py @@ -1,4 +1,4 @@ -"""Test functions for FOOOF analysis.""" +"""Test functions for fooof.analysis.""" import numpy as np @@ -11,19 +11,19 @@ def test_get_band_peak_fm(tfm): assert np.all(get_band_peak_fm(tfm, (8, 12))) -def test_get_band_peaks_fg(tfg): +def test_get_band_peak_fg(tfg): - assert np.all(get_band_peaks_fg(tfg, (8, 12))) + assert np.all(get_band_peak_fg(tfg, (8, 12))) -def test_get_band_peaks_group(): +def test_get_band_peak_group(): dat = np.array([[10, 1, 1.8, 0], [13, 1, 2, 2], [14, 2, 4, 2]]) - out1 = get_band_peaks_group(dat, [8, 12], 3) + out1 = get_band_peak_group(dat, [8, 12], 3) assert out1.shape == (3, 3) assert np.array_equal(out1[0, :], [10, 1, 1.8]) - out2 = get_band_peaks_group(dat, [12, 16], 3) + out2 = get_band_peak_group(dat, [12, 16], 3) assert out2.shape == (3, 3) assert np.array_equal(out2[2, :], [14, 2, 4]) @@ -58,4 +58,4 @@ def test_empty_inputs(): dat = np.empty(shape=[0, 4]) - assert np.all(get_band_peaks_group(dat, [8, 12], 0)) + assert np.all(get_band_peak_group(dat, [8, 12], 0)) diff --git a/fooof/tests/test_bands.py b/fooof/tests/test_bands.py index 3b5bbd783..3aa2082bd 100644 --- a/fooof/tests/test_bands.py +++ b/fooof/tests/test_bands.py @@ -1,4 +1,4 @@ -"""Test functions for FOOOF bands.""" +"""Test functions for fooof.bands.""" from py.test import raises diff --git a/fooof/tests/test_core_funcs.py b/fooof/tests/test_core_funcs.py index 2eb343631..920624802 100644 --- a/fooof/tests/test_core_funcs.py +++ b/fooof/tests/test_core_funcs.py @@ -1,4 +1,4 @@ -"""Tests for FOOOF core.funcs.""" +"""Tests for fooof.core.funcs.""" from py.test import raises @@ -34,7 +34,7 @@ def test_expo_function(): assert np.all(ys) # Note: no obvious way to test the knee specifically - # Here - test that past the knee, has expected slope & offset value + # Here - test that past the knee, has expected exponent & offset value exp_meas, off_meas, _, _, _ = linregress(np.log10(xs[knee**2:]), ys[knee**2:]) assert np.isclose(off_meas, off, 0.1) @@ -87,26 +87,24 @@ def test_quadratic_function(): def test_get_ap_func(): - bgf_nk = get_ap_func('fixed') - assert bgf_nk + apf_nk = get_ap_func('fixed') + assert apf_nk - bgf_kn = get_ap_func('knee') - assert bgf_kn + apf_kn = get_ap_func('knee') + assert apf_kn - # Check error with raises(ValueError): get_ap_func('bad') def test_infer_ap_func(): - bgp_nk = [50, 1] - bgm_nk = infer_ap_func(bgp_nk) - assert bgm_nk == 'fixed' + ap_nk = [50, 1] + apf_nk = infer_ap_func(ap_nk) + assert apf_nk == 'fixed' - bgp_kn = [50, 2, 1] - bgm_kn = infer_ap_func(bgp_kn) - assert bgm_kn == 'knee' + ap_kn = [50, 2, 1] + apf_kn = infer_ap_func(ap_kn) + assert apf_kn == 'knee' - # Check error with raises(ValueError): infer_ap_func([1, 2, 3, 4]) diff --git a/fooof/tests/test_core_info.py b/fooof/tests/test_core_info.py index f7d3085e5..c71e1dfe8 100644 --- a/fooof/tests/test_core_info.py +++ b/fooof/tests/test_core_info.py @@ -1,13 +1,13 @@ -"""Tests for FOOOF core.info.""" +"""Tests for fooof.core.info.""" from fooof.core.info import * ################################################################################################### ################################################################################################### -def test_get_obj_desc(tfm): +def test_get_description(tfm): - desc = get_obj_desc() + desc = get_description() objs = dir(tfm) # Test that everything in dict is a valid component of the fooof object @@ -15,9 +15,9 @@ def test_get_obj_desc(tfm): for it in va: assert it in objs -def test_get_data_indices(): +def test_get_indices(): - indices_fixed = get_data_indices('fixed') + indices_fixed = get_indices('fixed') assert indices_fixed for ke, va in indices_fixed.items(): if ke == 'knee': @@ -25,7 +25,7 @@ def test_get_data_indices(): else: assert isinstance(va, int) - indices_knee = get_data_indices('knee') + indices_knee = get_indices('knee') assert indices_knee for ke, va in indices_knee.items(): assert isinstance(va, int) diff --git a/fooof/tests/test_core_io.py b/fooof/tests/test_core_io.py index 3510fc2b2..f6dea45dd 100644 --- a/fooof/tests/test_core_io.py +++ b/fooof/tests/test_core_io.py @@ -4,7 +4,7 @@ import pkg_resources as pkg from fooof import FOOOF -from fooof.core.info import get_obj_desc +from fooof.core.info import get_description from fooof.core.io import * @@ -142,7 +142,7 @@ def test_load_file_contents(): loaded_data = load_json(file_name, file_path) - desc = get_obj_desc() + desc = get_description() # Check settings for setting in desc['settings']: diff --git a/fooof/tests/test_core_modutils.py b/fooof/tests/test_core_modutils.py index 598821b08..047d5c0b5 100644 --- a/fooof/tests/test_core_modutils.py +++ b/fooof/tests/test_core_modutils.py @@ -1,4 +1,4 @@ -"""Tests for FOOOF core.modutils. +"""Tests for fooof.core.modutils. Note: decorators (that are in modutils) are currently not tested. """ diff --git a/fooof/tests/test_core_strings.py b/fooof/tests/test_core_strings.py index 68282e679..b18cacde1 100644 --- a/fooof/tests/test_core_strings.py +++ b/fooof/tests/test_core_strings.py @@ -6,21 +6,21 @@ ################################################################################################### ################################################################################################### -def test_gen_wid_warn_str(): +def test_gen_width_warning_str(): - assert gen_wid_warn_str(0.5, 0.5) + assert gen_width_warning_str(0.5, 0.5) def test_gen_settings_str(tfm): assert gen_settings_str(tfm) -def test_gen_results_str_fm(tfm): +def test_gen_results_fm_str(tfm): - assert gen_results_str_fm(tfm) + assert gen_results_fm_str(tfm) -def test_gen_results_str_fg(tfg): +def test_gen_results_fg_str(tfg): - assert gen_results_str_fg(tfg) + assert gen_results_fg_str(tfg) def test_gen_issue_str(): diff --git a/fooof/tests/test_core_utils.py b/fooof/tests/test_core_utils.py index 98c3aa27b..08fa68a5c 100644 --- a/fooof/tests/test_core_utils.py +++ b/fooof/tests/test_core_utils.py @@ -1,6 +1,6 @@ -"""Tests for FOOOF core.utils.""" +"""Tests for fooof.core.utils.""" -from collections import Iterable +from collections.abc import Iterable from itertools import repeat from fooof import FOOOF diff --git a/fooof/tests/test_data.py b/fooof/tests/test_data.py index cb9575c81..50cc06cd8 100644 --- a/fooof/tests/test_data.py +++ b/fooof/tests/test_data.py @@ -1,6 +1,6 @@ -"""Tests for the FOOOF data objects.""" +"""Tests for the fooof.data.""" -from fooof.core.info import get_obj_desc +from fooof.core.info import get_description from fooof.data import * @@ -13,7 +13,7 @@ def test_fooof_settings(): assert settings # Check that the object has the correct fields, given the object description - settings_fields = get_obj_desc()['settings'] + settings_fields = get_description()['settings'] for field in settings_fields: getattr(settings, field) assert True @@ -24,17 +24,17 @@ def test_fooof_results(): assert results # Check that the object has the correct fields, given the object description - results_fields = get_obj_desc()['results'] + results_fields = get_description()['results'] for field in results_fields: getattr(results, field.strip('_')) assert True -def test_syn_params(): +def test_sim_params(): - syn_params = SynParams([1, 1], [10, 1, 1], 0.05) - assert syn_params + sim_params = SimParams([1, 1], [10, 1, 1], 0.05) + assert sim_params # Check that the object has the correct fields for field in ['aperiodic_params', 'gaussian_params', 'nlv']: - getattr(syn_params, field) + getattr(sim_params, field) assert True diff --git a/fooof/tests/test_fit.py b/fooof/tests/test_fit.py index 4d1712234..66ddfb907 100644 --- a/fooof/tests/test_fit.py +++ b/fooof/tests/test_fit.py @@ -1,4 +1,4 @@ -"""Tests for the FOOOF fit object and methods. +"""Tests for fooof.fit, including the FOOOF object it's methods. NOTES ----- @@ -12,10 +12,10 @@ import pkg_resources as pkg from fooof import FOOOF -from fooof.data import FOOOFSettings, FOOOFDataInfo, FOOOFResults -from fooof.synth import gen_power_spectrum +from fooof.data import FOOOFSettings, FOOOFMetaData, FOOOFResults +from fooof.sim import gen_power_spectrum from fooof.core.utils import group_three -from fooof.core.info import get_obj_desc +from fooof.core.info import get_description from fooof.tests.utils import get_tfm, plot_test @@ -25,35 +25,35 @@ def test_fooof(): """Check FOOOF object initializes properly.""" - assert FOOOF() + assert FOOOF(verbose=False) def test_fooof_fit_nk(): """Test FOOOF fit, no knee.""" - bgp = [50, 2] - gaussian_params = [10, 0.5, 2, 20, 0.3, 4] + ap_params = [50, 2] + gauss_params = [10, 0.5, 2, 20, 0.3, 4] - xs, ys = gen_power_spectrum([3, 50], bgp, gaussian_params) + xs, ys = gen_power_spectrum([3, 50], ap_params, gauss_params) - tfm = FOOOF() + tfm = FOOOF(verbose=False) tfm.fit(xs, ys) # Check model results - aperiodic parameters - assert np.all(np.isclose(bgp, tfm.aperiodic_params_, [0.5, 0.1])) + assert np.all(np.isclose(ap_params, tfm.aperiodic_params_, [0.5, 0.1])) # Check model results - gaussian parameters - for ii, gauss in enumerate(group_three(gaussian_params)): - assert np.all(np.isclose(gauss, tfm._gaussian_params[ii], [2.0, 0.5, 1.0])) + for ii, gauss in enumerate(group_three(gauss_params)): + assert np.all(np.isclose(gauss, tfm.gaussian_params_[ii], [2.0, 0.5, 1.0])) def test_fooof_fit_knee(): """Test FOOOF fit, with a knee.""" - bgp = [50, 2, 1] + ap_params = [50, 2, 1] gaussian_params = [10, 0.5, 2, 20, 0.3, 4] - xs, ys = gen_power_spectrum([3, 50], bgp, gaussian_params) + xs, ys = gen_power_spectrum([3, 50], ap_params, gaussian_params) - tfm = FOOOF(aperiodic_mode='knee') + tfm = FOOOF(aperiodic_mode='knee', verbose=False) tfm.fit(xs, ys) # Note: currently, this test has no accuracy checking at all @@ -65,7 +65,7 @@ def test_fooof_checks(): xs, ys = gen_power_spectrum([3, 50], [50, 2], [10, 0.5, 2]) - tfm = FOOOF() + tfm = FOOOF(verbose=False) # Check dimension error with raises(ValueError): @@ -88,7 +88,7 @@ def test_fooof_checks(): assert tfm.freqs[0] != 0 # Check fit, and string report model error (no data / model fit) - tfm = FOOOF() + tfm = FOOOF(verbose=False) with raises(ValueError): tfm.fit() @@ -99,7 +99,7 @@ def test_fooof_load(): file_name_res = 'test_fooof_str_res' file_path = pkg.resource_filename(__name__, 'test_files') - tfm = FOOOF() + tfm = FOOOF(verbose=False) tfm.load(file_name_all, file_path) assert tfm @@ -125,38 +125,52 @@ def test_adds(): # Test adding settings fooof_settings = FOOOFSettings([1, 4], 6, 0, 2, 'fixed') tfm.add_settings(fooof_settings) - for setting in get_obj_desc()['settings']: + for setting in get_description()['settings']: assert getattr(tfm, setting) == getattr(fooof_settings, setting) - # Test adding data info - fooof_data_info = FOOOFDataInfo([3, 40], 0.5) - tfm.add_data_info(fooof_data_info) - for data_info in get_obj_desc()['data_info']: - assert getattr(tfm, data_info) == getattr(fooof_data_info, data_info) + # Test adding meta data + fooof_meta_data = FOOOFMetaData([3, 40], 0.5) + tfm.add_meta_data(fooof_meta_data) + for meta_dat in get_description()['meta_data']: + assert getattr(tfm, meta_dat) == getattr(fooof_meta_data, meta_dat) # Test adding results fooof_results = FOOOFResults([1, 1], [10, 0.5, 0.5], 0.95, 0.02, [10, 0.5, 0.25]) tfm.add_results(fooof_results) - for setting in get_obj_desc()['results']: + for setting in get_description()['results']: assert getattr(tfm, setting) == getattr(fooof_results, setting.strip('_')) -def test_gets(tfm): +def test_obj_gets(tfm): """Tests methods that return FOOOF data objects. - Checks: get_settings, get_data_info, get_results + Checks: get_settings, get_meta_data, get_results """ settings = tfm.get_settings() assert isinstance(settings, FOOOFSettings) - data_info = tfm.get_data_info() - assert isinstance(data_info, FOOOFDataInfo) + meta_data = tfm.get_meta_data() + assert isinstance(meta_data, FOOOFMetaData) results = tfm.get_results() assert isinstance(results, FOOOFResults) +def test_get_params(tfm): + """Test the get_params method.""" + + for dname in ['aperiodic_params', 'peak_params', 'error', 'r_squared', 'gaussian_params']: + assert np.any(tfm.get_params(dname)) + + if dname == 'aperiodic_params': + for dtype in ['offset', 'exponent']: + assert np.any(tfm.get_params(dname, dtype)) + + if dname == 'peak_params': + for dtype in ['CF', 'PW', 'BW']: + assert np.any(tfm.get_params(dname, dtype)) + def test_copy(): """Test copy FOOOF method.""" - tfm = FOOOF() + tfm = FOOOF(verbose=False) ntfm = tfm.copy() assert tfm != ntfm @@ -164,7 +178,7 @@ def test_copy(): def test_fooof_prints(tfm): """Test methods that print (alias and pass through methods). - Checks: print_settings, print_results. + Checks: print_settings, print_results, print_report_issue. """ tfm.print_settings() @@ -186,7 +200,7 @@ def test_fooof_resets(): tfm._reset_data_results() tfm._reset_internal_settings() - desc = get_obj_desc() + desc = get_description() for data in ['data', 'results', 'model_components']: for field in desc[data]: @@ -196,7 +210,7 @@ def test_fooof_resets(): def test_fooof_report(skip_if_no_mpl): """Check that running the top level model method runs.""" - tfm = FOOOF() + tfm = FOOOF(verbose=False) tfm.report(*gen_power_spectrum([3, 50], [50, 2], [10, 0.5, 2, 20, 0.3, 4])) @@ -207,7 +221,7 @@ def test_fooof_fit_failure(): # Use a new FOOOF, that is monkey-patched to raise an error # This mimicks the main fit-failure, without requiring bad data / waiting for it to fail. - tfm = FOOOF() + tfm = FOOOF(verbose=False) def raise_runtime_error(*args, **kwargs): raise RuntimeError('Test-MonkeyPatch') tfm._fit_peaks = raise_runtime_error @@ -216,6 +230,6 @@ def raise_runtime_error(*args, **kwargs): tfm.fit(*gen_power_spectrum([3, 50], [50, 2], [10, 0.5, 2, 20, 0.3, 4])) # Check after failing out of fit, all results are reset - for result in get_obj_desc()['results']: + for result in get_description()['results']: cur_res = getattr(tfm, result) assert cur_res is None or np.all(np.isnan(cur_res)) diff --git a/fooof/tests/test_funcs.py b/fooof/tests/test_funcs.py index 24a3f9743..0981d3ee5 100644 --- a/fooof/tests/test_funcs.py +++ b/fooof/tests/test_funcs.py @@ -1,4 +1,4 @@ -"""Test functions for ...""" +"""Test functions for fooof.funcs.""" from py.test import raises @@ -6,7 +6,7 @@ from fooof.utils import compare_info from fooof.group import FOOOFGroup -from fooof.synth import gen_group_power_spectra +from fooof.sim import gen_group_power_spectra from fooof.funcs import * from fooof.tests.utils import default_group_params @@ -85,7 +85,7 @@ def test_combine_errors(tfm, tfg): # Incompatible data information for f_obj in [tfm, tfg]: f_obj2 = f_obj.copy() - f_obj2.freq_range= [5, 30] + f_obj2.freq_range = [5, 30] with raises(ValueError): combine_fooofs([f_obj, f_obj2]) diff --git a/fooof/tests/test_group.py b/fooof/tests/test_group.py index f63b2ebf7..6820d27c1 100644 --- a/fooof/tests/test_group.py +++ b/fooof/tests/test_group.py @@ -1,4 +1,4 @@ -"""Tests for the FOOOFGroup fit object and methods. +"""Tests for the fooof.group, including the FOOOFGroup object and it's methods. NOTES ----- @@ -12,8 +12,8 @@ from fooof.group import * from fooof.fit import FOOOFResults -from fooof.synth import gen_group_power_spectra -from fooof.core.info import get_obj_desc +from fooof.sim import gen_group_power_spectra +from fooof.core.info import get_description from fooof.tests.utils import default_group_params, plot_test @@ -25,8 +25,8 @@ def test_fg(): # Note: doesn't assert fg itself, as it return false when group_results are empty # This is due to the __len__ used in FOOOFGroup - fg = FOOOFGroup() - assert True + fg = FOOOFGroup(verbose=False) + assert isinstance(fg, FOOOFGroup) def test_fg_iter(tfg): """Check iterating through FOOOFGroup.""" @@ -45,7 +45,7 @@ def test_fg_fit(): n_spectra = 2 xs, ys, _ = gen_group_power_spectra(n_spectra, *default_group_params()) - tfg = FOOOFGroup() + tfg = FOOOFGroup(verbose=False) tfg.fit(xs, ys) out = tfg.get_results() @@ -60,7 +60,7 @@ def test_fg_fit_par(): n_spectra = 2 xs, ys, _ = gen_group_power_spectra(n_spectra, *default_group_params()) - tfg = FOOOFGroup() + tfg = FOOOFGroup(verbose=False) tfg.fit(xs, ys, n_jobs=2) out = tfg.get_results() @@ -80,19 +80,19 @@ def test_get_results(tfg): assert tfg.get_results() -def test_get_all_data(tfg): - """Check get_all_data method.""" +def test_get_params(tfg): + """Check get_params method.""" for dname in ['aperiodic_params', 'peak_params', 'error', 'r_squared', 'gaussian_params']: - assert np.any(tfg.get_all_data(dname)) + assert np.any(tfg.get_params(dname)) if dname == 'aperiodic_params': for dtype in ['offset', 'exponent']: - assert np.any(tfg.get_all_data(dname, dtype)) + assert np.any(tfg.get_params(dname, dtype)) if dname == 'peak_params': for dtype in ['CF', 'PW', 'BW']: - assert np.any(tfg.get_all_data(dname, dtype)) + assert np.any(tfg.get_params(dname, dtype)) @plot_test def test_fg_plot(tfg, skip_if_no_mpl): @@ -107,7 +107,7 @@ def test_fg_load(): res_file_name = 'test_fooof_group_res' file_path = pkg.resource_filename(__name__, 'test_files') - tfg = FOOOFGroup() + tfg = FOOOFGroup(verbose=False) tfg.load(set_file_name, file_path) assert tfg @@ -121,7 +121,7 @@ def test_fg_report(skip_if_no_mpl): n_spectra = 2 xs, ys, _ = gen_group_power_spectra(n_spectra, *default_group_params()) - tfg = FOOOFGroup() + tfg = FOOOFGroup(verbose=False) tfg.report(xs, ys) assert tfg @@ -129,7 +129,7 @@ def test_fg_report(skip_if_no_mpl): def test_fg_get_fooof(tfg): """Check return of an individual model fit to a FOOOF object from FOOOFGroup.""" - desc = get_obj_desc() + desc = get_description() # Check without regenerating tfm0 = tfg.get_fooof(0, False) @@ -151,5 +151,5 @@ def test_fg_get_fooof(tfg): tfm2 = new_tfg.get_fooof(0, True) assert tfm2 # Check that data info is copied over properly - for data_info in desc['data_info']: - assert getattr(tfm2, data_info) + for meta_dat in desc['meta_data']: + assert getattr(tfm2, meta_dat) diff --git a/fooof/tests/test_plts_fg.py b/fooof/tests/test_plts_fg.py index c9e4b6979..8d62d715e 100644 --- a/fooof/tests/test_plts_fg.py +++ b/fooof/tests/test_plts_fg.py @@ -22,9 +22,9 @@ def test_plot_fg_error(skip_if_no_mpl): tfg.plot() @plot_test -def test_plot_fg_bg(tfg, skip_if_no_mpl): +def test_plot_fg_ap(tfg, skip_if_no_mpl): - plot_fg_bg(tfg) + plot_fg_ap(tfg) @plot_test def test_plot_fg_gf(tfg, skip_if_no_mpl): diff --git a/fooof/tests/test_plts_templates.py b/fooof/tests/test_plts_templates.py index c87ff8f52..cc98d81c5 100644 --- a/fooof/tests/test_plts_templates.py +++ b/fooof/tests/test_plts_templates.py @@ -1,4 +1,4 @@ -"""Test functions for FOOOF plots.""" +"""Test functions for fooof.plts.templates.""" import numpy as np diff --git a/fooof/tests/test_synth_gen.py b/fooof/tests/test_sim_gen.py similarity index 71% rename from fooof/tests/test_synth_gen.py rename to fooof/tests/test_sim_gen.py index 12a3e3613..a2c0590b8 100644 --- a/fooof/tests/test_synth_gen.py +++ b/fooof/tests/test_sim_gen.py @@ -1,10 +1,10 @@ -"""Test functions for FOOOF synth.gen""" +"""Test functions for fooof.sim.gen""" import numpy as np from fooof.tests.utils import default_group_params -from fooof.synth.gen import * +from fooof.sim.gen import * ################################################################################################### ################################################################################################### @@ -23,10 +23,10 @@ def test_gen_freqs(): def test_gen_power_spectrum(): freq_range = [3, 50] - bgp = [50, 2] + ap_params = [50, 2] gaussian_params = [10, 0.5, 2, 20, 0.3, 4] - xs, ys = gen_power_spectrum(freq_range, bgp, gaussian_params) + xs, ys = gen_power_spectrum(freq_range, ap_params, gaussian_params) assert np.all(xs) assert np.all(ys) @@ -57,19 +57,19 @@ def test_gen_aperiodic(): xs = gen_freqs([3, 50], 0.5) - bgp_nk = [50, 2] - bgv_nk = gen_aperiodic(xs, bgp_nk, 'fixed') - assert np.all(bgv_nk) + ap_nk = [50, 2] + apv_nk = gen_aperiodic(xs, ap_nk, 'fixed') + assert np.all(apv_nk) - bgp_kn = [50, 1, 1] - bgv_kn = gen_aperiodic(xs, bgp_kn, 'knee') - assert np.all(bgv_kn) + ap_kn = [50, 1, 1] + apv_kn = gen_aperiodic(xs, ap_kn, 'knee') + assert np.all(apv_kn) # Check without specifying aperiodic mode - bgv_nk_2 = gen_aperiodic(xs, bgp_nk) - assert np.array_equal(bgv_nk, bgv_nk_2) - bgv_kn_2 = gen_aperiodic(xs, bgp_kn) - assert np.array_equal(bgv_kn, bgv_kn_2) + apv_nk_2 = gen_aperiodic(xs, ap_nk) + assert np.array_equal(apv_nk, apv_nk_2) + apv_kn_2 = gen_aperiodic(xs, ap_kn) + assert np.array_equal(apv_kn, apv_kn_2) def test_gen_peaks(): @@ -84,10 +84,10 @@ def test_gen_power_values(): xs = gen_freqs([3, 50], 0.5) - bg_params = [50, 2] - gaussian_params = [10, 2, 1] + ap_params = [50, 2] + gauss_params = [10, 2, 1] nlv = 0.1 - ys = gen_power_vals(xs, bg_params, gaussian_params, nlv) + ys = gen_power_vals(xs, ap_params, gauss_params, nlv) assert np.all(ys) diff --git a/fooof/tests/test_synth_params.py b/fooof/tests/test_sim_params.py similarity index 52% rename from fooof/tests/test_synth_params.py rename to fooof/tests/test_sim_params.py index b11a44f05..cf94a81db 100644 --- a/fooof/tests/test_synth_params.py +++ b/fooof/tests/test_sim_params.py @@ -1,37 +1,51 @@ -"""Test functions for FOOOF synth.params.""" +"""Test functions for fooof.sim.params.""" from py.test import raises -from fooof.synth.params import * +from fooof.sim.params import * ################################################################################################### ################################################################################################### -def test_update_syn_ap_params(): +def test_update_sim_ap_params(): - syn_params = SynParams([1, 1], [10, 1, 1], 0.05) + sim_params = SimParams([1, 1], [10, 1, 1], 0.05) # Check updating of a single specified parameter - new_syn_params = update_syn_ap_params(syn_params, 1, 'exponent') - assert new_syn_params.aperiodic_params == [1, 2] + new_sim_params = update_sim_ap_params(sim_params, 1, 'exponent') + assert new_sim_params.aperiodic_params == [1, 2] # Check updating of multiple specified parameters - new_syn_params = update_syn_ap_params(syn_params, [1, 1], ['offset', 'exponent']) - assert new_syn_params.aperiodic_params == [2, 2] + new_sim_params = update_sim_ap_params(sim_params, [1, 1], ['offset', 'exponent']) + assert new_sim_params.aperiodic_params == [2, 2] # Check updating of all parameters - new_syn_params = update_syn_ap_params(syn_params, [1, 1]) - assert new_syn_params.aperiodic_params == [2, 2] + new_sim_params = update_sim_ap_params(sim_params, [1, 1]) + assert new_sim_params.aperiodic_params == [2, 2] # Check error with invalid overwrite with raises(ValueError): - new_syn_params = update_syn_ap_params(syn_params, [1, 1, 1]) + new_sim_params = update_sim_ap_params(sim_params, [1, 1, 1]) def test_stepper(): - assert Stepper(8,12,.1) + stepper = Stepper(8, 12, 1) + assert stepper + assert len(stepper) == 4 + for val in stepper: + assert True - # TODO: add more tests of Stepper +def test_stepper_errors(): + """Test the checks in Stepper._check_values()""" + + with raises(ValueError): + Stepper(-1, 0, 0) + + with raises(ValueError): + Stepper(10, 8, 1) + + with raises(ValueError): + Stepper(8, 12, 5) def test_param_iter(): @@ -41,12 +55,12 @@ def test_param_iter(): iter_1 = param_iter(osc) for ind, val in enumerate(iter_1): - assert val == [8 + (.1*ind), .5 , .5] + assert val == [8 + (.1*ind), .5, .5] # Test aperiodic step = Stepper(.25, 3, .25) - bg = [0, step] - iter_1 = param_iter(bg) + ap_params = [0, step] + iter_1 = param_iter(ap_params) for ind, val in enumerate(iter_1): assert val == [0, .25 + (.25*ind)] @@ -57,7 +71,7 @@ def test_param_iter(): iter_1 = param_iter(oscs) for ind, val in enumerate(iter_1): - assert val == [8 + (.1*ind), .5 , .5, 10, .25, 1] + assert val == [8 + (.1*ind), .5, .5, 10, .25, 1] # Test list of lists step = Stepper(8, 12, .1) @@ -70,6 +84,11 @@ def test_param_iter(): for ind, val in enumerate(iter_2): assert val == [1, 2, 3, 4, 5, 6, 7, 8, 8 + (.1*ind)] + # Test multiple stepper error + step = Stepper(8, 12, .1) + with raises(ValueError): + for params in param_iter([[step, step, step]]): pass + def test_param_sampler(): pos = [1, 2, 3, 4] diff --git a/fooof/tests/test_synth_transform.py b/fooof/tests/test_sim_transform.py similarity index 65% rename from fooof/tests/test_synth_transform.py rename to fooof/tests/test_sim_transform.py index 29ec89103..4229bd97a 100644 --- a/fooof/tests/test_synth_transform.py +++ b/fooof/tests/test_sim_transform.py @@ -1,10 +1,10 @@ -"""Test functions for FOOOF synth.transform""" +"""Test functions for fooof.sim.transform""" import numpy as np -from fooof.synth.gen import gen_power_spectrum -from fooof.synth.params import SynParams -from fooof.synth.transform import * +from fooof.sim.gen import gen_power_spectrum +from fooof.sim.params import SimParams +from fooof.sim.transform import * ################################################################################################### ################################################################################################### @@ -35,24 +35,24 @@ def test_translate_spectrum(): translated_spectrum = translate_spectrum(spectrum, delta_offset=0.) assert np.all(translated_spectrum == spectrum) -def test_rotate_syn_spectrum(): +def test_rotate_sim_spectrum(): - syn_params = SynParams([1, 1], [10, 0.5, 1], 0) - freqs, spectrum = gen_power_spectrum([3, 40], *syn_params) + sim_params = SimParams([1, 1], [10, 0.5, 1], 0) + freqs, spectrum = gen_power_spectrum([3, 40], *sim_params) - rotated_spectrum, new_syn_params = rotate_syn_spectrum(freqs, spectrum, 0.5, 20, syn_params) + rotated_spectrum, new_sim_params = rotate_sim_spectrum(freqs, spectrum, 0.5, 20, sim_params) assert not np.all(rotated_spectrum == spectrum) - assert new_syn_params.aperiodic_params[1] == 1.5 + assert new_sim_params.aperiodic_params[1] == 1.5 -def test_translate_syn_spectrum(): +def test_translate_sim_spectrum(): - syn_params = SynParams([1, 1], [10, 0.5, 1], 0) - freqs, spectrum = gen_power_spectrum([3, 40], *syn_params) + sim_params = SimParams([1, 1], [10, 0.5, 1], 0) + freqs, spectrum = gen_power_spectrum([3, 40], *sim_params) - translated_spectrum, new_syn_params = translate_syn_spectrum(spectrum, 0.5, syn_params) + translated_spectrum, new_sim_params = translate_sim_spectrum(spectrum, 0.5, sim_params) assert not np.all(translated_spectrum == spectrum) - assert new_syn_params.aperiodic_params[0] == 1.5 + assert new_sim_params.aperiodic_params[0] == 1.5 def test_compute_rotation_offset(): diff --git a/fooof/tests/test_utils.py b/fooof/tests/test_utils.py index 574628936..f97ce5df6 100644 --- a/fooof/tests/test_utils.py +++ b/fooof/tests/test_utils.py @@ -1,4 +1,4 @@ -"""Test functions for FOOOF utils.""" +"""Test functions for fooof.utils.""" import numpy as np @@ -21,7 +21,7 @@ def test_get_info(tfm, tfg): for f_obj in [tfm, tfg]: assert get_info(f_obj, 'settings') - assert get_info(f_obj, 'data_info') + assert get_info(f_obj, 'meta_data') assert get_info(f_obj, 'results') def test_compare_info(tfm, tfg): @@ -35,6 +35,6 @@ def test_compare_info(tfm, tfg): f_obj2._reset_internal_settings() assert not compare_info([f_obj, f_obj2], 'settings') - assert compare_info([f_obj, f_obj2], 'data_info') + assert compare_info([f_obj, f_obj2], 'meta_data') f_obj2.freq_range = [5, 25] - assert not compare_info([f_obj, f_obj2], 'data_info') + assert not compare_info([f_obj, f_obj2], 'meta_data') diff --git a/fooof/tests/utils.py b/fooof/tests/utils.py index 911b914b9..c41f36f99 100644 --- a/fooof/tests/utils.py +++ b/fooof/tests/utils.py @@ -4,7 +4,8 @@ from fooof import FOOOF, FOOOFGroup from fooof.bands import Bands -from fooof.synth import gen_power_spectrum, gen_group_power_spectra, param_sampler +from fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra +from fooof.sim.params import param_sampler from fooof.core.modutils import safe_import plt = safe_import('.pyplot', 'matplotlib') @@ -16,12 +17,12 @@ def get_tfm(): """Get a FOOOF object, with a fit power spectrum, for testing.""" freq_range = [3, 50] - bg_params = [50, 2] + ap_params = [50, 2] gaussian_params = [10, 0.5, 2, 20, 0.3, 4] - xs, ys = gen_power_spectrum(freq_range, bg_params, gaussian_params) + xs, ys = gen_power_spectrum(freq_range, ap_params, gaussian_params) - tfm = FOOOF() + tfm = FOOOF(verbose=False) tfm.fit(xs, ys) return tfm @@ -32,7 +33,7 @@ def get_tfg(): n_spectra = 2 xs, ys, _ = gen_group_power_spectra(n_spectra, *default_group_params()) - tfg = FOOOFGroup() + tfg = FOOOFGroup(verbose=False) tfg.fit(xs, ys) return tfg @@ -46,10 +47,10 @@ def default_group_params(): """Create default parameters for generating a test group of power spectra.""" freq_range = [3, 50] - bgp_opts = param_sampler([[20, 2], [50, 2.5], [35, 1.5]]) + ap_opts = param_sampler([[20, 2], [50, 2.5], [35, 1.5]]) gauss_opts = param_sampler([[10, 0.5, 2], [10, 0.5, 2, 20, 0.3, 4]]) - return freq_range, bgp_opts, gauss_opts + return freq_range, ap_opts, gauss_opts def plot_test(func): """Decorator for simple testing of plotting functions. diff --git a/fooof/utils.py b/fooof/utils.py index 8e5140855..8ab677a3b 100644 --- a/fooof/utils.py +++ b/fooof/utils.py @@ -2,8 +2,7 @@ import numpy as np -from fooof.synth import gen_freqs -from fooof.core.info import get_obj_desc +from fooof.core.info import get_description ################################################################################################### ################################################################################################### @@ -51,7 +50,7 @@ def get_info(f_obj, aspect): ---------- f_obj : FOOOF or FOOOFGroup FOOOF derived object to get attributes from. - aspect : {'settings', 'data_info', 'results'} + aspect : {'settings', 'meta_data', 'results'} Which set of attributes to compare the objects across. Returns @@ -60,7 +59,7 @@ def get_info(f_obj, aspect): The set of specified info from the FOOOF derived object. """ - return {key : getattr(f_obj, key) for key in get_obj_desc()[aspect]} + return {key : getattr(f_obj, key) for key in get_description()[aspect]} def compare_info(lst, aspect): @@ -70,7 +69,7 @@ def compare_info(lst, aspect): ---------- lst : list of FOOOF or FOOOFGroup objects FOOOF related objects whose attibutes are to be compared. - aspect : {'setting', 'data_info'} + aspect : {'setting', 'meta_data'} Which set of attributes to compare the objects across. Returns diff --git a/fooof/version.py b/fooof/version.py index a68efb699..f617a23c3 100644 --- a/fooof/version.py +++ b/fooof/version.py @@ -1 +1 @@ -__version__ = '1.0.0-dev' \ No newline at end of file +__version__ = '1.0.0rc1' \ No newline at end of file diff --git a/tutorials/plot_03-FOOOFAlgorithm.py b/tutorials/plot_03-FOOOFAlgorithm.py index 25ea77c25..a05754713 100644 --- a/tutorials/plot_03-FOOOFAlgorithm.py +++ b/tutorials/plot_03-FOOOFAlgorithm.py @@ -31,8 +31,8 @@ # Import the FOOOF object from fooof import FOOOF -# Import a function to generate synthetic power spectra -from fooof.synth.gen import gen_aperiodic +# Import a function to generate simulated power spectra +from fooof.sim.gen import gen_aperiodic # Import some internal functions from FOOOF # Note that these are used here for demonstration: - you do not need to import them to run FOOOF diff --git a/tutorials/plot_06-FOOOFGroup.py b/tutorials/plot_06-FOOOFGroup.py index ace4ab503..cc1ef650e 100644 --- a/tutorials/plot_06-FOOOFGroup.py +++ b/tutorials/plot_06-FOOOFGroup.py @@ -10,15 +10,15 @@ # FOOOF imports: import FOOOFGroup object from fooof import FOOOFGroup -# Import some utilities for synthesizing some test data -from fooof.synth.params import param_sampler -from fooof.synth.gen import gen_group_power_spectra +# Import some utilities for simulating some test data +from fooof.sim.params import param_sampler +from fooof.sim.gen import gen_group_power_spectra ################################################################################################### -# Synthesizing Power Spectra +# Simulated Power Spectra # -------------------------- # -# FOOOF includes some support for creating synthetic power-spectra, that mimic real data. +# FOOOF includes some support for creating simulated power-spectra, that mimic real data. # # Here we will use that functionality to create a matrix of power spectra to test with. # @@ -27,12 +27,12 @@ # them to generate power spectra. # # If you would like to generate single power spectra, you can use :func:`gen_power_spectrum`, -# also in `fooof.synth.gen`. +# also in `fooof.sim.gen`. # ################################################################################################### -# Settings for synthesizing power spectra +# Settings for simulating power spectra n_spectra = 10 f_range = [3, 40] @@ -55,9 +55,9 @@ ################################################################################################### -# Generate the group of synthetic spectra +# Simulate the group of simulated spectra # Note that this function also returns a list of the parameters for each func -freqs, spectra, syn_params = gen_group_power_spectra(n_spectra, f_range, ap_opts, gauss_opts) +freqs, spectra, sim_params = gen_group_power_spectra(n_spectra, f_range, ap_opts, gauss_opts) ################################################################################################### # FOOOFGroup diff --git a/tutorials/plot_07-TroubleShooting.py b/tutorials/plot_07-TroubleShooting.py index 96ba95301..0f0acdee8 100644 --- a/tutorials/plot_07-TroubleShooting.py +++ b/tutorials/plot_07-TroubleShooting.py @@ -12,14 +12,14 @@ # FOOOF imports from fooof import FOOOF, FOOOFGroup -# Import some utilities, and tools for creating synthetic power-spectra -from fooof.synth.params import param_sampler -from fooof.synth.gen import gen_power_spectrum, gen_group_power_spectra +# Import some utilities, and tools for creating simulated power-spectra +from fooof.sim.params import param_sampler +from fooof.sim.gen import gen_power_spectrum, gen_group_power_spectra from fooof.core.utils import group_three ################################################################################################### -# Set random state, for consistency for generating synthetic data +# Set random state, for consistency for generating simulated data np.random.seed(321) #################################################################################################### @@ -123,7 +123,7 @@ ################################################################################################### -# Generate a noisy synthetic power spectrum +# Generate a noisy simulated power spectrum # Set the frequency range to generate the power spectrum f_range = [1, 50] @@ -134,7 +134,7 @@ # Set the level of noise to generate the power spectrum with nlv = 0.1 -# Create a synthetic power spectrum +# Create a simulated power spectrum freqs, spectrum = gen_power_spectrum(f_range, ap_params, gauss_params, nlv) ################################################################################################### @@ -162,16 +162,16 @@ ################################################################################################### # -# The synthetic definition is defined in terms of Gaussian parameters (these are +# The simulated definition is defined in terms of Gaussian parameters (these are # slightly different from the peak parameters - see the note in tutorial 02). # # We can compare how FOOOF, with our updated settings, compares to the -# ground truth of the synthetic spectrum. +# ground truth of the simulated spectrum. # ################################################################################################### -# Compare ground truth synthetic parameters to model fit results +# Compare ground truth simulated parameters to model fit results print('Ground Truth \t\t FOOOF Reconstructions') for sy, fi in zip(np.array(group_three(gauss_params)), fm._gaussian_params): print('{:5.2f} {:5.2f} {:5.2f} \t {:5.2f} {:5.2f} {:5.2f}'.format(*sy, *fi)) @@ -203,7 +203,7 @@ # ################################################################################################### -# Create a cleaner synthetic power spectrum +# Create a cleaner simulated power spectrum # ----------------------------------------- # Set the frequency range to generate the power spectrum @@ -215,7 +215,7 @@ # Set the level of noise to generate the power spectrum with nlv = 0.025 -# Create a synthetic power spectrum +# Create a simulated power spectrum freqs, spectrum = gen_power_spectrum([1, 50], ap_params, gauss_params, nlv=nlv) # Update settings to make sure they are sensitive to smaller peaks in smoother power spectra @@ -224,7 +224,7 @@ ################################################################################################### -# Check reconstructed parameters from synthetic definition +# Check reconstructed parameters from simulated definition print('Ground Truth \t\t FOOOF Reconstructions') for sy, fi in zip(np.array(group_three(gauss_params)), fm._gaussian_params): print('{:5.2f} {:5.2f} {:5.2f} \t {:5.2f} {:5.2f} {:5.2f}'.format(*sy, *fi)) @@ -237,8 +237,8 @@ ap_opts = param_sampler([[20, 2], [50, 2.5], [35, 1.5]]) gauss_opts = param_sampler([[], [10, 0.5, 2], [10, 0.5, 2, 20, 0.3, 4]]) -# Generate a group of power spectra -freqs, power_spectra, syn_params = gen_group_power_spectra(10, [3, 50], ap_opts, gauss_opts) +# Simulate a group of power spectra +freqs, power_spectra, sim_params = gen_group_power_spectra(10, [3, 50], ap_opts, gauss_opts) ################################################################################################### diff --git a/tutorials/plot_08-FurtherAnalysis.py b/tutorials/plot_08-FurtherAnalysis.py index 3bfd9e411..b2519a4d8 100644 --- a/tutorials/plot_08-FurtherAnalysis.py +++ b/tutorials/plot_08-FurtherAnalysis.py @@ -26,10 +26,10 @@ # General imports import numpy as np -# Import FOOOF objects & synth utilities +# Import FOOOF objects & sim utilities from fooof import FOOOF, FOOOFGroup -from fooof.synth.params import param_sampler -from fooof.synth.gen import gen_group_power_spectra +from fooof.sim.params import param_sampler +from fooof.sim.gen import gen_group_power_spectra # FOOOF comes with some basic analysis function to work with FOOOF outputs from fooof.analysis import get_band_peak, get_band_peak_group @@ -104,15 +104,15 @@ ################################################################################################### -# Generate some synthetic power spectra and fit a FOOOFGroup to use +# Generate some simulated power spectra and fit a FOOOFGroup to use freqs, spectra, _ = gen_group_power_spectra(n_spectra=10, freq_range=[3, 40], aperiodic_params=param_sampler([[20, 2], [35, 1.5]]), - gauss_params=param_sampler([[], [10, 0.5, 2]])) + gaussian_params=param_sampler([[], [10, 0.5, 2]])) ################################################################################################### -# Fit FOOOF models across the group of synthesized power spectra +# Fit FOOOF models across the group of simulated power spectra fg = FOOOFGroup(peak_width_limits=[1, 8], min_peak_height=0.05, max_n_peaks=6, verbose=False) fg.fit(freqs, spectra)