diff --git a/astroquery/mast/cutouts.py b/astroquery/mast/cutouts.py index 0f87bef2b9..9f75fd6f33 100644 --- a/astroquery/mast/cutouts.py +++ b/astroquery/mast/cutouts.py @@ -714,14 +714,13 @@ def download_cutouts(self, coordinates, *, size=5, survey=None, cutout_format="f coordinates : str or `astropy.coordinates` object The target around which to search. It may be specified as a string or as the appropriate `astropy.coordinates` object. - size : int, array-like, `~astropy.units.Quantity` + size : int, float, array-like, `~astropy.units.Quantity` Optional, default 5 pixels. The size of the cutout array. If ``size`` is a scalar number or a scalar `~astropy.units.Quantity`, then a square cutout of ``size`` will be created. If ``size`` has two elements, they should be in - ``(ny, nx)`` order. Scalar numbers in ``size`` are assumed to be in - units of pixels. `~astropy.units.Quantity` objects must be in pixel or - angular units. + ``(ny, nx)`` order. Pixel sizes must be whole numbers; `~astropy.units.Quantity` + objects may also use angular units. survey : str Optional The survey to restrict the cutout. The survey parameter will restrict to @@ -756,6 +755,11 @@ def download_cutouts(self, coordinates, *, size=5, survey=None, cutout_format="f # Get Skycoord object for coordinates/object coordinates = parse_input_location(coordinates=coordinates) size_dict = _parse_cutout_size(size) + if size_dict["units"] == "px": + if any(value % 1 for value in (size_dict["x"], size_dict["y"])): + raise InvalidQueryError("Zcut pixel cutout sizes must be whole numbers.") + size_dict["x"] = int(size_dict["x"]) + size_dict["y"] = int(size_dict["y"]) path = os.path.join(path, '') astrocut_request = "ra={}&dec={}&y={}&x={}&units={}".format(coordinates.ra.deg, @@ -812,14 +816,13 @@ def get_cutouts(self, coordinates, *, size=5, survey=None): coordinates : str or `astropy.coordinates` object The target around which to search. It may be specified as a string or as the appropriate `astropy.coordinates` object. - size : int, array-like, `~astropy.units.Quantity` + size : int, float, array-like, `~astropy.units.Quantity` Optional, default 5 pixels. The size of the cutout array. If ``size`` is a scalar number or a scalar `~astropy.units.Quantity`, then a square cutout of ``size`` will be created. If ``size`` has two elements, they should be in - ``(ny, nx)`` order. Scalar numbers in ``size`` are assumed to be in - units of pixels. `~astropy.units.Quantity` objects must be in pixel or - angular units. + ``(ny, nx)`` order. Pixel sizes must be whole numbers; `~astropy.units.Quantity` + objects may also use angular units. survey : str Optional The survey to restrict the cutout. The survey parameter will restrict to @@ -828,13 +831,18 @@ def get_cutouts(self, coordinates, *, size=5, survey=None): Returns ------- response : A list of `~astropy.io.fits.HDUList` objects. - Cutoutfiles for given coordinates + Cutout files for given coordinates """ # Get Skycoord object for coordinates/object coordinates = parse_input_location(coordinates=coordinates) param_dict = _parse_cutout_size(size) + if param_dict["units"] == "px": + if any(value % 1 for value in (param_dict["x"], param_dict["y"])): + raise InvalidQueryError("Zcut pixel cutout sizes must be whole numbers.") + param_dict["x"] = int(param_dict["x"]) + param_dict["y"] = int(param_dict["y"]) param_dict["ra"] = coordinates.ra.deg param_dict["dec"] = coordinates.dec.deg diff --git a/astroquery/mast/tests/test_mast.py b/astroquery/mast/tests/test_mast.py index 98392a4fc1..0a27ecb6c6 100644 --- a/astroquery/mast/tests/test_mast.py +++ b/astroquery/mast/tests/test_mast.py @@ -1943,6 +1943,15 @@ def test_zcut_get_cutouts(tmpdir): assert isinstance(cutout_list[0], fits.HDUList) +@pytest.mark.parametrize("method", ["download_cutouts", "get_cutouts"]) +@pytest.mark.parametrize("size", [5.5, [1, 2.5], np.array([1.0, 2.5])]) +def test_zcut_rejects_fractional_pixel_size(method, size): + coord = SkyCoord(189.49206, 62.20615, unit="deg") + + with pytest.raises(InvalidQueryError, match="Zcut pixel cutout sizes must be whole numbers"): + getattr(Zcut, method)(coordinates=coord, size=size) + + ################ # Utils tests # ################ diff --git a/astroquery/mast/tests/test_mast_remote.py b/astroquery/mast/tests/test_mast_remote.py index 35a666ff8c..74fb9426b6 100644 --- a/astroquery/mast/tests/test_mast_remote.py +++ b/astroquery/mast/tests/test_mast_remote.py @@ -31,7 +31,7 @@ def msa_product_table(): products = Observations.get_product_list(obs['obsid'][0]) # Filter out everything but the MSA config file - mask = np.char.find(np.char.asarray(products["dataURI"]), "_msa.fits") != -1 + mask = np.char.find(np.asarray(products["dataURI"]), "_msa.fits") != -1 products = products[mask] return products @@ -413,18 +413,13 @@ def check_result(result, path): ('jwst', {'fileSetName': 'jw01189001001_02101_00001'}), ('classy', {'Target': 'J0021+0052'}), ('ullyses', {'host_galaxy_name': 'WLM', 'select_cols': ['observation_id']}), - ('roman', {'program': 3, 'pass_id': 1}), + # ('roman', {'program': 3, 'pass_id': 1}), # Commenting this case out until Roman data is publicly available ('iue', {'iue_data_id': 'LWR08496'}), ]) def test_missions_workflow(self, tmp_path, mission, query_params): # Test workflow with other missions m = MastMissions(mission=mission) - # Roman requires extra setup to point towards the test server - if mission == 'roman': - m._service_api_connection.SERVICE_URL = 'https://masttest.stsci.edu' - m._service_api_connection.REQUEST_URL = 'https://masttest.stsci.edu/search/roman/api/v0.1/' - # Criteria query datasets = m.query_criteria(**query_params) assert isinstance(datasets, Table) @@ -693,7 +688,8 @@ def test_observations_get_product_list(self, capsys): def test_observations_get_product_list_tess_tica(self, caplog): # Get observations and products with both TESS and TICA FFIs - obs = Observations.query_criteria(target_name=['TESS FFI', 'TICA FFI', '429031146']) + obs_id = '1258205337' + obs = Observations.query_criteria(object_name="M4", target_name=['TESS FFI', 'TICA FFI', obs_id]) prods = Observations.get_product_list(obs) # Check that WARNING messages about FFIs were logged @@ -701,9 +697,9 @@ def test_observations_get_product_list_tess_tica(self, caplog): assert "TESS FFI products" in caplog.text assert "TICA FFI products" in caplog.text - # Should only return products corresponding to target 429031146 + # Should only return products corresponding to target 1258205337 assert len(prods) > 0 - assert (np.char.find(np.char.asarray(prods['obs_id']), '429031146') != -1).all() + assert (np.char.find(np.asarray(prods['obs_id']), obs_id) != -1).all() def test_observations_get_unique_product_list(self, caplog): # Check that no rows are filtered out when all products are unique @@ -1080,6 +1076,7 @@ def test_catalogs_query_region(self): def check_result(result, row, exp_values): assert isinstance(result, Table) for k, v in exp_values.items(): + print(result[row][k]) assert result[row][k] == v in_radius = 0.1 * u.deg @@ -1087,7 +1084,7 @@ def check_result(result, row, exp_values): radius=in_radius, catalog="Gaia") row = np.where(result['source_id'] == '3774902350511581696') - check_result(result, row, {'solution_id': '1635721458409799680'}) + check_result(result, row, {'solution_id': '1636148068921376768'}) result = Catalogs.query_region("322.49324 12.16683", radius=0.001*u.deg, @@ -1109,10 +1106,11 @@ def check_result(result, row, exp_values): check_result(result, row, {'NumImages': 11, 'TargetName': 'NGC7078'}) result = Catalogs.query_region("322.49324 12.16683", - radius=in_radius, + radius=0.01, catalog="Gaia", version=1) row = np.where(result['source_id'] == '1745948323734098688') + print(result[row]) check_result(result, row, {'solution_id': '1635378410781933568'}) result = Catalogs.query_region("322.49324 12.16683", radius=0.01*u.deg, diff --git a/docs/mast/mast_cut.rst b/docs/mast/mast_cut.rst index 545d8e05b6..d41b994ce4 100644 --- a/docs/mast/mast_cut.rst +++ b/docs/mast/mast_cut.rst @@ -390,18 +390,18 @@ You can also request cutouts in image formats such as jpg by setting the ``cutou Downloading URL https://mast.stsci.edu/zcut/api/v0.1/astrocut?ra=189.49206&dec=62.20615&y=200&x=300&units=px&format=jpg to ./zcut_20201202132453.zip ... [Done] ... >>> print(manifest) - Local Path - ------------------------------------------------------------------------------------------------------- - ./hlsp_3dhst_spitzer_irac_goods-n_irac1_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_spitzer_irac_goods-n-s2_irac3_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_spitzer_irac_goods-n-s1_irac4_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_spitzer_irac_goods-n_irac2_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_mayall_mosaic_goods-n_u_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_subaru_suprimecam_goods-n_rc_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_subaru_suprimecam_goods-n_v_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_subaru_suprimecam_goods-n_ic_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_subaru_suprimecam_goods-n_zp_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg - ./hlsp_3dhst_subaru_suprimecam_goods-n_b_v4.0_sc_189.492060_62.206150_10.0pix-x-5.0pix_astrocut_0.jpg + Local Path + ---------------------------------------------------------------------------------------------------------- + ./hlsp_3dhst_spitzer_irac_goods-n_irac1_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_0.jpg + ./hlsp_3dhst_spitzer_irac_goods-n-s2_irac3_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_1.jpg + ./hlsp_3dhst_spitzer_irac_goods-n-s1_irac4_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_2.jpg + ./hlsp_3dhst_spitzer_irac_goods-n_irac2_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_3.jpg + ./hlsp_3dhst_mayall_mosaic_goods-n_u_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_4.jpg + ./hlsp_3dhst_subaru_suprimecam_goods-n_rc_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_5.jpg + ./hlsp_3dhst_subaru_suprimecam_goods-n_v_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_6.jpg + ./hlsp_3dhst_subaru_suprimecam_goods-n_ic_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_7.jpg + ./hlsp_3dhst_subaru_suprimecam_goods-n_zp_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_8.jpg + ./hlsp_3dhst_subaru_suprimecam_goods-n_b_v4.0_sci_189.4920600_62.2061500_10.0pix-x-5.0pix_astrocut_9.jpg HAPCut diff --git a/docs/mast/mast_obsquery.rst b/docs/mast/mast_obsquery.rst index 6ef2a65d47..8796a65c3a 100644 --- a/docs/mast/mast_obsquery.rst +++ b/docs/mast/mast_obsquery.rst @@ -579,16 +579,16 @@ use the `~astropy.io.fits.open` function with the S3 URI and appropriate ``fsspe >>> from astropy.io import fits ... - >>> s3_uri = 's3://stpubdata/hst/public/jbev/jbeveo010/jbeveo010_drz.fits' + >>> s3_uri = 's3://stpubdata/hst/public/ibzd/ibzda1010/ibzda1010_spt.fits' >>> with fits.open(s3_uri, fsspec_kwargs={"anon": True}) as hdul: ... hdul.info() Filename: No. Name Ver Type Cards Dimensions Format - 0 PRIMARY 1 PrimaryHDU 857 () - 1 SCI 1 ImageHDU 82 (4240, 4313) float32 - 2 WHT 1 ImageHDU 44 (4240, 4313) float32 - 3 CTX 1 ImageHDU 37 (4240, 4313) int32 - 4 HDRTAB 1 BinTableHDU 595 10R x 293C [9A, 3A, K, D, D, D, D, D, D, D, D, D, D, D, D, D, K, 3A, 9A, 7A, 18A, 4A, D, D, D, D, 3A, D, D, D, D, D, D, D, D, D, D, D, D, K, 8A, 23A, D, D, D, D, K, K, K, 8A, K, 23A, 9A, 20A, K, 4A, K, D, K, K, K, K, 23A, D, D, D, D, K, K, 3A, 3A, 4A, 4A, L, D, D, D, 3A, 1A, K, D, D, D, D, D, 4A, 4A, 12A, 12A, 23A, 8A, 23A, 10A, 10A, D, D, 3A, 3A, 23A, 4A, 8A, 7A, 23A, D, K, D, 6A, 9A, 8A, D, D, L, 9A, 18A, 3A, K, 5A, 7A, 3A, D, 13A, 8A, 4A, 3A, L, K, L, K, L, K, K, D, D, D, D, D, D, 3A, 1A, D, 23A, D, D, D, 3A, 23A, L, 1A, 3A, 6A, D, 3A, 6A, K, D, D, D, D, D, D, D, D, D, D, 23A, D, D, D, D, 3A, D, D, D, 1A, K, K, K, K, K, K, 23A, K, 5A, 7A, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, 12A, D, 24A, 23A, D, 1A, 1A, D, K, D, D, 1A, 1A, D, 4A, K, D, K, 7A, D, D, D, D, D, 23A, 23A, D, 8A, D, 29A, D, 3A, D, L, D, D, 4A, 6A, 5A, 2A, D, 3A, K, 1A, 1A, 1A, 1A, D, D, D, D, D, D, 4A, D, 4A, D, 4A, K, 4A, 3A, 1A, L, K, K, 37A, 1A, D, D, D, D, K, 3A, L, L, 6A, L, D, D, 3A, D, D, 3A, 8A, 1A, D, K, D, L, 30A, L, 5A] + 0 PRIMARY 1 PrimaryHDU 344 () + 1 UDL 1 ImageHDU 196 (965,) int16 + 2 SNAP1 1 ImageHDU 650 () + 3 UDL 2 ImageHDU 196 (965,) int16 + 4 SNAP1 2 ImageHDU 650 () Hybrid Workflows: Cloud-First Downloads