def test_interact_functions(): """Do the helper functions in the interact module run without syntax error?""" import bokeh from lightkurve.interact import ( prepare_tpf_datasource, prepare_lightcurve_datasource, get_lightcurve_y_limits, make_lightcurve_figure_elements, make_tpf_figure_elements, show_interact_widget, ) tpf = TessTargetPixelFile(example_tpf) mask = tpf.flux[0, :, :] == tpf.flux[0, :, :] tpf_source = prepare_tpf_datasource(tpf, aperture_mask=mask) lc = tpf.to_lightcurve(aperture_mask=mask) lc_source = prepare_lightcurve_datasource(lc) get_lightcurve_y_limits(lc_source) make_lightcurve_figure_elements(lc, lc_source) def ylim_func_sample(lc): return (np.nanpercentile(lc.flux, 0.1), np.nanpercentile(lc.flux, 99.9)) make_lightcurve_figure_elements(lc, lc_source, ylim_func=ylim_func_sample) def ylim_func_unitless(lc): return ( np.nanpercentile(lc.flux, 0.1).value, np.nanpercentile(lc.flux, 99.9).value, ) make_lightcurve_figure_elements(lc, lc_source, ylim_func=ylim_func_unitless) make_tpf_figure_elements(tpf, tpf_source) show_interact_widget(tpf)
def test_graceful_exit_outside_notebook(): """Test if running interact outside of a notebook does fails gracefully.""" import bokeh tpf = TessTargetPixelFile(example_tpf) result = tpf.interact() assert result is None
def test_bokeh_import_error(caplog): """If bokeh is not installed (optional dependency), is a friendly error message printed?""" try: import bokeh except ImportError: tpf = TessTargetPixelFile(example_tpf) tpf.interact() assert "requires the `bokeh` Python package" in caplog.text
def test_tess_simulation(): """Can we read simulated TESS data?""" tpf = TessTargetPixelFile(TESS_SIM) assert tpf.mission == "TESS" assert tpf.time.scale == "tdb" assert tpf.flux.shape == tpf.flux_err.shape tpf.wcs col, row = tpf.estimate_centroids() # Regression test for https://github.com/lightkurve/lightkurve/pull/236 assert (tpf.time.value == 0).sum() == 0
def test_SSOs(): # TESS test tpf = TessTargetPixelFile(asteroid_TPF) result = tpf.query_solar_system_objects( ) # default cadence_mask = 'outliers' assert ( result is None ) # the TPF has only data for 1 epoch. The lone time is removed as outlier result = tpf.query_solar_system_objects(cadence_mask="all", cache=False) assert len(result) == 1 result = tpf.query_solar_system_objects(cadence_mask=np.asarray([True]), cache=False) assert len(result) == 1 result = tpf.query_solar_system_objects(cadence_mask=[True], cache=False) assert len(result) == 1 result = tpf.query_solar_system_objects(cadence_mask=(True), cache=False) assert len(result) == 1 result, mask = tpf.query_solar_system_objects(cadence_mask=np.asarray( [True]), cache=True, return_mask=True) assert len(mask) == len(tpf.flux) try: result = tpf.query_solar_system_objects( cadence_mask="str-not-supported", cache=False) pytest.fail("Unsupported cadence_mask should have thrown Error") except ValueError: pass
def test_accessor_tess_sector(): lc0 = TessLightCurve( time=np.arange(1, 5), flux=np.arange(1, 5), flux_err=np.arange(1, 5), targetid=50000, ) lc0.meta["SECTOR"] = 14 lc1 = TessLightCurve( time=np.arange(10, 15), flux=np.arange(10, 15), flux_err=np.arange(10, 15), targetid=120334, ) lc1.meta["SECTOR"] = 26 lcc = LightCurveCollection([lc0, lc1]) assert (lcc.sector == [14, 26]).all() # The sector accessor can be used to generate boolean array # to support filter collection by sector assert ((lcc.sector == 26) == [False, True]).all() assert ((lcc.sector < 20) == [True, False]).all() # boundary condition: some lightcurve objects do not have sector lc2 = LightCurve( time=np.arange(15, 20), flux=np.arange(15, 20), flux_err=np.arange(15, 20), targetid=23456, ) lcc.append(lc2) # expecting [14, 26, np.nan], need 2 asserts to do it. assert (lcc.sector[:-1] == [14, 26]).all() assert np.isnan(lcc.sector[-1]) # The sector accessor can be used to generate boolean array # to support filter collection by sector assert ((lcc.sector == 26) == [False, True, False]).all() assert ((lcc.sector < 20) == [True, False, False]).all() # ensure it works for TPFs too. with warnings.catch_warnings(): warnings.simplefilter("ignore", LightkurveWarning) # Ignore "A Kepler data product is being opened using the `TessTargetPixelFile` class" # the test only cares about the SECTOR header that it sets. tpf = TessTargetPixelFile(filename_tpf_all_zeros) tpf.hdu[0].header["SECTOR"] = 23 tpf2 = TessTargetPixelFile(filename_tpf_one_center) # tpf2 has no sector defined tpf3 = TessTargetPixelFile(filename_tpf_one_center) tpf3.hdu[0].header["SECTOR"] = 1 tpfc = TargetPixelFileCollection([tpf, tpf2, tpf3]) assert (tpfc.sector == [23, None, 1]).all()
def test_tpf_plot(): """Sanity check to verify that tpf plotting works""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tpf_one_center), ] for tpf in tpfs: tpf.plot() tpf.plot(aperture_mask=tpf.pipeline_mask) tpf.plot(aperture_mask="all") tpf.plot(frame=3) with pytest.raises(ValueError): tpf.plot(frame=999999) tpf.plot(cadenceno=125250) with pytest.raises(ValueError): tpf.plot(cadenceno=999) tpf.plot(bkg=True) tpf.plot(scale="sqrt") tpf.plot(scale="log") with pytest.raises(ValueError): tpf.plot(scale="blabla") tpf.plot(column="FLUX") tpf.plot(column="FLUX_ERR") tpf.plot(column="FLUX_BKG") tpf.plot(column="FLUX_BKG_ERR") tpf.plot(column="RAW_CNTS") tpf.plot(column="COSMIC_RAYS") with pytest.raises(ValueError): tpf.plot(column="not a column") plt.close("all")
def test_interact_sky_functions_case_nearby_tics_failed(monkeypatch): """Test to ensure in case Nearby TIC service from ExoFOP not available, interact_sky will still function (without the TIC information) rather than raising exceptions. """ import bokeh from lightkurve.interact import ( prepare_tpf_datasource, make_tpf_figure_elements, add_gaia_figure_elements, ) import lightkurve.interact as lk_interact def mock_raise(*args): raise IOError("simulated service unavailable") monkeypatch.setattr(lk_interact, "_search_nearby_of_tess_target", mock_raise) tpf = TessTargetPixelFile(example_tpf_tess) mask = tpf.flux[0, :, :] == tpf.flux[0, :, :] tpf_source = prepare_tpf_datasource(tpf, aperture_mask=mask) fig1, slider1 = make_tpf_figure_elements(tpf, tpf_source) with pytest.warns(LightkurveWarning, match="cannot obtain nearby TICs"): add_gaia_figure_elements(tpf, fig1)
def test_interact_sky(): """Test the Jupyter notebook interact() widget.""" for tpf in [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tess), ]: tpf.interact_sky()
def test_repr(): """Do __str__ and __repr__ work?""" for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: str(tpf) repr(tpf)
def test_tpf_tess(): """Does a TESS Sector 1 TPF work?""" tpf = TessTargetPixelFile(filename_tess, quality_bitmask=None) assert tpf.mission == "TESS" assert tpf.targetid == 25155310 assert tpf.sector == 1 assert tpf.camera == 4 assert tpf.ccd == 1 assert tpf.pipeline_mask.sum() == 9 assert tpf.background_mask.sum() == 30 lc = tpf.to_lightcurve() assert isinstance(lc, TessLightCurve) assert_array_equal(lc.time, tpf.time) assert tpf.time.scale == "tdb" assert tpf.flux.shape == tpf.flux_err.shape tpf.wcs col, row = tpf.estimate_centroids()
def test_load_bad_file(): """Test if a light curve can be opened without exception.""" with pytest.raises(ValueError) as exc: KeplerTargetPixelFile(TABBY_Q8) assert "is this a target pixel file?" in exc.value.args[0] with pytest.raises(ValueError) as exc: TessTargetPixelFile(TABBY_Q8) assert "is this a target pixel file?" in exc.value.args[0]
def test_wcs(): """Test the wcs property.""" for tpf in [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tess), ]: w = tpf.wcs ra, dec = tpf.get_coordinates() assert ra.shape == tpf.shape assert dec.shape == tpf.shape assert type(w).__name__ == "WCS"
def test_transform_and_ylim_funcs(): """Test the transform_func and ylim_func""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [KeplerTargetPixelFile(filename_tpf_tabby_lite), TessTargetPixelFile(example_tpf)] for tpf in tpfs: tpf.interact(transform_func=lambda lc: lc.normalize()) tpf.interact(transform_func=lambda lc: lc.flatten().normalize()) tpf.interact(transform_func=lambda lc: lc, ylim_func=lambda lc: (0, 2)) tpf.interact(ylim_func=lambda lc: (0, lc.flux.max()))
def test_bkg_lightcurve(): for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: lc = tpf.get_bkg_lightcurve() lc = tpf.get_bkg_lightcurve(aperture_mask=None) lc = tpf.get_bkg_lightcurve(aperture_mask="all") assert lc.time.scale == "tdb" assert lc.flux.shape == lc.flux_err.shape assert len(lc.time) == len(lc.flux)
def test_tpf_shapes(): """Are the data array shapes of the TargetPixelFile object consistent?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tpf_all_zeros), ] for tpf in tpfs: assert tpf.quality_mask.shape == tpf.hdu[1].data["TIME"].shape assert tpf.flux.shape == tpf.flux_err.shape
def test_aperture_photometry(): for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: tpf.extract_aperture_photometry() for mask in [None, "all", "default", "threshold", "background"]: tpf.extract_aperture_photometry(aperture_mask=mask) if np.any(tpf.pipeline_mask): tpf.extract_aperture_photometry(aperture_mask="pipeline") else: with pytest.raises(ValueError): tpf.extract_aperture_photometry(aperture_mask="pipeline")
def test_tpf_to_fits(): """Can we write a TPF back to a fits file?""" for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: # `delete=False` is necessary to enable writing to the file on Windows # but it means we have to clean up the tmp file ourselves tmp = tempfile.NamedTemporaryFile(delete=False) try: tpf.to_fits(tmp.name) finally: tmp.close() os.remove(tmp.name)
def test_custom_aperture_mask(): """Can we provide a custom lightcurve to show?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [KeplerTargetPixelFile(filename_tpf_tabby_lite), TessTargetPixelFile(example_tpf)] import bokeh for tpf in tpfs: mask = tpf.flux[0, :, :] == tpf.flux[0, :, :] tpf.interact(aperture_mask=mask) mask = None tpf.interact(aperture_mask=mask) mask = "threshold" tpf.interact(aperture_mask=mask)
def test_interact_sky_functions(): """Do the helper functions in the interact module run without syntax error?""" import bokeh from lightkurve.interact import ( prepare_tpf_datasource, make_tpf_figure_elements, add_gaia_figure_elements, ) tpf = TessTargetPixelFile(example_tpf) mask = tpf.flux[0, :, :] == tpf.flux[0, :, :] tpf_source = prepare_tpf_datasource(tpf, aperture_mask=mask) fig1, slider1 = make_tpf_figure_elements(tpf, tpf_source) add_gaia_figure_elements(tpf, fig1) add_gaia_figure_elements(tpf, fig1, magnitude_limit=22)
def test_to_lightcurve(): for tpf in [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tess), ]: tpf.to_lightcurve() tpf.to_lightcurve(aperture_mask=None) tpf.to_lightcurve(aperture_mask="all") lc = tpf.to_lightcurve(aperture_mask="threshold") assert lc.time.scale == "tdb" assert lc.label == tpf.hdu[0].header["OBJECT"] if np.any(tpf.pipeline_mask): tpf.to_lightcurve(aperture_mask="pipeline") else: with pytest.raises(ValueError): tpf.to_lightcurve(aperture_mask="pipeline")
def test_tpf_math(): """Can you add, subtract, multiply and divide?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_all_zeros), TessTargetPixelFile(filename_tpf_all_zeros), ] # These should work for tpf in tpfs: for other in [1, np.ones(tpf.flux.shape[1:]), np.ones(tpf.shape)]: tpf + other tpf - other tpf * other tpf / other tpf += other tpf -= other tpf *= other tpf /= other # These should fail with a value error because their shape is wrong. for tpf in tpfs: for other in [ np.asarray([1, 2]), np.arange(len(tpf.time) - 1), np.ones([100, 1]), np.ones([1, 2, 3]), ]: with pytest.raises(ValueError): tpf + other # Check the values are correct assert np.all(((tpf.flux.value + 2) == (tpf + 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux.value - 2) == (tpf - 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux.value * 2) == (tpf * 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux.value / 2) == (tpf / 2).flux.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux_err.value * 2) == (tpf * 2).flux_err.value)[np.isfinite(tpf.flux)]) assert np.all(((tpf.flux_err.value / 2) == (tpf / 2).flux_err.value)[np.isfinite(tpf.flux)])
def test_malformed_notebook_url(): """Test if malformed notebook_urls raise proper exceptions.""" import bokeh tpf = TessTargetPixelFile(example_tpf) with pytest.raises(ValueError) as exc: tpf.interact(notebook_url="") assert "Empty host value" in exc.value.args[0] with pytest.raises(AttributeError) as exc: tpf.interact(notebook_url=None) assert "object has no attribute" in exc.value.args[0]
def test_cutout(): """Test tpf.cutout() function.""" for tpf in [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tess, quality_bitmask=None), ]: ntpf = tpf.cutout(size=2) assert ntpf.flux[0].shape == (2, 2) assert ntpf.flux_err[0].shape == (2, 2) assert ntpf.flux_bkg[0].shape == (2, 2) ntpf = tpf.cutout((0, 0), size=3) ntpf = tpf.cutout(size=(1, 2)) assert ntpf.flux.shape[1] == 2 assert ntpf.flux.shape[2] == 1 ntpf = tpf.cutout(SkyCoord(tpf.ra, tpf.dec, unit="deg"), size=2) ntpf = tpf.cutout(size=2) assert np.product(ntpf.flux.shape[1:]) == 4 assert ntpf.targetid == "{}_CUTOUT".format(tpf.targetid)
def test_tpf_ones(centroid_method): """Does the LightCurve of a one-flux TPF make sense?""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tpf_one_center), ] for tpf in tpfs: lc = tpf.to_lightcurve(aperture_mask="all", centroid_method=centroid_method) assert np.all(lc.flux.value == 1) assert np.all( (lc.centroid_col.value < tpf.column + tpf.shape[1]).all() * (lc.centroid_col.value > tpf.column).all()) assert np.all((lc.centroid_row.value < tpf.row + tpf.shape[2]).all() * (lc.centroid_row.value > tpf.row).all())
def test_custom_exported_filename(): """Can we provide a custom lightcurve to show?""" import bokeh with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [KeplerTargetPixelFile(filename_tpf_tabby_lite), TessTargetPixelFile(example_tpf)] for tpf in tpfs: tpf.interact(exported_filename="demo.fits") tpf[0:2].interact() tpf[0:2].interact(exported_filename="string_only") tpf[0:2].interact(exported_filename="demo2.FITS") tpf[0:2].interact(exported_filename="demo3.png") tpf[0:2].interact(exported_filename="") tpf.interact(exported_filename=210690913) mask = tpf.time == tpf.time tpf[mask].interact()
def test_tpf_ones(centroid_method): """Does the LightCurve of a one-flux TPF make sense? Regression test for #1103.""" with warnings.catch_warnings(): # Ignore the "TELESCOP is not equal to TESS" warning warnings.simplefilter("ignore", LightkurveWarning) tpfs = [ KeplerTargetPixelFile(filename_tpf_one_center), TessTargetPixelFile(filename_tpf_one_center), ] for tpf in tpfs: lc = tpf.to_lightcurve(aperture_mask="all", centroid_method=centroid_method) assert np.all(lc.flux.value == 1) # The test TPF file contains 3x3 pixels with a single bright pixel in the center pixel. # Because pixel coordinates refer to the center of a pixel (cf. #755), # we expect the centroid to be exactly one larger than the corner coordinates. # This is a regression test for #1103. assert np.all(lc.centroid_row.value == tpf.row + 1) assert np.all(lc.centroid_col.value == tpf.column + 1)
def test_threshold_aperture_mask(): """Does the threshold mask work?""" tpf = KeplerTargetPixelFile(filename_tpf_one_center) tpf.plot(aperture_mask="threshold") lc = tpf.to_lightcurve(aperture_mask=tpf.create_threshold_mask( threshold=1)) assert (lc.flux.value == 1).all() # The TESS file shows three pixel regions above a 2-sigma threshold; # let's make sure the `reference_pixel` argument allows them to be selected. tpf = TessTargetPixelFile(filename_tess) assert tpf.create_threshold_mask(threshold=2.0).sum() == 25 assert (tpf.create_threshold_mask(threshold=2.0, reference_pixel="center").sum() == 25) assert tpf.create_threshold_mask(threshold=2.0, reference_pixel=None).sum() == 28 assert tpf.create_threshold_mask(threshold=2.0, reference_pixel=(5, 0)).sum() == 2 # A mask which contains zero-flux pixels should work without crashing tpf = KeplerTargetPixelFile(filename_tpf_all_zeros) assert tpf.create_threshold_mask().sum() == 9