Skip to content

[ENH] - Update options to plot a broader frequency range #276

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

Merged
merged 5 commits into from
Jul 21, 2023
Merged

Conversation

TomDonoghue
Copy link
Member

@TomDonoghue TomDonoghue commented Jul 5, 2023

Responds to #245, and an alternative to #246

This PR adds functionality for making it easier to plot a model over a broader frequency range (across a frequency range beyond the fit range). It does so by making it easier to pass in frequency and power vectors to plot with a model. This strategy means that the model object does not store the broader range, but during exploration phases this can be visualized.

Notes:

  • This strategy generally means the broader range spectrum needs to be "around" (in memory) to be passed in explicitly.
    • A limitation of this is that if a fooof object is reloaded, the broader range spectrum while not de facto be available for this.
    • The upshot of this is trying to find a balance between supporting evaluation without increasing the amount of data stored in the object and/or saved out, which could otherwise lead to managing a lot of extra data that is rarely used.
  • The above points are in relation to the alternate strategy explored in [ENH] Enable full plot range for fm.plot() #246 (I commented in that PR why I personally do not prefer that option).
  • Below is a fairly comprehensive exploration of this functionality, with the idea that this can / should be turned into a docsite example to illustrate the underlying points here, and show the functionality

For reviewing, @ryanhammonds and @voytek (if you have time) - before a code deep-dive, I would appreciate your thoughts on strategy here (comparing this to #246). If we like this approach then code should be reviewed as normal - I think it should be pretty solid, although there could be some tweaks on how to manage the API for FOOOF.report if y'all have any thoughts on that.

Demonstration

Code for running following examples:

from fooof import FOOOF
from fooof.sim import gen_power_spectrum
freqs, powers = gen_power_spectrum([1, 150], [1, 100, 1], [[10, 0.15, 0.5], [25, 0.1, 2.5]])

Using plot_fm to plot models on top of broader range power spectra

# With this PR, can do the following to plot the model on top of a broader frequency range
fm.plot(freqs=freqs, power_spectrum=powers, plt_log=True, freq_range=[3, 75])

Which gives the following output:
Screen Shot 2023-07-05 at 10 57 44 AM

Exploring frequency ranges using fm.report

fm = FOOOF()
fm.report(freqs, powers, freq_range=[3, 30], plt_log=True, plot_full_range=True)

This gives the following output:
Screen Shot 2023-07-05 at 11 01 00 AM

In addition, these reports can be saved out.

# Save out model report, adding in a broader range frequency spectrum
fm.save_report('test_fm.pdf', freqs=freqs, power_spectrum=powers, plt_log=True, freq_range=[3, 75])

Showing how this works with FOOOFGroup

This process can also be used from a FOOOFGroup object, to examine individual model fits:

from fooof.sim import gen_group_power_spectra
from fooof import FOOOFGroup

freqs, spectra = gen_group_power_spectra(10, [1, 150], [1, 100, 1], [[10, 0.15, 0.5], [25, 0.1, 2.5]])
fg = FOOOFGroup()
fg.fit(freqs, spectra, [3, 30])

# Then, plot the model over the broad range (can also make report / save, etc)
fg.get_fooof(ind).plot(freqs=freqs, power_spectrum=spectra[ind, :])

Output:
Screen Shot 2023-07-05 at 11 15 47 AM

@fooof-tools fooof-tools deleted a comment from codecov-commenter Jul 5, 2023
@TomDonoghue TomDonoghue added the 1.1 Targetted for a fooof 1.1 release. label Jul 5, 2023
@ryanhammonds
Copy link
Contributor

@TomDonoghue I think either approach could work. The one thing I'd change about the other PR is to store a reference to the original array, rather a copy of it, and then to log & plot the original reference based on an kwarg in .plot / .report. I like your approach here too, it's efficient and makes sense.

This does add slight complications to the api for reporting and plotting. I can see an argument for leaving this up to the user to manage memory / create plots and not supporting the functionality.

@TomDonoghue
Copy link
Member Author

@ryanhammonds - yeh, I went back and forth a bit about the best way to do it and agree that I don't love complicating the API, and that the other approach should use a mask / selector rather than a copy (that idea also relates the fit range idea of #147). In the end, and after chatting with Voytek a bit, I think it is worth supporting this functionality, and we're going to go with this lighter weight version here, that allows for this without changing the data stored in the object. We can always revisit and extend the options for stuff like this in 2.0 or after.

So, for now, I'm going to merge this in, instead of (and close) #246

@TomDonoghue TomDonoghue merged commit 93febaf into main Jul 21, 2023
@TomDonoghue TomDonoghue deleted the plotfull branch July 21, 2023 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.1 Targetted for a fooof 1.1 release.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants