From 39057254f6f995f199bfb2ac1c1037a4deca850e Mon Sep 17 00:00:00 2001 From: Nschanche Date: Tue, 21 May 2024 11:30:05 -0400 Subject: [PATCH 01/14] initial restructuring --- src/lksearch/MASTSearch.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index e7aec38..3199540 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -327,11 +327,12 @@ def _searchtable_from_table( else: raise (ValueError("No Target or object table supplied")) - def _mask(self, mask): + def _downsize_table(self, ds_table): + #def _mask(self, mask): """Masks down the product and observation tables given an input mask, then returns them as a new Search object. deepcopy is used to preserve the class metadata stored in class variables""" new_MASTSearch = deepcopy(self) - new_MASTSearch.table = self.table[mask].reset_index() + new_MASTSearch.table = ds_table.reset_index() return new_MASTSearch From 189ba69f96dfc3a580abdbaa4c1f1706647ebcae Mon Sep 17 00:00:00 2001 From: Nschanche Date: Tue, 11 Jun 2024 16:18:36 -0400 Subject: [PATCH 02/14] added query_table and modified filter_table --- src/lksearch/MASTSearch.py | 122 ++++++++++++++++++++++++++++++++++--- src/lksearch/TESSSearch.py | 26 ++++---- tests/test_search.py | 7 +++ 3 files changed, 133 insertions(+), 22 deletions(-) diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index 3199540..f77d8f4 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -268,20 +268,28 @@ def _searchtable_from_target(self, target: Union[str, tuple[float], SkyCoord]): None - sets self.table equal to the masked/filtered joint table """ self._parse_input(target) - seq = self.search_sequence self.table = self._search( search_radius=self.search_radius, exptime=self.search_exptime, mission=self.search_mission, pipeline=self.search_pipeline, - sequence=seq, + sequence=self.search_sequence, ) - mask = self._filter( + + filetype = [ + "target pixel", + "lightcurve", + "dvreport", + ] + + mask = self.filter_table( exptime=self.search_exptime, mission=self.search_mission, pipeline=self.search_pipeline, sequence=self.search_sequence, + filetype=filetype, + inplace=True, ) # setting provenance_name=None will return HLSPs self.table = self.table[mask] @@ -327,12 +335,12 @@ def _searchtable_from_table( else: raise (ValueError("No Target or object table supplied")) - def _downsize_table(self, ds_table): - #def _mask(self, mask): + #def _downsize_table(self, ds_table): + def _mask(self, mask): """Masks down the product and observation tables given an input mask, then returns them as a new Search object. deepcopy is used to preserve the class metadata stored in class variables""" new_MASTSearch = deepcopy(self) - new_MASTSearch.table = ds_table.reset_index() + new_MASTSearch.table = self.table[mask].reset_index() return new_MASTSearch @@ -846,7 +854,7 @@ def _filter( allowed_ftype = ["lightcurve", "target pixel", "dvreport"] filter_ftype = [ - file.lower() for file in filetype if file.lower() in allowed_ftype + file.lower() for file in np.atleast_1d(filetype) if file.lower() in allowed_ftype ] # First filter on filetype @@ -919,25 +927,121 @@ def _mask_by_exptime(self, exptime: Union[int, tuple[float]]): mask = np.ones(len(exposures), dtype=bool) log.debug("invalid string input. No exptime filter applied") return mask + + def query_table( + self, + criteria: str, + inplace: bool = False, + **kwargs, + ): + ''' Filter the Search Result table using pandas query + https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html + + Parameters + ---------- + criteria : str + string containing criteria to filter table. Can handle multiple criteria, + e.g. "exptime>=100 and exptime<=500". + inplace : bool + if True, modify table in MASTSearch object directly. If False, returns a + new MASTSearch object with the resulting table + + Returns + ------- + MASTSearch : MASTSearch object + Only returned if inplace = False + ''' + filtered_table = self.table.query(criteria).reset_index() + if inplace: + self.table = filtered_table + else: + new_MASTSearch = deepcopy(self) + new_MASTSearch.table = filtered_table + return new_MASTSearch def filter_table( self, # Filter the table by keywords limit: int = None, - exptime: Union[int, float, tuple, type(None)] = None, + filetype: Union[str, list[str]] = None, + exptime: Union[int, float, tuple[float], type(None)] = None, + distance: Union[float, tuple[float]] = None, + year: Union[int, list[int], tuple[int]] = None, + description: Union[str, list[str]] = None, pipeline: Union[str, list[str]] = None, + sequence: Union[int, list[int]] = None, + inplace: bool = False, + **kwargs, ): + mask = np.ones(len(self.table), dtype=bool) + if not isinstance(filetype, type(None)): + allowed_ftype = ["lightcurve", "target pixel", "dvreport"] + filter_ftype = [ + file.lower() for file in np.atleast_1d(filetype) if file.lower() in allowed_ftype + ] + if len(filter_ftype) == 0: + filter_ftype = allowed_ftype + log.warning("Invalid filetype filtered. Returning all filetypes.") + + file_mask = mask.copy() + for ftype in filter_ftype: + file_mask |= self._mask_product_type(ftype) + mask = mask & file_mask + if exptime is not None: mask = mask & self._mask_by_exptime(exptime) + + if distance is not None: + if isinstance(distance, float): + mask = mask & self.table["distance"].query("distance <= @distance") + elif isinstance(distance, tuple): + mask = mask & self.table["distance"].query("(distance >= @distance[0]) & (distance <= @distance[1])") + else: + log.warning("Invalid input for `distance`, allowed inputs are float and tuple. Ignoring `distance` search parameter.") + + if year is not None: + if isinstance(year, str): + year = int(year) + if hasattr(year, "__iter__"): + year_type = type(year) + year = [int(y) for y in year] + year = year_type(year) + if isinstance(year, np.int_) or isinstance(year, int) or isinstance(year, list): + mask = mask & self.table["year"].isin(np.atleast_1d(year)) + elif isinstance(year, tuple): + mask = mask & self.table.query("year>=@year[0] & year<=@year[1]") + else: + log.warning("Invalid input for `year`, allowed inputs are str, int, and tuple. Ignoring `year` search parameter.") + if pipeline is not None: mask = mask & self.table["pipeline"].isin(np.atleast_1d(pipeline)) + + if description is not None: + if isinstance(description, str): + mask = mask & self.table["description"].str.lower().str.contains(description.lower()) + elif hasattr(description, "__iter__"): + for word in description: + mask = mask & self.table["description"].str.lower().str.contains(word) + else: + log.warning("Invalid input for `description`, allowed inputs are str and list[str]. Ignoring `description` search parameter.") + + if not isinstance(sequence, type(None)): + sequence_mask = mask.copy() + for s in np.atleast_1d(sequence).tolist(): + sequence_mask |= self.table.sequence_number == s + mask = mask & sequence_mask + if limit is not None: cusu = np.cumsum(mask) if max(cusu) > limit: mask = mask & (cusu <= limit) - return self._mask(mask) + + if (inplace): + self.table = self.table[mask].reset_index() + else: + return self._mask(mask) @suppress_stdout def _download_one( diff --git a/src/lksearch/TESSSearch.py b/src/lksearch/TESSSearch.py index ee5eed1..7c73441 100644 --- a/src/lksearch/TESSSearch.py +++ b/src/lksearch/TESSSearch.py @@ -392,6 +392,8 @@ def filter_table( exptime: Union[int, float, tuple, type(None)] = None, pipeline: Union[str, list[str]] = None, sector: Union[int, list[int]] = None, + inplace = False, + **kwargs ): """ Filters the search result table by specified parameters @@ -411,19 +413,17 @@ def filter_table( ------- TESSSearch object with updated table """ - mask = np.ones(len(self.table), dtype=bool) - - if exptime is not None: - mask = mask & self._mask_by_exptime(exptime) - if pipeline is not None: - mask = mask & self.table["pipeline"].isin(np.atleast_1d(pipeline)) - if sector is not None: - mask = mask & self.table["sequence_number"].isin(np.atleast_1d(sector)) - if limit is not None: - cusu = np.cumsum(mask) - if max(cusu) > limit: - mask = mask & (cusu <= limit) - return self._mask(mask) + return super().filter_table( + limit = limit + filetype = filetype + exptime = exptime + distance = distance + year = year + description = description + pipeline = pipeline + sequence = sector + inplace = inplace + ) def download( self, diff --git a/tests/test_search.py b/tests/test_search.py index 9a0863a..3f00b57 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -442,3 +442,10 @@ def test_tesscut(): assert len(results.cubedata) == 3 manifest = results.cubedata[2].download() assert len(manifest) == 1 + + +'''def test_filter(): + """Can we properly filter the data""" + + results = TESSSearch("Kepler 16b") + filtered = results.filter_table(sector=14)''' \ No newline at end of file From 97b648b4205130a84aee6710c19a0354e897ba74 Mon Sep 17 00:00:00 2001 From: Nschanche Date: Tue, 11 Jun 2024 16:47:39 -0400 Subject: [PATCH 03/14] removed mask in searchtable_from_target --- src/lksearch/MASTSearch.py | 11 ++++++++--- src/lksearch/TESSSearch.py | 30 ++++++++++++++++++------------ tests/test_search.py | 7 +++++-- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index f77d8f4..6258963 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -111,7 +111,7 @@ def __init__( if isinstance(table, type(None)): self._searchtable_from_target(target) - self.table = self._update_table(self.table) + #self.table = self._update_table(self.table) self.table = self._fix_table_times(self.table) # If MAST search tables are provided, another MAST search is not necessary @@ -276,6 +276,7 @@ def _searchtable_from_target(self, target: Union[str, tuple[float], SkyCoord]): pipeline=self.search_pipeline, sequence=self.search_sequence, ) + self.table = self._update_table(self.table) filetype = [ "target pixel", @@ -292,7 +293,7 @@ def _searchtable_from_target(self, target: Union[str, tuple[float], SkyCoord]): inplace=True, ) # setting provenance_name=None will return HLSPs - self.table = self.table[mask] + #self.table = self.table[mask] def _searchtable_from_table( self, @@ -970,9 +971,10 @@ def filter_table( description: Union[str, list[str]] = None, pipeline: Union[str, list[str]] = None, sequence: Union[int, list[int]] = None, + mission: Union[str, list[str]] = None, inplace: bool = False, - **kwargs, ): + mask = np.ones(len(self.table), dtype=bool) @@ -1033,6 +1035,9 @@ def filter_table( sequence_mask |= self.table.sequence_number == s mask = mask & sequence_mask + if mission is not None: + mask = mask & self.table["mission"].isin(np.atleast_1d(mission)) + if limit is not None: cusu = np.cumsum(mask) if max(cusu) > limit: diff --git a/src/lksearch/TESSSearch.py b/src/lksearch/TESSSearch.py index 7c73441..da88978 100644 --- a/src/lksearch/TESSSearch.py +++ b/src/lksearch/TESSSearch.py @@ -389,11 +389,16 @@ def search_individual_ffi( def filter_table( self, limit: int = None, - exptime: Union[int, float, tuple, type(None)] = None, + filetype: Union[str, list[str]] = None, + exptime: Union[int, float, tuple[float], type(None)] = None, + distance: Union[float, tuple[float]] = None, + year: Union[int, list[int], tuple[int]] = None, + description: Union[str, list[str]] = None, pipeline: Union[str, list[str]] = None, sector: Union[int, list[int]] = None, - inplace = False, - **kwargs + mission: Union[str, list[str]] = None, + #sequence = None, + inplace: bool = False, ): """ Filters the search result table by specified parameters @@ -413,16 +418,17 @@ def filter_table( ------- TESSSearch object with updated table """ + return super().filter_table( - limit = limit - filetype = filetype - exptime = exptime - distance = distance - year = year - description = description - pipeline = pipeline - sequence = sector - inplace = inplace + limit = limit, + filetype = filetype, + exptime = exptime, + distance = distance, + year = year, + description = description, + pipeline = pipeline, + sequence = sector, + inplace = inplace, ) def download( diff --git a/tests/test_search.py b/tests/test_search.py index 3f00b57..8b49908 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -444,8 +444,11 @@ def test_tesscut(): assert len(manifest) == 1 -'''def test_filter(): +def test_filter(): """Can we properly filter the data""" results = TESSSearch("Kepler 16b") - filtered = results.filter_table(sector=14)''' \ No newline at end of file + filtered = results.filter_table(sector=14) + queried = results.filter_table("sector == 14") + assert len(filtered) == len(queried) + \ No newline at end of file From cdf728131b3fd65d02345ac8737e7218c734bd01 Mon Sep 17 00:00:00 2001 From: Daniel Giles Date: Wed, 12 Jun 2024 09:50:29 -0400 Subject: [PATCH 04/14] fixed issue in filter_table, changed query to eval --- docs/tutorials/Example_searches.ipynb | 8 ++++---- src/lksearch/MASTSearch.py | 7 +++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/tutorials/Example_searches.ipynb b/docs/tutorials/Example_searches.ipynb index a35e110..3c39736 100644 --- a/docs/tutorials/Example_searches.ipynb +++ b/docs/tutorials/Example_searches.ipynb @@ -15,7 +15,7 @@ "metadata": {}, "outputs": [], "source": [ - "from tssc import MASTSearch, KeplerSearch, K2Search, TESSSearch" + "from lksearch import MASTSearch, KeplerSearch, K2Search, TESSSearch" ] }, { @@ -4132,9 +4132,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "lksearch312", "language": "python", - "name": "python3" + "name": "lksearch312" }, "language_info": { "codemirror_mode": { @@ -4146,7 +4146,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.2" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index 6258963..9f19e52 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -975,7 +975,6 @@ def filter_table( inplace: bool = False, ): - mask = np.ones(len(self.table), dtype=bool) if not isinstance(filetype, type(None)): @@ -997,9 +996,9 @@ def filter_table( if distance is not None: if isinstance(distance, float): - mask = mask & self.table["distance"].query("distance <= @distance") + mask = mask & self.table["distance"].eval("distance <= @distance") elif isinstance(distance, tuple): - mask = mask & self.table["distance"].query("(distance >= @distance[0]) & (distance <= @distance[1])") + mask = mask & self.table["distance"].eval("(distance >= @distance[0]) & (distance <= @distance[1])") else: log.warning("Invalid input for `distance`, allowed inputs are float and tuple. Ignoring `distance` search parameter.") @@ -1013,7 +1012,7 @@ def filter_table( if isinstance(year, np.int_) or isinstance(year, int) or isinstance(year, list): mask = mask & self.table["year"].isin(np.atleast_1d(year)) elif isinstance(year, tuple): - mask = mask & self.table.query("year>=@year[0] & year<=@year[1]") + mask = mask & self.table.eval("year>=@year[0] & year<=@year[1]") else: log.warning("Invalid input for `year`, allowed inputs are str, int, and tuple. Ignoring `year` search parameter.") From 318e098cc873b287af4db74d301dc1b932f40c6b Mon Sep 17 00:00:00 2001 From: Daniel Giles Date: Wed, 12 Jun 2024 13:50:23 -0400 Subject: [PATCH 05/14] added tests --- src/lksearch/MASTSearch.py | 40 ++++++++++++++++++++++++--------- tests/test_search.py | 46 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 11 deletions(-) diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index 9f19e52..c83bada 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -118,6 +118,10 @@ def __init__( else: self._searchtable_from_table(table, obs_table, prod_table) + for col in self.table.columns: + if not hasattr(self, col): + setattr(self, col, self.table[col]) + def __len__(self): """Returns the number of products in the SearchResult table.""" return len(self.table) @@ -927,6 +931,11 @@ def _mask_by_exptime(self, exptime: Union[int, tuple[float]]): else: mask = np.ones(len(exposures), dtype=bool) log.debug("invalid string input. No exptime filter applied") + elif isinstance(exptime, list): + mask = np.zeros(len(exposures), dtype=bool) + for et in exptime: + mask = mask | (exposures == et) + return mask def query_table( @@ -963,6 +972,7 @@ def query_table( def filter_table( self, # Filter the table by keywords + target_name: Union[str, list[str]] = None, limit: int = None, filetype: Union[str, list[str]] = None, exptime: Union[int, float, tuple[float], type(None)] = None, @@ -976,7 +986,9 @@ def filter_table( ): mask = np.ones(len(self.table), dtype=bool) - + if target_name is not None: + target_name = np.atleast_1d(target_name).astype(str) + mask = mask & self.table['target_name'].isin(target_name) if not isinstance(filetype, type(None)): allowed_ftype = ["lightcurve", "target pixel", "dvreport"] filter_ftype = [ @@ -996,9 +1008,9 @@ def filter_table( if distance is not None: if isinstance(distance, float): - mask = mask & self.table["distance"].eval("distance <= @distance") + mask = mask & self.table.eval("distance <= @distance") elif isinstance(distance, tuple): - mask = mask & self.table["distance"].eval("(distance >= @distance[0]) & (distance <= @distance[1])") + mask = mask & self.table.eval("(distance >= @distance[0]) & (distance <= @distance[1])") else: log.warning("Invalid input for `distance`, allowed inputs are float and tuple. Ignoring `distance` search parameter.") @@ -1017,25 +1029,31 @@ def filter_table( log.warning("Invalid input for `year`, allowed inputs are str, int, and tuple. Ignoring `year` search parameter.") if pipeline is not None: - mask = mask & self.table["pipeline"].isin(np.atleast_1d(pipeline)) + pipeline = list(map(str.lower, np.atleast_1d(pipeline))) + mask = mask & self.table["pipeline"].str.lower().isin(pipeline) if description is not None: if isinstance(description, str): mask = mask & self.table["description"].str.lower().str.contains(description.lower()) + elif isinstance(description, tuple): + # Looks for descriptions which contain *all* of the given keywords + for word in description: + mask = mask & self.table["description"].str.lower().str.contains(word.lower()) elif hasattr(description, "__iter__"): + # Looks for descriptions which contain *any* of the given keywords + desc_mask = np.zeros(len(self.table), dtype=bool) for word in description: - mask = mask & self.table["description"].str.lower().str.contains(word) + desc_mask = desc_mask | self.table["description"].str.lower().str.contains(word.lower()) + mask = mask & desc_mask else: log.warning("Invalid input for `description`, allowed inputs are str and list[str]. Ignoring `description` search parameter.") - if not isinstance(sequence, type(None)): - sequence_mask = mask.copy() - for s in np.atleast_1d(sequence).tolist(): - sequence_mask |= self.table.sequence_number == s - mask = mask & sequence_mask + if sequence is not None): + mask = mask & self.table.sequence_number.isin(np.atleast_1d(s)) if mission is not None: - mask = mask & self.table["mission"].isin(np.atleast_1d(mission)) + mission = list(map(str.lower, np.atleast_1d(mission))) + mask = mask & self.table["mission"].str.lower().isin(mission) if limit is not None: cusu = np.cumsum(mask) diff --git a/tests/test_search.py b/tests/test_search.py index 8b49908..31e117e 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -443,6 +443,52 @@ def test_tesscut(): manifest = results.cubedata[2].download() assert len(manifest) == 1 +@pytest.mark.parametrize("target_name", (None, 0, 299096355, "kplr012644769", [299096355, "kplr012644769"], [299096355, "299096355"])) +@pytest.mark.parametrize("limit", (None, 0, 10, 1000)) +@pytest.mark.parametrize("filetype", (None, 0, "lightcurve")) +@pytest.mark.parametrize("exptime", (None, 0, 20, 20.0, [0, 20], [20, 60.0], (0, 100), "fast", "short", "long", "shortest", "longest")) +@pytest.mark.parametrize("distance", (None, 0, 0.2, (0.2, 0.4))) +@pytest.mark.parametrize("year", (None, 0, 2013, (2000, 2020), [2013, 2019])) +@pytest.mark.parametrize("description", (None, 0, "data", ["TPS", "report"], ("TPS", "report"))) +@pytest.mark.parametrize("pipeline", (None, 0, "Kepler", "spoc", ["kepler", "spoc"])) +@pytest.mark.parametrize("sequence", (None, 0, 14, [14, 15])) +@pytest.mark.parametrize("mission", (None, 0, "Kepler", "Tess", ["Kepler", "Tess"])) +def test_mastsearch_filter(target_name, limit, filetype, exptime, distance, year, description, pipeline, sequence, mission): + results = MASTSearch("Kepler 16b") + filter_results = results.filter_table(target_name=target_name, + limit=limit, + filetype=filetype, + exptime=exptime, + distance=distance, + year=year, + description=description, + pipeline=pipeline, + sequence=sequence, + mission=mission) + # from pandas.testing import assert_frame_equal + + # assert results.table.shape == (220, 61), "Test search result returned unexpected size." + # ft = results.filter_table + # assert ft(target_name=0).table.shape == (0, 62), "Null filter_table test returned unexpected size." + # ft_tn = ft(target_name="299096355") + # assert ft_tn.table.shape == (125, 62), "filter_table on target_name returned unexpected size." + + # def frame_assertion(ft1, ft2, msg): + # try: + # assert_frame_equal(ft1.table, ft2.table) + # except AssertionError: + # raise(AssertionError(msg)) + # frame_assertion(ft_tn, ft(target_name=299096355), "Problem parsing target name of type `int`.") + # frame_assertion(ft_tn, ft(target_name=[299096355]), "Problem parsing list[int] target names") + # frame_assertion(ft_tn, ft(target_name=["299096355"]), "Problem parsing list[str] target names") + + # assert ft(target_name="kplr012644769").table.shape == (95, 62), "Filter table on target_name returned unexpected size." + # ft_tn = ft(target_name=["299096355", "kplr012644769"]) + # assert ft_tn.table.shape == (220, 62), "Filter table on target_name returned unexpected size." + # frame_assertion(ft_tn, ft(target_name=[299096355, "kplr012644769"]), "Problem parsing list[mixed] target names") + # assert ft(target_name=[0, "299096355"]).shape == (125, 62), "filter_table on target_name with valid and invalid keys returned unexpected size." + # assert ft(target_name=[299096355, "299096355"]).shape == (125, 62), "filter_table on target_name with duplicate keys returned unexpected size." + def test_filter(): """Can we properly filter the data""" From 444fbd0f882735fd7baaaa9723c47ec55c09da64 Mon Sep 17 00:00:00 2001 From: Daniel Giles Date: Wed, 12 Jun 2024 17:24:16 -0400 Subject: [PATCH 06/14] Updating filter_table in all Search objects which wrap the base _filter method. Added tests for the filter_table methods. Co-authored-by: Pritchard, Tyler A. (GSFC-667.0)[UNIV OF MARYLAND COLLEGE PARK] Co-authored-by: Schanche, Nicole E. (GSFC-667.0)[UNIV OF MARYLAND COLLEGE PARK] --- src/lksearch/K2Search.py | 68 +++++-- src/lksearch/KeplerSearch.py | 61 +++++-- src/lksearch/MASTSearch.py | 341 +++++++++++++++++++---------------- src/lksearch/TESSSearch.py | 82 ++++++--- tests/test_search.py | 97 +++++----- 5 files changed, 383 insertions(+), 266 deletions(-) diff --git a/src/lksearch/K2Search.py b/src/lksearch/K2Search.py index 0c257b8..6040095 100644 --- a/src/lksearch/K2Search.py +++ b/src/lksearch/K2Search.py @@ -154,39 +154,69 @@ def _sort_K2(self): def filter_table( self, - limit: int = None, - exptime: Union[int, float, tuple, type(None)] = None, + target_name: Union[str, list[str]] = None, pipeline: Union[str, list[str]] = None, + mission: Union[str, list[str]] = None, + exptime: Union[int, float, tuple[float]] = None, + distance: Union[float, tuple[float]] = None, + year: Union[int, list[int], tuple[int]] = None, + description: Union[str, list[str]] = None, + filetype: Union[str, list[str]] = None, campaign: Union[int, list] = None, + limit: int = None, + inplace=False, + **kwargs ): """ Filters the search result table by specified parameters Parameters ---------- - limit : int, optional - limit to the number of results, by default None - exptime : Union[int, float, tuple, type, optional - exposure times to filter by, by default None - pipeline : Union[str, list[str]], optional - pipeline used for data reduction, by default None + target_name : str, optional + Name of targets. A list will look for multiple target names. + pipeline : str or list[str]], optional + Data pipeline. A list will look for multiple pipelines. + mission : str or list[str]], optional + Mission. A list will look for muliple missions. + exptime : int or float, tuple[float]], optional + Exposure Time. A tuple will look for a range of times. + distance : float or tuple[float]], optional + Distance. A float searches for products with a distance less than the value given, + a tuple will search between the given values. + year : int or list[int], tuple[int]], optional + Year. A list will look for multiple years, a tuple will look in the range of years. + description : str or list[str]], optional + Description of product. A list will look for descriptions containing any keywords given, + a tuple will look for descriptions containing all the keywords. + filetype : str or list[str]], optional + Type of product. A list will look for multiple filetypes. campaign : Optional[int], optional - K2 observing campaign(s), by default None + K2 observing campaign, by default None + limit : int, optional + how many rows to return, by default None + inplace : bool, optional + whether to modify the KeplerSearch inplace, by default False Returns ------- - K2Search object with updated table. + K2Search object with updated table or None if `inplace==True` """ - mask = np.ones(len(self.table), dtype=bool) - - if exptime is not None: - mask = mask & self._mask_by_exptime(exptime) - if pipeline is not None: - mask = mask & self.table["pipeline"].isin(np.atleast_1d(pipeline)) - if campaign is not None: - mask = mask & self.table["sequence_number"].isin(np.atleast_1d(campaign)) + mask = self._filter( + target_name = target_name, + filetype = filetype, + exptime = exptime, + distance = distance, + year = year, + description = description, + pipeline = pipeline, + mission = mission, + sequence_number=campaign + ) if limit is not None: cusu = np.cumsum(mask) if max(cusu) > limit: mask = mask & (cusu <= limit) - return self._mask(mask) + if inplace: + self.table = self.table[mask].reset_index() + else: + return self._mask(mask) \ No newline at end of file diff --git a/src/lksearch/KeplerSearch.py b/src/lksearch/KeplerSearch.py index e53716f..e6a6ff2 100644 --- a/src/lksearch/KeplerSearch.py +++ b/src/lksearch/KeplerSearch.py @@ -238,42 +238,75 @@ def _sort_Kepler(self): def filter_table( self, - limit: int = None, - exptime: Union[int, float, tuple, type(None)] = None, + target_name: Union[str, list[str]] = None, pipeline: Union[str, list[str]] = None, + mission: Union[str, list[str]] = None, + exptime: Union[int, float, tuple[float]] = None, + distance: Union[float, tuple[float]] = None, + year: Union[int, list[int], tuple[int]] = None, + description: Union[str, list[str]] = None, + filetype: Union[str, list[str]] = None, + limit: int = None, + inplace=False, quarter: Optional[int] = None, month: Optional[int] = None, + **kwargs ): """ Filters the search result table by specified parameters Parameters ---------- - limit : int, optional - limit to the number of results, by default None - exptime : Union[int, float, tuple, type, optional - exposure times to filter by, by default None - pipeline : Union[str, list[str]], optional - pipeline used for data reduction, by default None + target_name : str, optional + Name of targets. A list will look for multiple target names. + pipeline : str or list[str]], optional + Data pipeline. A list will look for multiple pipelines. + mission : str or list[str]], optional + Mission. A list will look for muliple missions. + exptime : int or float, tuple[float]], optional + Exposure Time. A tuple will look for a range of times. + distance : float or tuple[float]], optional + Distance. A float searches for products with a distance less than the value given, + a tuple will search between the given values. + year : int or list[int], tuple[int]], optional + Year. A list will look for multiple years, a tuple will look in the range of years. + description : str or list[str]], optional + Description of product. A list will look for descriptions containing any keywords given, + a tuple will look for descriptions containing all the keywords. + filetype : str or list[str]], optional + Type of product. A list will look for multiple filetypes. quarter : Optional[int], optional Kepler observing quarter, by default None month : Optional[int], optional Kepler observing month, by default None + limit : int, optional + how many rows to return, by default None + inplace : bool, optional + whether to modify the KeplerSearch inplace, by default False Returns ------- - KeplerSearch object with updated table. + KeplerSearch object with updated table or None if `inplace==True` """ mask = np.ones(len(self.table), dtype=bool) + mask = self._filter( + target_name = target_name, + filetype = filetype, + exptime = exptime, + distance = distance, + year = year, + description = description, + pipeline = pipeline, + mission = mission, + ) - if exptime is not None: - mask = mask & self._mask_by_exptime(exptime) - if pipeline is not None: - mask = mask & self.table["pipeline"].isin(np.atleast_1d(pipeline)) if (quarter is not None) | (month is not None): mask = mask & self._filter_kepler(quarter=quarter, month=month) if limit is not None: cusu = np.cumsum(mask) if max(cusu) > limit: mask = mask & (cusu <= limit) - return self._mask(mask) + if inplace: + self.table = self.table[mask].reset_index() + else: + return self._mask(mask) \ No newline at end of file diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index c83bada..6f4c132 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -111,7 +111,6 @@ def __init__( if isinstance(table, type(None)): self._searchtable_from_target(target) - #self.table = self._update_table(self.table) self.table = self._fix_table_times(self.table) # If MAST search tables are provided, another MAST search is not necessary @@ -120,7 +119,7 @@ def __init__( for col in self.table.columns: if not hasattr(self, col): - setattr(self, col, self.table[col]) + setattr(self, col, self.table[col]) def __len__(self): """Returns the number of products in the SearchResult table.""" @@ -281,23 +280,21 @@ def _searchtable_from_target(self, target: Union[str, tuple[float], SkyCoord]): sequence=self.search_sequence, ) self.table = self._update_table(self.table) - + filetype = [ "target pixel", "lightcurve", "dvreport", ] - mask = self.filter_table( + mask = self._filter( exptime=self.search_exptime, mission=self.search_mission, pipeline=self.search_pipeline, - sequence=self.search_sequence, + sequence_number=self.search_sequence, filetype=filetype, - inplace=True, ) # setting provenance_name=None will return HLSPs - - #self.table = self.table[mask] + self.table = self.table[mask].reset_index(drop=True) def _searchtable_from_table( self, @@ -340,7 +337,7 @@ def _searchtable_from_table( else: raise (ValueError("No Target or object table supplied")) - #def _downsize_table(self, ds_table): + # def _downsize_table(self, ds_table): def _mask(self, mask): """Masks down the product and observation tables given an input mask, then returns them as a new Search object. deepcopy is used to preserve the class metadata stored in class variables""" @@ -808,102 +805,6 @@ def _mask_product_type( mask |= self.table.productFilename.str.endswith(value) return mask - def _filter( - self, - exptime: Union[str, int, tuple[int], type(None)] = (0, 9999), - mission: Union[str, list[str]] = ["Kepler", "K2", "TESS"], - pipeline: Union[str, list[str]] = ["kepler", "k2", "spoc"], - filetype: Union[str, list[str]] = [ - "target pixel", - "lightcurve", - "dvreport", - ], - sequence: Union[int, list[int]] = None, - ) -> pd.DataFrame: - """filter self.table based on your product search preferences - - Parameters - ---------- - exptime : Union[str, int, tuple[int], type, optional - exposure time of data products to search, by default (0, 9999) - project : Union[str, list[str]], optional - mission project to search, by default ["Kepler", "K2", "TESS"] - pipeline : Union[str, list[str]], optional - pipeline provinence to search for data from, by default ["kepler", "k2", "spoc"] - filetype : Union[str, list[str]], optional - file types to search for, by default [ "target pixel", "lightcurve", "dvreport", ] - sequence : Union[int, list[int]], optional - sequence number to filter by. Corresponds to sector for TESS, campaign for K2, and quarter for Kepler - Returns - ------- - mask - cumulative boolean mask for self.table based off of - the product of individual filter properties - """ - - """ Modify this so that it can choose what types of products to keep? - Since this will be used by mission specific search we want this to filter: - Filetype - ExposureTime/cadence - Pipe(Provenance)/Project - e.g. (SPOC/TESSSpoc) - this will be in mission specific search - """ - - self.search_exptime = exptime - mask = np.zeros(len(self.table), dtype=bool) - - # First filter on filetype - file_mask = mask.copy() - - # This is the list of allowed filetypes we can interact with - allowed_ftype = ["lightcurve", "target pixel", "dvreport"] - - filter_ftype = [ - file.lower() for file in np.atleast_1d(filetype) if file.lower() in allowed_ftype - ] - # First filter on filetype - - if len(filter_ftype) == 0: - filter_ftype = allowed_ftype - log.warning("Invalid filetype filtered. Returning all data.") - - file_mask = mask.copy() - for ftype in filter_ftype: - file_mask |= self._mask_product_type(ftype) - - # Next Filter on mission - mission_mask = mask.copy() - if not isinstance(mission_mask, type(None)): - for m in mission: - mission_mask |= self.table.project_obs.values == m - else: - mission_mask = np.logical_not(mission_mask) - - # Next Filter on pipeline (provenance_name in mast table) - provenance_mask = mask.copy() - if not isinstance(pipeline, type(None)): - for a in np.atleast_1d(pipeline).tolist(): - provenance_mask |= self.table.provenance_name.str.lower() == a.lower() - else: - provenance_mask = np.logical_not(provenance_mask) - - # Filter by cadence - if not isinstance(exptime, type(None)): - exptime_mask = self._mask_by_exptime(exptime) - else: - exptime_mask = not mask - - # Filter by sequence - sequence_mask = mask.copy() - if not isinstance(sequence, type(None)): - for s in np.atleast_1d(sequence).tolist(): - sequence_mask |= self.table.sequence_number == s - else: - sequence_mask = np.logical_not(sequence_mask) - - mask = file_mask & mission_mask & provenance_mask & exptime_mask & sequence_mask - return mask - def _mask_by_exptime(self, exptime: Union[int, tuple[float]]): """Helper function to filter by exposure time. Returns a boolean array""" @@ -935,32 +836,32 @@ def _mask_by_exptime(self, exptime: Union[int, tuple[float]]): mask = np.zeros(len(exposures), dtype=bool) for et in exptime: mask = mask | (exposures == et) - + return mask - + def query_table( - self, - criteria: str, - inplace: bool = False, - **kwargs, - ): - ''' Filter the Search Result table using pandas query - https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html - - Parameters - ---------- - criteria : str - string containing criteria to filter table. Can handle multiple criteria, - e.g. "exptime>=100 and exptime<=500". - inplace : bool - if True, modify table in MASTSearch object directly. If False, returns a - new MASTSearch object with the resulting table - - Returns - ------- - MASTSearch : MASTSearch object - Only returned if inplace = False - ''' + self, + criteria: str, + inplace: bool = False, + **kwargs, + ): + """Filter the Search Result table using pandas query + https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html + + Parameters + ---------- + criteria : str + string containing criteria to filter table. Can handle multiple criteria, + e.g. "exptime>=100 and exptime<=500". + inplace : bool + if True, modify table in MASTSearch object directly. If False, returns a + new MASTSearch object with the resulting table + + Returns + ------- + MASTSearch : MASTSearch object + Only returned if inplace = False + """ filtered_table = self.table.query(criteria).reset_index() if inplace: self.table = filtered_table @@ -969,36 +870,75 @@ def query_table( new_MASTSearch.table = filtered_table return new_MASTSearch - def filter_table( + def _filter( self, - # Filter the table by keywords target_name: Union[str, list[str]] = None, - limit: int = None, - filetype: Union[str, list[str]] = None, - exptime: Union[int, float, tuple[float], type(None)] = None, - distance: Union[float, tuple[float]] = None, - year: Union[int, list[int], tuple[int]] = None, - description: Union[str, list[str]] = None, pipeline: Union[str, list[str]] = None, - sequence: Union[int, list[int]] = None, mission: Union[str, list[str]] = None, - inplace: bool = False, + exptime: Union[int, float, tuple[float]] = None, + distance: Union[float, tuple[float]] = None, + year: Union[int, list[int], tuple[int]] = None, + description: Union[str, list[str], tuple[str]] = None, + filetype: Union[str, list[str]] = None, + sequence_number: Union[int, list[int]] = None, ): - + """filter self.table based on your product search preferences + + Parameters + ---------- + target_name : str, optional + Name of targets. + pipeline : str or list[str]], optional + Pipeline provenance to search for data from. + mission : str or list[str], optional + Mission projects to search, options are "Kepler", "K2", and "TESS". + exptime : int or float, tuple[float]], optional + Exposure time of data products to search. + An int, float, or list will look for exact matches, + a tuple will look for a range of times, + and string values "fast", "short", "long", "shortest", and "longest" + will match the appropriate exposure times. + distance : float or tuple[float]], optional + Distance from given search target to get data products. + A float searches for products within the given distance, + a tuple searches between the given values. + year : int or list[int], tuple[int], optional + Year of creation. + A list will look for all years given, + a tuple will look in the range of years given. + description : str or list[str], optional + Key words to search for in the description of the data product. + A list will look for descriptions containing any keywords given, + a tuple will look for descriptions containing all the keywords. + filetype : str or list[str], optional + file types to search for, options are "target pixel", "lightcurve", "dvreport". + sequence_number : int or list[int]], optional + Sequence number to filter by. Corresponds to sector for TESS, campaign for K2, and quarter for Kepler. + + Returns + ------- + mask : np.ndarray + cumulative boolean mask for self.table based off of + the product of individual filter properties + """ + mask = np.ones(len(self.table), dtype=bool) if target_name is not None: target_name = np.atleast_1d(target_name).astype(str) - mask = mask & self.table['target_name'].isin(target_name) + mask = mask & self.table["target_name"].isin(target_name) + if not isinstance(filetype, type(None)): allowed_ftype = ["lightcurve", "target pixel", "dvreport"] filter_ftype = [ - file.lower() for file in np.atleast_1d(filetype) if file.lower() in allowed_ftype - ] + file.lower() + for file in np.atleast_1d(filetype) + if file.lower() in allowed_ftype + ] if len(filter_ftype) == 0: filter_ftype = allowed_ftype log.warning("Invalid filetype filtered. Returning all filetypes.") - file_mask = mask.copy() + file_mask = np.zeros(len(self.table), dtype=bool) for ftype in filter_ftype: file_mask |= self._mask_product_type(ftype) mask = mask & file_mask @@ -1010,9 +950,13 @@ def filter_table( if isinstance(distance, float): mask = mask & self.table.eval("distance <= @distance") elif isinstance(distance, tuple): - mask = mask & self.table.eval("(distance >= @distance[0]) & (distance <= @distance[1])") + mask = mask & self.table.eval( + "(distance >= @distance[0]) & (distance <= @distance[1])" + ) else: - log.warning("Invalid input for `distance`, allowed inputs are float and tuple. Ignoring `distance` search parameter.") + log.warning( + "Invalid input for `distance`, allowed inputs are float and tuple. Ignoring `distance` search parameter." + ) if year is not None: if isinstance(year, str): @@ -1021,46 +965,127 @@ def filter_table( year_type = type(year) year = [int(y) for y in year] year = year_type(year) - if isinstance(year, np.int_) or isinstance(year, int) or isinstance(year, list): + if ( + isinstance(year, np.int_) + or isinstance(year, int) + or isinstance(year, list) + ): mask = mask & self.table["year"].isin(np.atleast_1d(year)) elif isinstance(year, tuple): mask = mask & self.table.eval("year>=@year[0] & year<=@year[1]") else: - log.warning("Invalid input for `year`, allowed inputs are str, int, and tuple. Ignoring `year` search parameter.") - + log.warning( + "Invalid input for `year`, allowed inputs are str, int, and tuple. Ignoring `year` search parameter." + ) + if pipeline is not None: pipeline = list(map(str.lower, np.atleast_1d(pipeline))) mask = mask & self.table["pipeline"].str.lower().isin(pipeline) - + if description is not None: if isinstance(description, str): - mask = mask & self.table["description"].str.lower().str.contains(description.lower()) + mask = mask & self.table["description"].str.lower().str.contains( + description.lower() + ) elif isinstance(description, tuple): # Looks for descriptions which contain *all* of the given keywords for word in description: - mask = mask & self.table["description"].str.lower().str.contains(word.lower()) + mask = mask & self.table["description"].str.lower().str.contains( + word.lower() + ) elif hasattr(description, "__iter__"): # Looks for descriptions which contain *any* of the given keywords desc_mask = np.zeros(len(self.table), dtype=bool) for word in description: - desc_mask = desc_mask | self.table["description"].str.lower().str.contains(word.lower()) + desc_mask = desc_mask | self.table[ + "description" + ].str.lower().str.contains(word.lower()) mask = mask & desc_mask else: - log.warning("Invalid input for `description`, allowed inputs are str and list[str]. Ignoring `description` search parameter.") + log.warning( + "Invalid input for `description`, allowed inputs are str and list[str]. Ignoring `description` search parameter." + ) - if sequence is not None): - mask = mask & self.table.sequence_number.isin(np.atleast_1d(s)) + if sequence_number is not None: + mask = mask & self.table.sequence_number.isin( + np.atleast_1d(sequence_number) + ) if mission is not None: mission = list(map(str.lower, np.atleast_1d(mission))) mask = mask & self.table["mission"].str.lower().isin(mission) + return mask + + def filter_table( + self, + target_name: Union[str, list[str]] = None, + pipeline: Union[str, list[str]] = None, + mission: Union[str, list[str]] = None, + exptime: Union[int, float, tuple[float]] = None, + distance: Union[float, tuple[float]] = None, + year: Union[int, list[int], tuple[int]] = None, + description: Union[str, list[str]] = None, + filetype: Union[str, list[str]] = None, + limit: int = None, + inplace=False, + **kwargs + ): + """Filter the search by keywords + + Parameters + ---------- + target_name : str, optional + Name of targets. A list will look for multiple target names. + pipeline : str or list[str]], optional + Data pipeline. A list will look for multiple pipelines. + mission : str or list[str]], optional + Mission. A list will look for muliple missions. + exptime : int or float, tuple[float]], optional + Exposure Time. A tuple will look for a range of times. + distance : float or tuple[float]], optional + Distance. A float searches for products with a distance less than the value given, + a tuple will search between the given values. + year : int or list[int], tuple[int]], optional + Year. A list will look for multiple years, a tuple will look in the range of years. + description : str or list[str]], optional + Description of product. A list will look for descriptions containing any keywords given, + a tuple will look for descriptions containing all the keywords. + filetype : str or list[str]], optional + Type of product. A list will look for multiple filetypes. + sequence : int or list[int]], optional + Sequence number refers to "quarter" for Kepler, "campaign" for K2, and "sector" for TESS. + limit : int, optional + _description_, by default None + inplace : bool, optional + _description_, by default False + + Returns + ------- + MASTSearch or None + Returns a filtered MASTSearch object or None if `inplace=True` + """ + if "sequence" in kwargs: + sequence = kwargs["sequence"] + + mask = self._filter( + target_name=target_name, + pipeline=pipeline, + mission=mission, + exptime=exptime, + distance=distance, + year=year, + description=description, + filetype=filetype, + sequence_number=sequence, + ) + if limit is not None: cusu = np.cumsum(mask) if max(cusu) > limit: mask = mask & (cusu <= limit) - - if (inplace): + + if inplace: self.table = self.table[mask].reset_index() else: return self._mask(mask) diff --git a/src/lksearch/TESSSearch.py b/src/lksearch/TESSSearch.py index da88978..852102f 100644 --- a/src/lksearch/TESSSearch.py +++ b/src/lksearch/TESSSearch.py @@ -388,48 +388,74 @@ def search_individual_ffi( def filter_table( self, - limit: int = None, - filetype: Union[str, list[str]] = None, - exptime: Union[int, float, tuple[float], type(None)] = None, + target_name: Union[str, list[str]] = None, + pipeline: Union[str, list[str]] = None, + mission: Union[str, list[str]] = None, + exptime: Union[int, float, tuple[float]] = None, distance: Union[float, tuple[float]] = None, year: Union[int, list[int], tuple[int]] = None, description: Union[str, list[str]] = None, - pipeline: Union[str, list[str]] = None, - sector: Union[int, list[int]] = None, - mission: Union[str, list[str]] = None, - #sequence = None, - inplace: bool = False, + filetype: Union[str, list[str]] = None, + limit: int = None, + inplace=False, + sector: Union[int, list[str]] = None, + **kwargs ): """ Filters the search result table by specified parameters Parameters ---------- - limit : int, optional - limit to the number of results, by default None - exptime : Union[int, float, tuple, type, optional - exposure times to filter by, by default None - pipeline : Union[str, list[str]], optional - pipeline used for data reduction, by default None + target_name : str, optional + Name of targets. A list will look for multiple target names. + pipeline : str or list[str]], optional + Data pipeline. A list will look for multiple pipelines. + mission : str or list[str]], optional + Mission. A list will look for muliple missions. + exptime : int or float, tuple[float]], optional + Exposure Time. A tuple will look for a range of times. + distance : float or tuple[float]], optional + Distance. A float searches for products with a distance less than the value given, + a tuple will search between the given values. + year : int or list[int], tuple[int]], optional + Year. A list will look for multiple years, a tuple will look in the range of years. + description : str or list[str]], optional + Description of product. A list will look for descriptions containing any keywords given, + a tuple will look for descriptions containing all the keywords. + filetype : str or list[str]], optional + Type of product. A list will look for multiple filetypes. sector : Optional[int], optional - TESS observing sector(s), by default None + TESS observing sector, by default None + limit : int, optional + how many rows to return, by default None + inplace : bool, optional + whether to modify the KeplerSearch inplace, by default False Returns ------- - TESSSearch object with updated table + TESSSearch object with updated table or None if `inplace==True` """ - - return super().filter_table( - limit = limit, - filetype = filetype, - exptime = exptime, - distance = distance, - year = year, - description = description, - pipeline = pipeline, - sequence = sector, - inplace = inplace, - ) + mask = self._filter( + target_name=target_name, + filetype=filetype, + exptime=exptime, + distance=distance, + year=year, + description=description, + pipeline=pipeline, + sequence_number=sector, + mission=mission, + ) + + if limit is not None: + cusu = np.cumsum(mask) + if max(cusu) > limit: + mask = mask & (cusu <= limit) + + if inplace: + self.table = self.table[mask].reset_index() + else: + return self._mask(mask) def download( self, diff --git a/tests/test_search.py b/tests/test_search.py index 31e117e..ae16872 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -426,8 +426,8 @@ def test_split_k2_campaigns(): assert search_c11.table["campaign"][1] == "11b" -def test_tesscut(): - """Can we find TESS tesscut tpfs""" +def test_FFI_retrieval(): + """Can we find TESS individual FFI's""" target = "Kepler 16b" assert ( len(TESSSearch("Kepler 16b").search_individual_ffi(58682, 58710, sector=14)) @@ -443,52 +443,55 @@ def test_tesscut(): manifest = results.cubedata[2].download() assert len(manifest) == 1 -@pytest.mark.parametrize("target_name", (None, 0, 299096355, "kplr012644769", [299096355, "kplr012644769"], [299096355, "299096355"])) -@pytest.mark.parametrize("limit", (None, 0, 10, 1000)) -@pytest.mark.parametrize("filetype", (None, 0, "lightcurve")) -@pytest.mark.parametrize("exptime", (None, 0, 20, 20.0, [0, 20], [20, 60.0], (0, 100), "fast", "short", "long", "shortest", "longest")) -@pytest.mark.parametrize("distance", (None, 0, 0.2, (0.2, 0.4))) -@pytest.mark.parametrize("year", (None, 0, 2013, (2000, 2020), [2013, 2019])) -@pytest.mark.parametrize("description", (None, 0, "data", ["TPS", "report"], ("TPS", "report"))) -@pytest.mark.parametrize("pipeline", (None, 0, "Kepler", "spoc", ["kepler", "spoc"])) -@pytest.mark.parametrize("sequence", (None, 0, 14, [14, 15])) -@pytest.mark.parametrize("mission", (None, 0, "Kepler", "Tess", ["Kepler", "Tess"])) -def test_mastsearch_filter(target_name, limit, filetype, exptime, distance, year, description, pipeline, sequence, mission): +def test_mastsearch_filter(): results = MASTSearch("Kepler 16b") - filter_results = results.filter_table(target_name=target_name, - limit=limit, - filetype=filetype, - exptime=exptime, - distance=distance, - year=year, - description=description, - pipeline=pipeline, - sequence=sequence, - mission=mission) - # from pandas.testing import assert_frame_equal - - # assert results.table.shape == (220, 61), "Test search result returned unexpected size." - # ft = results.filter_table - # assert ft(target_name=0).table.shape == (0, 62), "Null filter_table test returned unexpected size." - # ft_tn = ft(target_name="299096355") - # assert ft_tn.table.shape == (125, 62), "filter_table on target_name returned unexpected size." - - # def frame_assertion(ft1, ft2, msg): - # try: - # assert_frame_equal(ft1.table, ft2.table) - # except AssertionError: - # raise(AssertionError(msg)) - # frame_assertion(ft_tn, ft(target_name=299096355), "Problem parsing target name of type `int`.") - # frame_assertion(ft_tn, ft(target_name=[299096355]), "Problem parsing list[int] target names") - # frame_assertion(ft_tn, ft(target_name=["299096355"]), "Problem parsing list[str] target names") - - # assert ft(target_name="kplr012644769").table.shape == (95, 62), "Filter table on target_name returned unexpected size." - # ft_tn = ft(target_name=["299096355", "kplr012644769"]) - # assert ft_tn.table.shape == (220, 62), "Filter table on target_name returned unexpected size." - # frame_assertion(ft_tn, ft(target_name=[299096355, "kplr012644769"]), "Problem parsing list[mixed] target names") - # assert ft(target_name=[0, "299096355"]).shape == (125, 62), "filter_table on target_name with valid and invalid keys returned unexpected size." - # assert ft(target_name=[299096355, "299096355"]).shape == (125, 62), "filter_table on target_name with duplicate keys returned unexpected size." - + @pytest.mark.parametrize("target_name", (0, 299096355, "kplr012644769", [299096355, "kplr012644769"], [299096355, "299096355"])) + def test_target_name(target_name): + filter_results = results.filter_table(target_name=target_name) + @pytest.mark.parametrize("limit", (0, 10, 1000)) + def test_limit(limit): + filter_results = results.filter_table(limit=limit) + @pytest.mark.parametrize("filetype", (0, "lightcurve")) + def test_filetype(filetype): + filter_results = results.filter_table(filetype=filetype) + @pytest.mark.parametrize("exptime", (0, 20, 20.0, [0, 20], [20, 60.0], (0, 100), "fast", "short", "long", "shortest", "longest")) + def test_exptime(exptime): + filter_results = results.filter_table(exptime=exptime) + @pytest.mark.parametrize("distance", (0, 0.2, (0.2, 0.4))) + def test_distance(distance): + filter_results = results.filter_table(distance=distance) + @pytest.mark.parametrize("year", (0, 2013, (2000, 2020), [2013, 2019])) + def test_year(year): + filter_results = results.filter_table(year=year) + @pytest.mark.parametrize("description", (0, "data", ["TPS", "report"], ("TPS", "report"))) + def test_description(description): + filter_results = results.filter_table(description=description) + @pytest.mark.parametrize("pipeline", (0, "Kepler", "spoc", ["kepler", "spoc"])) + def test_pipeline(pipeline): + filter_results = results.filter_table(pipeline=pipeline) + @pytest.mark.parametrize("sequence", (0, 14, [14, 15])) + def test_sequence(sequence): + filter_results = results.filter_table(sequence=sequence) + @pytest.mark.parametrize("mission", (0, "Kepler", "Tess", ["Kepler", "Tess"])) + def test_mission(mission): + filter_results = results.filter_table(mission=mission) + def test_combination(): + filter_results = results.filter_table(target_name=299096355, + pipeline="SPOC", + mission="TESS", + exptime=120, + distance=.1, + year=2022, + description="light curves", + filetype="lightcurve", + sequence=55, + limit=10, + ) + from pandas.testing import assert_series_equal + try: + assert_series_equal(filter_results.set_index('index').iloc[0], results.table.iloc[5]) + except AssertionError as exc: + raise AssertionError("Problem applying search parameters together.") from exc def test_filter(): """Can we properly filter the data""" From 49df06e2acc8f02930ede782c8e6949ed2f583db Mon Sep 17 00:00:00 2001 From: Daniel Giles Date: Thu, 13 Jun 2024 10:15:16 -0400 Subject: [PATCH 07/14] MASTSearch filter_table test fixes, filter tests passing --- src/lksearch/MASTSearch.py | 8 +++--- tests/test_search.py | 53 ++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index 6f4c132..d09dec2 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -931,7 +931,7 @@ def _filter( allowed_ftype = ["lightcurve", "target pixel", "dvreport"] filter_ftype = [ file.lower() - for file in np.atleast_1d(filetype) + for file in np.atleast_1d(filetype).astype(str) if file.lower() in allowed_ftype ] if len(filter_ftype) == 0: @@ -979,7 +979,7 @@ def _filter( ) if pipeline is not None: - pipeline = list(map(str.lower, np.atleast_1d(pipeline))) + pipeline = list(map(str.lower, np.atleast_1d(pipeline).astype(str))) mask = mask & self.table["pipeline"].str.lower().isin(pipeline) if description is not None: @@ -1012,7 +1012,7 @@ def _filter( ) if mission is not None: - mission = list(map(str.lower, np.atleast_1d(mission))) + mission = list(map(str.lower, np.atleast_1d(mission).astype(str))) mask = mask & self.table["mission"].str.lower().isin(mission) return mask @@ -1067,6 +1067,8 @@ def filter_table( """ if "sequence" in kwargs: sequence = kwargs["sequence"] + else: + sequence = None mask = self._filter( target_name=target_name, diff --git a/tests/test_search.py b/tests/test_search.py index ae16872..060a73f 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -443,40 +443,40 @@ def test_tesscut(): manifest = results.cubedata[2].download() assert len(manifest) == 1 -def test_mastsearch_filter(): +class TestMASTSearchFilter(): results = MASTSearch("Kepler 16b") @pytest.mark.parametrize("target_name", (0, 299096355, "kplr012644769", [299096355, "kplr012644769"], [299096355, "299096355"])) - def test_target_name(target_name): - filter_results = results.filter_table(target_name=target_name) + def test_target_name(self, target_name): + filter_results = self.results.filter_table(target_name=target_name) @pytest.mark.parametrize("limit", (0, 10, 1000)) - def test_limit(limit): - filter_results = results.filter_table(limit=limit) + def test_limit(self, limit): + filter_results = self.results.filter_table(limit=limit) @pytest.mark.parametrize("filetype", (0, "lightcurve")) - def test_filetype(filetype): - filter_results = results.filter_table(filetype=filetype) + def test_filetype(self, filetype): + filter_results = self.results.filter_table(filetype=filetype) @pytest.mark.parametrize("exptime", (0, 20, 20.0, [0, 20], [20, 60.0], (0, 100), "fast", "short", "long", "shortest", "longest")) - def test_exptime(exptime): - filter_results = results.filter_table(exptime=exptime) + def test_exptime(self, exptime): + filter_results = self.results.filter_table(exptime=exptime) @pytest.mark.parametrize("distance", (0, 0.2, (0.2, 0.4))) - def test_distance(distance): - filter_results = results.filter_table(distance=distance) + def test_distance(self, distance): + filter_results = self.results.filter_table(distance=distance) @pytest.mark.parametrize("year", (0, 2013, (2000, 2020), [2013, 2019])) - def test_year(year): - filter_results = results.filter_table(year=year) + def test_year(self, year): + filter_results = self.results.filter_table(year=year) @pytest.mark.parametrize("description", (0, "data", ["TPS", "report"], ("TPS", "report"))) - def test_description(description): - filter_results = results.filter_table(description=description) + def test_description(self, description): + filter_results = self.results.filter_table(description=description) @pytest.mark.parametrize("pipeline", (0, "Kepler", "spoc", ["kepler", "spoc"])) - def test_pipeline(pipeline): - filter_results = results.filter_table(pipeline=pipeline) + def test_pipeline(self, pipeline): + filter_results = self.results.filter_table(pipeline=pipeline) @pytest.mark.parametrize("sequence", (0, 14, [14, 15])) - def test_sequence(sequence): - filter_results = results.filter_table(sequence=sequence) + def test_sequence(self, sequence): + filter_results = self.results.filter_table(sequence=sequence) @pytest.mark.parametrize("mission", (0, "Kepler", "Tess", ["Kepler", "Tess"])) - def test_mission(mission): - filter_results = results.filter_table(mission=mission) - def test_combination(): - filter_results = results.filter_table(target_name=299096355, + def test_mission(self, mission): + filter_results = self.results.filter_table(mission=mission) + def test_combination(self, ): + filter_results = self.results.filter_table(target_name=299096355, pipeline="SPOC", mission="TESS", exptime=120, @@ -487,11 +487,8 @@ def test_combination(): sequence=55, limit=10, ) - from pandas.testing import assert_series_equal - try: - assert_series_equal(filter_results.set_index('index').iloc[0], results.table.iloc[5]) - except AssertionError as exc: - raise AssertionError("Problem applying search parameters together.") from exc + assert filter_results.table.obs_id.values[0] == "tess2022217014003-s0055-0000000299096355-0242-s" + def test_filter(): """Can we properly filter the data""" From 74196388216398caa2af257e24d754878c39bf60 Mon Sep 17 00:00:00 2001 From: Tyler Pritchard Date: Thu, 11 Jul 2024 15:46:40 -0400 Subject: [PATCH 08/14] ruff --- src/lksearch/K2Search.py | 24 +++++------ src/lksearch/KeplerSearch.py | 22 +++++----- src/lksearch/MASTSearch.py | 2 +- src/lksearch/TESSSearch.py | 2 +- tests/test_search.py | 80 ++++++++++++++++++++++++++++-------- 5 files changed, 87 insertions(+), 43 deletions(-) diff --git a/src/lksearch/K2Search.py b/src/lksearch/K2Search.py index de88590..98d2957 100644 --- a/src/lksearch/K2Search.py +++ b/src/lksearch/K2Search.py @@ -163,7 +163,7 @@ def filter_table( campaign: Union[int, list] = None, limit: int = None, inplace=False, - **kwargs + **kwargs, ): """ Filters the search result table by specified parameters @@ -200,16 +200,16 @@ def filter_table( K2Search object with updated table or None if `inplace==True` """ mask = self._filter( - target_name = target_name, - filetype = filetype, - exptime = exptime, - distance = distance, - year = year, - description = description, - pipeline = pipeline, - mission = mission, - sequence_number=campaign - ) + target_name=target_name, + filetype=filetype, + exptime=exptime, + distance=distance, + year=year, + description=description, + pipeline=pipeline, + mission=mission, + sequence_number=campaign, + ) if limit is not None: cusu = np.cumsum(mask) if max(cusu) > limit: @@ -217,4 +217,4 @@ def filter_table( if inplace: self.table = self.table[mask].reset_index() else: - return self._mask(mask) \ No newline at end of file + return self._mask(mask) diff --git a/src/lksearch/KeplerSearch.py b/src/lksearch/KeplerSearch.py index e32f28d..ca2efa2 100644 --- a/src/lksearch/KeplerSearch.py +++ b/src/lksearch/KeplerSearch.py @@ -248,7 +248,7 @@ def filter_table( inplace=False, quarter: Optional[int] = None, month: Optional[int] = None, - **kwargs + **kwargs, ): """ Filters the search result table by specified parameters @@ -288,15 +288,15 @@ def filter_table( """ mask = np.ones(len(self.table), dtype=bool) mask = self._filter( - target_name = target_name, - filetype = filetype, - exptime = exptime, - distance = distance, - year = year, - description = description, - pipeline = pipeline, - mission = mission, - ) + target_name=target_name, + filetype=filetype, + exptime=exptime, + distance=distance, + year=year, + description=description, + pipeline=pipeline, + mission=mission, + ) if (quarter is not None) | (month is not None): mask = mask & self._filter_kepler(quarter=quarter, month=month) @@ -307,4 +307,4 @@ def filter_table( if inplace: self.table = self.table[mask].reset_index() else: - return self._mask(mask) \ No newline at end of file + return self._mask(mask) diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index 83ee346..b0d53eb 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -1032,7 +1032,7 @@ def filter_table( filetype: Union[str, list[str]] = None, limit: int = None, inplace=False, - **kwargs + **kwargs, ): """Filter the search by keywords diff --git a/src/lksearch/TESSSearch.py b/src/lksearch/TESSSearch.py index 1043337..8879c1f 100644 --- a/src/lksearch/TESSSearch.py +++ b/src/lksearch/TESSSearch.py @@ -400,7 +400,7 @@ def filter_table( limit: int = None, inplace=False, sector: Union[int, list[str]] = None, - **kwargs + **kwargs, ): """ Filters the search result table by specified parameters diff --git a/tests/test_search.py b/tests/test_search.py index 38a6425..2b16bd0 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -446,51 +446,95 @@ def test_tesscut(): manifest = results.cubedata[2].download() assert len(manifest) == 1 -class TestMASTSearchFilter(): + +class TestMASTSearchFilter: results = MASTSearch("Kepler 16b") - @pytest.mark.parametrize("target_name", (0, 299096355, "kplr012644769", [299096355, "kplr012644769"], [299096355, "299096355"])) + + @pytest.mark.parametrize( + "target_name", + ( + 0, + 299096355, + "kplr012644769", + [299096355, "kplr012644769"], + [299096355, "299096355"], + ), + ) def test_target_name(self, target_name): filter_results = self.results.filter_table(target_name=target_name) + @pytest.mark.parametrize("limit", (0, 10, 1000)) def test_limit(self, limit): filter_results = self.results.filter_table(limit=limit) + @pytest.mark.parametrize("filetype", (0, "lightcurve")) def test_filetype(self, filetype): filter_results = self.results.filter_table(filetype=filetype) - @pytest.mark.parametrize("exptime", (0, 20, 20.0, [0, 20], [20, 60.0], (0, 100), "fast", "short", "long", "shortest", "longest")) + + @pytest.mark.parametrize( + "exptime", + ( + 0, + 20, + 20.0, + [0, 20], + [20, 60.0], + (0, 100), + "fast", + "short", + "long", + "shortest", + "longest", + ), + ) def test_exptime(self, exptime): filter_results = self.results.filter_table(exptime=exptime) + @pytest.mark.parametrize("distance", (0, 0.2, (0.2, 0.4))) def test_distance(self, distance): filter_results = self.results.filter_table(distance=distance) + @pytest.mark.parametrize("year", (0, 2013, (2000, 2020), [2013, 2019])) def test_year(self, year): filter_results = self.results.filter_table(year=year) - @pytest.mark.parametrize("description", (0, "data", ["TPS", "report"], ("TPS", "report"))) + + @pytest.mark.parametrize( + "description", (0, "data", ["TPS", "report"], ("TPS", "report")) + ) def test_description(self, description): filter_results = self.results.filter_table(description=description) + @pytest.mark.parametrize("pipeline", (0, "Kepler", "spoc", ["kepler", "spoc"])) def test_pipeline(self, pipeline): filter_results = self.results.filter_table(pipeline=pipeline) + @pytest.mark.parametrize("sequence", (0, 14, [14, 15])) def test_sequence(self, sequence): filter_results = self.results.filter_table(sequence=sequence) + @pytest.mark.parametrize("mission", (0, "Kepler", "Tess", ["Kepler", "Tess"])) def test_mission(self, mission): filter_results = self.results.filter_table(mission=mission) - def test_combination(self, ): - filter_results = self.results.filter_table(target_name=299096355, - pipeline="SPOC", - mission="TESS", - exptime=120, - distance=.1, - year=2022, - description="light curves", - filetype="lightcurve", - sequence=55, - limit=10, - ) - assert filter_results.table.obs_id.values[0] == "tess2022217014003-s0055-0000000299096355-0242-s" + + def test_combination( + self, + ): + filter_results = self.results.filter_table( + target_name=299096355, + pipeline="SPOC", + mission="TESS", + exptime=120, + distance=0.1, + year=2022, + description="light curves", + filetype="lightcurve", + sequence=55, + limit=10, + ) + assert ( + filter_results.table.obs_id.values[0] + == "tess2022217014003-s0055-0000000299096355-0242-s" + ) def test_filter(): @@ -500,7 +544,7 @@ def test_filter(): filtered = results.filter_table(sector=14) queried = results.filter_table("sector == 14") assert len(filtered) == len(queried) - + def test_tess_clouduris(): """regression test - do tesscut/nan's in dataURI column break cloud uri fetching""" From 77d4c66c6d3bf4375691bcc059230e0b8d5c8752 Mon Sep 17 00:00:00 2001 From: Tyler Pritchard Date: Thu, 11 Jul 2024 18:38:06 -0400 Subject: [PATCH 09/14] fixed bug where HLSP didn't appear in TESSSEarch --- src/lksearch/MASTSearch.py | 5 +---- src/lksearch/TESSSearch.py | 6 +++++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lksearch/MASTSearch.py b/src/lksearch/MASTSearch.py index b0d53eb..ce751b9 100644 --- a/src/lksearch/MASTSearch.py +++ b/src/lksearch/MASTSearch.py @@ -285,14 +285,13 @@ def _searchtable_from_target(self, target: Union[str, tuple[float], SkyCoord]): "lightcurve", "dvreport", ] - mask = self._filter( exptime=self.search_exptime, mission=self.search_mission, pipeline=self.search_pipeline, sequence_number=self.search_sequence, filetype=filetype, - ) # setting provenance_name=None will return HLSPs + ) self.table = self.table[mask].reset_index(drop=True) def _searchtable_from_table( @@ -924,7 +923,6 @@ def _filter( cumulative boolean mask for self.table based off of the product of individual filter properties """ - mask = np.ones(len(self.table), dtype=bool) if target_name is not None: target_name = np.atleast_1d(target_name).astype(str) @@ -1122,7 +1120,6 @@ def _download_one( if pd.notna(row["cloud_uri"]): download = False if conf.DOWNLOAD_CLOUD or download: - print(cloud_only) manifest = Observations.download_products( Table().from_pandas(row.to_frame(name=" ").transpose()), download_dir=download_dir, diff --git a/src/lksearch/TESSSearch.py b/src/lksearch/TESSSearch.py index 8879c1f..33d0f80 100644 --- a/src/lksearch/TESSSearch.py +++ b/src/lksearch/TESSSearch.py @@ -88,10 +88,13 @@ def __init__( ): if hlsp is False: pipeline = ["SPOC", "TESS-SPOC", "TESScut"] + self.mission_search = ["TESS"] + else: + self.mission_search = ["TESS", "HLSP"] super().__init__( target=target, - mission=["TESS"], + mission=self.mission_search, obs_table=obs_table, prod_table=prod_table, table=table, @@ -100,6 +103,7 @@ def __init__( pipeline=pipeline, sequence=sector, ) + if table is None: if ("TESScut" in np.atleast_1d(pipeline)) or (type(pipeline) is type(None)): self._add_tesscut_products(sector) From b367a290a4e50a511b57600c3790d00aed66ea51 Mon Sep 17 00:00:00 2001 From: Tyler Pritchard Date: Fri, 12 Jul 2024 10:05:28 -0400 Subject: [PATCH 10/14] HLSP fix for Kepler/K2 --- src/lksearch/K2Search.py | 8 +++++++- src/lksearch/KeplerSearch.py | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/lksearch/K2Search.py b/src/lksearch/K2Search.py index 98d2957..ed687d4 100644 --- a/src/lksearch/K2Search.py +++ b/src/lksearch/K2Search.py @@ -78,10 +78,16 @@ def __init__( exptime: Optional[Union[str, int, tuple]] = (0, 9999), pipeline: Optional[Union[str, list[str]]] = None, campaign: Optional[Union[int, list[int]]] = None, + hlsp: bool = True, ): + if hlsp is False: + pipeline = ["K2"] + self.mission_search = ["K2"] + else: + self.mission_search = ["K2", "HLSP"] super().__init__( target=target, - mission=["K2"], + mission=self.mission_search, obs_table=obs_table, prod_table=prod_table, table=table, diff --git a/src/lksearch/KeplerSearch.py b/src/lksearch/KeplerSearch.py index ca2efa2..47a61d2 100644 --- a/src/lksearch/KeplerSearch.py +++ b/src/lksearch/KeplerSearch.py @@ -81,10 +81,17 @@ def __init__( pipeline: Optional[Union[str, list[str]]] = None, quarter: Optional[Union[int, list[int]]] = None, month: Optional[int] = None, + hlsp: bool = True, ): + if hlsp is False: + pipeline = ["Kepler"] + self.mission_search = ["Kepler"] + else: + self.mission_search = ["Kepler", "HLSP"] + super().__init__( target=target, - mission=["Kepler"], + mission=self.mission_search, obs_table=obs_table, prod_table=prod_table, table=table, From 702b63e059f56fd1ad0e401c5b0a4b29443cecd7 Mon Sep 17 00:00:00 2001 From: Tyler Pritchard Date: Fri, 12 Jul 2024 15:36:19 -0400 Subject: [PATCH 11/14] updated tests --- tests/test_search.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_search.py b/tests/test_search.py index 2b16bd0..65d97d2 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -434,16 +434,16 @@ def test_FFI_retrieval(): target = "Kepler 16b" assert ( len(TESSSearch("Kepler 16b").search_individual_ffi(58682, 58710, sector=14)) - == 1281 + == 1241 ) def test_tesscut(): """Can we find and download TESS tesscut tpfs""" results = TESSSearch("Kepler 16b", hlsp=False, sector=14) - assert len(results) == 11 - assert len(results.cubedata) == 3 - manifest = results.cubedata[2].download() + assert len(results) == 9 + assert len(results.cubedata) == 2 + manifest = results.cubedata[1].download() assert len(manifest) == 1 From 48c154829d93d09661e029a74385b3b26d55733d Mon Sep 17 00:00:00 2001 From: Tyler Pritchard Date: Fri, 12 Jul 2024 18:18:42 -0400 Subject: [PATCH 12/14] fix querty_table test --- tests/test_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_search.py b/tests/test_search.py index 65d97d2..7c48286 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -542,7 +542,7 @@ def test_filter(): results = TESSSearch("Kepler 16b") filtered = results.filter_table(sector=14) - queried = results.filter_table("sector == 14") + queried = results.query_table("sector == 14") assert len(filtered) == len(queried) From d5e823265d6d73f095ef4ca429e6cbd1202e78da Mon Sep 17 00:00:00 2001 From: Tyler Pritchard Date: Mon, 15 Jul 2024 13:50:51 -0400 Subject: [PATCH 13/14] changed search_individual_ffi to search_sector_ffis to better reflect functionaly, updated tests, added query_table example to documentation --- docs/tutorials/Example_searches.ipynb | 952 ++++++++++++++------------ src/lksearch/TESSSearch.py | 47 +- tests/test_search.py | 5 +- 3 files changed, 515 insertions(+), 489 deletions(-) diff --git a/docs/tutorials/Example_searches.ipynb b/docs/tutorials/Example_searches.ipynb index c66f700..41d3a57 100644 --- a/docs/tutorials/Example_searches.ipynb +++ b/docs/tutorials/Example_searches.ipynb @@ -69,7 +69,8 @@ { "data": { "text/html": [ - "MASTSearch object containing 244 data products
\n", + "MASTSearch object containing 244 data products \n", + "
\n", "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
target_namepipelinemissionsectorexptimedistanceyeardescription
0158324245SPOCTESS14120.00.02019Light curves
1158324245TASOCHLSP14120.00.02019FITS
\n", + "
" + ], + "text/plain": [ + "TESSSearch object containing 2 data products \n", + " target_name pipeline mission sector exptime distance year description\n", + "0 158324245 SPOC TESS 14 120.0 0.0 2019 Light curves\n", + "1 158324245 TASOC HLSP 14 120.0 0.0 2019 FITS" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "toi_short_lcs = toi.timeseries.query_table('sector == 14 & exptime == 120')\n", + "toi_short_lcs" + ] + }, { "cell_type": "markdown", "id": "b97fca26", @@ -2664,14 +2768,15 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 18, "id": "d2cfa795", "metadata": {}, "outputs": [ { "data": { "text/html": [ - "TESSSearch object containing 6 data products
\n", + "TESSSearch object containing 6 data products \n", + "
\n", "