Skip to content

Commit 1f4934a

Browse files
Minor Issues (#1270)
* error if fetch1_dataframe on multiple * 1262 fix * tools to check table disc usage * set orientation to nan for single led data * remove humanize dependency * fix function call * 1240 fix * update test expected value for null orientation in single led * 1211 fix * 1042_fix * log python env in analysis files * update changelog * fix spelling * Fix f-string Co-authored-by: Copilot <[email protected]> * apply suggestions from review * Revert accidental inclusion of interval list change * remove on as confirmation option * cleanup size check function * update fetch1_dataframe error * linting * Apply suggestions from code review Co-authored-by: Copilot <[email protected]> * more fetch1_dataframe error message updates * move human readable to util * fix docstring --------- Co-authored-by: Copilot <[email protected]>
1 parent 4dd1b39 commit 1f4934a

32 files changed

+172
-27
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ ImportedLFP().drop()
7979
- Only add merge parts to `source_class_dict` if present in codebase #1237
8080
- Remove cli module #1250
8181
- Fix column error in `check_threads` method #1256
82+
- Export python env and store in newly created analysis files #1270
83+
- Enforce single table entry in `fetch1_dataframe` calls #1270
8284
- Add recompute ability for `SpikeSortingRecording` for both v0 and v1 #1093,
8385
#1311
8486
- Track Spyglass version in dedicated table for enforcing updates #1281
@@ -96,6 +98,7 @@ ImportedLFP().drop()
9698
- Common
9799
- Default `AnalysisNwbfile.create` permissions are now 777 #1226
98100
- Make `Nwbfile.fetch_nwb` functional # 1256
101+
- Calculate mode of timestep size in log scale when estimating sampling rate #1270
99102
- Ingest all `ImageSeries` objects in nwb file to `VideoFile` #1278
100103
- Allow ingestion of multi-row task epoch tables #1278
101104
- Add `SensorData` to `populate_all_common` #1281
@@ -111,6 +114,8 @@ ImportedLFP().drop()
111114
of `DLCPoseEstimation` #1208
112115
- Enable import of existing pose data to `ImportedPose` in position pipeline
113116
#1247
117+
- Change key value `position_source` to "imported" during ingestion #1270
118+
- Define orientation as `nan` for single-led data #1270
114119
- Sanitize new project names for unix file system #1247
115120
- Add arg to return percent below threshold in `get_subthresh_inds` #1304,
116121
#1305
@@ -123,6 +128,8 @@ ImportedLFP().drop()
123128
- Revise cleanup for `v0.SpikeSorting` #1271
124129
- Fix type compatibility of `time_slice` in
125130
`SortedSpikesGroup.fetch_spike_data` #1261
131+
- Update transaction and parallel make settings for `v0` and `v1`
132+
`SpikeSorting` tables #1270
126133
- Disable make transactionsfor `CuratedSpikeSorting` #1288
127134
- Refactor `SpikeSortingOutput.get_restricted_merge_ids` #1304
128135
- Add burst merge curation #1209

src/spyglass/behavior/v1/moseq.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ def make(self, key):
403403
self.insert1(key)
404404

405405
def fetch1_dataframe(self):
406+
self.ensure_single_entry()
406407
dataframe = self.fetch_nwb()[0]["moseq"]
407408
dataframe.set_index("time", inplace=True)
408409
return dataframe

src/spyglass/common/common_behav.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def insert_from_nwbfile(cls, nwb_file_name, skip_duplicates=False) -> None:
7979
nwbf = get_nwb_file(nwb_file_name)
8080
all_pos = get_all_spatial_series(nwbf, verbose=True)
8181
sess_key = Nwbfile.get_file_key(nwb_file_name)
82-
src_key = dict(**sess_key, source="trodes", import_file_name="")
82+
src_key = dict(**sess_key, source="imported", import_file_name="")
8383

8484
if all_pos is None:
8585
return

src/spyglass/common/common_ephys.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ def nwb_object(self, key):
575575

576576
def fetch1_dataframe(self, *attrs, **kwargs) -> pd.DataFrame:
577577
"""Fetch the LFP data as a pandas DataFrame."""
578+
self.ensure_single_entry()
578579
nwb_lfp = self.fetch_nwb()[0]
579580
return pd.DataFrame(
580581
nwb_lfp["lfp"].data,
@@ -951,6 +952,7 @@ def make(self, key):
951952

952953
def fetch1_dataframe(self, *attrs, **kwargs) -> pd.DataFrame:
953954
"""Fetch the LFP band data as a pandas DataFrame."""
955+
self.ensure_single_entry()
954956
filtered_nwb = self.fetch_nwb()[0]
955957
return pd.DataFrame(
956958
filtered_nwb["filtered_data"].data,

src/spyglass/common/common_nwbfile.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import random
33
import string
4+
import subprocess
45
from pathlib import Path
56
from typing import Dict, Optional, Union
67
from uuid import uuid4
@@ -223,7 +224,7 @@ def create(
223224
nwb_object.pop(module)
224225
# add the version of spyglass that created this file
225226
if nwbf.source_script is None:
226-
nwbf.source_script = f"spyglass={sg_version}"
227+
nwbf.source_script = self._logged_env_info()
227228
else:
228229
alter_source_script = True
229230

@@ -267,11 +268,22 @@ def create(
267268

268269
return analysis_file_name
269270

270-
@staticmethod
271-
def _alter_spyglass_version(nwb_file_path: str) -> None:
271+
@classmethod
272+
def _alter_spyglass_version(cls, nwb_file_path: str) -> None:
272273
"""Change the source script to the current version of spyglass"""
273274
with h5py.File(nwb_file_path, "a") as f:
274-
f["/general/source_script"][()] = f"spyglass={sg_version}"
275+
f["/general/source_script"][()] = cls._logged_env_info()
276+
277+
@staticmethod
278+
def _logged_env_info():
279+
"""Get the environment information for logging."""
280+
env_info = f"spyglass={sg_version} \n\n"
281+
env_info += "Python Environment:\n"
282+
python_env = subprocess.check_output(
283+
["conda", "env", "export"], text=True
284+
)
285+
env_info += python_env
286+
return env_info
275287

276288
@classmethod
277289
def __get_new_file_name(cls, nwb_file_name: str) -> str:

src/spyglass/common/common_position.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,13 @@ def calculate_position_info(
464464
# convert back to between -pi and pi
465465
orientation[~is_nan] = np.angle(np.exp(1j * orientation[~is_nan]))
466466

467+
# set orientation to NaN in single LED data
468+
if np.all(front_LED == 0) or np.all(back_LED == 0):
469+
logger.warning(
470+
"Single LED data detected. Setting orientation to NaN."
471+
)
472+
orientation = np.full_like(orientation, np.nan)
473+
467474
velocity = get_velocity(
468475
position,
469476
time=time,
@@ -482,6 +489,7 @@ def calculate_position_info(
482489

483490
def fetch1_dataframe(self) -> pd.DataFrame:
484491
"""Fetches the position data as a pandas dataframe."""
492+
self.ensure_single_entry()
485493
return self._data_to_df(self.fetch_nwb()[0])
486494

487495
@staticmethod

src/spyglass/common/common_sensors.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ def fetch1_dataframe(
105105
"""
106106
if len(self) == 0:
107107
return None
108-
if len(self) > 1:
109-
raise ValueError("More than one sensor data object found.")
108+
self.ensure_single_entry()
110109

111110
nwb = self.fetch_nwb()[0]
112111
columns = nwb["sensor_data"].description.split()

src/spyglass/decoding/v0/clusterless.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ def make(self, key):
266266

267267
def fetch1_dataframe(self) -> pd.DataFrame:
268268
"""Convenience function for returning the marks in a readable format"""
269+
self.ensure_single_entry()
269270
return self.fetch_dataframe()[0]
270271

271272
def fetch_dataframe(self) -> list[pd.DataFrame]:
@@ -450,6 +451,7 @@ def plot_all_marks(
450451

451452
def fetch1_dataframe(self) -> pd.DataFrame:
452453
"""Convenience function for returning the first dataframe"""
454+
self.ensure_single_entry()
453455
return self.fetch_dataframe()[0]
454456

455457
def fetch_dataframe(self) -> list[pd.DataFrame]:

src/spyglass/decoding/v0/sorted_spikes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ def make(self, key):
164164

165165
def fetch1_dataframe(self) -> pd.DataFrame:
166166
"""Return the first spike indicator as a dataframe."""
167+
self.ensure_single_entry()
167168
return self.fetch_dataframe()[0]
168169

169170
def fetch_dataframe(self) -> list[pd.DataFrame]:

src/spyglass/lfp/analysis/v1/lfp_band.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -478,15 +478,8 @@ def make(self, key: dict) -> None:
478478

479479
def fetch1_dataframe(self, *attrs, **kwargs) -> pd.DataFrame:
480480
"""Fetches the filtered data as a dataframe"""
481-
filtered_nwb = self.fetch_nwb()
482-
483-
if len(filtered_nwb) != 1:
484-
raise ValueError(
485-
"Expected 1 filtered data, but got "
486-
+ f"{len(filtered_nwb)} for this LFPBandSelection"
487-
)
488-
489-
filtered_nwb = filtered_nwb[0]
481+
self.ensure_single_entry()
482+
filtered_nwb = self.fetch_nwb()[0]
490483
return pd.DataFrame(
491484
filtered_nwb["lfp_band"].data,
492485
index=pd.Index(filtered_nwb["lfp_band"].timestamps, name="time"),

0 commit comments

Comments
 (0)