diff --git a/.circleci/config.yml b/.circleci/config.yml index 28c860eef..b3604c29f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,7 +32,7 @@ jobs: jobname: type: string docker: - - image: cimg/python:3.12 + - image: cimg/python:3.14 environment: TOXENV=<< parameters.jobname >> steps: @@ -57,7 +57,7 @@ jobs: jobname: type: string docker: - - image: cimg/python:3.12 + - image: cimg/python:3.14 environment: TOXENV: << parameters.jobname >> GIT_SSH_COMMAND: ssh -i ~/.ssh/id_rsa_b1c8b094a8ec67162b0f18a949a6b1db @@ -99,16 +99,16 @@ workflows: matrix: parameters: jobname: - - "py312-figure" - - "py312-figure-devdeps" + - "py314-figure" + - "py314-figure-devdeps" - deploy-reference-images: name: baseline-<< matrix.jobname >> matrix: parameters: jobname: - - "py312-figure" - - "py312-figure-devdeps" + - "py314-figure" + - "py314-figure-devdeps" requires: - << matrix.jobname >> filters: diff --git a/ndcube/conftest.py b/ndcube/conftest.py index 1810d0160..24c86b0bb 100644 --- a/ndcube/conftest.py +++ b/ndcube/conftest.py @@ -224,6 +224,57 @@ def gwcs_2d_lt_ln(): return (wcs.WCS(forward_transform=cel_model, output_frame=sky_frame, input_frame=input_frame)) + +@pytest.fixture +def gwcs_2d_t_f_linear(): + """ + 2D gWCS for a dynamic spectrum: uniform time (array axis 1 / X) and linear + frequency (array axis 0 / Y). + """ + time_model = models.Scale(14.0) + freq_model = models.Scale(1e6) + + time_frame = cf.TemporalFrame(axes_order=(0,), unit=u.s, + reference_frame=Time("2024-03-23T00:03:23")) + freq_frame = cf.SpectralFrame(axes_order=(1,), unit=u.Hz, axes_names=('frequency',)) + + transform = time_model & freq_model + frame = cf.CompositeFrame([time_frame, freq_frame]) + detector_frame = cf.CoordinateFrame(name="detector", naxes=2, + axes_order=(0, 1), + axes_type=("pixel", "pixel"), + unit=(u.pix, u.pix)) + return wcs.WCS(forward_transform=transform, output_frame=frame, + input_frame=detector_frame) + + +@pytest.fixture +def gwcs_2d_t_f_log(): + """ + 2D gWCS for a dynamic spectrum: irregularly-spaced time (array axis 1 / X) + and log-spaced frequency (array axis 0 / Y) via Tabular1D lookup tables. + """ + times_s = np.array([0.0, 14.0, 27.4, 41.1, 55.2, 67.8, 82.3, 95.9, 109.1, 122.5]) + freqs_hz = np.logspace(np.log10(3.992e6), np.log10(978.572e6), 16) + + time_model = models.Tabular1D(points=np.arange(10), lookup_table=times_s, + method='linear', bounds_error=False) + freq_model = models.Tabular1D(points=np.arange(16), lookup_table=freqs_hz, + method='linear', bounds_error=False) + + time_frame = cf.TemporalFrame(axes_order=(0,), unit=u.s, + reference_frame=Time("2024-03-23T00:03:23")) + freq_frame = cf.SpectralFrame(axes_order=(1,), unit=u.Hz, axes_names=('frequency',)) + + transform = time_model & freq_model + frame = cf.CompositeFrame([time_frame, freq_frame]) + detector_frame = cf.CoordinateFrame(name="detector", naxes=2, + axes_order=(0, 1), + axes_type=("pixel", "pixel"), + unit=(u.pix, u.pix)) + return wcs.WCS(forward_transform=transform, output_frame=frame, + input_frame=detector_frame) + @pytest.fixture def wcs_4d_t_l_lt_ln(): header = { @@ -564,6 +615,20 @@ def extra_coords_sharing_axis(): # NOTE: If you add more fixtures please add to the all_ndcubes fixture ################################################################################ +@pytest.fixture +def ndcube_gwcs_2d_t_f_linear(gwcs_2d_t_f_linear): + shape = (16, 10) # (n_freq, n_time): freq on Y axis, time on X axis + gwcs_2d_t_f_linear.array_shape = shape + return NDCube(data_nd(shape), wcs=gwcs_2d_t_f_linear) + + +@pytest.fixture +def ndcube_gwcs_2d_t_f_log(gwcs_2d_t_f_log): + shape = (16, 10) # (n_freq, n_time): freq on Y axis, time on X axis + gwcs_2d_t_f_log.array_shape = shape + return NDCube(data_nd(shape), wcs=gwcs_2d_t_f_log) + + @pytest.fixture def ndcube_gwcs_4d_ln_lt_l_t(gwcs_4d_t_l_lt_ln): shape = (5, 8, 10, 12) @@ -1074,6 +1139,8 @@ def ndcube_1d_l(wcs_1d_l): @pytest.fixture(params=[ + "ndcube_gwcs_2d_t_f_linear", + "ndcube_gwcs_2d_t_f_log", "ndcube_gwcs_4d_ln_lt_l_t", "ndcube_gwcs_4d_ln_lt_l_t_unit", "ndcube_gwcs_3d_ln_lt_l", diff --git a/ndcube/tests/test_ndcube_dynspec.py b/ndcube/tests/test_ndcube_dynspec.py new file mode 100644 index 000000000..9de9be2f9 --- /dev/null +++ b/ndcube/tests/test_ndcube_dynspec.py @@ -0,0 +1,135 @@ +""" +Tests to simulate dynamic spectrum WCSes (frequency x time). +""" +import pytest +from numpy.testing import assert_allclose + +import astropy.units as u + +from ndcube.wcs.wrappers import ResampledLowLevelWCS + + +def _world_at(cube, time_pixel, freq_pixel): + return cube.wcs.low_level_wcs.pixel_to_world_values(time_pixel, freq_pixel) + + +@pytest.mark.parametrize("ndc", [ + "ndcube_gwcs_2d_t_f_linear", + "ndcube_gwcs_2d_t_f_log", +], indirect=True) +def test_dynspec_array_axis_physical_types(ndc): + types = ndc.array_axis_physical_types + assert "em.freq" in types[0] + assert "time" in types[1] + + +def test_linear_dynspec_pixel_to_world(ndcube_gwcs_2d_t_f_linear): + time, freq = ndcube_gwcs_2d_t_f_linear.wcs.low_level_wcs.pixel_to_world_values(3, 2) + assert_allclose(time, 42.0) + assert_allclose(freq, 2e6) + + +def test_linear_dynspec_world_to_pixel(ndcube_gwcs_2d_t_f_linear): + pix_t, pix_f = ndcube_gwcs_2d_t_f_linear.wcs.low_level_wcs.world_to_pixel_values(28.0, 4e6) + assert_allclose(pix_t, 2.0) + assert_allclose(pix_f, 4.0) + + +@pytest.mark.parametrize(("bin_shape", "expected_shape", "expected_time", "expected_freq"), [ + ((2, 1), (8, 10), 0.0, 0.5e6), + ((1, 2), (16, 5), 7.0, 0.0), +]) +def test_linear_dynspec_rebin_wcs(ndcube_gwcs_2d_t_f_linear, bin_shape, + expected_shape, expected_time, expected_freq): + rebinned = ndcube_gwcs_2d_t_f_linear.rebin(bin_shape) + time0, freq0 = rebinned.wcs.low_level_wcs.pixel_to_world_values(0, 0) + + assert rebinned.shape == expected_shape + assert isinstance(rebinned.wcs.low_level_wcs, ResampledLowLevelWCS) + assert_allclose(time0, expected_time) + assert_allclose(freq0, expected_freq) + + +@pytest.mark.parametrize(("lower_corner", "upper_corner", "expected_shape"), [ + ([None, 3e6 * u.Hz], [None, 7e6 * u.Hz], (5, 10)), + ([14 * u.s, None], [56 * u.s, None], (16, 4)), +]) +def test_linear_dynspec_crop_by_values_shape(ndcube_gwcs_2d_t_f_linear, + lower_corner, upper_corner, + expected_shape): + cropped = ndcube_gwcs_2d_t_f_linear.crop_by_values(lower_corner, upper_corner) + assert cropped.shape == expected_shape + + +def test_log_dynspec_world_axis_units(ndcube_gwcs_2d_t_f_log): + assert ndcube_gwcs_2d_t_f_log.wcs.world_axis_units == ("s", "Hz") + + +@pytest.mark.parametrize(("time_pixel", "freq_pixel", "expected_time", "expected_freq"), [ + (0, 0, 0.0, 3.992e6), + (9, 15, 122.5, 978.572e6), +]) +def test_log_dynspec_pixel_to_world_endpoints(ndcube_gwcs_2d_t_f_log, + time_pixel, freq_pixel, + expected_time, expected_freq): + time, freq = ndcube_gwcs_2d_t_f_log.wcs.low_level_wcs.pixel_to_world_values( + time_pixel, freq_pixel) + assert_allclose(time, expected_time) + assert_allclose(freq, expected_freq, rtol=1e-6) + + +def test_log_dynspec_world_to_pixel_roundtrip(ndcube_gwcs_2d_t_f_log): + time, freq = _world_at(ndcube_gwcs_2d_t_f_log, 3, 7) + pix_t, pix_f = ndcube_gwcs_2d_t_f_log.wcs.low_level_wcs.world_to_pixel_values( + time, freq) + assert_allclose(pix_t, 3.0, atol=1e-10) + assert_allclose(pix_f, 7.0, atol=1e-10) + + +@pytest.mark.parametrize(("bin_shape", "expected_shape", "axis"), [ + ((2, 1), (8, 10), "freq"), + ((1, 2), (16, 5), "time"), +]) +def test_log_dynspec_rebin_wcs_midpoint(ndcube_gwcs_2d_t_f_log, bin_shape, + expected_shape, axis): + rebinned = ndcube_gwcs_2d_t_f_log.rebin(bin_shape) + time0, freq0 = rebinned.wcs.low_level_wcs.pixel_to_world_values(0, 0) + + assert rebinned.shape == expected_shape + assert isinstance(rebinned.wcs.low_level_wcs, ResampledLowLevelWCS) + if axis == "freq": + _, freq_left = _world_at(ndcube_gwcs_2d_t_f_log, 0, 0) + _, freq_right = _world_at(ndcube_gwcs_2d_t_f_log, 0, 1) + assert_allclose(freq0, (freq_left + freq_right) / 2, rtol=1e-6) + else: + time_left, _ = _world_at(ndcube_gwcs_2d_t_f_log, 0, 0) + time_right, _ = _world_at(ndcube_gwcs_2d_t_f_log, 1, 0) + assert_allclose(time0, (time_left + time_right) / 2, rtol=1e-6) + + +@pytest.mark.parametrize(("lower_corner", "upper_corner", "expected_shape", + "axis", "bounds"), [ + ([None, 10e6 * u.Hz], [None, 100e6 * u.Hz], (8, 10), "freq", (10e6, 100e6)), + ([20 * u.s, None], [80 * u.s, None], (16, 6), "time", (20.0, 80.0)), +]) +def test_log_dynspec_crop_by_values_single_axis(ndcube_gwcs_2d_t_f_log, + lower_corner, upper_corner, + expected_shape, axis, bounds): + cropped = ndcube_gwcs_2d_t_f_log.crop_by_values(lower_corner, upper_corner) + assert cropped.shape == expected_shape + + if axis == "freq": + values = [cropped.wcs.low_level_wcs.pixel_to_world_values(0, i)[1] + for i in range(cropped.shape[0])] + else: + values = [cropped.wcs.low_level_wcs.pixel_to_world_values(i, 0)[0] + for i in range(cropped.shape[1])] + + assert values[0] <= bounds[0] + assert values[-1] >= bounds[1] + + +def test_log_dynspec_crop_by_freq_and_time(ndcube_gwcs_2d_t_f_log): + cropped = ndcube_gwcs_2d_t_f_log.crop_by_values( + [20 * u.s, 10e6 * u.Hz], [80 * u.s, 100e6 * u.Hz]) + assert cropped.shape == (8, 6) diff --git a/ndcube/tests/test_ndcube_slice_and_crop.py b/ndcube/tests/test_ndcube_slice_and_crop.py index cb4cb4c07..56b7cd4a4 100644 --- a/ndcube/tests/test_ndcube_slice_and_crop.py +++ b/ndcube/tests/test_ndcube_slice_and_crop.py @@ -615,3 +615,25 @@ def test_crop_all_points_beyond_cube_extent_error(points): with pytest.raises(ValueError, match="are outside the range of the NDCube being cropped"): cube.crop(*points, keepdims=True) + + +def test_crop_by_values_quantity_table_coordinate(): + # Regression: QuantityTableCoordinate-based WCS raised + # "High Level objects are not supported with the native API" because + # world_to_pixel_values received Quantity objects instead of plain values. + freqs_hz = np.logspace(np.log10(4e6), np.log10(200e6), 16) + times_s = np.linspace(0, 140, 10) + wcs2d = astropy.wcs.WCS(naxis=2) + wcs2d.wcs.ctype = ["PIXEL", "PIXEL"] + wcs2d.wcs.crpix = [1, 1] + wcs2d.wcs.cdelt = [1, 1] + wcs2d.wcs.crval = [0, 0] + data = np.arange(16 * 10).reshape(16, 10) + cube = NDCube(data, wcs=wcs2d) + cube.extra_coords.add("frequency", (0,), freqs_hz * u.Hz) + cube.extra_coords.add("time", (1,), times_s * u.s) + + cropped = cube.crop_by_values([10e6 * u.Hz, 20 * u.s], [100e6 * u.Hz, 80 * u.s], + wcs=cube.extra_coords) + assert cropped.shape == (10, 5) + np.testing.assert_array_equal(cropped.data, data[3:13, 1:6]) diff --git a/ndcube/utils/cube.py b/ndcube/utils/cube.py index 241aae066..d1c188a13 100644 --- a/ndcube/utils/cube.py +++ b/ndcube/utils/cube.py @@ -181,8 +181,20 @@ def get_crop_item_from_points(points, wcs, crop_by_values, keepdims, original_sh # Derive the pixel indices of the input point and place each index # in the list corresponding to its axis. # Use the to_pixel methods to preserve fractional indices for future rounding. - point_pixel_indices = (sliced_wcs.world_to_pixel_values(*sliced_point) if crop_by_values - else HighLevelWCSWrapper(sliced_wcs).world_to_pixel(*sliced_point)) + if crop_by_values: + # world_to_pixel_values is APE14 low-level API and expects plain + # floats, not Quantity objects. So we need to strip units here; the values are + # already in the correct units because _get_crop_by_values_item called + # .to(wcs.world_axis_units[j]) before reaching this point. + # + # Passing Quantity objects raises TypeError in gWCS when the WCS's + # declared high-level type is itself Quantity (e.g., a WCS built from + # QuantityTableCoordinate), because gWCS cannot distinguish such inputs + # from an accidental high-level API call. + stripped_point = [p.value if hasattr(p, "value") else p for p in sliced_point] + point_pixel_indices = sliced_wcs.world_to_pixel_values(*stripped_point) + else: + point_pixel_indices = HighLevelWCSWrapper(sliced_wcs).world_to_pixel(*sliced_point) # For each pixel axis associated with this point, place the pixel coords for # that pixel axis into the corresponding list within combined_points_pixel_idx. if sliced_wcs.pixel_n_dim == 1: diff --git a/ndcube/visualization/tests/figure_hashes_mpl_3100_ft_261_astropy_710_animators_124.json b/ndcube/visualization/tests/figure_hashes_mpl_3109_ft_261_astropy_720_animators_124.json similarity index 100% rename from ndcube/visualization/tests/figure_hashes_mpl_3100_ft_261_astropy_710_animators_124.json rename to ndcube/visualization/tests/figure_hashes_mpl_3109_ft_261_astropy_720_animators_124.json diff --git a/ndcube/visualization/tests/figure_hashes_mpl_dev_ft_2143_astropy_dev_animators_dev.json b/ndcube/visualization/tests/figure_hashes_mpl_dev_ft_2143_astropy_dev_animators_dev.json new file mode 100644 index 000000000..0172099f3 --- /dev/null +++ b/ndcube/visualization/tests/figure_hashes_mpl_dev_ft_2143_astropy_dev_animators_dev.json @@ -0,0 +1,29 @@ +{ + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube": "61b743e90986d7c624d2cbd78ca78cfdd6c46e0f7726aed10af178f9f8d7d1e3", + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice0-kwargs0]": "ea9da0f97ceb0538ff7acd017aa63a475a2648b575c0005cd9a38693791f0092", + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice1-kwargs1]": "e5922ae535968af5833b5d10ebe2ed5870e01cbeccece83212bfccf6999700c7", + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice2-kwargs2]": "c525c9d2e51d348dca04383444710261d9b46b71b36b6af770a0cf12972aae61", + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice3-kwargs3]": "d318ec88e5515e61c8e53525734b1e424f58559bc2ccc7af154e3ce3f5405387", + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[uncertainty-cslice4-kwargs4]": "855cd9c8ec77dddd092ca6d4506f9bc5bf309869e502a0256b542b2cbbccc8dd", + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[unit_uncertainty-cslice5-kwargs5]": "e44c87f05655e7c11aa5e1947d1506033acb4cde165616118055a063ebc5c9df", + "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[mask-cslice6-kwargs6]": "ec0b8fdb355f47945d893858abd61a1fd097e7cea210148a7699a05fd3f14e2d", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube": "8dacf131e153015efc66fccf4f475d17fc9b87d2be9ca6d2f9cd01a24a2a5a18", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_colorbar": "378f0b34d69ba8ad4caa76df93b9fb57d1f0a9c540b6c5afe238737970e0e854", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_custom_axis": "8dacf131e153015efc66fccf4f475d17fc9b87d2be9ca6d2f9cd01a24a2a5a18", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_custom_axis_plot_axes": "f0913c14ae37080b56bc16a1ef3129b69922932c31849102c49ae4ab91b9aaca", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[ln_lt_l_t-cslice0-kwargs0]": "43534b4bf0a1d901ed410188f26e29a8067ec6c0adb621e6623c3a68b8fa3afb", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[ln_lt_l_t-cslice1-kwargs1]": "24f65c026fd64b24f416db69c3fa4a7607191f3f5596268c00af5794d7123aa2", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[ln_lt_l_t-cslice2-kwargs2]": "520ba0ba241cbad9b042ace302c1c25c0b5b1c6d4652ee8f76dba63fcc691929", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[unit_uncertainty-cslice3-kwargs3]": "43534b4bf0a1d901ed410188f26e29a8067ec6c0adb621e6623c3a68b8fa3afb", + "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[mask-cslice4-kwargs4]": "1b9495133636c27923ac7701dcd77fec51239a6509c0e198274e40529fbca3b8", + "ndcube.visualization.tests.test_plotting.test_animate_2D_cube": "cfad6d4794b50026abea9de223ae97f3f5dfbd28b9e75a14e955a0b45fc1ecce", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice0-kwargs0]": "628751fc2fc5cdcacf42a88e9152bbdce69a3fb6dd2f46e1e2c00d82f051843c", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice1-kwargs1]": "61e991fb1a45005720e60faab9f0f41adad8f8ac827d3dc018c44c8d7c422207", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-None-kwargs2]": "5f2a07be30fcff768f458c6a2d18e6cbbadcec605af15cf2977421556bbb5bda", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-None-kwargs3]": "62b6fa3af726115e7f4b1579744564fdfff4efde3f5612cf651a8fd161f7661d", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-None-kwargs4]": "1b24cbbe4da25b222754e96a547c9f9bd1905df30bc742033babebc093dbe2a0", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice5-kwargs5]": "d34b83c14da1348cf1d9ba20fb0c929c061d922303465daf46f6bb67f8ee2d6e", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice6-kwargs6]": "5f2a07be30fcff768f458c6a2d18e6cbbadcec605af15cf2977421556bbb5bda", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[unit_uncertainty-cslice7-kwargs7]": "d34b83c14da1348cf1d9ba20fb0c929c061d922303465daf46f6bb67f8ee2d6e", + "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[mask-cslice8-kwargs8]": "86d89a4034798c01a016ec8756b353a5b8d9d9332664fd1162c8fb2dc1f201c1" +} \ No newline at end of file diff --git a/ndcube/visualization/tests/figure_hashes_mpl_dev_ft_261_astropy_dev_animators_dev.json b/ndcube/visualization/tests/figure_hashes_mpl_dev_ft_261_astropy_dev_animators_dev.json deleted file mode 100644 index c3757929f..000000000 --- a/ndcube/visualization/tests/figure_hashes_mpl_dev_ft_261_astropy_dev_animators_dev.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube": "040edf223f40754b7a53915da165d10dad9d4456622f1f8217269679c3b22550", - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice0-kwargs0]": "ea89b5d1c2fdcf34ba353dffe528f5ecd5ce364a77f43a08d00a6a7f11a869f4", - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice1-kwargs1]": "f5d10df37509d1ba9429deb95ee29cf37dddea1a30f4c84cf2b10034c74c31bd", - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice2-kwargs2]": "e48765a561ea0f43f5a80d3da27fd71654b18d276cbb7617e1918843012425f9", - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[ln_lt_l_t-cslice3-kwargs3]": "7d9c6a470077d7ea1e2a38160d9dd27e9c82e9106d8bfdcec789055e9089c8cd", - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[uncertainty-cslice4-kwargs4]": "04083a963e79e9aaf2d1771e9a86158ef4be51c4b8cde7b6b7b85f80e1452ea9", - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[unit_uncertainty-cslice5-kwargs5]": "53f90627c0612aac7edcca97e108069b915bc7edaf871e62ba747732510e7cb2", - "ndcube.visualization.tests.test_plotting.test_plot_1D_cube_from_slice[mask-cslice6-kwargs6]": "b888887d05f9f7654968bd59a33fd86a12111503222904bfd369475210da7abb", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube": "4b194dbc850bfd9ae983ec5f0e07e7295f537e591e61177aadca28e41d74bd98", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_colorbar": "8adf60402dbd71d066547a08c81757f99db4f55b85288212420cf3a70f967c3e", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_custom_axis": "4b194dbc850bfd9ae983ec5f0e07e7295f537e591e61177aadca28e41d74bd98", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_custom_axis_plot_axes": "712809a75e7d587c064d9631ed218214071a9dd2d8017d937ae73c613e4c2ab4", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[ln_lt_l_t-cslice0-kwargs0]": "77b0b9a0067897786777a78974cff240a3268ed38937047c3945473e82bc4cf0", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[ln_lt_l_t-cslice1-kwargs1]": "2af86ad3672ef70d51b3637325c5e7860cad26f70032b51877d45d0a9b647a44", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[ln_lt_l_t-cslice2-kwargs2]": "af99b2460f2ed4a99f159fe854cdf63285eaffb55c09932f74f15f2198a7f1b1", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[unit_uncertainty-cslice3-kwargs3]": "77b0b9a0067897786777a78974cff240a3268ed38937047c3945473e82bc4cf0", - "ndcube.visualization.tests.test_plotting.test_plot_2D_cube_from_slice[mask-cslice4-kwargs4]": "490f4d37a93ab800ab2eb4fa077c448bcd6ebc30d64ab374118f5a9288246fb3", - "ndcube.visualization.tests.test_plotting.test_animate_2D_cube": "f0622456d02808c9845336e7bead8f4ac22e99d2450bf6f14bb74686a45fd5ed", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice0-kwargs0]": "47a0279e3244139f5b7126625a1aeb2bd038b3b39b38829a6b5a9129d8bba09d", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice1-kwargs1]": "8e9303bb77aef56991d2cf470de6840cea1994dd8ffb17bec48be9428ec5f7b8", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-None-kwargs2]": "4ae632474865d7df8434f66560c83205597437eadb61840266c334a836e4df7d", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-None-kwargs3]": "6ed647bf57c788e3f8bbdb730b1efa5c77f3b4f3cc44a149c16b62ee1fd8c6e3", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-None-kwargs4]": "4a983ef4f55fefde7c157f0d2799084db2bc4241e64d7a1d3b2e752bbba81518", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice5-kwargs5]": "b6acd10439bdc945b762ef9be430b5805c735e715ac4a1621d2fb834e48e91c1", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[ln_lt_l_t-cslice6-kwargs6]": "4ae632474865d7df8434f66560c83205597437eadb61840266c334a836e4df7d", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[unit_uncertainty-cslice7-kwargs7]": "b6acd10439bdc945b762ef9be430b5805c735e715ac4a1621d2fb834e48e91c1", - "ndcube.visualization.tests.test_plotting.test_animate_cube_from_slice[mask-cslice8-kwargs8]": "27db07c262fdb78bc45e9302c9c18d60e73c840d6f26e4af156355f73c3ef6e0" -} \ No newline at end of file diff --git a/pytest.ini b/pytest.ini index 8d042b270..a1c2f7bff 100644 --- a/pytest.ini +++ b/pytest.ini @@ -58,3 +58,5 @@ filterwarnings = ignore:Animating a NDCube does not support transposing the array. The world axes may not display as expected because the array will not be transposed:UserWarning # This is raised by the Windows and mac os build for visualization.rst ignore:FigureCanvasAgg is non-interactive, and thus cannot be shown:UserWarning + # wcsaxes/formatter_locator.py hates angles + ignore:.*invalid value encountered in do_format.*:RuntimeWarning diff --git a/tox.ini b/tox.ini index e7a843a2f..e41473dc2 100644 --- a/tox.ini +++ b/tox.ini @@ -57,9 +57,9 @@ deps = # Oldest Dependencies oldestdeps: minimum_dependencies # Figure tests need a tightly controlled environment - figure-!devdeps: astropy==7.1.0 + figure-!devdeps: astropy==7.2.0 figure-!devdeps: dask - figure-!devdeps: matplotlib==3.10.0 + figure-!devdeps: matplotlib==3.10.9 figure-!devdeps: mpl-animators==1.2.4 figure-!devdeps: scipy # The following indicates which extras_require will be installed