From dca7b82b93c3a4988527b2b7427347482ce5c296 Mon Sep 17 00:00:00 2001 From: Daniela Huppenkothen Date: Wed, 14 Dec 2022 09:28:02 +0100 Subject: [PATCH 1/5] automatic conversion of column names to lowercase on SoniSeries isntantiation --- astronify/series/series.py | 12 +++- astronify/series/tests/test_series.py | 94 +++++++++++++++++++-------- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/astronify/series/series.py b/astronify/series/series.py index 0b74d30..44d1760 100644 --- a/astronify/series/series.py +++ b/astronify/series/series.py @@ -125,6 +125,10 @@ def __init__(self, data, time_col="time", val_col="flux"): self.val_col = val_col self.data = data + print(self.data.columns) + for c in list(self.data.columns): + self.data.rename_column(c, c.lower()) + # Default specs self.note_duration = 0.5 # note duration in seconds self.note_spacing = 0.01 # spacing between notes in seconds @@ -144,7 +148,13 @@ def data(self): @data.setter def data(self, data_table): - assert isinstance(data_table, Table), 'Data must be a Table.' + assert isinstance(data_table, Table), 'Data must be an astropy.table.Table object.' + + for c in list(data_table.columns): + data_table.rename_column(c, c.lower()) + + assert "time" in data_table.columns, "Input Table must contain a column 'time'" + assert "flux" in data_table.columns, "Input Table must contain a column 'flux'" # Removing any masked values as they interfere with the sonification if isinstance(data_table[self.val_col], MaskedColumn): diff --git a/astronify/series/tests/test_series.py b/astronify/series/tests/test_series.py index f9e7c8a..9bbbb44 100644 --- a/astronify/series/tests/test_series.py +++ b/astronify/series/tests/test_series.py @@ -52,38 +52,76 @@ def my_map_func(data): # dummy function assert (my_pitchmapper([1, 1]) == [0.5, 0.5]).all() -def test_soniseries(tmpdir): - """ - Testing SoniSeries class. - """ +class TestSoniSeries(object): + + @classmethod + def setup_class(cls): + + cls.data = Table({"time": [0, 1, 2, 3, 4, 5, 6], + "Flux": [1, 2, 1, 2, 5, 3, np.nan]}) + + cls.soni_obj = SoniSeries(cls.data) - data = Table({"time": [0, 1, 2, 3, 4, 5, 6], - "flux": [1, 2, 1, 2, 5, 3, np.nan]}) - - # defaults - soni_obj = SoniSeries(data) - assert soni_obj.note_duration == 0.5 - assert soni_obj.note_spacing == 0.01 - assert soni_obj.gain == 0.05 - assert isinstance(soni_obj.server, Server) - assert len(soni_obj.data) == len(data) - 1 # nan row should be removed - assert ~np.isnan(soni_obj.data["flux"]).any() - assert soni_obj.data["flux"].dtype == np.float64 - - soni_obj.sonify() - assert "asf_pitch" in soni_obj.data.colnames - assert "asf_onsets" in soni_obj.data.colnames - assert soni_obj.data.meta['asf_exposure_time'] == 1 - assert soni_obj.data.meta['asf_note_duration'] == soni_obj.note_duration - assert soni_obj.data.meta['asf_spacing'] == soni_obj.note_spacing + def test_soniseries_initializes(self): + SoniSeries(self.data) + + def test_conversion_to_lowercase(self): + assert list(self.soni_obj.data.columns)[1] == "flux" + + def test_assert_time_exists(self): + + new_data = Table({"foo": [0, 1, 2, 3, 4, 5, 6], + "Flux": [1, 2, 1, 2, 5, 3, np.nan]}) - onset_spacing = soni_obj.data['asf_onsets'][1:]-soni_obj.data['asf_onsets'][:-1] - assert (np.isclose(onset_spacing, soni_obj.note_spacing)).all() + with pytest.raises(AssertionError): + so = SoniSeries(new_data) + + def test_assert_flux_exists(self): + + new_data = Table({"time": [0, 1, 2, 3, 4, 5, 6], + "bar": [1, 2, 1, 2, 5, 3, np.nan]}) + + with pytest.raises(AssertionError): + so = SoniSeries(new_data) + + def test_default_parameters(self): + assert self.soni_obj.note_duration == 0.5 + assert self.soni_obj.note_spacing == 0.01 + assert self.soni_obj.gain == 0.05 - pitch_min, pitch_max = soni_obj.pitch_mapper.pitch_map_args["pitch_range"] - assert soni_obj.data["asf_pitch"].min() >= pitch_min - assert soni_obj.data["asf_pitch"].max() <= pitch_max + def test_server_class(self): + assert isinstance(self.soni_obj.server, Server) + + def test_nans_removed(self): + assert len(self.soni_obj.data) == len(self.data) - 1 # nan row should be removed + assert ~np.isnan(self.soni_obj.data["flux"]).any() + + def test_flux_type_correct(self): + assert self.soni_obj.data["flux"].dtype == np.float64 + + def test_sonify_works(self): + self.soni_obj.sonify() + + def test_sonify_new_columns_exist(self): + assert "asf_pitch" in self.soni_obj.data.colnames + assert "asf_onsets" in self.soni_obj.data.colnames + + def test_sonify_metadata(self): + assert self.soni_obj.data.meta['asf_exposure_time'] == 1 + assert self.soni_obj.data.meta['asf_note_duration'] == self.soni_obj.note_duration + assert self.soni_obj.data.meta['asf_spacing'] == self.soni_obj.note_spacing + + def test_onset_spacing(self): + onset_spacing = self.soni_obj.data['asf_onsets'][1:]-self.soni_obj.data['asf_onsets'][:-1] + assert (np.isclose(onset_spacing, self.soni_obj.note_spacing)).all() + + def test_pitch_min_max(self): + pitch_min, pitch_max = self.soni_obj.pitch_mapper.pitch_map_args["pitch_range"] + assert self.soni_obj.data["asf_pitch"].min() >= pitch_min + assert self.soni_obj.data["asf_pitch"].max() <= pitch_max # TODO: change args and test # TODO: test write + + From aa1a93b781f9fbd1810341bd6f399ef819c483db Mon Sep 17 00:00:00 2001 From: Daniela Huppenkothen Date: Wed, 14 Dec 2022 09:37:42 +0100 Subject: [PATCH 2/5] Changed assertions to more useful errors --- astronify/series/series.py | 14 +++++++++----- astronify/series/tests/test_series.py | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/astronify/series/series.py b/astronify/series/series.py index 44d1760..0c7c906 100644 --- a/astronify/series/series.py +++ b/astronify/series/series.py @@ -125,7 +125,6 @@ def __init__(self, data, time_col="time", val_col="flux"): self.val_col = val_col self.data = data - print(self.data.columns) for c in list(self.data.columns): self.data.rename_column(c, c.lower()) @@ -148,13 +147,18 @@ def data(self): @data.setter def data(self, data_table): - assert isinstance(data_table, Table), 'Data must be an astropy.table.Table object.' + + if not isinstance(data_table, Table): + raise TypeError('Data must be an astropy.table.Table object.') for c in list(data_table.columns): - data_table.rename_column(c, c.lower()) + data_table.rename_column(c, c.lower()) + + if "time" not in data_table.columns: + raise AttributeError("Input Table must contain a column 'time'") - assert "time" in data_table.columns, "Input Table must contain a column 'time'" - assert "flux" in data_table.columns, "Input Table must contain a column 'flux'" + if "flux" not in data_table.columns: + raise AttributeError("Input Table must contain a column 'flux'") # Removing any masked values as they interfere with the sonification if isinstance(data_table[self.val_col], MaskedColumn): diff --git a/astronify/series/tests/test_series.py b/astronify/series/tests/test_series.py index 9bbbb44..0ea8d52 100644 --- a/astronify/series/tests/test_series.py +++ b/astronify/series/tests/test_series.py @@ -73,7 +73,7 @@ def test_assert_time_exists(self): new_data = Table({"foo": [0, 1, 2, 3, 4, 5, 6], "Flux": [1, 2, 1, 2, 5, 3, np.nan]}) - with pytest.raises(AssertionError): + with pytest.raises(AttributeError): so = SoniSeries(new_data) def test_assert_flux_exists(self): @@ -81,7 +81,7 @@ def test_assert_flux_exists(self): new_data = Table({"time": [0, 1, 2, 3, 4, 5, 6], "bar": [1, 2, 1, 2, 5, 3, np.nan]}) - with pytest.raises(AssertionError): + with pytest.raises(AttributeError): so = SoniSeries(new_data) def test_default_parameters(self): From 615d42d32341d66187c51cb5b17d736dcf3b614b Mon Sep 17 00:00:00 2001 From: Daniela Huppenkothen Date: Wed, 14 Dec 2022 09:54:04 +0100 Subject: [PATCH 3/5] Changed hardcoded time and flux checks to time_col and val_col --- astronify/series/series.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/astronify/series/series.py b/astronify/series/series.py index 0c7c906..d8c4ea2 100644 --- a/astronify/series/series.py +++ b/astronify/series/series.py @@ -125,9 +125,6 @@ def __init__(self, data, time_col="time", val_col="flux"): self.val_col = val_col self.data = data - for c in list(self.data.columns): - self.data.rename_column(c, c.lower()) - # Default specs self.note_duration = 0.5 # note duration in seconds self.note_spacing = 0.01 # spacing between notes in seconds @@ -154,10 +151,11 @@ def data(self, data_table): for c in list(data_table.columns): data_table.rename_column(c, c.lower()) - if "time" not in data_table.columns: + + if self.time_col not in data_table.columns: raise AttributeError("Input Table must contain a column 'time'") - if "flux" not in data_table.columns: + if self.val_col not in data_table.columns: raise AttributeError("Input Table must contain a column 'flux'") # Removing any masked values as they interfere with the sonification From 38b84ba2d1cbfa89d847e9dbcaf6cbfcd69d1780 Mon Sep 17 00:00:00 2001 From: "C. E. Brasseur" Date: Fri, 16 Dec 2022 19:20:55 +0100 Subject: [PATCH 4/5] pep8 --- astronify/series/tests/test_series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astronify/series/tests/test_series.py b/astronify/series/tests/test_series.py index 0ea8d52..0c4462f 100644 --- a/astronify/series/tests/test_series.py +++ b/astronify/series/tests/test_series.py @@ -74,7 +74,7 @@ def test_assert_time_exists(self): "Flux": [1, 2, 1, 2, 5, 3, np.nan]}) with pytest.raises(AttributeError): - so = SoniSeries(new_data) + SoniSeries(new_data) def test_assert_flux_exists(self): @@ -82,7 +82,7 @@ def test_assert_flux_exists(self): "bar": [1, 2, 1, 2, 5, 3, np.nan]}) with pytest.raises(AttributeError): - so = SoniSeries(new_data) + SoniSeries(new_data) def test_default_parameters(self): assert self.soni_obj.note_duration == 0.5 From 0f7cab6809c03bfa7b10b94b985142f7b8a2d433 Mon Sep 17 00:00:00 2001 From: "C. E. Brasseur" Date: Fri, 16 Dec 2022 19:24:57 +0100 Subject: [PATCH 5/5] changing error messages slightly --- astronify/series/series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astronify/series/series.py b/astronify/series/series.py index d8c4ea2..98e737f 100644 --- a/astronify/series/series.py +++ b/astronify/series/series.py @@ -153,10 +153,10 @@ def data(self, data_table): if self.time_col not in data_table.columns: - raise AttributeError("Input Table must contain a column 'time'") + raise AttributeError(f"Input Table must contain time column '{self.time_col}'") if self.val_col not in data_table.columns: - raise AttributeError("Input Table must contain a column 'flux'") + raise AttributeError(f"Input Table must contain a value column '{self.val_col}'") # Removing any masked values as they interfere with the sonification if isinstance(data_table[self.val_col], MaskedColumn):