From 36b5c0ddebe0c02ed25d045a31dc91098b48c1f6 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Wed, 29 Jan 2025 10:20:40 +0100 Subject: [PATCH 1/5] replace chained assignment --- iblrig/base_choice_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iblrig/base_choice_world.py b/iblrig/base_choice_world.py index 10733a946..12ab30574 100644 --- a/iblrig/base_choice_world.py +++ b/iblrig/base_choice_world.py @@ -972,7 +972,7 @@ def get_subject_training_info(self): def compute_performance(self): """Aggregate the trials table to compute the performance of the mouse on each contrast.""" idx = self.trials_table.position.notna() - self.trials_table.signed_contrast[idx] = self.trials_table.contrast[idx] * np.sign(self.trials_table.position[idx]) + self.trials_table.loc[idx, 'signed_contrast'] = self.trials_table.contrast[idx] * np.sign(self.trials_table.position[idx]) performance = self.trials_table.groupby(['signed_contrast']).agg( last_50_perf=pd.NamedAgg(column='trial_correct', aggfunc=lambda x: np.sum(x[np.maximum(-50, -x.size) :]) / 50), ntrials=pd.NamedAgg(column='trial_correct', aggfunc='count'), From 02acb5352d82bd339350320152e2817795e6a204 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Wed, 29 Jan 2025 10:23:43 +0100 Subject: [PATCH 2/5] PD011 - replace use of .values on Pandas Series and Index objects with .to_numpy() --- iblrig/base_tasks.py | 2 +- iblrig/online_plots.py | 8 ++++---- iblrig/test/tasks/test_biased_choice_world_family.py | 6 +++--- iblrig/test/tasks/test_passive_choice_world.py | 2 +- iblrig/test/tasks/test_training_choice_world.py | 2 +- iblrig/test/test_choice_world.py | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iblrig/base_tasks.py b/iblrig/base_tasks.py index 1ba71d104..5f5f99580 100644 --- a/iblrig/base_tasks.py +++ b/iblrig/base_tasks.py @@ -1043,7 +1043,7 @@ def compute_reward_time(self, amount_ul: float | None = None) -> float: Valve opening time in seconds. """ amount_ul = self.task_params.REWARD_AMOUNT_UL if amount_ul is None else amount_ul - return self.valve.values.ul2ms(amount_ul) / 1e3 + return self.valve.values.ul2ms(amount_ul) / 1e3 # noqa: PD011 def valve_open(self, reward_valve_time): """ diff --git a/iblrig/online_plots.py b/iblrig/online_plots.py index 7183a2974..d4561584d 100644 --- a/iblrig/online_plots.py +++ b/iblrig/online_plots.py @@ -298,7 +298,7 @@ def update_graphics(self, pupdate: float | None = None): if self.data.psychometrics.loc[p]['count'].sum() == 0: continue # update psychometric curves - iok = ~np.isnan(self.data.psychometrics.loc[p]['choice'].values.astype(np.float32)) + iok = ~np.isnan(self.data.psychometrics.loc[p]['choice'].to_numpy().astype(np.float32)) xval = self.data.psychometrics.loc[p].index[iok] h.curve_psych[p][0].set(xdata=xval, ydata=self.data.psychometrics.loc[p]['choice'][iok]) h.curve_reaction[p][0].set(xdata=xval, ydata=self.data.psychometrics.loc[p]['response_time'][iok]) @@ -391,9 +391,9 @@ def display_full_jsonable(self, jsonable_file: Path | str): self.data.water_delivered = trials_table.reward_amount.sum() # init the last trials table it = self.data.last_trials.index[-np.minimum(self.data.ntrials, NTRIALS_PLOT) :] - self.data.last_trials.loc[it, 'correct'] = trials_table.trial_correct.iloc[-NTRIALS_PLOT:].values - self.data.last_trials.loc[it, 'signed_contrast'] = trials_table.signed_contrast.iloc[-NTRIALS_PLOT:].values - self.data.last_trials.loc[it, 'response_time'] = trials_table.response_time.iloc[-NTRIALS_PLOT:].values + self.data.last_trials.loc[it, 'correct'] = trials_table.trial_correct.iloc[-NTRIALS_PLOT:].to_numpy() + self.data.last_trials.loc[it, 'signed_contrast'] = trials_table.signed_contrast.iloc[-NTRIALS_PLOT:].to_numpy() + self.data.last_trials.loc[it, 'response_time'] = trials_table.response_time.iloc[-NTRIALS_PLOT:].to_numpy() self.data.last_trials.loc[it, 'stim_on'] = np.array( [bpod_data[i]['States timestamps']['stim_on'][0][0] for i in np.arange(-it.size, 0)] ) diff --git a/iblrig/test/tasks/test_biased_choice_world_family.py b/iblrig/test/tasks/test_biased_choice_world_family.py index ff5b96717..775af336d 100644 --- a/iblrig/test/tasks/test_biased_choice_world_family.py +++ b/iblrig/test/tasks/test_biased_choice_world_family.py @@ -55,13 +55,13 @@ def test_task(self, reward_set: np.ndarray | None = None): first_trial=pd.NamedAgg(column='block_trial_num', aggfunc='first'), ) # test that the first block is 90 trials - assert df_blocks['count'].values[0] == 90 + assert df_blocks['count'].to_numpy()[0] == 90 # make all first block trials were reset to 0 assert np.all(df_blocks['first_trial'] == 0) # test that the first block has 50/50 probability - assert df_blocks['stim_probability_left'].values[0] == 0.5 + assert df_blocks['stim_probability_left'].to_numpy()[0] == 0.5 # make sure that all subsequent blocks alternate between 0.2 and 0.8 left probability - assert np.all(np.isclose(np.abs(np.diff(df_blocks['stim_probability_left'].values[1:])), 0.6)) + assert np.all(np.isclose(np.abs(np.diff(df_blocks['stim_probability_left'].to_numpy()[1:])), 0.6)) # assert the the trial outcomes are within 0.3 of the generating probability np.testing.assert_array_less(np.abs(df_blocks['position'] - df_blocks['stim_probability_left']), 0.4) np.testing.assert_array_equal(np.unique(task.trials_table['reward_amount']), reward_set) diff --git a/iblrig/test/tasks/test_passive_choice_world.py b/iblrig/test/tasks/test_passive_choice_world.py index 51043cd77..c5cb8b1d9 100644 --- a/iblrig/test/tasks/test_passive_choice_world.py +++ b/iblrig/test/tasks/test_passive_choice_world.py @@ -52,7 +52,7 @@ def test_fixtures(self) -> None: for position in positions: counts = f[(f.stim_type == 'G') & (f.position == position) & (f.contrast != 0.0)].contrast.value_counts() assert set(counts.keys()) == {0.0625, 0.125, 0.25, 1.0} - assert all([v == 20 for v in counts.values]) + assert all([v == 20 for v in counts.to_numpy()]) assert len(f[f.stim_type == 'V']) == 40 assert len(f[f.stim_type == 'T']) == 40 assert len(f[f.stim_type == 'N']) == 40 diff --git a/iblrig/test/tasks/test_training_choice_world.py b/iblrig/test/tasks/test_training_choice_world.py index 5c41b895c..4d189a44d 100644 --- a/iblrig/test/tasks/test_training_choice_world.py +++ b/iblrig/test/tasks/test_training_choice_world.py @@ -72,7 +72,7 @@ def test_task(self): contrast_set = np.array([0.5, 1.0]) np.testing.assert_equal(contrasts['contrast'].values, contrast_set) - normalized_counts = np.abs(nt / contrast_set.size - contrasts['count'].values) + normalized_counts = np.abs(nt / contrast_set.size - contrasts['count'].to_numpy()) normalized_counts = normalized_counts * probas / np.sum(probas) normalized_counts = normalized_counts / (nt / contrast_set.size) np.testing.assert_array_less(normalized_counts, 0.33) diff --git a/iblrig/test/test_choice_world.py b/iblrig/test/test_choice_world.py index 32f8ab0c6..efbac4ca5 100644 --- a/iblrig/test/test_choice_world.py +++ b/iblrig/test/test_choice_world.py @@ -167,7 +167,7 @@ def count_contrasts(pc): df = pd.DataFrame(data=pc, columns=['angle', 'contrast', 'proba']) df['signed_contrasts'] = df['contrast'] * np.sign(df['angle']) c = df.groupby('signed_contrasts')['signed_contrasts'].count() / pc.shape[0] - return c.values + return c.to_numpy() def test_default(self): np.random.seed(7816) From 8dabc28719500d7288b6e882973dbf0c7ba01cc7 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Wed, 29 Jan 2025 10:50:38 +0100 Subject: [PATCH 3/5] add pandas-vet --- iblrig/test/tasks/test_passive_choice_world.py | 2 +- pyproject.toml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/iblrig/test/tasks/test_passive_choice_world.py b/iblrig/test/tasks/test_passive_choice_world.py index c5cb8b1d9..680da38f0 100644 --- a/iblrig/test/tasks/test_passive_choice_world.py +++ b/iblrig/test/tasks/test_passive_choice_world.py @@ -35,7 +35,7 @@ def test_fixtures(self) -> None: # The task stimuli replays consist of 300 stimulus presentations ordered randomly. assert len(f) == 300 - assert f.stim_type.iloc[:10].nunique() > 1 + assert f.stim_type.iloc[:10].nunique() > 1 # noqa: PD101 assert set(f.stim_type.unique()) == {'G', 'N', 'T', 'V'} # 180 gabor patches with 300 ms duration diff --git a/pyproject.toml b/pyproject.toml index ee89a608f..3065fa28d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -143,6 +143,7 @@ select = [ "SIM", # flake8-simplify "UP", # pyupgrade "D", # pydocstyle + "PD", # pandas-vet ] ignore = [ # TODO: The following entries should be gradually removed / fixed: @@ -159,6 +160,9 @@ ignore = [ "D205", # 1 blank line required between summary line and description "D400", # First line should end with a period "D401", # First line of docstring should be in imperative mood + "PD002", # Checks for inplace=True usages in pandas function and method calls + "PD008", # Checks for uses of .at on Pandas objects + "PD901", # Avoid using the generic variable name `df` for DataFrames ] [tool.ruff.lint.per-file-ignores] From 84f6c99d2e8294c714d8e00c526cdf6feabf5d7f Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Wed, 29 Jan 2025 10:53:41 +0100 Subject: [PATCH 4/5] changelog / version number --- CHANGELOG.md | 4 ++++ iblrig/__init__.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87e71608f..ba73bc78b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ Changelog ========= +8.27.1 +------ +* fixed: resolved warning about chained assignment in TrainingChoiceWorld.compute_performance() + 8.27.0 ------ * feature: allow for external tasks to be registered as plugins diff --git a/iblrig/__init__.py b/iblrig/__init__.py index efdc661a4..a224516de 100644 --- a/iblrig/__init__.py +++ b/iblrig/__init__.py @@ -6,4 +6,4 @@ # 5) git tag the release in accordance to the version number below (after merge!) # >>> git tag 8.15.6 # >>> git push origin --tags -__version__ = '8.27.0' +__version__ = '8.27.1' From d7d61b8879c80c15923635aa6abc6aafb1305ad9 Mon Sep 17 00:00:00 2001 From: Florian Rau Date: Wed, 29 Jan 2025 14:18:15 +0100 Subject: [PATCH 5/5] Revert "replace chained assignment" This reverts commit 36b5c0ddebe0c02ed25d045a31dc91098b48c1f6. --- iblrig/base_choice_world.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iblrig/base_choice_world.py b/iblrig/base_choice_world.py index 12ab30574..10733a946 100644 --- a/iblrig/base_choice_world.py +++ b/iblrig/base_choice_world.py @@ -972,7 +972,7 @@ def get_subject_training_info(self): def compute_performance(self): """Aggregate the trials table to compute the performance of the mouse on each contrast.""" idx = self.trials_table.position.notna() - self.trials_table.loc[idx, 'signed_contrast'] = self.trials_table.contrast[idx] * np.sign(self.trials_table.position[idx]) + self.trials_table.signed_contrast[idx] = self.trials_table.contrast[idx] * np.sign(self.trials_table.position[idx]) performance = self.trials_table.groupby(['signed_contrast']).agg( last_50_perf=pd.NamedAgg(column='trial_correct', aggfunc=lambda x: np.sum(x[np.maximum(-50, -x.size) :]) / 50), ntrials=pd.NamedAgg(column='trial_correct', aggfunc='count'),