Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENH] Simplified saving kwargs #200

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 17 additions & 55 deletions fooof/core/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,46 +33,15 @@ def fname(file_name, extension):
return file_name


def fpath(file_path, file_name):
"""Build the full file path from file name and directory.

Parameters
----------
file_path : str or None
Path to the directory where the file is located.
file_name : str
Name of the file.

Returns
-------
full_path : str
Full file path to the file, including directory, if provided.

Notes
-----
This function is mainly used to deal with the case in which file_path is None.
"""

if not file_path:
full_path = file_name
else:
full_path = os.path.join(file_path, file_name)

return full_path


def save_fm(fm, file_name, file_path=None, append=False,
save_results=False, save_settings=False, save_data=False):
def save_fm(fm, file_name, append=False, save_results=False, save_settings=False, save_data=False):
"""Save out data, results and/or settings from a FOOOF object into a JSON file.

Parameters
----------
fm : FOOOF
Object to save data from.
file_name : str or FileObject
File to save data to.
file_path : str, optional
Path to directory to save to. If None, saves to current directory.
File to save data to. Absolute or relative paths may be included.
append : bool, optional, default: False
Whether to append to an existing file, if available.
This option is only valid (and only used) if 'file_name' is a str.
Expand Down Expand Up @@ -101,12 +70,12 @@ def save_fm(fm, file_name, file_path=None, append=False,

# Save out - create new file, (creates a JSON file)
if isinstance(file_name, str) and not append:
with open(fpath(file_path, fname(file_name, 'json')), 'w') as outfile:
with open(fname(file_name, 'json'), 'w') as outfile:
json.dump(obj_dict, outfile)

# Save out - append to file_name (appends to a JSONlines file)
elif isinstance(file_name, str) and append:
with open(fpath(file_path, fname(file_name, 'json')), 'a') as outfile:
with open(fname(file_name, 'json'), 'a') as outfile:
json.dump(obj_dict, outfile)
outfile.write('\n')

Expand All @@ -119,18 +88,15 @@ def save_fm(fm, file_name, file_path=None, append=False,
raise ValueError("Save file not understood.")


def save_fg(fg, file_name, file_path=None, append=False,
save_results=False, save_settings=False, save_data=False):
def save_fg(fg, file_name, append=False, save_results=False, save_settings=False, save_data=False):
"""Save out results and/or settings from FOOOFGroup object. Saves out to a JSON file.

