-
Notifications
You must be signed in to change notification settings - Fork 201
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
Ibl exporter #3522
base: main
Are you sure you want to change the base?
Ibl exporter #3522
Conversation
Co-authored-by: Garcia Samuel <[email protected]>
…release Prepare minor 0.100.1 release
…ug-fixes Add batch size to KS4 wrapper
for more information, see https://pre-commit.ci
…release Prepare 0.100.2
…_similarity_diff_units Fix template similarity when there are multiple sizes of units
Prepare minor release 0.100.3
Prepare 0.100.4
Preprare 0.100.5
Port bug fix PRs from Main over to 0.100-bug-fixes
Prepare release 0.100.6
for more information, see https://pre-commit.ci
This looks like it is off of the bug fixes branch. @jonahpearl you want to switch this to main instead? |
I'm not 100% sure what you mean. Do you want me to cherry-pick / rebase my changes onto the main branch? I branched it a while ago so I've had to merge main in a few times. |
@jonahpearl thanks for this! Is it ok if I push to this PR? I've been working on refining the export function so I'd be good to be in sync :) |
I think it's correctly using the |
@@ -194,7 +194,7 @@ def export_to_phy( | |||
templates[unit_ind, :, :][:, : len(chan_inds)] = template | |||
templates_ind[unit_ind, : len(chan_inds)] = chan_inds | |||
|
|||
if not sorting_analyzer.has_extension("template_similarity"): | |||
if sorting_analyzer.get_extension("template_similarity") is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
revert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're suggesting we put this back to "has_extension"? Any reason this one and not the other ones? The ibl export relies on doing a Phy export, and as discussed elsewhere this "has_extension" pattern is no longer safe if the folder exists but without any data inside.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, all of them. I think it's much easier to read :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it'd be easier to read, but I disagree that it's preferable, because it will break if the extension folder exists but doesn't have data. It's not unusual to end up in that kind of state — eg if you run analyzer.compute(["random_spikes", "spike_amplitudes"])
on a new analyzer, the spike_amplitudes
folder will get made but nothing will be in it because the analyzer will need "templates" to be computed. There are various ways to fix that involving try/excepts / clean-ups, but in the current context, I don't think it makes sense to not catch this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a separate issue :) we should delay folder creation until dependencies are checked. Can you open another issue about it?
from spikeinterface.core import extract_waveforms | ||
from spikeinterface.extractors import toy_example | ||
from spikeinterface.comparison import compare_templates | ||
|
||
import numpy as np |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this belongs to a different PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, not sure how this slipped in.
|
||
import numpy as np | ||
import numpy.typing as npt | ||
from scipy.signal import welch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import scipy
should be done within the functions using it because it's not a mandatory requirement (see failing tests)
Co-authored-by: Alessio Buccino <[email protected]>
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a docstring fix while you're at it. I believe we add this to the dev docs after this PR was started which is why this was missed.
---------- | ||
analyzer: SortingAnalyzer | ||
The sorting analyzer object. | ||
output_folder: str | Path | ||
The output folder where the phy template-gui files are saved | ||
rms_win_length_sec: float, default: 3 | ||
The window length in seconds for the RMS calculation. | ||
welch_win_length_samples: int, default: 1024 | ||
The window length in samples for the Welch method. | ||
total_secs: int, default: 100 | ||
The total number of seconds to use for the spectral density calculation. | ||
only_ibl_specific_steps: bool, default: False | ||
If True, only the IBL specific steps are run (i.e. skips calling `export_to_phy`) | ||
compute_pc_features: bool, default: False | ||
If True, pc features are computed | ||
compute_amplitudes: bool, default: True | ||
If True, waveforms amplitudes are computed | ||
sparsity: ChannelSparsity or None, default: None | ||
The sparsity object (currently only respected for phy part of the export) | ||
copy_binary: bool, default: True | ||
If True, the recording is copied and saved in the phy "output_folder" | ||
remove_if_exists: bool, default: False | ||
If True and "output_folder" exists, it is removed and overwritten | ||
template_mode: str, default: "median" | ||
Parameter "mode" to be given to WaveformExtractor.get_template() | ||
dtype: dtype or None, default: None | ||
Dtype to save binary data | ||
verbose: bool, default: True | ||
If True, output is verbose | ||
use_relative_path : bool, default: False | ||
If True and `copy_binary=True` saves the binary file `dat_path` in the `params.py` relative to `output_folder` (ie `dat_path=r"recording.dat"`). If `copy_binary=False`, then uses a path relative to the `output_folder` | ||
If False, uses an absolute path in the `params.py` (ie `dat_path=r"path/to/the/recording.dat"`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
---------- | |
analyzer: SortingAnalyzer | |
The sorting analyzer object. | |
output_folder: str | Path | |
The output folder where the phy template-gui files are saved | |
rms_win_length_sec: float, default: 3 | |
The window length in seconds for the RMS calculation. | |
welch_win_length_samples: int, default: 1024 | |
The window length in samples for the Welch method. | |
total_secs: int, default: 100 | |
The total number of seconds to use for the spectral density calculation. | |
only_ibl_specific_steps: bool, default: False | |
If True, only the IBL specific steps are run (i.e. skips calling `export_to_phy`) | |
compute_pc_features: bool, default: False | |
If True, pc features are computed | |
compute_amplitudes: bool, default: True | |
If True, waveforms amplitudes are computed | |
sparsity: ChannelSparsity or None, default: None | |
The sparsity object (currently only respected for phy part of the export) | |
copy_binary: bool, default: True | |
If True, the recording is copied and saved in the phy "output_folder" | |
remove_if_exists: bool, default: False | |
If True and "output_folder" exists, it is removed and overwritten | |
template_mode: str, default: "median" | |
Parameter "mode" to be given to WaveformExtractor.get_template() | |
dtype: dtype or None, default: None | |
Dtype to save binary data | |
verbose: bool, default: True | |
If True, output is verbose | |
use_relative_path : bool, default: False | |
If True and `copy_binary=True` saves the binary file `dat_path` in the `params.py` relative to `output_folder` (ie `dat_path=r"recording.dat"`). If `copy_binary=False`, then uses a path relative to the `output_folder` | |
If False, uses an absolute path in the `params.py` (ie `dat_path=r"path/to/the/recording.dat"`) | |
---------- | |
analyzer : SortingAnalyzer | |
The sorting analyzer object. | |
output_folder : str | Path | |
The output folder where the phy template-gui files are saved | |
rms_win_length_sec : float, default: 3 | |
The window length in seconds for the RMS calculation. | |
welch_win_length_samples : int, default: 1024 | |
The window length in samples for the Welch method. | |
total_secs : int, default: 100 | |
The total number of seconds to use for the spectral density calculation. | |
only_ibl_specific_steps : bool, default: False | |
If True, only the IBL specific steps are run (i.e. skips calling `export_to_phy`) | |
compute_pc_features : bool, default: False | |
If True, pc features are computed | |
compute_amplitudes : bool, default: True | |
If True, waveforms amplitudes are computed | |
sparsity : ChannelSparsity or None, default: None | |
The sparsity object (currently only respected for phy part of the export) | |
copy_binary : bool, default: True | |
If True, the recording is copied and saved in the phy "output_folder" | |
remove_if_exists : bool, default: False | |
If True and "output_folder" exists, it is removed and overwritten | |
template_mode : str, default: "median" | |
Parameter "mode" to be given to WaveformExtractor.get_template() | |
dtype : dtype or None, default: None | |
Dtype to save binary data | |
verbose : bool, default: True | |
If True, output is verbose | |
use_relative_path : bool, default: False | |
If True and `copy_binary=True` saves the binary file `dat_path` in the `params.py` relative to `output_folder` (ie `dat_path=r"recording.dat"`). If `copy_binary=False`, then uses a path relative to the `output_folder` | |
If False, uses an absolute path in the `params.py` (ie `dat_path=r"path/to/the/recording.dat"`) |
We are working on implementing numpydoc linting in the future and it requires there to be a space after the parameter.
try: | ||
from scipy.signal import welch | ||
except ImportError as e: | ||
raise ImportError("Please install scipy to use the export_to_ibl function.") from e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never seen this before. How does this raise error from e work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just import it in the function. The problem is that core tests will look in all files for tests, and script is not installed in core tests
"fscale": fscale(welch_win_length_samples, 1 / fs_ap, one_sided=True), | ||
"tscale": wingen.tscale(fs=fs_ap), | ||
} | ||
win["spectral_density"] = np.zeros((len(win["fscale"]), analyzer.recording.get_num_channels())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should have a proper function to compute the spectrum if you need it.
So we could have proper tests for this.
total_samples_ap = int(np.min([fs_ap * total_secs, analyzer.recording.get_num_samples()])) | ||
|
||
# the window generator will generates window indices | ||
wingen = WindowGenerator(ns=total_samples_ap, nswin=rms_win_length_samples_ap, overlap=0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have already some function to generate window in spikeinterface.
Hi @jonahpearl About About the spectrum, I would implement it in a speparate file using the spikeinterface machinery on chunk parralelisation. |
Fair enough -- I don't have time to refactor this right now but I can work on it in the coming months. |
Function for #2843
Would be great if a few others could test on their data. Thanks!