Parameters
----------
fg : FOOOFGroup
Object to save data from.
file_name : str or FileObject
File to save data to.
file_path : str, optional
Path to directory to load from. If None, loads from current directory.
File to save data to, including absolute or relative path.
append : bool, optional, default: False
Whether to append to an existing file, if available.
This option is only valid (and only used) if 'file_name' is a str.
Expand All @@ -152,12 +118,12 @@ def save_fg(fg, file_name, file_path=None, append=False,

# Save to string specified file, do not append
if isinstance(file_name, str) and not append:
with open(fpath(file_path, fname(file_name, 'json')), 'w') as f_obj:
with open(fname(file_name, 'json'), 'w') as f_obj:
_save_fg(fg, f_obj, save_results, save_settings, save_data)

# Save to string specified file, appending
elif isinstance(file_name, str) and append:
with open(fpath(file_path, fname(file_name, 'json')), 'a') as f_obj:
with open(fname(file_name, 'json'), 'a') as f_obj:
_save_fg(fg, f_obj, save_results, save_settings, save_data)

# Save to file-object specified file
Expand All @@ -168,15 +134,13 @@ def save_fg(fg, file_name, file_path=None, append=False,
raise ValueError("Save file not understood.")


def load_json(file_name, file_path):
def load_json(file_name):
"""Load json file.

Parameters
----------
file_name : str or FileObject
File to load data from.
file_path : str
Path to directory to load from.
File to load data from, including absolute or relative path.

Returns
-------
Expand All @@ -186,7 +150,7 @@ def load_json(file_name, file_path):

# Load data from file
if isinstance(file_name, str):
with open(fpath(file_path, fname(file_name, 'json')), 'r') as infile:
with open(fname(file_name, 'json'), 'r') as infile:
data = json.load(infile)
elif isinstance(file_name, io.IOBase):
data = json.loads(file_name.readline())
Expand All @@ -197,29 +161,27 @@ def load_json(file_name, file_path):
return data


def load_jsonlines(file_name, file_path):
def load_jsonlines(file_name):
"""Load a json-lines file, yielding data line by line.

Parameters
----------
file_name : str
File to load data from.
file_path : str
Path to directory from load from.
File to load data from, including absolute or relative path.

Yields
------
dict
Dictionary of data loaded from file.
"""

with open(fpath(file_path, fname(file_name, 'json')), 'r') as f_obj:
with open(fname(file_name, 'json'), 'r') as f_obj:

while True:

# Load each line, as JSON file
try:
yield load_json(f_obj, '')
yield load_json(f_obj)

# Break off when get a JSON error - end of the file
except JSONDecodeError:
Expand All @@ -245,11 +207,11 @@ def _save_fg(fg, f_obj, save_results, save_settings, save_data):

# Since there is a single set of object settings, save them out once, at the top
if save_settings:
save_fm(fg, file_name=f_obj, file_path=None, append=False, save_settings=True)
save_fm(fg, file_name=f_obj, append=False, save_settings=True)

# For results & data, loop across all data and/or models, and save each out to a new line
if save_results or save_data:
for ind in range(len(fg.group_results)):
fm = fg.get_fooof(ind, regenerate=False)
save_fm(fm, file_name=f_obj, file_path=None, append=False,
save_fm(fm, file_name=f_obj, append=False,
save_results=save_results, save_data=save_data)
18 changes: 7 additions & 11 deletions fooof/core/reports.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Generate reports from FOOOF objects."""

from fooof.core.io import fname, fpath
from fooof.core.io import fname
from fooof.core.modutils import safe_import, check_dependency
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
Expand All @@ -22,17 +22,15 @@
###################################################################################################

@check_dependency(plt, 'matplotlib')
def save_report_fm(fm, file_name, file_path=None, plt_log=False):
def save_report_fm(fm, file_name, plt_log=False):
"""Generate and save out a PDF report for a power spectrum model fit.

Parameters
----------
fm : FOOOF
Object with results from fitting a power spectrum.
file_name : str
Name to give the saved out file.
file_path : str, optional
Path to directory to save to. If None, saves to current directory.
Name of output file to save, including absolute or relative path.
plt_log : bool, optional, default: False
Whether or not to plot the frequency axis in log space.
"""
Expand Down Expand Up @@ -62,22 +60,20 @@ def save_report_fm(fm, file_name, file_path=None, plt_log=False):
ax2.set_yticks([])

# Save out the report
plt.savefig(fpath(file_path, fname(file_name, SAVE_FORMAT)))
plt.savefig(fname(file_name, SAVE_FORMAT))
plt.close()


@check_dependency(plt, 'matplotlib')
def save_report_fg(fg, file_name, file_path=None):
def save_report_fg(fg, file_name):
"""Generate and save out a PDF report for a group of power spectrum models.

Parameters
----------
fg : FOOOFGroup
Object with results from fitting a group of power spectra.
file_name : str
Name to give the saved out file.
file_path : str, optional
Path to directory to save to. If None, saves to current directory.
Name of output file to save, including absolute or relative path.
"""

# Initialize figure
Expand Down Expand Up @@ -105,5 +101,5 @@ def save_report_fg(fg, file_name, file_path=None):
plot_fg_peak_cens(fg, ax3)

# Save out the report
plt.savefig(fpath(file_path, fname(file_name, SAVE_FORMAT)))
plt.savefig(fname(file_name, SAVE_FORMAT))
plt.close()
28 changes: 12 additions & 16 deletions fooof/objs/fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -633,38 +633,34 @@ def get_results(self):


@copy_doc_func_to_method(plot_fm)
def plot(self, plot_peaks=None, plot_aperiodic=True, plt_log=False,
add_legend=True, save_fig=False, file_name=None, file_path=None,
ax=None, plot_style=style_spectrum_plot,
data_kwargs=None, model_kwargs=None, aperiodic_kwargs=None, peak_kwargs=None):
def plot(self, plot_peaks=None, plot_aperiodic=True, plt_log=False, add_legend=True,
file_name=None, ax=None, plot_style=style_spectrum_plot, data_kwargs=None,
model_kwargs=None, aperiodic_kwargs=None, peak_kwargs=None):

plot_fm(self, plot_peaks, plot_aperiodic, plt_log, add_legend,
save_fig, file_name, file_path, ax, plot_style,
data_kwargs, model_kwargs, aperiodic_kwargs, peak_kwargs)
plot_fm(self, plot_peaks, plot_aperiodic, plt_log, add_legend, file_name, ax,
plot_style, data_kwargs, model_kwargs, aperiodic_kwargs, peak_kwargs)


@copy_doc_func_to_method(save_report_fm)
def save_report(self, file_name, file_path=None, plt_log=False):
def save_report(self, file_name, plt_log=False):

save_report_fm(self, file_name, file_path, plt_log)
save_report_fm(self, file_name, plt_log)


@copy_doc_func_to_method(save_fm)
def save(self, file_name, file_path=None, append=False,
def save(self, file_name, append=False,
save_results=False, save_settings=False, save_data=False):

save_fm(self, file_name, file_path, append, save_results, save_settings, save_data)
save_fm(self, file_name, append, save_results, save_settings, save_data)


def load(self, file_name, file_path=None, regenerate=True):
def load(self, file_name, regenerate=True):
"""Load in a FOOOF formatted JSON file to the current object.

Parameters
----------
file_name : str or FileObject
File to load data from.
file_path : str or None, optional
Path to directory to load from. If None, loads from current directory.
File to load data from, including absolute or relative path.
regenerate : bool, optional, default: True
Whether to regenerate the model fit from the loaded data, if data is available.
"""
Expand All @@ -673,7 +669,7 @@ def load(self, file_name, file_path=None, regenerate=True):
self._reset_data_results(True, True, True)

# Load JSON file, add to self and check loaded data
data = load_json(file_name, file_path)
data = load_json(file_name)
self._add_from_dict(data)
self._check_loaded_settings(data)
self._check_loaded_results(data)
Expand Down
20 changes: 9 additions & 11 deletions fooof/objs/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,40 +398,38 @@ def get_params(self, name, col=None):


@copy_doc_func_to_method(plot_fg)
def plot(self, save_fig=False, file_name=None, file_path=None):
def plot(self, file_name=None):

plot_fg(self, save_fig, file_name, file_path)
plot_fg(self, file_name)


@copy_doc_func_to_method(save_report_fg)
def save_report(self, file_name, file_path=None):
def save_report(self, file_name):

save_report_fg(self, file_name, file_path)
save_report_fg(self, file_name)


@copy_doc_func_to_method(save_fg)
def save(self, file_name, file_path=None, append=False,
def save(self, file_name, append=False,
save_results=False, save_settings=False, save_data=False):

save_fg(self, file_name, file_path, append, save_results, save_settings, save_data)
save_fg(self, file_name, append, save_results, save_settings, save_data)


def load(self, file_name, file_path=None):
def load(self, file_name):
"""Load FOOOFGroup data from file.

Parameters
----------
file_name : str
File to load data from.
file_path : str, optional
Path to directory to load from. If None, loads from current directory.
File to load data from, including absolute or relative path.
"""

# Clear results so as not to have possible prior results interfere
self._reset_group_results()

power_spectra = []
for ind, data in enumerate(load_jsonlines(file_name, file_path)):
for ind, data in enumerate(load_jsonlines(file_name)):

self._add_from_dict(data)

Expand Down
18 changes: 6 additions & 12 deletions fooof/plts/fg.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
This file contains plotting functions that take as input a FOOOFGroup object.
"""

from fooof.core.io import fname, fpath
from fooof.core.io import fname
from fooof.core.errors import NoModelError
from fooof.core.modutils import safe_import, check_dependency
from fooof.plts.settings import PLT_FIGSIZES
Expand All @@ -18,19 +18,15 @@
###################################################################################################

@check_dependency(plt, 'matplotlib')
def plot_fg(fg, save_fig=False, file_name=None, file_path=None):
def plot_fg(fg, file_name=None):
"""Plot a figure with subplots visualizing the parameters from a FOOOFGroup object.

Parameters
----------
fg : FOOOFGroup
Object containing results from fitting a group of power spectra.
save_fig : bool, optional, default: False
Whether to save out a copy of the plot.
file_name : str, optional
Name to give the saved out file.
file_path : str, optional
Path to directory to save to. If None, saves to current directory.
file_name : str, optional, default: None
Name with format to save as, including absolute or relative path.

Raises
------
Expand All @@ -56,10 +52,8 @@ def plot_fg(fg, save_fig=False, file_name=None, file_path=None):
ax2 = plt.subplot(gs[1, :])
plot_fg_peak_cens(fg, ax2)

if save_fig:
if not file_name:
raise ValueError("Input 'file_name' is required to save out the plot.")
plt.savefig(fpath(file_path, fname(file_name, 'png')))
if file_name is not None:
plt.savefig(fname(file_name, 'png'))


@check_dependency(plt, 'matplotlib')
Expand Down
Loading