From f48bc16a746e38e48e00fd34324d2af116c0b647 Mon Sep 17 00:00:00 2001 From: Jesse Averbukh Date: Mon, 30 Sep 2024 08:10:57 -0400 Subject: [PATCH] Create import_region method for loading region objects (#3104) * Create import_region method for loading region objects * Remove call to load_regions * Add deprecated fixture to load_regions methods * Update combination_mode to listen to UI * Update import_region to switch from new to replace mode correctly * Remove unused pytest fixture * Add docs and fix rampviz test * Replace load_regions calls with import_region in notebooks * Replace applpy_roi with import_region in tests * Add new parameter to set combination mode to new after subset creation * Update tests to use subset_plugin._obj * Replace mode and create_as_new with combination_mode --- docs/cubeviz/import_data.rst | 4 +- docs/imviz/import_data.rst | 4 +- .../moment_maps/tests/test_moment_maps.py | 8 +- .../tests/test_spectral_extraction.py | 87 ++-- .../plugins/tests/test_cubeviz_aperphot.py | 8 +- .../plugins/tests/test_cubeviz_helper.py | 7 +- .../cubeviz/plugins/tests/test_parsers.py | 7 +- .../cubeviz/plugins/tests/test_regions.py | 16 +- .../data_quality/tests/test_data_quality.py | 2 +- .../plugins/export/tests/test_export.py | 53 ++- .../model_fitting/tests/test_plugin.py | 24 +- .../plugins/subset_plugin/subset_plugin.py | 360 +++++++++++++++-- .../subset_plugin/tests/test_subset_plugin.py | 47 ++- jdaviz/configs/imviz/plugins/parsers.py | 3 +- .../configs/imviz/tests/test_delete_data.py | 7 +- jdaviz/configs/imviz/tests/test_linking.py | 3 +- .../configs/imviz/tests/test_orientation.py | 2 +- jdaviz/configs/imviz/tests/test_regions.py | 52 +-- .../imviz/tests/test_simple_aper_phot.py | 26 +- .../imviz/tests/test_subset_centroid.py | 50 +-- jdaviz/configs/imviz/tests/test_viewers.py | 2 +- jdaviz/configs/imviz/tests/utils.py | 1 + .../rampviz/tests/test_ramp_extraction.py | 2 +- .../line_analysis/tests/test_line_analysis.py | 67 ++-- .../tests/test_unit_conversion.py | 3 +- jdaviz/configs/specviz/tests/test_helper.py | 107 ++--- jdaviz/core/tests/test_data_menu.py | 5 +- jdaviz/core/tests/test_helpers.py | 20 +- jdaviz/core/tests/test_template_mixin.py | 7 +- jdaviz/core/tools.py | 6 +- jdaviz/tests/test_subsets.py | 370 +++++++++--------- notebooks/CubevizExample.ipynb | 4 +- notebooks/ImvizDitheredExample.ipynb | 4 +- notebooks/ImvizExample.ipynb | 4 +- notebooks/concepts/RampvizExample.ipynb | 4 +- .../cubeviz_aperture_photometry.ipynb | 6 +- .../concepts/imviz_advanced_aper_phot.ipynb | 4 +- notebooks/concepts/imviz_color_display.ipynb | 4 +- notebooks/concepts/imviz_colorbar_mpl.ipynb | 4 +- .../imviz_edit_subset_programmatic.ipynb | 20 +- .../concepts/imviz_simple_aper_phot.ipynb | 4 +- 41 files changed, 898 insertions(+), 520 deletions(-) diff --git a/docs/cubeviz/import_data.rst b/docs/cubeviz/import_data.rst index 0f83a1ad61..77177ca452 100644 --- a/docs/cubeviz/import_data.rst +++ b/docs/cubeviz/import_data.rst @@ -197,7 +197,7 @@ can load the regions into Cubeviz as follows: .. code-block:: python - cubeviz.load_regions_from_file("/path/to/data/myregions.reg") + cubeviz.plugins['Subset Tools']._obj.import_region("/path/to/data/myregions.reg") Unsupported regions will be skipped and trigger a warning. Those that failed to load, if any, can be returned as a list of tuples of the @@ -205,7 +205,7 @@ form ``(region, reason)``: .. code-block:: python - bad_regions = cubeviz.load_regions_from_file("/path/to/data/myregions.reg", return_bad_regions=True) + bad_regions = cubeviz.plugins['Subset Tools']._obj.import_region("/path/to/data/myregions.reg", return_bad_regions=True) .. note:: Sky regions are currently unsupported in Cubeviz, unlike Imviz. diff --git a/docs/imviz/import_data.rst b/docs/imviz/import_data.rst index 7f9dcb4e2d..df682e66ee 100644 --- a/docs/imviz/import_data.rst +++ b/docs/imviz/import_data.rst @@ -215,7 +215,7 @@ can load the regions into Imviz as follows: .. code-block:: python - imviz.load_regions_from_file("/path/to/data/myregions.reg") + imviz.plugins['Subset Tools']._obj.import_region("/path/to/data/myregions.reg") Unsupported regions will be skipped and trigger a warning. Those that failed to load, if any, can be returned as a list of tuples of the @@ -223,7 +223,7 @@ form ``(region, reason)``: .. code-block:: python - bad_regions = imviz.load_regions_from_file("/path/to/data/myregions.reg", return_bad_regions=True) + bad_regions = imviz.plugins['Subset Tools']._obj.import_region("/path/to/data/myregions.reg", return_bad_regions=True) You could also define :ref:`regions:shapes` programmatically and load them; e.g.: diff --git a/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py b/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py index fa6941b81a..c587ed53d6 100644 --- a/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py +++ b/jdaviz/configs/cubeviz/plugins/moment_maps/tests/test_moment_maps.py @@ -8,8 +8,8 @@ from astropy.io import fits from astropy.nddata import CCDData from astropy.wcs import WCS -from glue.core.roi import XRangeROI from numpy.testing import assert_allclose +from specutils import SpectralRegion @pytest.mark.parametrize("cube_type", ["Surface Brightness", "Flux"]) @@ -233,8 +233,10 @@ def test_moment_frequency_unit_conversion(cubeviz_helper, spectrum1d_cube_larger uc = cubeviz_helper.plugins['Unit Conversion'] mm = cubeviz_helper.plugins['Moment Maps'] - viewer = cubeviz_helper.app.get_viewer('spectrum-viewer') - viewer.apply_roi(XRangeROI(4.624e-07, 4.627e-07)) + + unit = u.Unit(uc.spectral_unit.selected) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(4.624e-07 * unit, + 4.627e-07 * unit)) uc.spectral_unit = 'Hz' mm.spectral_subset = 'Subset 1' diff --git a/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py b/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py index 6e855decfd..3d79e3cff1 100644 --- a/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py +++ b/jdaviz/configs/cubeviz/plugins/spectral_extraction/tests/test_spectral_extraction.py @@ -10,7 +10,6 @@ from astropy.utils.exceptions import AstropyUserWarning from glue.core.roi import CircularROI, RectangularROI -from glue.core.edit_subset_mode import ReplaceMode, AndNotMode, NewMode from numpy.testing import assert_allclose, assert_array_equal from regions import (CirclePixelRegion, CircleAnnulusPixelRegion, EllipsePixelRegion, RectanglePixelRegion, PixCoord) @@ -84,7 +83,7 @@ def test_gauss_smooth_before_spec_extract(cubeviz_helper, spectrum1d_cube_with_u # two-pixel region: CirclePixelRegion(PixCoord(0.5, 0), radius=1.2) ] - cubeviz_helper.load_regions(regions) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(regions, combination_mode='new') extract_plugin = cubeviz_helper.plugins['Spectral Extraction'] extract_plugin.function = "Sum" @@ -124,7 +123,7 @@ def test_subset( ] cubeviz_helper.load_data(spectrum1d_cube_with_uncerts) - cubeviz_helper.load_regions(regions) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(regions, combination_mode='new') plg = cubeviz_helper.plugins['Spectral Extraction'] plg.function = function @@ -199,7 +198,8 @@ def test_save_collapsed_to_fits(cubeviz_helper, spectrum1d_cube_with_uncerts, tm def test_aperture_markers(cubeviz_helper, spectrum1d_cube): cubeviz_helper.load_data(spectrum1d_cube) - cubeviz_helper.load_regions([CirclePixelRegion(PixCoord(0.5, 0), radius=1.2)]) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + [CirclePixelRegion(PixCoord(0.5, 0), radius=1.2)]) extract_plg = cubeviz_helper.plugins['Spectral Extraction'] slice_plg = cubeviz_helper.plugins['Slice'] @@ -251,9 +251,10 @@ def test_cone_aperture_with_different_methods(cubeviz_helper, spectrum1d_cube_la expected_flux_2400): cubeviz_helper.load_data(spectrum1d_cube_largest) center = PixCoord(5, 10) - cubeviz_helper.load_regions([ - CirclePixelRegion(center, radius=2.5), - EllipsePixelRegion(center, width=5, height=5)]) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + CirclePixelRegion(center, radius=2.5), combination_mode='new') + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + EllipsePixelRegion(center, width=5, height=5), combination_mode='new') extract_plg = cubeviz_helper.plugins['Spectral Extraction'] @@ -283,9 +284,9 @@ def test_cylindrical_aperture_with_different_methods(cubeviz_helper, spectrum1d_ subset, aperture_method, expected_flux_wav): cubeviz_helper.load_data(spectrum1d_cube_largest, data_label="test") center = PixCoord(5, 10) - cubeviz_helper.load_regions([ + cubeviz_helper.plugins['Subset Tools']._obj.import_region([ CirclePixelRegion(center, radius=2.5), - EllipsePixelRegion(center, width=5, height=5)]) + EllipsePixelRegion(center, width=5, height=5)], combination_mode='new') extract_plg = cubeviz_helper.plugins['Spectral Extraction'] @@ -307,7 +308,8 @@ def test_cylindrical_aperture_with_different_methods(cubeviz_helper, spectrum1d_ # NOTE: Not as thorough as circle and ellipse above but good enough. def test_rectangle_aperture_with_exact(cubeviz_helper, spectrum1d_cube_largest): cubeviz_helper.load_data(spectrum1d_cube_largest) - cubeviz_helper.load_regions(RectanglePixelRegion(PixCoord(5, 10), width=4, height=4)) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + RectanglePixelRegion(PixCoord(5, 10), width=4, height=4)) extract_plg = cubeviz_helper.plugins['Spectral Extraction'] @@ -334,9 +336,9 @@ def test_background_subtraction(cubeviz_helper, spectrum1d_cube_largest): spectrum1d_cube_largest = spectrum1d_cube_largest + 1 * u.Jy cubeviz_helper.load_data(spectrum1d_cube_largest) - cubeviz_helper.load_regions([ + cubeviz_helper.plugins['Subset Tools']._obj.import_region([ CirclePixelRegion(PixCoord(5, 10), radius=2.5), - EllipsePixelRegion(PixCoord(13, 10), width=3, height=5)]) + EllipsePixelRegion(PixCoord(13, 10), width=3, height=5)], combination_mode='new') extract_plg = cubeviz_helper.plugins['Spectral Extraction'] with extract_plg.as_active(): @@ -387,9 +389,9 @@ def test_background_subtraction(cubeviz_helper, spectrum1d_cube_largest): def test_cone_and_cylinder_errors(cubeviz_helper, spectrum1d_cube_largest): cubeviz_helper.load_data(spectrum1d_cube_largest) center = PixCoord(5, 10) - cubeviz_helper.load_regions([ + cubeviz_helper.plugins['Subset Tools']._obj.import_region([ CirclePixelRegion(center, radius=2.5), - CircleAnnulusPixelRegion(center, inner_radius=2.5, outer_radius=4)]) + CircleAnnulusPixelRegion(center, inner_radius=2.5, outer_radius=4)], combination_mode='new') extract_plg = cubeviz_helper.plugins['Spectral Extraction'] @@ -414,7 +416,8 @@ def test_cone_and_cylinder_errors(cubeviz_helper, spectrum1d_cube_largest): def test_cone_aperture_with_frequency_units(cubeviz_helper, spectral_cube_wcs): data = Spectrum1D(flux=np.ones((128, 129, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data, data_label="Test Flux") - cubeviz_helper.load_regions([CirclePixelRegion(PixCoord(14, 15), radius=2.5)]) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + [CirclePixelRegion(PixCoord(14, 15), radius=2.5)]) extract_plg = cubeviz_helper.plugins['Spectral Extraction'] @@ -434,7 +437,8 @@ def test_cube_extraction_with_nan(cubeviz_helper, image_cube_hdu_obj): sp = extract_plg.extract() # Default settings (sum) assert_allclose(sp.flux.value, 9.6E-16) # (10 x 10) - 4 - cubeviz_helper.load_regions(RectanglePixelRegion(PixCoord(1.5, 1.5), width=4, height=4)) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + RectanglePixelRegion(PixCoord(1.5, 1.5), width=4, height=4)) extract_plg.aperture = 'Subset 1' sp_subset = extract_plg.extract() # Default settings but on Subset assert_allclose(sp_subset.flux.value, 1.2E-16) # (4 x 4) - 4 @@ -442,8 +446,8 @@ def test_cube_extraction_with_nan(cubeviz_helper, image_cube_hdu_obj): def test_autoupdate_results(cubeviz_helper, spectrum1d_cube_largest): cubeviz_helper.load_data(spectrum1d_cube_largest) - fv = cubeviz_helper.viewers['flux-viewer']._obj - fv.apply_roi(CircularROI(xc=5, yc=5, radius=2)) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + CircularROI(xc=5, yc=5, radius=2)) extract_plg = cubeviz_helper.plugins['Spectral Extraction'] extract_plg.aperture = 'Subset 1' @@ -454,8 +458,8 @@ def test_autoupdate_results(cubeviz_helper, spectrum1d_cube_largest): # orig_med_flux = np.median(cubeviz_helper.get_data('extracted').flux) # replace Subset 1 with a larger subset, resulting fluxes should increase - cubeviz_helper.app.session.edit_subset_mode.mode = ReplaceMode - fv.apply_roi(CircularROI(xc=5, yc=5, radius=3)) + cubeviz_helper.plugins['Subset Tools']._obj.combination_mode.selected = 'replace' + cubeviz_helper.plugins['Subset Tools']._obj.import_region(CircularROI(xc=5, yc=5, radius=3)) # update should take place automatically, but since its async, we'll call manually to ensure # the update is complete before comparing results @@ -469,26 +473,22 @@ def test_autoupdate_results(cubeviz_helper, spectrum1d_cube_largest): def test_aperture_composite_detection(cubeviz_helper, spectrum1d_cube): cubeviz_helper.load_data(spectrum1d_cube) - flux_viewer = cubeviz_helper.app.get_viewer('flux-viewer') subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj spec_extr_plugin = cubeviz_helper.plugins['Spectral Extraction']._obj # create a rectangular subset with all spaxels: rectangle = RectangularROI(-0.5, 1.5, -0.5, 3.5) - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:rectangle'] - flux_viewer.apply_roi(rectangle) + subset_plugin.import_region(rectangle) # select subset 1, ensure it's not a composite subset: spec_extr_plugin.aperture_selected = 'Subset 1' assert not spec_extr_plugin.aperture.is_composite # now remove from this subset a circular region in the center: - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:truecircle'] - subset_plugin.subset_selected = 'Subset 1' - cubeviz_helper.app.session.edit_subset_mode.mode = AndNotMode - circle = CircularROI(0.5, 1.5, 1) - flux_viewer.apply_roi(circle) + + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(circle) # now the subset is composite: assert spec_extr_plugin.aperture.is_composite @@ -497,18 +497,15 @@ def test_aperture_composite_detection(cubeviz_helper, spectrum1d_cube): def test_extraction_composite_subset(cubeviz_helper, spectrum1d_cube): cubeviz_helper.load_data(spectrum1d_cube) - flux_viewer = cubeviz_helper.app.get_viewer('flux-viewer') subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj spec_extr_plugin = cubeviz_helper.plugins['Spectral Extraction']._obj lower_aperture = RectangularROI(-0.5, 0.5, -0.5, 1.5) upper_aperture = RectangularROI(2.5, 3.5, -0.5, 1.5) - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:rectangle'] - flux_viewer.apply_roi(lower_aperture) - - cubeviz_helper.app.session.edit_subset_mode.mode = NewMode - flux_viewer.apply_roi(upper_aperture) + subset_plugin.import_region(lower_aperture) + subset_plugin.combination_mode.selected = 'new' + subset_plugin.import_region(upper_aperture) spec_extr_plugin.aperture_selected = 'Subset 1' spectrum_1 = spec_extr_plugin.extract() @@ -516,16 +513,16 @@ def test_extraction_composite_subset(cubeviz_helper, spectrum1d_cube): spec_extr_plugin.aperture_selected = 'Subset 2' spectrum_2 = spec_extr_plugin.extract() - subset_plugin.subset_selected = 'Create New' rectangle = RectangularROI(-0.5, 3.5, -0.5, 1.5) - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:rectangle'] - flux_viewer.apply_roi(rectangle) - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:truecircle'] + subset_plugin.combination_mode.selected = 'new' + subset_plugin.import_region(rectangle) + subset_plugin.subset_selected = 'Subset 3' - cubeviz_helper.app.session.edit_subset_mode.mode = AndNotMode circle = CircularROI(1.5, 0.5, 1.1) - flux_viewer.apply_roi(circle) + + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(circle) spec_extr_plugin.aperture_selected = 'Subset 3' @@ -559,10 +556,10 @@ def test_default_spectral_extraction(cubeviz_helper, spectrum1d_cube_fluxunit_jy # regression tests make sure that doesn't happen anymore by accounting # for non-science pixels in the sums: cubeviz_helper.load_data(spectrum1d_cube_fluxunit_jy_per_steradian) - flux_viewer = cubeviz_helper.app.get_viewer('flux-viewer') - # create a spatial subset that spans all spaxels: - flux_viewer.apply_roi(CircularROI(1.5, 2, 5)) + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + + subset_plugin.import_region(CircularROI(1.5, 2, 5)) # the first and second spectra correspond to the default extraction # and the subset extraction. the fluxes in these extractions should agree: @@ -646,8 +643,8 @@ def test_spectral_extraction_scientific_validation( cubeviz_helper.load_data(uri, cache=True) # add a subset with an aperture centered on each source - flux_viewer = cubeviz_helper.app.get_viewer('flux-viewer') - flux_viewer.apply_roi(CircularROI(*aperture)) + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(*aperture)) # set the slice to the blue end of MIRI CH1 slice_plugin = cubeviz_helper.plugins['Slice'] diff --git a/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_aperphot.py b/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_aperphot.py index 43b170c3e6..59916c9619 100644 --- a/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_aperphot.py +++ b/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_aperphot.py @@ -14,7 +14,7 @@ def test_cubeviz_aperphot_cube_orig_flux(cubeviz_helper, image_cube_hdu_obj_micr solid_angle_unit = u.pix * u.pix aper = RectanglePixelRegion(center=PixCoord(x=1, y=2), width=3, height=5) - cubeviz_helper.load_regions(aper) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(aper) # Make sure MASK is not an option even when shown in viewer. cubeviz_helper.app.add_data_to_viewer("flux-viewer", "test[MASK]", visible=True) @@ -110,7 +110,7 @@ def test_cubeviz_aperphot_generated_3d_gaussian_smooth(cubeviz_helper, image_cub cubeviz_helper.app.add_data_to_viewer("uncert-viewer", "test[FLUX] spatial-smooth stddev-1.0") aper = RectanglePixelRegion(center=PixCoord(x=1, y=2), width=3, height=5) - cubeviz_helper.load_regions(aper) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(aper) plg = cubeviz_helper.plugins["Aperture Photometry"]._obj plg.dataset_selected = "test[FLUX] spatial-smooth stddev-1.0" @@ -208,7 +208,7 @@ def test_cubeviz_aperphot_cube_orig_flux_mjysr(cubeviz_helper, spectrum1d_cube_c aper = RectanglePixelRegion(center=PixCoord(x=3, y=1), width=1, height=1) bg = RectanglePixelRegion(center=PixCoord(x=2, y=0), width=1, height=1) - cubeviz_helper.load_regions([aper, bg]) + cubeviz_helper.plugins['Subset Tools']._obj.import_region([aper, bg], combination_mode='new') plg = cubeviz_helper.plugins["Aperture Photometry"]._obj plg.dataset_selected = "test[FLUX]" @@ -275,7 +275,7 @@ def test_cubeviz_aperphot_unit_conversion(cubeviz_helper, spectrum1d_cube_custom bg = RectanglePixelRegion(center=PixCoord(x=1, y=2), width=1, height=1) cubeviz_helper.load_data(mjy_sr_cube, data_label="test") - cubeviz_helper.load_regions([aper, bg]) + cubeviz_helper.plugins['Subset Tools']._obj.import_region([aper, bg], combination_mode='new') ap = cubeviz_helper.plugins['Aperture Photometry']._obj diff --git a/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_helper.py b/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_helper.py index e5e90b881c..303d97b84c 100644 --- a/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_helper.py +++ b/jdaviz/configs/cubeviz/plugins/tests/test_cubeviz_helper.py @@ -1,4 +1,4 @@ -from glue.core.roi import XRangeROI +from specutils import SpectralRegion from jdaviz import Cubeviz from jdaviz.app import Application @@ -43,8 +43,9 @@ def test_get_data_spatial_and_spectral(cubeviz_helper, spectrum1d_cube_larger): cubeviz_helper._apply_interactive_region('bqplot:ellipse', (0, 0), (9, 8)) # Subset 2 (spectral) - spec_viewer = cubeviz_helper.app.get_viewer(cubeviz_helper._default_spectrum_viewer_reference_name) # noqa - spec_viewer.apply_roi(XRangeROI(4.62440061e-07, 4.62520112e-07)) + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + unit = spectrum1d_cube_larger.spectral_axis.unit + subset_plugin.import_region(SpectralRegion(4.62440061e-07 * unit, 4.62520112e-07 * unit)) spatial_with_spec = cubeviz_helper.get_data(data_label="Spectrum (Subset 1, sum)", spectral_subset="Subset 2") diff --git a/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py b/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py index 720959202a..9c3d715548 100644 --- a/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py +++ b/jdaviz/configs/cubeviz/plugins/tests/test_parsers.py @@ -2,8 +2,7 @@ import pytest from astropy import units as u from astropy.wcs import WCS -from specutils import Spectrum1D -from glue.core.roi import XRangeROI +from specutils import Spectrum1D, SpectralRegion from glue_astronomy.translators.spectrum1d import PaddedSpectrumWCS from numpy.testing import assert_allclose, assert_array_equal @@ -71,7 +70,9 @@ def test_spectrum1d_with_fake_fixed_units(spectrum1d, cubeviz_helper): dc[0].meta["_orig_spec"] = spectrum1d cubeviz_helper.app.add_data_to_viewer('spectrum-viewer', 'test') - cubeviz_helper.app.get_viewer('spectrum-viewer').apply_roi(XRangeROI(6600, 7400)) + unit = u.Unit(cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6600 * unit, + 7400 * unit)) subsets = cubeviz_helper.app.get_subsets() reg = subsets.get('Subset 1') diff --git a/jdaviz/configs/cubeviz/plugins/tests/test_regions.py b/jdaviz/configs/cubeviz/plugins/tests/test_regions.py index 751f738327..671dbacf98 100644 --- a/jdaviz/configs/cubeviz/plugins/tests/test_regions.py +++ b/jdaviz/configs/cubeviz/plugins/tests/test_regions.py @@ -6,9 +6,8 @@ import pytest from astropy import units as u from astropy.coordinates import SkyCoord -from glue.core.roi import XRangeROI from regions import PixCoord, CirclePixelRegion, CircleSkyRegion, EllipsePixelRegion -from specutils import Spectrum1D +from specutils import Spectrum1D, SpectralRegion from jdaviz.configs.imviz.tests.test_regions import BaseRegionHandler @@ -30,7 +29,8 @@ def teardown_method(self, method): def test_regions_mask(self): mask = np.zeros((9, 10), dtype=np.bool_) mask[0, 0] = True - bad_regions = self.cubeviz.load_regions([mask], return_bad_regions=True) + bad_regions = self.cubeviz.plugins['Subset Tools']._obj.import_region( + [mask], return_bad_regions=True) # TODO: Update expected results if we ever support masked Subset in Cubeviz. assert len(bad_regions) == 1 and bad_regions[0][1] == 'Mask creation failed' @@ -38,7 +38,8 @@ def test_regions_mask(self): def test_regions_pixel(self): # A little out-of-bounds should still overlay the overlapped part. my_reg = CirclePixelRegion(center=PixCoord(x=6, y=2), radius=5) - bad_regions = self.cubeviz.load_regions([my_reg], return_bad_regions=True) + bad_regions = self.cubeviz.plugins['Subset Tools']._obj.import_region( + [my_reg], return_bad_regions=True) assert len(bad_regions) == 0 self.verify_region_loaded('Subset 1', count=1) assert len(self.cubeviz.get_interactive_regions()) == 1 @@ -46,7 +47,8 @@ def test_regions_pixel(self): def test_regions_sky_has_wcs(self): sky = SkyCoord(205.4397, 27.0035, unit='deg') my_reg_sky_1 = CircleSkyRegion(center=sky, radius=0.0004 * u.deg) - bad_regions = self.cubeviz.load_regions(my_reg_sky_1, return_bad_regions=True) + bad_regions = self.cubeviz.plugins['Subset Tools']._obj.import_region( + my_reg_sky_1, return_bad_regions=True) # TODO: Update expected results when we support sky regions in Cubeviz. assert len(bad_regions) == 1 and bad_regions[0][1] == 'Sky region provided but data has no valid WCS' # noqa @@ -56,7 +58,9 @@ def test_spatial_spectral_mix(self): self.cubeviz._apply_interactive_region('bqplot:ellipse', (0, 0), (9, 8)) # Manually draw wavelength range. - self.spectrum_viewer.apply_roi(XRangeROI(4.892, 4.896)) + unit = u.Unit(self.cubeviz.plugins['Unit Conversion'].spectral_unit.selected) + self.cubeviz.plugins['Subset Tools']._obj.import_region(SpectralRegion(4.892 * unit, + 4.896 * unit)) self.cubeviz.app.session.edit_subset_mode.edit_subset = None # Get interactive spatial regions only. diff --git a/jdaviz/configs/default/plugins/data_quality/tests/test_data_quality.py b/jdaviz/configs/default/plugins/data_quality/tests/test_data_quality.py index 13b9f5dacc..593e454073 100644 --- a/jdaviz/configs/default/plugins/data_quality/tests/test_data_quality.py +++ b/jdaviz/configs/default/plugins/data_quality/tests/test_data_quality.py @@ -241,7 +241,7 @@ def test_cubeviz_layer_visibility_bug(cubeviz_helper, tmp_path): # create a spatial subset in the flux-viewer roi = RectangularROI(22, 27, 22, 30) - viewer.apply_roi(roi) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(roi) # toggle layer visibility, this used to trigger an AttributeError: cubeviz_helper.app.set_data_visibility('flux-viewer', dc[-1].label) diff --git a/jdaviz/configs/default/plugins/export/tests/test_export.py b/jdaviz/configs/default/plugins/export/tests/test_export.py index ebec3820d9..cde404ca80 100644 --- a/jdaviz/configs/default/plugins/export/tests/test_export.py +++ b/jdaviz/configs/default/plugins/export/tests/test_export.py @@ -6,10 +6,9 @@ from astropy import units as u from astropy.io import fits from astropy.nddata import NDData -from glue.core.edit_subset_mode import AndMode, NewMode -from glue.core.roi import CircularROI, XRangeROI +from glue.core.roi import CircularROI from regions import Regions, CircleSkyRegion -from specutils import Spectrum1D +from specutils import Spectrum1D, SpectralRegion from pathlib import Path @@ -25,10 +24,9 @@ def test_basic_export_subsets_imviz(self, imviz_helper): data = NDData(np.ones((500, 500)) * u.nJy) imviz_helper.load_data(data) + subset_plugin = imviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(xc=250, yc=250, radius=100)) - imviz_helper.app.get_viewer('imviz-0').apply_roi(CircularROI(xc=250, - yc=250, - radius=100)) export_plugin = imviz_helper.plugins['Export']._obj export_plugin.subset.selected = 'Subset 1' @@ -80,14 +78,10 @@ def test_not_implemented(self, cubeviz_helper, spectral_cube_wcs): data = Spectrum1D(flux=np.ones((500, 500, 2)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data) - - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(xc=255, - yc=255, - radius=50)) - cubeviz_helper.app.session.edit_subset_mode.mode = AndMode - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(xc=200, - yc=250, - radius=50)) + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(xc=255, yc=255, radius=50)) + subset_plugin.combination_mode.selected = 'and' + subset_plugin.import_region(CircularROI(xc=200, yc=250, radius=50)) export_plugin = cubeviz_helper.plugins['Export']._obj export_plugin.subset.selected = 'Subset 1' @@ -106,10 +100,8 @@ def test_export_subsets_wcs(self, imviz_helper, spectral_cube_wcs): imviz_helper.load_data(data) imviz_helper.link_data(align_by='wcs') - - imviz_helper.app.get_viewer('imviz-0').apply_roi(CircularROI(xc=8, - yc=6, - radius=.2)) + subset_plugin = imviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(xc=8, yc=6, radius=.2)) export_plugin = imviz_helper.plugins['Export']._obj export_plugin.subset.selected = 'Subset 1' @@ -130,10 +122,8 @@ def test_basic_export_subsets_cubeviz(self, cubeviz_helper, spectral_cube_wcs): data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data) - - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(xc=50, - yc=50, - radius=10)) + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(xc=50, yc=50, radius=10)) export_plugin = cubeviz_helper.plugins['Export']._obj export_plugin.subset.selected = 'Subset 1' @@ -198,17 +188,20 @@ def test_basic_export_subsets_cubeviz(self, cubeviz_helper, spectral_cube_wcs): export_plugin.subset_format.selected = 'ecsv' # test that attempting to save a composite subset raises an error - cubeviz_helper.app.session.edit_subset_mode.mode = AndMode - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(xc=25, yc=25, radius=5)) - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(xc=20, yc=25, radius=5)) + subset_plugin.combination_mode.selected = 'and' + subset_plugin.import_region(CircularROI(xc=25, yc=25, radius=5)) + subset_plugin.import_region(CircularROI(xc=20, yc=25, radius=5)) with pytest.raises(NotImplementedError, match='Subset can not be exported - Export for composite subsets not yet supported.'): # noqa export_plugin.export() # Test saving spectral subset - cubeviz_helper.app.session.edit_subset_mode.mode = NewMode - cubeviz_helper.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(5, 15.5)) + subset_plugin.combination_mode.selected = 'new' + spectral_axis_unit = u.Unit( + cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + subset_plugin.import_region(SpectralRegion(5 * spectral_axis_unit, + 15.5 * spectral_axis_unit)) export_plugin.subset.selected = 'Subset 2' # Format should auto-update to first non-disabled entry @@ -326,10 +319,8 @@ def test_ap_phot_plot_export(self, imviz_helper): imviz_helper.load_data(data) export_plugin = imviz_helper.plugins['Export']._obj - - imviz_helper.app.get_viewer('imviz-0').apply_roi(CircularROI(xc=250, - yc=250, - radius=100)) + subset_plugin = imviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(xc=250, yc=250, radius=100)) phot_plugin = imviz_helper.app.get_tray_item_from_name('imviz-aper-phot-simple') phot_plugin.aperture_selected = 'Subset 1' diff --git a/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py b/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py index a5bc92f011..4818de1640 100644 --- a/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py +++ b/jdaviz/configs/default/plugins/model_fitting/tests/test_plugin.py @@ -14,8 +14,8 @@ from astropy.utils.introspection import minversion import astropy.units as u -from glue.core.roi import CircularROI, XRangeROI -from specutils import Spectrum1D +from glue.core.roi import CircularROI +from specutils import Spectrum1D, SpectralRegion from jdaviz.configs.default.plugins.model_fitting.initializers import MODELS @@ -182,8 +182,9 @@ def test_toggle_cube_fit_subset(cubeviz_helper): cubeviz_helper.load_data(sp, data_label="test_cube") mf = cubeviz_helper.plugins['Model Fitting'] - sv = cubeviz_helper.app.get_viewer('spectrum-viewer') - sv.apply_roi(XRangeROI(7.5, 8)) + unit = u.Unit(cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(7.5 * unit, + 8 * unit)) mf.spectral_subset = 'Subset 1' mf.cube_fit = True @@ -295,8 +296,9 @@ def test_reestimate_parameters(specviz_helper, spectrum1d): assert mc['parameters']['stddev']['value'] == 1 assert mc['parameters']['stddev']['fixed'] is True - sv = specviz_helper.app.get_viewer('spectrum-viewer') - sv.apply_roi(XRangeROI(7500, 8000)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(7500 * unit, + 8000 * unit)) mf.spectral_subset = 'Subset 1' @@ -313,9 +315,8 @@ def test_subset_masks(cubeviz_helper, spectrum1d_cube_larger): cubeviz_helper.load_data(spectrum1d_cube_larger) assert spectrum1d_cube_larger.mask is None - fv = cubeviz_helper.app.get_viewer('flux-viewer') # create a "Subset 1" entry in spatial dimension, selected "interactively" - fv.apply_roi(CircularROI(0.5, 0.5, 1)) + cubeviz_helper.plugins['Subset Tools']._obj.import_region(CircularROI(0.5, 0.5, 1)) # check that when no subset is selected, the spectral cube has no mask: p = cubeviz_helper.app.get_tray_item_from_name('g-model-fitting') @@ -330,7 +331,8 @@ def test_subset_masks(cubeviz_helper, spectrum1d_cube_larger): sv.toolbar_active_subset.selected = [] # Now create the new spectral subset: - sv.apply_roi(XRangeROI(min=min_wavelength.to_value(u.m), max=max_wavelength.to_value(u.m))) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + SpectralRegion(min_wavelength.to(u.m), max_wavelength.to(u.m))) assert "Subset 2" in p.spectral_subset.choices # Select the spectral subset @@ -362,7 +364,9 @@ def test_invalid_subset(specviz_helper, spectrum1d): # apply subset that overlaps on left_spectrum, but not right_spectrum # NOTE: using a subset that overlaps the right_spectrum (reference) results in errors when # retrieving the subset (https://github.com/spacetelescope/jdaviz/issues/1868) - specviz_helper.app.get_viewer('spectrum-viewer').apply_roi(XRangeROI(5000, 6000)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(5000 * unit, + 6000 * unit)) plugin = specviz_helper.plugins['Model Fitting'] plugin.create_model_component('Linear1D') diff --git a/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py b/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py index 50e8e092bc..dc76774b29 100644 --- a/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py +++ b/jdaviz/configs/default/plugins/subset_plugin/subset_plugin.py @@ -8,17 +8,32 @@ from glue.core.edit_subset_mode import (AndMode, AndNotMode, OrMode, ReplaceMode, XorMode, NewMode) from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI -from glue.core.subset import RoiSubsetState, RangeSubsetState, CompositeSubsetState +from glue.core.subset import (RoiSubsetState, RangeSubsetState, CompositeSubsetState, + MaskSubsetState) from glue.icons import icon_path from glue_jupyter.widgets.subset_mode_vuetify import SelectionModeMenu from glue_jupyter.common.toolbar_vuetify import read_icon from traitlets import Any, List, Unicode, Bool, observe +from specutils import SpectralRegion +from photutils.aperture import (CircularAperture, SkyCircularAperture, + EllipticalAperture, SkyEllipticalAperture, + RectangularAperture, SkyRectangularAperture, + CircularAnnulus, SkyCircularAnnulus) +from regions import (Regions, CirclePixelRegion, CircleSkyRegion, + EllipsePixelRegion, EllipseSkyRegion, + RectanglePixelRegion, RectangleSkyRegion, + CircleAnnulusPixelRegion, CircleAnnulusSkyRegion) + +from jdaviz.core.region_translators import regions2roi, aperture2regions from jdaviz.core.events import SnackbarMessage, GlobalDisplayUnitChanged, LinkUpdatedMessage from jdaviz.core.registries import tray_registry -from jdaviz.core.template_mixin import PluginTemplateMixin, DatasetSelectMixin, SubsetSelect +from jdaviz.core.template_mixin import (PluginTemplateMixin, DatasetSelectMixin, + SubsetSelect, SelectPluginComponent) from jdaviz.core.tools import ICON_DIR -from jdaviz.utils import MultiMaskSubsetState +from jdaviz.core.user_api import PluginUserApi +from jdaviz.core.helpers import _next_subset_num +from jdaviz.utils import MultiMaskSubsetState, data_has_valid_wcs from jdaviz.configs.default.plugins.subset_plugin import utils @@ -26,6 +41,7 @@ __all__ = ['SubsetPlugin'] SUBSET_MODES = { + 'new': NewMode, 'replace': ReplaceMode, 'OrState': OrMode, 'AndState': AndMode, @@ -34,10 +50,30 @@ 'RangeSubsetState': RangeSubsetState, 'RoiSubsetState': RoiSubsetState } +SUBSET_MODES_PRETTY = { + 'new': NewMode, + 'replace': ReplaceMode, + 'or': OrMode, + 'and': AndMode, + 'xor': XorMode, + 'andnot': AndNotMode, +} +SUBSET_TO_PRETTY = {v: k for k, v in SUBSET_MODES_PRETTY.items()} +COMBO_OPTIONS = list(SUBSET_MODES_PRETTY.keys()) @tray_registry('g-subset-plugin', label="Subset Tools") class SubsetPlugin(PluginTemplateMixin, DatasetSelectMixin): + """ + See the :ref:`Subset Tools ` for more details. + + Only the following attributes and methods are available through the + :ref:`public plugin API `: + + * :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.show` + * :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.open_in_tray` + * :meth:`~jdaviz.core.template_mixin.PluginTemplateMixin.close_in_tray` + """ template_file = __file__, "subset_plugin.vue" select = List([]).tag(sync=True) subset_items = List([]).tag(sync=True) @@ -66,6 +102,9 @@ class SubsetPlugin(PluginTemplateMixin, DatasetSelectMixin): icon_radialtocheck = Unicode(read_icon(os.path.join(ICON_DIR, 'radialtocheck.svg'), 'svg+xml')).tag(sync=True) # noqa icon_checktoradial = Unicode(read_icon(os.path.join(ICON_DIR, 'checktoradial.svg'), 'svg+xml')).tag(sync=True) # noqa + combination_items = List([]).tag(sync=True) + combination_selected = Any().tag(sync=True) + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -93,6 +132,16 @@ def __init__(self, *args, **kwargs): align_by = getattr(self.app, '_align_by', None) self.display_sky_coordinates = (align_by == 'wcs' and not self.multiselect) + self.combination_mode = SelectPluginComponent(self, + items='combination_items', + selected='combination_selected', + manual_options=COMBO_OPTIONS) + + @property + def user_api(self): + expose = [] + return PluginUserApi(self, expose) + def _on_link_update(self, *args): """When linking is changed pixels<>wcs, change display units of the subset plugin from pixel (for pixel linking) to sky (for WCS linking). @@ -121,6 +170,7 @@ def _sync_selected_from_state(self, *args): self._sync_available_from_state() self.subset_selected = self.session.edit_subset_mode.edit_subset[0].label self.show_region_info = True + self._update_combination_mode() def _on_subset_update(self, *args): self._sync_selected_from_state(*args) @@ -654,32 +704,290 @@ def _set_value_in_subset_definition(self, index, name, desired_key, new_value): self.subset_definitions[index][i]['value'] = new_value break - def _import_spectral_regions(self, spec_region, mode=NewMode, viewer=None): + def import_region(self, region, combination_mode=None, max_num_regions=None, + refdata_label=None, return_bad_regions=False, **kwargs): """ - Method for importing a SpectralRegion object or list of SpectralRegion objects. + Method for creating subsets from regions or region files. Parameters ---------- - spec_region : ~`specutils.SpectralRegion` object or list - The object that contains bounds for the spectral region or regions - mode : AndMode, AndNotMode, OrMode, ReplaceMode, XorMode, NewMode, or list - By default this is set to NewMode which creates a new subset per subregion. - OrMode will create a composite subset with each subregion corresponding - to a subregion of a single subset. + region : region, list of region objects, or str + A region object can be one of the following: + + * Astropy ``regions`` object + * ``photutils`` apertures (limited support until ``photutils`` + fully supports ``regions``) + * specutils ``SpectralRegion`` object + + A string which represents a ``regions`` or ``SpectralRegion`` file. + If given as a list, it can only contain spectral or non-spectral regions, not both. + + combination_mode : list, str, or `None` + The way that regions are created or combined. If a list, then it must be the + same length as regions. If `None`, then it will follow the default glue + functionality for subset creation. + + max_num_regions : int or `None` + Maximum number of regions to load, starting from top of the list. + Default is to load everything. If you are providing a large file/list + input for ``region``, it is recommended + + refdata_label : str or `None` + **This is only applicable to non-spectral regions.** + Label of data to use for sky-to-pixel conversion for a region, or + mask creation. Data must already be loaded into Jdaviz. + If `None`, defaults to the reference data in the default viewer. + Choice of this data is particularly important when sky + region is involved. + + return_bad_regions : bool + If `True`, return the regions that failed to load (see ``bad_regions``); + This is useful for debugging. If `False`, do not return anything (`None`). + + Returns + ------- + bad_regions : list of (obj, str) or `None` + If requested (see ``return_bad_regions`` option), return a + list of ``(region, reason)`` tuples for region objects that failed to load. + If all the regions loaded successfully, this list will be empty. + If not requested, return `None`. + """ - viewer_name = viewer or self.app._jdaviz_helper._default_spectrum_viewer_reference_name - range_viewer = self.app.get_viewer(viewer_name) - for index, sub_region in enumerate(spec_region): - if isinstance(mode, list): - if len(mode) != (len(spec_region) - 1): - raise ValueError("list of mode must be size of spec_region minus one") - if index == 0: - m = NewMode - else: - m = mode[index - 1] + if isinstance(region, str): + if os.path.exists(region): + from regions import Regions + region_format = kwargs.pop('region_format', None) + try: + raw_regs = Regions.read(region, format=region_format) + except Exception: # nosec + raw_regs = SpectralRegion.read(region) + + return self._load_regions(raw_regs, combination_mode, max_num_regions, + refdata_label, return_bad_regions, **kwargs) + else: + return self._load_regions(region, combination_mode, max_num_regions, refdata_label, + return_bad_regions, **kwargs) + + def _load_regions(self, regions, combination_mode=None, max_num_regions=None, + refdata_label=None, return_bad_regions=False, **kwargs): + """Load given region(s) into the viewer. + WCS-to-pixel translation and mask creation, if needed, is relative + to the image defined by ``refdata_label``. Meanwhile, the rest of + the Subset operations are based on reference image as defined by Glue. + + .. note:: Loading too many regions will affect performance. + + A valid region can be loaded into one of the following categories: + + * An interactive Subset, as if it was drawn by hand. This is + always done for supported shapes. Its label will be + ``'Subset N'``, where ``N`` is an integer. + * A masked Subset that will display on the image but cannot be + modified once loaded. This is done if the shape cannot be + made interactive. Its label will be ``'MaskedSubset N'``, + where ``N`` is an integer. + + Parameters + ---------- + regions : list of obj + A list of region objects. A region object can be one of the following: + + * Astropy ``regions`` object + * ``photutils`` apertures (limited support until ``photutils`` + fully supports ``regions``) + * specutils ``SpectralRegion`` object + + combination_mode : list, str, or `None` + The way that regions are created or combined. If a list, then it must be the + same length as regions. Each element describes how the corresponding region + in regions will be applied. If `None`, then it will follow the default glue + functionality for subset creation. Options are ['new', 'replace', 'or', 'and', + 'xor', 'andnot'] + + max_num_regions : int or `None` + Maximum number of regions to load, starting from top of the list. + Default is to load everything. + + refdata_label : str or `None` + Label of data to use for sky-to-pixel conversion for a region, or + mask creation. Data must already be loaded into Jdaviz. + If `None`, defaults to the reference data in the default viewer. + Choice of this data is particularly important when sky + region is involved. + + return_bad_regions : bool + If `True`, return the regions that failed to load (see ``bad_regions``); + This is useful for debugging. If `False`, do not return anything (`None`). + + kwargs : dict + Extra keywords to be passed into the region's ``to_mask`` method. + **This is ignored if the region can be made interactive.** + + Returns + ------- + bad_regions : list of (obj, str) or `None` + If requested (see ``return_bad_regions`` option), return a + list of ``(region, reason)`` tuples for region objects that failed to load. + If all the regions loaded successfully, this list will be empty. + If not requested, return `None`. + + """ + if len(self.app.data_collection) == 0: + raise ValueError('Cannot load regions without data.') + + if not isinstance(regions, (list, tuple, Regions, SpectralRegion)): + regions = [regions] + + n_loaded = 0 + bad_regions = [] + + # To keep track of masked subsets. + msg_prefix = 'MaskedSubset' + msg_count = _next_subset_num(msg_prefix, self.app.data_collection.subset_groups) + + viewer_parameter = kwargs.pop('viewer', None) + viewer_name = viewer_parameter or list(self.app._jdaviz_helper.viewers.keys())[0] + viewer = self.app.get_viewer(viewer_name) + # Subset is global but reference data is viewer-dependent. + if refdata_label is None: + data = viewer.state.reference_data + else: + data = self.app.data_collection[refdata_label] + + has_wcs = data_has_valid_wcs(data, ndim=2) + + combo_mode_is_list = isinstance(combination_mode, list) + if combo_mode_is_list and len(combination_mode) != (len(regions)): + raise ValueError("list of mode must be size of regions") + elif combo_mode_is_list: + for mode in combination_mode: + if mode not in COMBO_OPTIONS: + raise ValueError(f"{mode} not one of {COMBO_OPTIONS}") + + for index, region in enumerate(regions): + # Set combination mode for how region will be applied to current subset + # or created as a new subset + if combo_mode_is_list: + combo_mode = combination_mode[index] else: - m = mode - self.app.session.edit_subset_mode.mode = m - s = RangeSubsetState(lo=sub_region.lower.value, hi=sub_region.upper.value, - att=range_viewer.slice_component_label) - range_viewer.apply_subset_state(s) + combo_mode = combination_mode + + if combo_mode == 'new': + # Remove selection of subset so that new one will be created + self.app.session.edit_subset_mode.edit_subset = None # No overwrite next iteration + self.app.session.edit_subset_mode.mode = SUBSET_MODES_PRETTY['new'] + elif combo_mode: + self.combination_mode.selected = combo_mode + + if (isinstance(region, (SkyCircularAperture, SkyEllipticalAperture, + SkyRectangularAperture, SkyCircularAnnulus, + CircleSkyRegion, EllipseSkyRegion, + RectangleSkyRegion, CircleAnnulusSkyRegion)) + and not has_wcs): + bad_regions.append((region, 'Sky region provided but data has no valid WCS')) + continue + + if (isinstance(region, (CircularAperture, EllipticalAperture, + RectangularAperture, CircularAnnulus, + CirclePixelRegion, EllipsePixelRegion, + RectanglePixelRegion, CircleAnnulusPixelRegion)) + and (hasattr(self.app, '_link_type') and self.app._link_type == "wcs")): + bad_regions.append((region, 'Pixel region provided by data is linked by WCS')) + continue + + # photutils: Convert to region shape first + if isinstance(region, (CircularAperture, SkyCircularAperture, + EllipticalAperture, SkyEllipticalAperture, + RectangularAperture, SkyRectangularAperture, + CircularAnnulus, SkyCircularAnnulus)): + region = aperture2regions(region) + + # region: Convert to ROI. + # NOTE: Out-of-bounds ROI will succeed; this is native glue behavior. + if isinstance(region, (CirclePixelRegion, CircleSkyRegion, + EllipsePixelRegion, EllipseSkyRegion, + RectanglePixelRegion, RectangleSkyRegion, + CircleAnnulusPixelRegion, CircleAnnulusSkyRegion)): + state = regions2roi(region, wcs=data.coords) + viewer.apply_roi(state) + + elif isinstance(region, (CircularROI, CircularAnnulusROI, + EllipticalROI, RectangularROI)): + viewer.apply_roi(region) + + elif isinstance(region, SpectralRegion): + # Use viewer_name if provided in kwarg, otherwise use + # default spectrum viewer name + viewer_name = (viewer_parameter or + self.app._jdaviz_helper._default_spectrum_viewer_reference_name) + range_viewer = self.app.get_viewer(viewer_name) + + s = RangeSubsetState(lo=region.lower.value, hi=region.upper.value, + att=range_viewer.state.x_att) + range_viewer.apply_subset_state(s) + + # Last resort: Masked Subset that is static (if data is not a cube) + elif data.ndim == 2: + im = None + if hasattr(region, 'to_pixel'): # Sky region: Convert to pixel region + if not has_wcs: + bad_region.append((region, 'Sky region provided but data has no valid WCS')) # noqa + continue + region = region.to_pixel(data.coords) + + if hasattr(region, 'to_mask'): + try: + mask = region.to_mask(**kwargs) + im = mask.to_image(data.shape) # Can be None + except Exception as e: # pragma: no cover + bad_regions.append((region, f'Failed to load: {repr(e)}')) + continue + + # Boolean mask as input is supported but not advertised. + elif (isinstance(region, np.ndarray) and region.shape == data.shape + and region.dtype == np.bool_): + im = region + + if im is None: + bad_regions.append((region, 'Mask creation failed')) + continue + + # NOTE: Region creation info is thus lost. + try: + subset_label = f'{msg_prefix} {msg_count}' + state = MaskSubsetState(im, data.pixel_component_ids) + self.app.data_collection.new_subset_group(subset_label, state) + msg_count += 1 + except Exception as e: # pragma: no cover + bad_regions.append((region, f'Failed to load: {repr(e)}')) + continue + else: + bad_regions.append((region, 'Mask creation failed')) + continue + n_loaded += 1 + if max_num_regions is not None and n_loaded >= max_num_regions: + break + + n_reg_in = len(regions) + n_reg_bad = len(bad_regions) + if n_loaded == 0: + snack_color = "error" + elif n_reg_bad > 0: + snack_color = "warning" + else: + snack_color = "success" + self.app.hub.broadcast(SnackbarMessage( + f"Loaded {n_loaded}/{n_reg_in} regions, max_num_regions={max_num_regions}, " + f"bad={n_reg_bad}", color=snack_color, timeout=8000, sender=self.app)) + + if return_bad_regions: + return bad_regions + + @observe('combination_selected') + def _combination_selected_updated(self, change): + self.app.session.edit_subset_mode.mode = SUBSET_MODES_PRETTY[change['new']] + + def _update_combination_mode(self): + if self.app.session.edit_subset_mode.mode in SUBSET_TO_PRETTY.keys(): + self.combination_mode.selected = SUBSET_TO_PRETTY[ + self.app.session.edit_subset_mode.mode] diff --git a/jdaviz/configs/default/plugins/subset_plugin/tests/test_subset_plugin.py b/jdaviz/configs/default/plugins/subset_plugin/tests/test_subset_plugin.py index 0c1e56df08..825f9a366a 100644 --- a/jdaviz/configs/default/plugins/subset_plugin/tests/test_subset_plugin.py +++ b/jdaviz/configs/default/plugins/subset_plugin/tests/test_subset_plugin.py @@ -5,8 +5,7 @@ from astropy.nddata import NDData import astropy.units as u from specutils import SpectralRegion -from glue.core.roi import EllipticalROI, CircularROI, CircularAnnulusROI, RectangularROI, XRangeROI -from glue.core.edit_subset_mode import OrMode, NewMode, AndNotMode +from glue.core.roi import EllipticalROI, CircularROI, CircularAnnulusROI, RectangularROI from numpy.testing import assert_allclose from jdaviz.configs.default.plugins.subset_plugin import utils @@ -16,13 +15,13 @@ @pytest.mark.filterwarnings('ignore') def test_plugin(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) - p = specviz_helper.plugins['Subset Tools'] + p = specviz_helper.plugins['Subset Tools']._obj # regression test for https://github.com/spacetelescope/jdaviz/issues/1693 - sv = specviz_helper.app.get_viewer('spectrum-viewer') - sv.apply_roi(XRangeROI(6500, 7400)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + p.import_region(SpectralRegion(6500 * unit, 7400 * unit)) - p._obj.subset_select.selected = 'Create New' + p.subset_select.selected = 'Create New' po = specviz_helper.plugins['Plot Options'] po.layer = 'Subset 1' @@ -99,7 +98,7 @@ def test_circle_recenter_linking(roi_class, subset_info, imviz_helper, image_2d_ # apply subset roi_params = {key: subset_info[key]['initial_value'] for key in subset_info} - imviz_helper.app.get_viewer('imviz-0').apply_roi(roi_class(**roi_params)) + imviz_helper.plugins['Subset Tools']._obj.import_region(roi_class(**roi_params)) # get plugin and check that attribute tracking link type is set properly plugin = imviz_helper.plugins['Subset Tools']._obj @@ -146,7 +145,7 @@ def test_circle_recenter_linking(roi_class, subset_info, imviz_helper, image_2d_ img_wcs = imviz_helper.app.data_collection['Default orientation'].coords new_pix_region = original_sky_region.to_pixel(img_wcs) new_roi = regions2roi(new_pix_region) - imviz_helper.app.get_viewer('imviz-0').apply_roi(new_roi) + imviz_helper.plugins['Subset Tools']._obj.import_region(new_roi) # get subset definitions again, which should now be in sky coordinates subset_defs = plugin.subset_definitions @@ -177,23 +176,45 @@ def test_circle_recenter_linking(roi_class, subset_info, imviz_helper, image_2d_ ('spec_regions', 'mode', 'len_subsets', 'len_subregions'), [([SpectralRegion(5.772486091213352 * u.um, 6.052963676101135 * u.um), SpectralRegion(6.494371022809778 * u.um, 6.724270682553864 * u.um), - SpectralRegion(7.004748267441649 * u.um, 7.3404016303483965 * u.um)], NewMode, 3, 1), + SpectralRegion(7.004748267441649 * u.um, 7.3404016303483965 * u.um)], 'new', 3, 1), + ([SpectralRegion(5.772486091213352 * u.um, 6.052963676101135 * u.um), + SpectralRegion(6.494371022809778 * u.um, 6.724270682553864 * u.um), + SpectralRegion(7.004748267441649 * u.um, 7.3404016303483965 * u.um)], 'replace', 1, 1), ((SpectralRegion(5.772486091213352 * u.um, 6.052963676101135 * u.um) + SpectralRegion(6.494371022809778 * u.um, 6.724270682553864 * u.um) + - SpectralRegion(7.004748267441649 * u.um, 7.3404016303483965 * u.um)), OrMode, 1, 3), + SpectralRegion(7.004748267441649 * u.um, 7.3404016303483965 * u.um)), 'or', 1, 3), ((SpectralRegion(5.772486091213352 * u.um, 6.052963676101135 * u.um) + SpectralRegion(5.8 * u.um, 5.9 * u.um) + SpectralRegion(6.494371022809778 * u.um, 6.724270682553864 * u.um) + - SpectralRegion(7 * u.um, 7.2 * u.um)), [AndNotMode, OrMode, OrMode], 1, 4), + SpectralRegion(7 * u.um, 7.2 * u.um)), ['new', 'andnot', 'or', 'or'], 1, 4), (SpectralRegion(5.8 * u.um, 5.9 * u.um), None, 1, 1) ] ) def test_import_spectral_region(cubeviz_helper, spectrum1d_cube, spec_regions, mode, len_subsets, len_subregions): cubeviz_helper.load_data(spectrum1d_cube) - cubeviz_helper.app.get_tray_item_from_name('g-subset-plugin') plg = cubeviz_helper.plugins['Subset Tools']._obj - plg._import_spectral_regions(spec_region=spec_regions, mode=mode) + plg.import_region(spec_regions, combination_mode=mode) subsets = cubeviz_helper.app.get_subsets() assert len(subsets) == len_subsets assert len(subsets['Subset 1']) == len_subregions + + +def test_import_spectral_regions_file(cubeviz_helper, spectrum1d_cube, tmp_path): + cubeviz_helper.load_data(spectrum1d_cube) + plg = cubeviz_helper.plugins['Subset Tools']._obj + s = SpectralRegion(5*u.um, 6*u.um) + local_path = str(tmp_path / 'spectral_region.ecsv') + s.write(local_path) + plg.import_region(local_path) + subsets = cubeviz_helper.app.get_subsets() + assert len(subsets) == 1 + + plg.combination_mode.selected = 'or' + plg.import_region(SpectralRegion(7 * u.um, 8 * u.um)) + + subsets = cubeviz_helper.app.get_subsets() + assert len(subsets['Subset 1']) == 2 + + with pytest.raises(ValueError, match='test not one of'): + plg.combination_mode.selected = 'test' diff --git a/jdaviz/configs/imviz/plugins/parsers.py b/jdaviz/configs/imviz/plugins/parsers.py index 7267341f73..1ca2f0ba8f 100644 --- a/jdaviz/configs/imviz/plugins/parsers.py +++ b/jdaviz/configs/imviz/plugins/parsers.py @@ -126,7 +126,8 @@ def parse_data(app, file_obj, ext=None, data_label=None, elif file_obj_lower.endswith('.reg'): # This will load DS9 regions as Subset but only if there is already data. - app._jdaviz_helper.load_regions_from_file(file_obj) + app.get_tray_item_from_name('g-subset-plugin').import_region(file_obj, + combination_mode='new') else: # Assume FITS with fits.open(file_obj) as pf: diff --git a/jdaviz/configs/imviz/tests/test_delete_data.py b/jdaviz/configs/imviz/tests/test_delete_data.py index 16f49a0393..1502929f84 100644 --- a/jdaviz/configs/imviz/tests/test_delete_data.py +++ b/jdaviz/configs/imviz/tests/test_delete_data.py @@ -29,10 +29,11 @@ def test_delete_with_subset_wcs(self): # Add a subset reg = CirclePixelRegion(PixCoord(2, 2), 3).to_sky(self.wcs_1) - self.imviz.load_regions(reg) + self.imviz.plugins['Subset Tools']._obj.import_region(reg) + self.imviz.plugins['Subset Tools']._obj.combination_mode.selected = 'new' reg = RectanglePixelRegion(PixCoord(1, 1), 2, 2).to_sky(self.wcs_1) - self.imviz.load_regions(reg) + self.imviz.plugins['Subset Tools']._obj.import_region(reg) assert len(self.imviz.app.data_collection.subset_groups) == 2 @@ -90,7 +91,7 @@ def test_delete_wcs_layer_with_subset(self): # Create a rotated ellipse. reg = EllipsePixelRegion( PixCoord(3.5, 4.5), width=2, height=5, angle=Angle(30, 'deg')).to_sky(self.wcs_1) - self.imviz.load_regions(reg) + self.imviz.plugins['Subset Tools']._obj.import_region(reg) # Switch back to Default Orientation. self.imviz.app._change_reference_data("Default orientation") diff --git a/jdaviz/configs/imviz/tests/test_linking.py b/jdaviz/configs/imviz/tests/test_linking.py index 2ea2591b00..438dff7ac7 100644 --- a/jdaviz/configs/imviz/tests/test_linking.py +++ b/jdaviz/configs/imviz/tests/test_linking.py @@ -101,7 +101,8 @@ def test_wcslink_affine_with_extras(self): # Add subsets, both interactive and static. self.imviz._apply_interactive_region('bqplot:truecircle', (1.5, 2.5), (3.6, 4.6)) - self.imviz.load_regions([ + self.imviz.plugins['Subset Tools']._obj.combination_mode.selected = 'new' + self.imviz.plugins['Subset Tools']._obj.import_region([ CirclePixelRegion(center=PixCoord(x=6, y=2), radius=5).to_sky(self.wcs_1), PolygonPixelRegion(vertices=PixCoord(x=[1, 2, 2], y=[1, 1, 2])).to_sky(self.wcs_1), PolygonPixelRegion(vertices=PixCoord(x=[2, 3, 3], y=[2, 2, 3])).to_sky(self.wcs_1)]) diff --git a/jdaviz/configs/imviz/tests/test_orientation.py b/jdaviz/configs/imviz/tests/test_orientation.py index 837f08701f..904d274d35 100644 --- a/jdaviz/configs/imviz/tests/test_orientation.py +++ b/jdaviz/configs/imviz/tests/test_orientation.py @@ -197,7 +197,7 @@ def test_delete_orientation_with_subset(self, klass, angle, sbst_theta): # Create rotated shape reg = klass(center=SkyCoord(ra=337.51931488, dec=-20.83187472, unit="deg"), width=2.4 * u.arcsec, height=1.2 * u.arcsec, angle=angle) - self.imviz.load_regions(reg) + self.imviz.plugins['Subset Tools']._obj.import_region(reg) # Switch to N-up E-right lc_plugin._obj.create_north_up_east_right(set_on_create=True) diff --git a/jdaviz/configs/imviz/tests/test_regions.py b/jdaviz/configs/imviz/tests/test_regions.py index 8fa9c370cd..554a99e39e 100644 --- a/jdaviz/configs/imviz/tests/test_regions.py +++ b/jdaviz/configs/imviz/tests/test_regions.py @@ -32,39 +32,39 @@ def teardown_method(self, method): def test_regions_invalid(self): # Wrong object - bad_regions = self.imviz.load_regions([self.imviz], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([self.imviz], return_bad_regions=True) assert len(bad_regions) == 1 and bad_regions[0][1] == 'Mask creation failed' # Sky region on image without WCS sky = SkyCoord(337.51894337, -20.83208305, unit='deg') reg = CircleSkyRegion(center=sky, radius=0.0004 * u.deg) - bad_regions = self.imviz.load_regions([reg], refdata_label='no_wcs[SCI,1]', - return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([reg], refdata_label='no_wcs[SCI,1]', + return_bad_regions=True) assert len(bad_regions) == 1 and bad_regions[0][1] == 'Sky region provided but data has no valid WCS' # noqa reg = SkyCircularAperture(sky, 0.5 * u.arcsec) - bad_regions = self.imviz.load_regions([reg], refdata_label='no_wcs[SCI,1]', - return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([reg], refdata_label='no_wcs[SCI,1]', + return_bad_regions=True) assert len(bad_regions) == 1 and bad_regions[0][1] == 'Sky region provided but data has no valid WCS' # noqa reg = CircleAnnulusSkyRegion(center=sky, inner_radius=0.0004 * u.deg, outer_radius=0.0005 * u.deg) - bad_regions = self.imviz.load_regions([reg], refdata_label='no_wcs[SCI,1]', - return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([reg], refdata_label='no_wcs[SCI,1]', + return_bad_regions=True) assert len(bad_regions) == 1 and bad_regions[0][1] == 'Sky region provided but data has no valid WCS' # noqa # Unsupported functionality from outside load_regions reg = PointSkyRegion(center=sky) - bad_regions = self.imviz.load_regions(reg, return_bad_regions=True) + bad_regions = self.subset_plugin.import_region(reg, return_bad_regions=True) assert len(bad_regions) == 1 and bad_regions[0][1] == 'Failed to load: NotImplementedError()' # noqa # Out-of-bounds masked subset (pix) reg = PolygonPixelRegion(vertices=PixCoord(x=[11, 12, 12], y=[11, 11, 12])) - bad_regions = self.imviz.load_regions(reg, return_bad_regions=True) + bad_regions = self.subset_plugin.import_region(reg, return_bad_regions=True) assert len(bad_regions) == 1 and bad_regions[0][1] == 'Mask creation failed' # Make sure nothing is returned when not requested even on failure - bad_regions = self.imviz.load_regions(reg) + bad_regions = self.subset_plugin.import_region(reg) assert bad_regions is None # Make sure nothing is actually loaded @@ -74,7 +74,7 @@ def test_regions_invalid(self): def test_regions_fully_out_of_bounds(self): """Glue ROI will not error when out of bounds.""" my_reg = CirclePixelRegion(center=PixCoord(x=100, y=100), radius=5) - bad_regions = self.imviz.load_regions([my_reg], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([my_reg], return_bad_regions=True) assert len(bad_regions) == 0 self.verify_region_loaded('Subset 1') assert len(self.imviz.get_interactive_regions()) == 1 @@ -82,13 +82,13 @@ def test_regions_fully_out_of_bounds(self): def test_regions_mask(self): mask = np.zeros((10, 10), dtype=np.bool_) mask[0, 0] = True - bad_regions = self.imviz.load_regions([mask], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([mask], return_bad_regions=True) assert len(bad_regions) == 0 self.verify_region_loaded('MaskedSubset 1') assert self.imviz.get_interactive_regions() == {} mask[1, 1] = True - bad_regions = self.imviz.load_regions([mask], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([mask], return_bad_regions=True) assert len(bad_regions) == 0 self.verify_region_loaded('MaskedSubset 2') assert self.imviz.get_interactive_regions() == {} @@ -99,7 +99,7 @@ def test_regions_mask(self): # Adding another mask will increment from 2 even when 1 is now available. mask[2, 2] = True - bad_regions = self.imviz.load_regions([mask], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([mask], return_bad_regions=True) assert len(bad_regions) == 0 self.verify_region_loaded('MaskedSubset 3') assert self.imviz.get_interactive_regions() == {} @@ -110,7 +110,8 @@ def test_regions_mask(self): def test_regions_pixel(self): # A little out-of-bounds should still overlay the overlapped part. my_reg = CirclePixelRegion(center=PixCoord(x=6, y=2), radius=5) - bad_regions = self.imviz.load_regions([my_reg], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([my_reg], return_bad_regions=True, + combination_mode='new') assert len(bad_regions) == 0 self.verify_region_loaded('Subset 1') assert len(self.imviz.get_interactive_regions()) == 1 @@ -127,8 +128,9 @@ def test_regions_sky_has_wcs(self): # Masked subset. my_reg_sky_3 = PolygonPixelRegion(vertices=PixCoord(x=[1, 1, 3, 3, 1], y=[1, 3, 3, 1, 1])) # Add them all. - bad_regions = self.imviz.load_regions([my_reg_sky_1, my_reg_sky_2, my_reg_sky_3], - return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([my_reg_sky_1, my_reg_sky_2, my_reg_sky_3], + return_bad_regions=True, + combination_mode='new') assert len(bad_regions) == 0 # Mimic interactive regions (after) @@ -168,7 +170,7 @@ def test_regions_annulus_from_load_data(self): def test_photutils_pixel(self): my_aper = CircularAperture((5, 5), r=2) - bad_regions = self.imviz.load_regions([my_aper], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([my_aper], return_bad_regions=True) assert len(bad_regions) == 0 self.verify_region_loaded('Subset 1') assert len(self.imviz.get_interactive_regions()) == 1 @@ -176,7 +178,7 @@ def test_photutils_pixel(self): def test_photutils_sky_has_wcs(self): sky = SkyCoord(ra=337.5202808, dec=-20.833333059999998, unit='deg') my_aper_sky = SkyCircularAperture(sky, 0.5 * u.arcsec) - bad_regions = self.imviz.load_regions([my_aper_sky], return_bad_regions=True) + bad_regions = self.subset_plugin.import_region([my_aper_sky], return_bad_regions=True) assert len(bad_regions) == 0 self.verify_region_loaded('Subset 1') assert len(self.imviz.get_interactive_regions()) == 1 @@ -196,7 +198,8 @@ def test_ds9_load_all(self, imviz_helper): self.viewer = imviz_helper.default_viewer._obj imviz_helper.load_data(self.arr, data_label='my_image') - bad_regions = imviz_helper.load_regions_from_file(self.region_file, return_bad_regions=True) + bad_regions = imviz_helper.plugins['Subset Tools']._obj.import_region( + self.region_file, combination_mode='new', return_bad_regions=True) assert len(bad_regions) == 1 # Will load 8/9 and 7 of that become ROIs. @@ -210,8 +213,8 @@ def test_ds9_load_all(self, imviz_helper): def test_ds9_load_two_good(self, imviz_helper): self.viewer = imviz_helper.default_viewer._obj imviz_helper.load_data(self.arr, data_label='my_image') - bad_regions = imviz_helper.load_regions_from_file( - self.region_file, max_num_regions=2, return_bad_regions=True) + bad_regions = imviz_helper.plugins['Subset Tools']._obj.import_region( + self.region_file, combination_mode='new', max_num_regions=2, return_bad_regions=True) assert len(bad_regions) == 0 subsets = imviz_helper.get_interactive_regions() assert list(subsets.keys()) == ['Subset 1', 'Subset 2'], subsets @@ -220,7 +223,8 @@ def test_ds9_load_two_good(self, imviz_helper): def test_ds9_load_one_bad(self, imviz_helper): self.viewer = imviz_helper.default_viewer._obj imviz_helper.load_data(self.arr, data_label='my_image') - bad_regions = imviz_helper.load_regions(self.raw_regions[6], return_bad_regions=True) + bad_regions = imviz_helper.plugins['Subset Tools']._obj.import_region( + self.raw_regions[6], return_bad_regions=True) assert len(bad_regions) == 1 assert imviz_helper.get_interactive_regions() == {} self.verify_region_loaded('MaskedSubset 1', count=0) @@ -228,7 +232,7 @@ def test_ds9_load_one_bad(self, imviz_helper): def test_ds9_load_one_good_one_bad(self, imviz_helper): self.viewer = imviz_helper.default_viewer._obj imviz_helper.load_data(self.arr, data_label='my_image') - bad_regions = imviz_helper.load_regions( + bad_regions = imviz_helper.plugins['Subset Tools']._obj.import_region( [self.raw_regions[3], self.raw_regions[6]], return_bad_regions=True) assert len(bad_regions) == 1 diff --git a/jdaviz/configs/imviz/tests/test_simple_aper_phot.py b/jdaviz/configs/imviz/tests/test_simple_aper_phot.py index 2f00530d21..aeabae08d6 100644 --- a/jdaviz/configs/imviz/tests/test_simple_aper_phot.py +++ b/jdaviz/configs/imviz/tests/test_simple_aper_phot.py @@ -21,7 +21,7 @@ def test_plugin_wcs_dithered(self): self.imviz.link_data(align_by='wcs') # They are dithered by 1 pixel on X reg = CirclePixelRegion(center=PixCoord(x=4.5, y=4.5), radius=4.5).to_sky(self.wcs_1) - self.imviz.load_regions(reg) + self.imviz.plugins['Subset Tools']._obj.import_region(reg) phot_plugin = self.imviz.app.get_tray_item_from_name('imviz-aper-phot-simple') @@ -116,7 +116,8 @@ def test_plugin_wcs_dithered(self): # Make sure it also works on an ellipse subset. reg = EllipsePixelRegion(center=PixCoord(x=4.5, y=2.0), width=9.0, height=4.0).to_sky(self.wcs_1) # noqa: E501 - self.imviz.load_regions(reg) + self.imviz.plugins['Subset Tools']._obj.combination_mode.selected = 'new' + self.imviz.plugins['Subset Tools']._obj.import_region(reg) phot_plugin.dataset_selected = 'has_wcs_1[SCI,1]' phot_plugin.aperture_selected = 'Subset 2' @@ -139,7 +140,8 @@ def test_plugin_wcs_dithered(self): # Make sure it also works on a rectangle subset. # We also subtract off background from itself here. reg = RectanglePixelRegion(center=PixCoord(x=4.5, y=4.5), width=9, height=9).to_sky(self.wcs_1) # noqa: E501 - self.imviz.load_regions(reg) + self.imviz.plugins['Subset Tools']._obj.combination_mode.selected = 'new' + self.imviz.plugins['Subset Tools']._obj.import_region(reg) phot_plugin.dataset_selected = 'has_wcs_1[SCI,1]' phot_plugin.aperture_selected = 'Subset 3' @@ -276,11 +278,12 @@ def setup_class(self, imviz_helper): w = imviz_helper.app.data_collection[0].coords # Regions to be used for aperture photometry - imviz_helper.load_regions([ + imviz_helper.plugins['Subset Tools']._obj.import_region([ CirclePixelRegion(center=PixCoord(x=145.1, y=168.3), radius=5).to_sky(w), CirclePixelRegion(center=PixCoord(x=48.3, y=200.3), radius=5).to_sky(w), EllipsePixelRegion(center=PixCoord(x=84.7, y=224.1), width=23, height=9, angle=2.356 * u.rad).to_sky(w), # noqa: E501 - RectanglePixelRegion(center=PixCoord(x=229, y=152), width=17, height=7).to_sky(w)]) + RectanglePixelRegion(center=PixCoord(x=229, y=152), width=17, height=7).to_sky(w)], + combination_mode='new') self.imviz = imviz_helper self.viewer = imviz_helper.default_viewer._obj @@ -356,7 +359,8 @@ def test_annulus_background(imviz_helper): # Load annulus (this used to be part of the plugin but no longer) annulus_1 = CircleAnnulusPixelRegion( PixCoord(x=150, y=25), inner_radius=7, outer_radius=17) - imviz_helper.load_regions([circle_1, annulus_1]) + imviz_helper.plugins['Subset Tools']._obj.import_region([circle_1, annulus_1], + combination_mode='new') phot_plugin.aperture_selected = 'Subset 1' phot_plugin.background_selected = 'Subset 2' @@ -373,7 +377,8 @@ def test_annulus_background(imviz_helper): # Load annulus (this used to be part of the plugin but no longer) annulus_2 = CircleAnnulusPixelRegion( PixCoord(x=20.5, y=37.5), inner_radius=20.5, outer_radius=30.5) - imviz_helper.load_regions([ellipse_1, annulus_2]) + imviz_helper.plugins['Subset Tools']._obj.import_region([ellipse_1, annulus_2], + combination_mode='new') # Subset 4 (annulus) should be available in both sets of choices, but invalid for selection as # aperture @@ -495,9 +500,12 @@ def test_cubeviz_batch(cubeviz_helper, spectrum1d_cube_fluxunit_jy_per_steradian cubeviz_helper.load_data(spectrum1d_cube_fluxunit_jy_per_steradian, data_label='test') phot_plugin = cubeviz_helper.plugins['Aperture Photometry']._obj uc_plugin = cubeviz_helper.plugins['Unit Conversion'] + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj - cubeviz_helper.load_regions(CirclePixelRegion(center=PixCoord(x=5, y=5), radius=2)) - cubeviz_helper.load_regions(CirclePixelRegion(center=PixCoord(x=3, y=3), radius=2)) + subset_plugin.import_region(CirclePixelRegion(center=PixCoord(x=5, y=5), radius=2), + combination_mode='new') + subset_plugin.import_region(CirclePixelRegion(center=PixCoord(x=3, y=3), radius=2), + combination_mode='new') phot_plugin.dataset_selected = 'test[FLUX]' phot_plugin.multiselect = True diff --git a/jdaviz/configs/imviz/tests/test_subset_centroid.py b/jdaviz/configs/imviz/tests/test_subset_centroid.py index 61720c2e50..7221986520 100644 --- a/jdaviz/configs/imviz/tests/test_subset_centroid.py +++ b/jdaviz/configs/imviz/tests/test_subset_centroid.py @@ -9,28 +9,28 @@ class TestImvizSpatialSubsetCentroidPixelLinked(BaseImviz_WCS_GWCS): def test_centroiding_pixel(self): reg = CirclePixelRegion(PixCoord(2, 2), 3) - self.imviz.load_regions(reg) + plg = self.imviz.plugins['Subset Tools']._obj + plg.import_region(reg) - plg = self.imviz.plugins['Subset Tools'] - plg._obj.subset_selected = 'Subset 1' + plg.subset_selected = 'Subset 1' # Since they are linked by pixels, the bright corner pixel aligns # and nothing should change. for data_label in ('fits_wcs[DATA]', 'gwcs[DATA]'): - plg._obj.dataset_selected = data_label - plg._obj.set_center((2, 2), update=True) # Move the Subset back first. - plg._obj.vue_recenter_subset() + plg.dataset_selected = data_label + plg.set_center((2, 2), update=True) # Move the Subset back first. + plg.vue_recenter_subset() # Calculate and move to centroid. for key in ("X Center (pixels)", "Y Center (pixels)"): - assert plg._obj._get_value_from_subset_definition(0, key, "value") == -1 - assert plg._obj._get_value_from_subset_definition(0, key, "orig") == -1 + assert plg._get_value_from_subset_definition(0, key, "value") == -1 + assert plg._get_value_from_subset_definition(0, key, "orig") == -1 # Radius will not be touched. for key in ("value", "orig"): - assert plg._obj._get_value_from_subset_definition(0, "Radius (pixels)", key) == 3 + assert plg._get_value_from_subset_definition(0, "Radius (pixels)", key) == 3 - assert plg._obj.get_center() == (-1, -1) + assert plg.get_center() == (-1, -1) class TestImvizSpatialSubsetCentroidWCSLinked(BaseImviz_WCS_GWCS): @@ -40,34 +40,34 @@ def test_centroiding_wcs(self): self.imviz.link_data(align_by='wcs') reg = CirclePixelRegion(PixCoord(2, 2), 3).to_sky(self.wcs_1) - self.imviz.load_regions(reg) + plg = self.imviz.plugins['Subset Tools']._obj + plg.import_region(reg) - plg = self.imviz.plugins['Subset Tools'] - plg._obj.subset_selected = 'Subset 1' - plg._obj.dataset_selected = 'fits_wcs[DATA]' - plg._obj.vue_recenter_subset() + plg.subset_selected = 'Subset 1' + plg.dataset_selected = 'fits_wcs[DATA]' + plg.vue_recenter_subset() # Pixel value is now w.r.t. fake WCS layer, not the selected data. for key in ("value", "orig"): # subset definition is now in sky coordinates. get RA and Dec and convert back to pixel # to compare with expected recentered position. - ra = plg._obj._get_value_from_subset_definition(0, "RA Center (degrees)", key) * u.deg - dec = plg._obj._get_value_from_subset_definition(0, "Dec Center (degrees)", key) * u.deg + ra = plg._get_value_from_subset_definition(0, "RA Center (degrees)", key) * u.deg + dec = plg._get_value_from_subset_definition(0, "Dec Center (degrees)", key) * u.deg x, y = SkyCoord(ra, dec).to_pixel(self.wcs_1) assert_allclose((x, y), -1) # GWCS does not extrapolate and this Subset is out of bounds, # so will get NaNs and enter the exception handling logic. - plg._obj.dataset_selected = 'gwcs[DATA]' - plg._obj.set_center((2.6836, 1.6332), update=True) # Move the Subset back first. - plg._obj.vue_recenter_subset() + plg.dataset_selected = 'gwcs[DATA]' + plg.set_center((2.6836, 1.6332), update=True) # Move the Subset back first. + plg.vue_recenter_subset() subsets = self.imviz.app.get_subsets(include_sky_region=True) subsets_sky = subsets['Subset 1'][0]['sky_region'] subsets_pix = subsets['Subset 1'][0]['region'] assert_allclose((subsets_pix.center.x, subsets_pix.center.y), (2.6836, 1.6332)) for key in ("value", "orig"): - ra = plg._obj._get_value_from_subset_definition(0, "RA Center (degrees)", key) - dec = plg._obj._get_value_from_subset_definition(0, "Dec Center (degrees)", key) + ra = plg._get_value_from_subset_definition(0, "RA Center (degrees)", key) + dec = plg._get_value_from_subset_definition(0, "Dec Center (degrees)", key) # make sure what is in subset_definitions matches what is returned by get_subsets assert_allclose((ra, dec), (subsets_sky.center.ra.deg, subsets_sky.center.dec.deg)) @@ -75,10 +75,10 @@ def test_centroiding_wcs(self): # The functionality for set_center has changed so that the subset state itself # is updated but that change is not propagated to subset_definitions or the UI until # vue_update_subset is called. - plg._obj.set_center((2, 2), update=False) + plg.set_center((2, 2), update=False) for key in ("value", "orig"): - ra = plg._obj._get_value_from_subset_definition(0, "RA Center (degrees)", key) - dec = plg._obj._get_value_from_subset_definition(0, "Dec Center (degrees)", key) + ra = plg._get_value_from_subset_definition(0, "RA Center (degrees)", key) + dec = plg._get_value_from_subset_definition(0, "Dec Center (degrees)", key) # here 'ra' and 'dec' should remain unchanged from when they were defined, since # vue_update_subset hasn't run assert_allclose((ra, dec), (subsets_sky.center.ra.deg, subsets_sky.center.dec.deg)) diff --git a/jdaviz/configs/imviz/tests/test_viewers.py b/jdaviz/configs/imviz/tests/test_viewers.py index 852bd6e585..dd2c149cb3 100644 --- a/jdaviz/configs/imviz/tests/test_viewers.py +++ b/jdaviz/configs/imviz/tests/test_viewers.py @@ -67,7 +67,7 @@ def test_destroy_viewer_with_subset(imviz_helper): # Create a Subset. reg = CirclePixelRegion(center=PixCoord(x=4, y=4), radius=2) - imviz_helper.load_regions(reg) + imviz_helper.plugins['Subset Tools']._obj.import_region(reg) # Remove the second viewer. imviz_helper.destroy_viewer('second') diff --git a/jdaviz/configs/imviz/tests/utils.py b/jdaviz/configs/imviz/tests/utils.py index e781810d5d..39d8beb2b5 100644 --- a/jdaviz/configs/imviz/tests/utils.py +++ b/jdaviz/configs/imviz/tests/utils.py @@ -42,6 +42,7 @@ def setup_class(self, imviz_helper): self.wcs = WCS(hdu.header) self.imviz = imviz_helper self.viewer = imviz_helper.default_viewer._obj + self.subset_plugin = self.imviz.plugins['Subset Tools']._obj # Since we are not really displaying, need this to test zoom. self.viewer.shape = (100, 100) diff --git a/jdaviz/configs/rampviz/tests/test_ramp_extraction.py b/jdaviz/configs/rampviz/tests/test_ramp_extraction.py index 9c339ebd28..169c87ed05 100644 --- a/jdaviz/configs/rampviz/tests/test_ramp_extraction.py +++ b/jdaviz/configs/rampviz/tests/test_ramp_extraction.py @@ -18,7 +18,7 @@ def _ramp_extraction_previews(_rampviz_helper, _ramp_file): # add subset: region = CirclePixelRegion(center=PixCoord(12.5, 15.5), radius=2) - _rampviz_helper.load_regions(region) + _rampviz_helper.plugins['Subset Tools']._obj.import_region(region) ramp_extr = _rampviz_helper.plugins['Ramp Extraction']._obj subsets = _rampviz_helper.app.get_subsets() diff --git a/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py b/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py index b5e40f0aed..7643709b82 100644 --- a/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py +++ b/jdaviz/configs/specviz/plugins/line_analysis/tests/test_line_analysis.py @@ -3,11 +3,9 @@ from astropy import units as u from astropy.table import QTable from astropy.tests.helper import assert_quantity_allclose -from glue.core.roi import XRangeROI -from glue.core.edit_subset_mode import NewMode from numpy.testing import assert_allclose from regions import RectanglePixelRegion, PixCoord -from specutils import Spectrum1D +from specutils import Spectrum1D, SpectralRegion from jdaviz.configs.specviz.plugins.line_analysis.line_analysis import _coerce_unit from jdaviz.core.events import LineIdentifyMessage @@ -32,7 +30,9 @@ def test_plugin(specviz_helper, spectrum1d): assert np.all([cm.visible is False for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6500, 7400)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 7400 * unit)) specviz_helper.app.state.drawer = True assert 'Subset 1' in plugin.spectral_subset.labels @@ -57,11 +57,14 @@ def test_spatial_subset(cubeviz_helper, image_cube_hdu_obj): cubeviz_helper.load_data(image_cube_hdu_obj, data_label="Test Cube") # add a spatial region - cubeviz_helper.load_regions(RectanglePixelRegion(center=PixCoord(x=3, y=5), width=4, height=6)) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + RectanglePixelRegion(center=PixCoord(x=3, y=5), width=4, height=6)) # create a spectral region - spectrum_viewer = cubeviz_helper.app.get_viewer('spectrum-viewer') - spectrum_viewer.apply_roi(XRangeROI(3.623e-7, 3.627e-7)) # meters + unit = u.Unit(cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + cubeviz_helper.plugins['Subset Tools']._obj.combination_mode.selected = 'new' + cubeviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(3.623e-7 * unit, + 3.627e-7 * unit)) cubeviz_helper.app.state.drawer = True plugin = cubeviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -125,8 +128,9 @@ def test_user_api(specviz_helper, spectrum1d): label = "Test 1D Spectrum" specviz_helper.load_data(spectrum1d, data_label=label) - sv = specviz_helper.app.get_viewer('spectrum-viewer') - sv.apply_roi(XRangeROI(6500, 7400)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 7400 * unit)) la = specviz_helper.plugins['Line Analysis'] la.keep_active = True @@ -241,7 +245,9 @@ def test_continuum_surrounding_spectral_subset(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6500, 7400)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 7400 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -268,7 +274,9 @@ def test_continuum_spectral_same_value(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6500, 7400)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 7400 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -295,7 +303,9 @@ def test_continuum_surrounding_invalid_width(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6500, 7400)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 7400 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -320,7 +330,9 @@ def test_continuum_subset_spectral_entire(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6500, 7400)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 7400 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -347,12 +359,14 @@ def test_continuum_subset_spectral_subset2(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6200, 7000)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6200 * unit, + 7000 * unit)) specviz_helper.app.state.drawer = True - sv.session.edit_subset_mode._mode = NewMode - sv.session.edit_subset = [] - sv.apply_roi(XRangeROI(7100, 7700)) + specviz_helper.plugins['Subset Tools']._obj.combination_mode.selected = 'new' + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(7100 * unit, + 7700 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -380,7 +394,9 @@ def test_continuum_surrounding_no_right(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6500, 8000)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 8000 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -408,7 +424,9 @@ def test_continuum_surrounding_no_left(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6000, 7500)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6000 * unit, + 7500 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -436,7 +454,9 @@ def test_subset_changed(specviz_helper, spectrum1d): assert np.all([cm.visible for cm in continuum_marks]) # add a region and rerun stats for that region - sv.apply_roi(XRangeROI(6000, 7500)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6000 * unit, + 7500 * unit)) specviz_helper.app.state.drawer = True plugin = specviz_helper.app.get_tray_item_from_name('specviz-line-analysis') @@ -446,7 +466,8 @@ def test_subset_changed(specviz_helper, spectrum1d): plugin.continuum_subset_selected = 'Surrounding' plugin.width = 3 - sv.apply_roi(XRangeROI(6500, 7500)) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(6500 * unit, + 7500 * unit)) specviz_helper.app.state.drawer = True # Values have not yet been validated @@ -465,7 +486,9 @@ def test_invalid_subset(specviz_helper, spectrum1d): # apply subset that overlaps on left_spectrum, but not right_spectrum # NOTE: using a subset that overlaps the right_spectrum (reference) results in errors when # retrieving the subset (https://github.com/spacetelescope/jdaviz/issues/1868) - specviz_helper.app.get_viewer('spectrum-viewer').apply_roi(XRangeROI(5000, 6000)) + unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + specviz_helper.plugins['Subset Tools']._obj.import_region(SpectralRegion(5000 * unit, + 6000 * unit)) plugin = specviz_helper.plugins['Line Analysis'] plugin.dataset = 'right_spectrum' diff --git a/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py b/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py index 51fc06537b..0ace7db172 100644 --- a/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py +++ b/jdaviz/configs/specviz/plugins/unit_conversion/tests/test_unit_conversion.py @@ -157,7 +157,8 @@ def test_unit_translation(cubeviz_helper, angle_unit): cubeviz_helper.load_data(cube, data_label="test") center = PixCoord(5, 10) - cubeviz_helper.load_regions(CirclePixelRegion(center, radius=2.5)) + cubeviz_helper.plugins['Subset Tools']._obj.import_region( + CirclePixelRegion(center, radius=2.5)) uc_plg = cubeviz_helper.plugins['Unit Conversion'] diff --git a/jdaviz/configs/specviz/tests/test_helper.py b/jdaviz/configs/specviz/tests/test_helper.py index f75d5f9b4d..6ca8c67064 100644 --- a/jdaviz/configs/specviz/tests/test_helper.py +++ b/jdaviz/configs/specviz/tests/test_helper.py @@ -5,9 +5,7 @@ from astropy import units as u from astropy.io import fits from astropy.tests.helper import assert_quantity_allclose -from glue.core.roi import XRangeROI -from glue.core.edit_subset_mode import OrMode, AndMode, AndNotMode -from specutils import Spectrum1D, SpectrumList, SpectrumCollection +from specutils import Spectrum1D, SpectrumList, SpectrumCollection, SpectralRegion from astropy.utils.data import download_file from jdaviz.app import Application @@ -124,29 +122,30 @@ def test_get_spectral_regions_none(self): assert spec_region == {} def test_get_spectral_regions_one(self): - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6000, 6500)) + self.spec_app.plugins['Subset Tools']._obj.import_region( + SpectralRegion(6000*self.spec.spectral_axis.unit, 6500*self.spec.spectral_axis.unit)) spec_region = self.spec_app.get_spectral_regions() assert len(spec_region['Subset 1'].subregions) == 1 def test_get_spectral_regions_two(self): - spectrum_viewer = self.spec_app.app.get_viewer("spectrum-viewer") - - # Set the active edit_subset_mode to OrMode to be able to add multiple subregions - spectrum_viewer.session.edit_subset_mode._mode = OrMode - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6000, 6500)) - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(7300, 7800)) + subset = (SpectralRegion(6000*self.spec.spectral_axis.unit, + 6500*self.spec.spectral_axis.unit) + + SpectralRegion(7300*self.spec.spectral_axis.unit, + 7800*self.spec.spectral_axis.unit)) + self.spec_app.plugins['Subset Tools']._obj.import_region(subset, combination_mode='or') spec_region = self.spec_app.get_spectral_regions() assert len(spec_region['Subset 1'].subregions) == 2 def test_get_spectral_regions_three(self): - spectrum_viewer = self.spec_app.app.get_viewer("spectrum-viewer") - - spectrum_viewer.session.edit_subset_mode._mode = OrMode - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6000, 6400)) - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6600, 7000)) - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(7300, 7800)) + subset = (SpectralRegion(6000*self.spec.spectral_axis.unit, + 6400*self.spec.spectral_axis.unit) + + SpectralRegion(6600*self.spec.spectral_axis.unit, + 7000*self.spec.spectral_axis.unit) + + SpectralRegion(7300*self.spec.spectral_axis.unit, + 7800*self.spec.spectral_axis.unit)) + self.spec_app.plugins['Subset Tools']._obj.import_region(subset, combination_mode='or') spec_region = self.spec_app.get_spectral_regions() @@ -168,12 +167,11 @@ def test_get_spectral_regions_three(self): 7800., atol=1e-5) def test_get_spectral_regions_does_not_raise_value_error(self): - spectrum_viewer = self.spec_app.app.get_viewer("spectrum-viewer") - - spectrum_viewer.session.edit_subset_mode._mode = OrMode - # Selecting ROIs that are not part of the actual spectrum no longer raises an error - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(1, 3)) - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(4, 6)) + subset = (SpectralRegion(1*self.spec.spectral_axis.unit, + 3*self.spec.spectral_axis.unit) + + SpectralRegion(4*self.spec.spectral_axis.unit, + 6*self.spec.spectral_axis.unit)) + self.spec_app.plugins['Subset Tools']._obj.import_region(subset, combination_mode='or') spec_region = self.spec_app.get_spectral_regions() assert_quantity_allclose(spec_region['Subset 1'].subregions[0][0].value, @@ -187,17 +185,14 @@ def test_get_spectral_regions_does_not_raise_value_error(self): 6, atol=1e-5) def test_get_spectral_regions_composite_region(self): - spectrum_viewer = self.spec_app.app.get_viewer("spectrum-viewer") - - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6000, 7400)) - - spectrum_viewer.session.edit_subset_mode._mode = AndNotMode - - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6600, 7000)) - - spectrum_viewer.session.edit_subset_mode._mode = AndMode - - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(7300, 7800)) + subset = (SpectralRegion(6000*self.spec.spectral_axis.unit, + 7400*self.spec.spectral_axis.unit) + + SpectralRegion(6600*self.spec.spectral_axis.unit, + 7000*self.spec.spectral_axis.unit) + + SpectralRegion(7300*self.spec.spectral_axis.unit, + 7800*self.spec.spectral_axis.unit)) + self.spec_app.plugins['Subset Tools']._obj.import_region( + subset, combination_mode=['new', 'andnot', 'and']) spec_region = self.spec_app.get_spectral_regions() @@ -209,17 +204,14 @@ def test_get_spectral_regions_composite_region(self): 7400., atol=1e-5) def test_get_spectral_regions_composite_region_multiple_and_nots(self): - spectrum_viewer = self.spec_app.app.get_viewer("spectrum-viewer") - - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6000, 7800)) - - spectrum_viewer.session.edit_subset_mode._mode = AndNotMode - - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6200, 6600)) - - spectrum_viewer.session.edit_subset_mode._mode = AndNotMode - - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(7300, 7700)) + subset = (SpectralRegion(6000*self.spec.spectral_axis.unit, + 7800*self.spec.spectral_axis.unit) + + SpectralRegion(6200*self.spec.spectral_axis.unit, + 6600*self.spec.spectral_axis.unit) + + SpectralRegion(7300*self.spec.spectral_axis.unit, + 7700*self.spec.spectral_axis.unit)) + self.spec_app.plugins['Subset Tools']._obj.import_region( + subset, combination_mode=['new', 'andnot', 'andnot']) spec_region = self.spec_app.get_spectral_regions() @@ -267,7 +259,10 @@ def test_get_spectra_no_spectra_label_redshift_error(specviz_helper, spectrum1d) def test_add_spectrum_after_subset(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d, data_label="test") - specviz_helper.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6200, 7000)) + subset = SpectralRegion(6200 * spectrum1d.spectral_axis.unit, + 7000 * spectrum1d.spectral_axis.unit) + specviz_helper.plugins['Subset Tools']._obj.import_region(subset) + new_spec = specviz_helper.get_spectra(apply_slider_redshift=True)["test"]*0.9 specviz_helper.load_data(new_spec, data_label="test2") @@ -275,7 +270,9 @@ def test_add_spectrum_after_subset(specviz_helper, spectrum1d): def test_get_spectral_regions_unit(specviz_helper, spectrum1d): # Ensure units we put in are the same as the units we get out specviz_helper.load_data(spectrum1d) - specviz_helper.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6200, 7000)) + subset = SpectralRegion(6200 * spectrum1d.spectral_axis.unit, + 7000 * spectrum1d.spectral_axis.unit) + specviz_helper.plugins['Subset Tools']._obj.import_region(subset) subsets = specviz_helper.get_spectral_regions() reg = subsets.get('Subset 1') @@ -315,8 +312,9 @@ def test_get_spectral_regions_unit_conversion(specviz_helper, spectrum1d): # Convert the wavelength axis to micron new_spectral_axis = "um" specviz_helper.plugins['Unit Conversion'].spectral_unit = new_spectral_axis - - spec_viewer.apply_roi(XRangeROI(0.6, 0.7)) + spectral_axis_unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + subset = SpectralRegion(0.6 * spectral_axis_unit, 0.7 * spectral_axis_unit) + specviz_helper.plugins['Subset Tools']._obj.import_region(subset) # Retrieve the Subset subsets = specviz_helper.get_spectral_regions(use_display_units=False) @@ -347,8 +345,11 @@ def test_subset_default_thickness(specviz_helper, spectrum1d): sv = specviz_helper.app.get_viewer('spectrum-viewer') sv.toolbar.active_tool = sv.toolbar.tools['bqplot:xrange'] - from glue.core.roi import XRangeROI - sv.apply_roi(XRangeROI(2.5, 3.5)) + + spectral_axis_unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + subset = SpectralRegion(2.5 * spectral_axis_unit, + 3.5 * spectral_axis_unit) + specviz_helper.plugins['Subset Tools']._obj.import_region(subset) # _on_layers_update is not triggered within CI sv._on_layers_update() assert sv.state.layers[-1].linewidth == 3 @@ -487,7 +488,11 @@ def test_delete_data_with_subsets(specviz_helper, spectrum1d, spectrum1d_nm): specviz_helper.load_data(spectrum1d, 'my_spec_AA') specviz_helper.load_data(spectrum1d_nm, 'my_spec_nm') - specviz_helper.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6200, 7000)) + spectral_axis_unit = u.Unit(specviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + + subset = SpectralRegion(6200 * spectral_axis_unit, + 7000 * spectral_axis_unit) + specviz_helper.plugins['Subset Tools']._obj.import_region(subset) assert len(specviz_helper.app.data_collection.subset_groups) == 1 subset1 = specviz_helper.app.data_collection.subset_groups[0] diff --git a/jdaviz/core/tests/test_data_menu.py b/jdaviz/core/tests/test_data_menu.py index 40cf1c0c41..0ec0f9e656 100644 --- a/jdaviz/core/tests/test_data_menu.py +++ b/jdaviz/core/tests/test_data_menu.py @@ -1,8 +1,8 @@ import pytest import numpy as np -from glue.core.roi import XRangeROI from astropy.utils.data import download_file +from specutils import SpectralRegion from jdaviz.core.data_formats import identify_helper @@ -54,7 +54,8 @@ def test_data_menu_toggles(specviz_helper, spectrum1d): assert sv.layers[1].visible is False # add a subset and make sure it appears for the first data entry but not the second - app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6000, 6500)) + specviz_helper.plugins['Subset Tools']._obj.import_region( + SpectralRegion(6000 * spectrum1d.spectral_axis.unit, 6500 * spectrum1d.spectral_axis.unit)) assert len(sv.layers) == 4 assert sv.layers[2].visible is True # subset corresponding to first (visible) data entry diff --git a/jdaviz/core/tests/test_helpers.py b/jdaviz/core/tests/test_helpers.py index d651a2260c..8178fbe1cc 100644 --- a/jdaviz/core/tests/test_helpers.py +++ b/jdaviz/core/tests/test_helpers.py @@ -2,8 +2,7 @@ from astropy import units as u from astropy.tests.helper import assert_quantity_allclose -from glue.core.edit_subset_mode import NewMode -from glue.core.roi import XRangeROI +from specutils import SpectralRegion from jdaviz.core.helpers import _next_subset_num @@ -34,18 +33,23 @@ def setup_class(self, specviz_helper, spectrum1d, multi_order_spectrum_list): self.spec_app = specviz_helper self.spec = spectrum1d self.label = "Test 1D Spectrum" + spectral_axis_unit = u.AA - self.spec2 = spectrum1d._copy(spectral_axis=spectrum1d.spectral_axis+1000*u.AA) + self.spec2 = spectrum1d._copy( + spectral_axis=spectrum1d.spectral_axis+1000*spectral_axis_unit) self.label2 = "Test 1D Spectrum 2" self.spec_app.load_data(spectrum1d, data_label=self.label) self.spec_app.load_data(self.spec2, data_label=self.label2) # Add 3 subsets to cover different parts of spec and spec2 - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6000, 6500)) - self.spec_app.app.session.edit_subset_mode.mode = NewMode - - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(6700, 7200)) - self.spec_app.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(8200, 8800)) + self.spec_app.plugins['Subset Tools']._obj.import_region( + SpectralRegion(6000*spectral_axis_unit, 6500*spectral_axis_unit)) + self.spec_app.plugins['Subset Tools']._obj.import_region( + SpectralRegion(6700*spectral_axis_unit, 7200*spectral_axis_unit), + combination_mode='new') + self.spec_app.plugins['Subset Tools']._obj.import_region( + SpectralRegion(8200*spectral_axis_unit, 8800*spectral_axis_unit), + combination_mode='new') @pytest.mark.parametrize( ('label', 'subset_name', 'answer'), diff --git a/jdaviz/core/tests/test_template_mixin.py b/jdaviz/core/tests/test_template_mixin.py index 1e8cf450b0..05cd152f8e 100644 --- a/jdaviz/core/tests/test_template_mixin.py +++ b/jdaviz/core/tests/test_template_mixin.py @@ -1,8 +1,7 @@ import pytest import numpy as np import astropy.units as u - -from glue.core.roi import XRangeROI +from specutils import SpectralRegion def test_spectralsubsetselect(specviz_helper, spectrum1d): @@ -13,7 +12,9 @@ def test_spectralsubsetselect(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) sv = specviz_helper.app.get_viewer('spectrum-viewer') # create a "Subset 1" entry - sv.apply_roi(XRangeROI(6500, 7400)) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(SpectralRegion(6500 * spectrum1d.spectral_axis.unit, + 7400 * spectrum1d.spectral_axis.unit)) # model fitting uses the mixin p = specviz_helper.app.get_tray_item_from_name('g-model-fitting') diff --git a/jdaviz/core/tools.py b/jdaviz/core/tools.py index 91f8ea0bc5..e41b42474d 100644 --- a/jdaviz/core/tools.py +++ b/jdaviz/core/tools.py @@ -540,7 +540,11 @@ def on_mouse_event(self, data): if data['altKey'] is True: reg = self.get_subset(x, y, as_roi=False) - self.viewer.jdaviz_helper.load_regions(reg) + self.viewer.jdaviz_app.get_tray_item_from_name('g-subset-plugin').combination_mode.selected = 'new' # noqa + self.viewer.jdaviz_app.get_tray_item_from_name('g-subset-plugin').import_region( + reg, return_bad_regions=True) + self.viewer.jdaviz_app.get_tray_item_from_name('g-subset-plugin').combination_mode.selected = 'replace' # noqa + else: roi = self.get_subset(x, y, as_roi=True) self.viewer.apply_roi(roi) diff --git a/jdaviz/tests/test_subsets.py b/jdaviz/tests/test_subsets.py index 6f0bec6ce9..3892143a96 100644 --- a/jdaviz/tests/test_subsets.py +++ b/jdaviz/tests/test_subsets.py @@ -3,9 +3,8 @@ from astropy import units as u from astropy.tests.helper import assert_quantity_allclose from astropy.utils.data import get_pkg_data_filename -from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI, XRangeROI +from glue.core.roi import CircularROI, CircularAnnulusROI, EllipticalROI, RectangularROI from glue.core.subset_group import GroupedSubset -from glue.core.edit_subset_mode import AndMode, AndNotMode, NewMode, OrMode, XorMode from regions import (PixCoord, CirclePixelRegion, CircleSkyRegion, RectanglePixelRegion, EllipsePixelRegion, CircleAnnulusPixelRegion) from numpy.testing import assert_allclose @@ -18,11 +17,12 @@ def test_region_from_subset_2d(cubeviz_helper): cubeviz_helper.load_data(np.ones((128, 128, 1)), data_label='Test 2D Flux') - subset_plugin = cubeviz_helper.app.get_tray_item_from_name('g-subset-plugin') + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj cubeviz_helper.app.add_data_to_viewer('flux-viewer', 'Test 2D Flux') - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(EllipticalROI(1, 3.5, 1.2, 3.3)) + subset_plugin.import_region( + EllipsePixelRegion(center=PixCoord(x=1, y=3.5), width=2.4, height=6.6)) subsets = cubeviz_helper.app.get_subsets() reg = subsets.get('Subset 1')[0]['region'] @@ -54,12 +54,12 @@ def test_region_from_subset_2d(cubeviz_helper): def test_region_from_subset_3d(cubeviz_helper): cubeviz_helper.load_data(np.ones((128, 128, 256)), data_label='Test 3D Flux') - subset_plugin = cubeviz_helper.app.get_tray_item_from_name('g-subset-plugin') + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj assert subset_plugin.subset_selected == "Create New" cubeviz_helper.app.add_data_to_viewer('flux-viewer', 'Test 3D Flux') - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(RectangularROI(1, 3.5, -0.2, 3.3)) + subset_plugin.import_region(RectangularROI(1, 3.5, -0.2, 3.3)) subsets = cubeviz_helper.app.get_subsets() reg = cubeviz_helper.app.get_subsets('Subset 1', object_only=True)[0] @@ -120,10 +120,9 @@ def test_region_from_subset_3d(cubeviz_helper): assert_allclose(reg.angle.to_value(u.deg), 45) # Might be stored in radians # Circular Subset - flux_viewer = cubeviz_helper.app.get_viewer("flux-viewer") - # We set the active tool here to trigger a reset of the Subset state to "Create New" - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:truecircle'] - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(xc=3, yc=4, radius=2.4)) + subset_plugin.combination_mode.selected = 'new' + subset_plugin.import_region(CircularROI(xc=3, yc=4, radius=2.4)) + assert subset_plugin.subset_selected == "Subset 2" assert subset_plugin.subset_types == ["CircularROI"] assert subset_plugin.is_centerable @@ -133,13 +132,9 @@ def test_region_from_subset_3d(cubeviz_helper): assert subset_plugin._get_value_from_subset_definition(0, "Radius (pixels)", key) == 2.4 # Circular Annulus Subset - flux_viewer = cubeviz_helper.app.get_viewer("flux-viewer") - # We set the active tool here to trigger a reset of the Subset state to "Create New" - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:circannulus'] - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularAnnulusROI(xc=5, - yc=6, - inner_radius=2, - outer_radius=4)) + subset_plugin.combination_mode.selected = 'new' + subset_plugin.import_region(CircularAnnulusROI(xc=5, yc=6, inner_radius=2, outer_radius=4)) + assert subset_plugin.subset_selected == "Subset 3" assert subset_plugin.subset_types == ["CircularAnnulusROI"] for key in ("orig", "value"): @@ -151,11 +146,12 @@ def test_region_from_subset_3d(cubeviz_helper): def test_region_from_subset_profile(cubeviz_helper, spectral_cube_wcs): data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) - subset_plugin = cubeviz_helper.app.get_tray_item_from_name('g-subset-plugin') + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj cubeviz_helper.load_data(data, data_label='Test 1D Flux') - cubeviz_helper.app.get_viewer("spectrum-viewer").apply_roi(XRangeROI(5, 15.5)) + spectral_axis_unit = u.Unit(cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + subset_plugin.import_region(SpectralRegion(5*spectral_axis_unit, 15.5*spectral_axis_unit)) subsets = cubeviz_helper.app.get_subsets(spectral_only=True) reg = subsets.get('Subset 1') @@ -197,16 +193,14 @@ def test_region_from_subset_profile(cubeviz_helper, spectral_cube_wcs): def test_disjoint_spectral_subset(cubeviz_helper, spectral_cube_wcs): - subset_plugin = cubeviz_helper.app.get_tray_item_from_name('g-subset-plugin') + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj data = Spectrum1D(flux=np.ones((128, 128, 256)) * u.nJy, wcs=spectral_cube_wcs) cubeviz_helper.load_data(data, data_label="Test Flux") - spec_viewer = cubeviz_helper.app.get_viewer("spectrum-viewer") - spec_viewer.apply_roi(XRangeROI(5, 15.5)) - - # Add second region to Subset 1 - cubeviz_helper.app.session.edit_subset_mode.mode = OrMode - spec_viewer.apply_roi(XRangeROI(30, 35)) + spectral_axis_unit = u.Unit(cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + subset_plugin.import_region(SpectralRegion(5 * spectral_axis_unit, 15.5 * spectral_axis_unit)) + subset_plugin.combination_mode.selected = 'or' + subset_plugin.import_region(SpectralRegion(30 * spectral_axis_unit, 35 * spectral_axis_unit)) reg = cubeviz_helper.app.get_subsets('Subset 1') @@ -246,40 +240,45 @@ def test_composite_region_from_subset_3d(cubeviz_helper): cubeviz_helper.load_data(np.ones((128, 128, 10)), data_label='Test 3D Flux') cubeviz_helper.app.add_data_to_viewer('flux-viewer', 'Test 3D Flux') - viewer = cubeviz_helper.app.get_viewer('flux-viewer') - viewer.apply_roi(CircularROI(xc=25, yc=25, radius=5)) + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(xc=25, yc=25, radius=5)) + reg = cubeviz_helper.app.get_subsets("Subset 1") circle1 = CirclePixelRegion(center=PixCoord(x=25, y=25), radius=5) assert reg[-1] == {'name': 'CircularROI', 'glue_state': 'RoiSubsetState', 'region': circle1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - cubeviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(RectangularROI(25, 30, 25, 30)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(RectangularROI(25, 30, 25, 30)) + reg = cubeviz_helper.app.get_subsets("Subset 1") rectangle1 = RectanglePixelRegion(center=PixCoord(x=27.5, y=27.5), width=5, height=5, angle=0.0 * u.deg) assert reg[-1] == {'name': 'RectangularROI', 'glue_state': 'AndNotState', 'region': rectangle1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - cubeviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(EllipticalROI(xc=30, yc=30, radius_x=3, radius_y=6)) + subset_plugin.combination_mode.selected = 'or' + subset_plugin.import_region(EllipticalROI(xc=30, yc=30, radius_x=3, radius_y=6)) + reg = cubeviz_helper.app.get_subsets("Subset 1") ellipse1 = EllipsePixelRegion(center=PixCoord(x=30, y=30), width=6, height=12, angle=0.0 * u.deg) assert reg[-1] == {'name': 'EllipticalROI', 'glue_state': 'OrState', 'region': ellipse1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - cubeviz_helper.app.session.edit_subset_mode.mode = AndMode - viewer.apply_roi(RectangularROI(20, 25, 20, 25)) + subset_plugin.combination_mode.selected = 'and' + subset_plugin.import_region(RectangularROI(20, 25, 20, 25)) + reg = cubeviz_helper.app.get_subsets("Subset 1") rectangle2 = RectanglePixelRegion(center=PixCoord(x=22.5, y=22.5), width=5, height=5, angle=0.0 * u.deg) assert reg[-1] == {'name': 'RectangularROI', 'glue_state': 'AndState', 'region': rectangle2, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - cubeviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(CircularROI(xc=21, yc=24, radius=1)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(CircularROI(xc=21, yc=24, radius=1)) + reg = cubeviz_helper.app.get_subsets("Subset 1") circle2 = CirclePixelRegion(center=PixCoord(x=21, y=24), radius=1) assert reg[-1] == {'name': 'CircularROI', 'glue_state': 'AndNotState', 'region': circle2, @@ -295,26 +294,27 @@ def test_composite_region_from_subset_3d(cubeviz_helper): def test_composite_region_with_consecutive_and_not_states(cubeviz_helper): cubeviz_helper.load_data(np.ones((128, 128, 10)), data_label='Test 3D Flux') + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj cubeviz_helper.app.add_data_to_viewer('flux-viewer', 'Test 3D Flux') viewer = cubeviz_helper.app.get_viewer('flux-viewer') - viewer.apply_roi(CircularROI(xc=25, yc=25, radius=5)) + subset_plugin.import_region(CircularROI(xc=25, yc=25, radius=5)) reg = cubeviz_helper.app.get_subsets("Subset 1") circle1 = CirclePixelRegion(center=PixCoord(x=25, y=25), radius=5) assert reg[-1] == {'name': 'CircularROI', 'glue_state': 'RoiSubsetState', 'region': circle1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - cubeviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(RectangularROI(25, 30, 25, 30)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(RectangularROI(25, 30, 25, 30)) reg = cubeviz_helper.app.get_subsets("Subset 1") rectangle1 = RectanglePixelRegion(center=PixCoord(x=27.5, y=27.5), width=5, height=5, angle=0.0 * u.deg) assert reg[-1] == {'name': 'RectangularROI', 'glue_state': 'AndNotState', 'region': rectangle1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - cubeviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(EllipticalROI(xc=30, yc=30, radius_x=3, radius_y=6)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(EllipticalROI(xc=30, yc=30, radius_x=3, radius_y=6)) reg = cubeviz_helper.app.get_subsets("Subset 1") ellipse1 = EllipsePixelRegion(center=PixCoord(x=30, y=30), width=6, height=12, angle=0.0 * u.deg) @@ -333,7 +333,6 @@ def test_composite_region_with_consecutive_and_not_states(cubeviz_helper): spatial_list = cubeviz_helper.app.get_subsets("Subset 1", spatial_only=True) assert len(spatial_list) == 3 - subset_plugin = cubeviz_helper.app.get_tray_item_from_name('g-subset-plugin') assert subset_plugin.subset_selected == "Subset 1" assert subset_plugin.subset_types == ['CircularROI', 'RectangularROI', 'EllipticalROI'] assert subset_plugin.glue_state_types == ['AndState', 'AndNotState', 'AndNotState'] @@ -361,40 +360,38 @@ def test_composite_region_with_consecutive_and_not_states(cubeviz_helper): def test_composite_region_with_imviz(imviz_helper, image_2d_wcs): arr = NDData(np.ones((10, 10)), wcs=image_2d_wcs) - + subset_plugin = imviz_helper.plugins['Subset Tools']._obj data_label = 'image-data' - viewer = imviz_helper.default_viewer._obj imviz_helper.load_data(arr, data_label=data_label, show_in_viewer=True) - viewer.apply_roi(CircularROI(xc=5, yc=5, radius=2)) + subset_plugin.import_region(CircularROI(xc=5, yc=5, radius=2)) reg = imviz_helper.app.get_subsets("Subset 1") circle1 = CirclePixelRegion(center=PixCoord(x=5, y=5), radius=2) assert reg[-1] == {'name': 'CircularROI', 'glue_state': 'RoiSubsetState', 'region': circle1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - imviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(RectangularROI(xmin=2, xmax=4, ymin=2, ymax=4)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(RectangularROI(xmin=2, xmax=4, ymin=2, ymax=4)) reg = imviz_helper.app.get_subsets("Subset 1") rectangle1 = RectanglePixelRegion(center=PixCoord(x=3, y=3), width=2, height=2, angle=0.0 * u.deg) assert reg[-1] == {'name': 'RectangularROI', 'glue_state': 'AndNotState', 'region': rectangle1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - imviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(EllipticalROI(xc=3, yc=3, radius_x=3, radius_y=6)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(EllipticalROI(xc=3, yc=3, radius_x=3, radius_y=6)) reg = imviz_helper.app.get_subsets("Subset 1") ellipse1 = EllipsePixelRegion(center=PixCoord(x=3, y=3), width=6, height=12, angle=0.0 * u.deg) assert reg[-1] == {'name': 'EllipticalROI', 'glue_state': 'AndNotState', 'region': ellipse1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - imviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(CircularAnnulusROI(xc=5, yc=5, inner_radius=2.5, outer_radius=5)) + subset_plugin.combination_mode.selected = 'or' + subset_plugin.import_region(CircularAnnulusROI(xc=5, yc=5, inner_radius=2.5, outer_radius=5)) reg = imviz_helper.app.get_subsets("Subset 1") ann1 = CircleAnnulusPixelRegion(center=PixCoord(x=5, y=5), inner_radius=2.5, outer_radius=5) assert reg[-1] == {'name': 'CircularAnnulusROI', 'glue_state': 'OrState', 'region': ann1, 'sky_region': None, 'subset_state': reg[-1]['subset_state']} - subset_plugin = imviz_helper.app.get_tray_item_from_name('g-subset-plugin') assert subset_plugin.subset_selected == "Subset 1" assert subset_plugin.subset_types == ['CircularROI', 'RectangularROI', 'EllipticalROI', 'CircularAnnulusROI'] @@ -418,7 +415,7 @@ def test_recenter_linked_by_wcs(imviz_helper): # This rectangle is over a real object in reference image but # only the last row in the second image if linked by pixel. - imviz_helper.load_regions( + imviz_helper.plugins['Subset Tools']._obj.import_region( RectanglePixelRegion(center=PixCoord(x=229, y=152), width=17, height=7).to_sky(w)) subset_plugin = imviz_helper.plugins["Subset Tools"]._obj @@ -437,8 +434,8 @@ def test_recenter_linked_by_wcs(imviz_helper): # Now create a new subset that has a source in the corner and test # recentering with multiselect. - - imviz_helper.load_regions( + subset_plugin.combination_mode.selected = 'new' + subset_plugin.import_region( CirclePixelRegion(center=PixCoord(x=145, y=175), radius=17).to_sky(w)) subset_plugin.multiselect = True subset_plugin.subset_selected = ["Subset 1", "Subset 2"] @@ -466,41 +463,45 @@ def test_with_invalid_subset_name(cubeviz_helper): def test_composite_region_from_subset_2d(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) viewer = specviz_helper.app.get_viewer(specviz_helper._default_spectrum_viewer_reference_name) - viewer.apply_roi(XRangeROI(6000, 7000)) - reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj + subset1 = SpectralRegion(6000 * spectrum1d.spectral_axis.unit, 7000 * spectrum1d.spectral_axis.unit) + subset_plugin.import_region(subset1) + reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + assert reg[-1]['region'].lower == subset1.lower and reg[-1]['region'].upper == subset1.upper assert reg[-1]['glue_state'] == 'RangeSubsetState' - specviz_helper.app.session.edit_subset_mode.mode = AndNotMode - - viewer.apply_roi(XRangeROI(6500, 6800)) - reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + subset_plugin.combination_mode.selected = 'andnot' subset1 = SpectralRegion(6500 * spectrum1d.spectral_axis.unit, 6800 * spectrum1d.spectral_axis.unit) + subset_plugin.import_region(subset1) + reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + assert reg[-1]['region'].lower == subset1.lower and reg[-1]['region'].upper == subset1.upper assert reg[-1]['glue_state'] == 'AndNotState' - specviz_helper.app.session.edit_subset_mode.mode = OrMode - - viewer.apply_roi(XRangeROI(7200, 7800)) - reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + subset_plugin.combination_mode.selected = 'or' subset1 = SpectralRegion(7200 * spectrum1d.spectral_axis.unit, 7800 * spectrum1d.spectral_axis.unit) + subset_plugin.import_region(subset1) + + reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + assert reg[-1]['region'].lower == subset1.lower and reg[-1]['region'].upper == subset1.upper assert reg[-1]['glue_state'] == 'OrState' - specviz_helper.app.session.edit_subset_mode.mode = AndMode - - viewer.apply_roi(XRangeROI(6800, 7500)) - reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + subset_plugin.combination_mode.selected = 'and' subset1 = SpectralRegion(6800 * spectrum1d.spectral_axis.unit, 7500 * spectrum1d.spectral_axis.unit) + subset_plugin.import_region(subset1) + + reg = specviz_helper.app.get_subsets("Subset 1", simplify_spectral=False) + assert reg[-1]['region'].lower == subset1.lower and reg[-1]['region'].upper == subset1.upper assert reg[-1]['glue_state'] == 'AndState' - subset_plugin = specviz_helper.app.get_tray_item_from_name('g-subset-plugin') assert subset_plugin.subset_selected == "Subset 1" assert subset_plugin.subset_types == ['Range', 'Range', 'Range', 'Range'] assert subset_plugin.glue_state_types == ['AndState', 'AndNotState', 'OrState', 'AndState'] @@ -515,20 +516,18 @@ def test_composite_region_from_subset_2d(specviz_helper, spectrum1d): def test_edit_composite_spectral_subset(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) - viewer = specviz_helper.app.get_viewer(specviz_helper._default_spectrum_viewer_reference_name) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj - viewer.apply_roi(XRangeROI(6200, 6800)) - specviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(7200, 7600)) - - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(6200, 7600)) + unit = spectrum1d.spectral_axis.unit + subset = [SpectralRegion(6200 * unit, 6800 * unit), + SpectralRegion(7200 * unit, 7600 * unit), + SpectralRegion(6200 * unit, 7600 * unit)] + mode = ['new', 'or', 'xor'] + subset_plugin.import_region(region=subset, combination_mode=mode) reg = specviz_helper.app.get_subsets("Subset 1") assert reg.lower.value == 6800 and reg.upper.value == 7200 - subset_plugin = specviz_helper.app.get_tray_item_from_name('g-subset-plugin') - # We will now update one of the bounds of the composite subset subset_plugin._set_value_in_subset_definition(0, "Lower bound", "value", 6000) subset_plugin.vue_update_subset() @@ -542,8 +541,8 @@ def test_edit_composite_spectral_subset(specviz_helper, spectrum1d): # This makes it so that only spectral regions within this bound # are visible, so the API should reflect that. - specviz_helper.app.session.edit_subset_mode.mode = AndMode - viewer.apply_roi(XRangeROI(6600, 7400)) + subset_plugin.combination_mode.selected = 'and' + subset_plugin.import_region(SpectralRegion(6600 * unit, 7400 * unit)) reg = specviz_helper.app.get_subsets("Subset 1") assert reg.lower.value == 6800 and reg[0].upper.value == 7200 @@ -557,56 +556,66 @@ def test_edit_composite_spectral_subset(specviz_helper, spectrum1d): assert subset_plugin.can_simplify - viewer.apply_roi(XRangeROI(7800, 8000)) + subset_plugin.combination_mode.selected = 'and' + subset_plugin.import_region(SpectralRegion(7800 * unit, 8000 * unit)) with pytest.raises(ValueError, match="AND mode should overlap with existing subset"): specviz_helper.app.get_subsets("Subset 1") def test_composite_spectral_with_xor(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) - viewer = specviz_helper.app.get_viewer(specviz_helper._default_spectrum_viewer_reference_name) - viewer.apply_roi(XRangeROI(6200, 6800)) - specviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(7200, 7600)) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj + + unit = spectrum1d.spectral_axis.unit + subset = [SpectralRegion(6200 * unit, 6800 * unit), + SpectralRegion(7200 * unit, 7600 * unit), + SpectralRegion(6100 * unit, 7600 * unit)] + mode = ['new', 'or', 'xor'] + subset_plugin.import_region(region=subset, combination_mode=mode) - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(6100, 7600)) reg = specviz_helper.app.get_subsets("Subset 1") assert reg[0].lower.value == 6100 and reg[0].upper.value == 6200 assert reg[1].lower.value == 6800 and reg[1].upper.value == 7200 - specviz_helper.app.session.edit_subset_mode.mode = NewMode - viewer.apply_roi(XRangeROI(7000, 7200)) - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(7100, 7300)) - specviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(6900, 7105)) + subset_plugin.combination_mode.selected = 'new' + subset = [SpectralRegion(7000 * unit, 7200 * unit), + SpectralRegion(7100 * unit, 7300 * unit), + SpectralRegion(6900 * unit, 7105 * unit)] + mode = ['new', 'xor', 'or'] + subset_plugin.import_region(region=subset, combination_mode=mode) + reg = specviz_helper.app.get_subsets("Subset 2") assert reg[0].lower.value == 6900 and reg[0].upper.value == 7105 assert reg[1].lower.value == 7200 and reg[1].upper.value == 7300 - specviz_helper.app.session.edit_subset_mode.mode = NewMode - viewer.apply_roi(XRangeROI(6000, 6500)) - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(6100, 6200)) + subset_plugin.combination_mode.selected = 'new' + subset = [SpectralRegion(6000 * unit, 6500 * unit), + SpectralRegion(6100 * unit, 6200 * unit)] + mode = ['new', 'xor'] + subset_plugin.import_region(region=subset, combination_mode=mode) + reg = specviz_helper.app.get_subsets("Subset 3") assert reg[0].lower.value == 6000 and reg[0].upper.value == 6100 assert reg[1].lower.value == 6200 and reg[1].upper.value == 6500 - specviz_helper.app.session.edit_subset_mode.mode = NewMode - viewer.apply_roi(XRangeROI(6100, 6200)) - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(6000, 6500)) + subset_plugin.combination_mode.selected = 'new' + subset = [SpectralRegion(6100 * unit, 6200 * unit), + SpectralRegion(6000 * unit, 6500 * unit)] + mode = ['new', 'xor'] + subset_plugin.import_region(region=subset, combination_mode=mode) + reg = specviz_helper.app.get_subsets("Subset 4") assert reg[0].lower.value == 6000 and reg[0].upper.value == 6100 assert reg[1].lower.value == 6200 and reg[1].upper.value == 6500 - specviz_helper.app.session.edit_subset_mode.mode = NewMode - viewer.apply_roi(XRangeROI(7500, 7600)) - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(6000, 6010)) + subset_plugin.combination_mode.selected = 'new' + subset = [SpectralRegion(7500 * unit, 7600 * unit), + SpectralRegion(6000 * unit, 6010 * unit)] + mode = ['new', 'xor'] + subset_plugin.import_region(region=subset, combination_mode=mode) + reg = specviz_helper.app.get_subsets("Subset 5") assert reg[0].lower.value == 6000 and reg[0].upper.value == 6010 assert reg[1].lower.value == 7500 and reg[1].upper.value == 7600 @@ -614,28 +623,25 @@ def test_composite_spectral_with_xor(specviz_helper, spectrum1d): def test_composite_spectral_with_xor_complicated(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) - viewer = specviz_helper.app.get_viewer(specviz_helper._default_spectrum_viewer_reference_name) - viewer.apply_roi(XRangeROI(6100, 6700)) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj - # (6100, 6200), (6300, 6700) - specviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(XRangeROI(6200, 6300)) + unit = spectrum1d.spectral_axis.unit + subset = [SpectralRegion(6100 * unit, 6700 * unit), + SpectralRegion(6200 * unit, 6300 * unit), + SpectralRegion(6050 * unit, 6800 * unit), + SpectralRegion(7000 * unit, 7200 * unit), + SpectralRegion(6010 * unit, 6020 * unit), + SpectralRegion(6090 * unit, 6850 * unit) + ] + mode = ['new', 'andnot', 'xor', 'or', 'or', 'xor'] + subset_plugin.import_region(region=subset, combination_mode=mode) + # (6100, 6200), (6300, 6700) # (6050, 6100), (6200, 6300), (6700, 6800) - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(6050, 6800)) - # (6050, 6100), (6200, 6300), (6700, 6800), (7000, 7200) - specviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(7000, 7200)) - # (6010, 6020), (6050, 6100), (6200, 6300), (6700, 6800), (7000, 7200) - viewer.apply_roi(XRangeROI(6010, 6020)) - # (6010, 6020), (6050, 6090), (6100, 6200), (6300, 6700), (6800, 6850), (7000, 7200) - specviz_helper.app.session.edit_subset_mode.mode = XorMode - viewer.apply_roi(XRangeROI(6090, 6850)) reg = specviz_helper.app.get_subsets("Subset 1") assert reg[0].lower.value == 6010 and reg[0].upper.value == 6020 @@ -648,16 +654,14 @@ def test_composite_spectral_with_xor_complicated(specviz_helper, spectrum1d): def test_overlapping_spectral_regions(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) - viewer = specviz_helper.app.get_viewer(specviz_helper._default_spectrum_viewer_reference_name) - - viewer.apply_roi(XRangeROI(6400, 7400)) - specviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(XRangeROI(6600, 7200)) - - specviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(6600, 7300)) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj + unit = spectrum1d.spectral_axis.unit + subset = [SpectralRegion(6400 * unit, 7400 * unit), + SpectralRegion(6600 * unit, 7200 * unit), + SpectralRegion(6600 * unit, 7300 * unit)] + mode = ['new', 'andnot', 'or'] + subset_plugin.import_region(region=subset, combination_mode=mode) - subset_plugin = specviz_helper.app.get_tray_item_from_name('g-subset-plugin') assert subset_plugin.can_simplify subset_plugin.vue_simplify_subset() @@ -667,18 +671,17 @@ def test_overlapping_spectral_regions(specviz_helper, spectrum1d): def test_only_overlapping_spectral_regions(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) - viewer = specviz_helper.app.get_viewer(specviz_helper._default_spectrum_viewer_reference_name) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj + unit = spectrum1d.spectral_axis.unit + subset_plugin.import_region(SpectralRegion(6400 * unit, 6600 * unit)) - viewer.apply_roi(XRangeROI(6400, 6600)) assert specviz_helper.app.is_there_overlap_spectral_subset("Subset 1") is False - specviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(7000, 7400)) - - viewer.apply_roi(XRangeROI(6600, 7300)) - viewer.apply_roi(XRangeROI(7600, 7800)) + subset_plugin.combination_mode.selected = 'or' + subset_plugin.import_region(SpectralRegion(7000 * unit, 7400 * unit)) + subset_plugin.import_region(SpectralRegion(6600 * unit, 7300 * unit)) + subset_plugin.import_region(SpectralRegion(7600 * unit, 7800 * unit)) - subset_plugin = specviz_helper.app.get_tray_item_from_name('g-subset-plugin') assert subset_plugin.can_simplify subset_plugin.vue_simplify_subset() @@ -689,17 +692,16 @@ def test_only_overlapping_spectral_regions(specviz_helper, spectrum1d): def test_overlapping_in_specviz2d(specviz2d_helper, mos_spectrum2d): specviz2d_helper.load_data(spectrum_2d=mos_spectrum2d) - viewer = specviz2d_helper.app.get_viewer( - specviz2d_helper._default_spectrum_2d_viewer_reference_name) - viewer.apply_roi(XRangeROI(6400, 7400)) - specviz2d_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(XRangeROI(6600, 7200)) + subset_plugin = specviz2d_helper.plugins['Subset Tools']._obj + unit = mos_spectrum2d.spectral_axis.unit - specviz2d_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(6600, 7300)) + subset_plugin.import_region(SpectralRegion(6400 * unit, 7400 * unit)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(SpectralRegion(6600 * unit, 7200 * unit)) + subset_plugin.combination_mode.selected = 'or' + subset_plugin.import_region(SpectralRegion(6600 * unit, 7300 * unit)) - subset_plugin = specviz2d_helper.app.get_tray_item_from_name('g-subset-plugin') assert subset_plugin.can_simplify subset_plugin.vue_simplify_subset() @@ -709,18 +711,16 @@ def test_overlapping_in_specviz2d(specviz2d_helper, mos_spectrum2d): def test_only_overlapping_in_specviz2d(specviz2d_helper, mos_spectrum2d): specviz2d_helper.load_data(spectrum_2d=mos_spectrum2d) - viewer = specviz2d_helper.app.get_viewer( - specviz2d_helper._default_spectrum_2d_viewer_reference_name) - viewer.apply_roi(XRangeROI(6400, 6600)) - specviz2d_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(7000, 7400)) + subset_plugin = specviz2d_helper.plugins['Subset Tools']._obj + unit = mos_spectrum2d.spectral_axis.unit - viewer.apply_roi(XRangeROI(6600, 7300)) + subset_plugin.import_region(SpectralRegion(6400 * unit, 6600 * unit)) + subset_plugin.combination_mode.selected = 'or' + subset_plugin.import_region(SpectralRegion(7000 * unit, 7400 * unit)) + subset_plugin.import_region(SpectralRegion(6600 * unit, 7300 * unit)) + subset_plugin.import_region(SpectralRegion(7600 * unit, 7800 * unit)) - viewer.apply_roi(XRangeROI(7600, 7800)) - - subset_plugin = specviz2d_helper.app.get_tray_item_from_name('g-subset-plugin') assert subset_plugin.can_simplify subset_plugin.vue_simplify_subset() @@ -731,20 +731,19 @@ def test_only_overlapping_in_specviz2d(specviz2d_helper, mos_spectrum2d): def test_multi_mask_subset(specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d) - viewer = specviz_helper.app.get_viewer(specviz_helper._default_spectrum_viewer_reference_name) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj + unit = spectrum1d.spectral_axis.unit + subset_plugin.import_region(SpectralRegion(6200 * unit, 6800 * unit)) - viewer.apply_roi(XRangeROI(6200, 6800)) - - plugin = specviz_helper.app.get_tray_item_from_name("g-subset-plugin") - plugin.can_freeze = True - plugin.vue_freeze_subset() + subset_plugin.can_freeze = True + subset_plugin.vue_freeze_subset() reg = specviz_helper.app.get_subsets() assert reg["Subset 1"][0]["region"] == 3 assert isinstance(reg["Subset 1"][0]["subset_state"], MultiMaskSubsetState) - specviz_helper.app.session.edit_subset_mode.mode = OrMode - viewer.apply_roi(XRangeROI(7200, 7600)) + subset_plugin.combination_mode.selected = 'or' + subset_plugin.import_region(SpectralRegion(7200 * unit, 7600 * unit)) # Simplify subset ignores Mask subsets reg = specviz_helper.app.get_subsets() @@ -756,23 +755,23 @@ def test_multi_mask_subset(specviz_helper, spectrum1d): assert (reg["Subset 1"][1]["region"].lower.value == 7200 and reg["Subset 1"][1]["region"].upper.value == 7600) assert reg["Subset 1"][0]["region"] == 3 - assert plugin.can_simplify is False + assert subset_plugin.can_simplify is False # If we freeze again, all subregions become a Mask subset object - plugin.vue_freeze_subset() + subset_plugin.vue_freeze_subset() reg = specviz_helper.app.get_subsets() assert reg["Subset 1"][0]["region"] == 5 # When freezing an AndNot state, the number of mask values should decrease - specviz_helper.app.session.edit_subset_mode.mode = AndNotMode - viewer.apply_roi(XRangeROI(6600, 7200)) + subset_plugin.combination_mode.selected = 'andnot' + subset_plugin.import_region(SpectralRegion(6600 * unit, 7200 * unit)) reg = specviz_helper.app.get_subsets(simplify_spectral=False) assert (reg["Subset 1"][1]["region"].lower.value == 6600 and reg["Subset 1"][1]["region"].upper.value == 7200) assert reg["Subset 1"][0]["region"] == 5 - plugin.vue_freeze_subset() + subset_plugin.vue_freeze_subset() reg = specviz_helper.app.get_subsets() assert reg["Subset 1"][0]["region"] == 4 @@ -786,17 +785,19 @@ def test_delete_subsets(cubeviz_helper, spectral_cube_wcs): dc = cubeviz_helper.app.data_collection spectrum_viewer = cubeviz_helper.app.get_viewer("spectrum-viewer") - spectrum_viewer.toolbar.active_tool = spectrum_viewer.toolbar.tools['bqplot:xrange'] - spectrum_viewer.apply_roi(XRangeROI(5, 15.5)) + + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + unit = u.Unit(cubeviz_helper.plugins['Unit Conversion'].spectral_unit.selected) + subset_plugin.import_region(SpectralRegion(6200 * unit, 6800 * unit)) dc.remove_subset_group(dc.subset_groups[0]) assert spectrum_viewer.toolbar.active_tool_id == "jdaviz:selectslice" flux_viewer = cubeviz_helper.app.get_viewer("flux-viewer") - # We set the active tool here to trigger a reset of the Subset state to "Create New" - flux_viewer.toolbar.active_tool = flux_viewer.toolbar.tools['bqplot:rectangle'] - flux_viewer.apply_roi(RectangularROI(1, 3.5, -0.2, 3.3)) + + subset_plugin.combination_mode.selected = 'new' + subset_plugin.import_region(RectangularROI(1, 3.5, -0.2, 3.3)) dc.remove_subset_group(dc.subset_groups[0]) @@ -814,7 +815,8 @@ def test_get_regions_from_subsets_cubeviz(self, cubeviz_helper, spectral_cube_wc cubeviz_helper.load_data(data) # basic test, a single circular region - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(25, 25, 10)) + subset_plugin = cubeviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(25, 25, 10)) subsets = cubeviz_helper.app.get_subsets(include_sky_region=True) sky_region = subsets['Subset 1'][0]['sky_region'] assert isinstance(sky_region, CircleSkyRegion) @@ -827,8 +829,8 @@ def test_get_regions_from_subsets_cubeviz(self, cubeviz_helper, spectral_cube_wc assert subsets['Subset 1'][0]['sky_region'] is None # now test a composite subset, each component should have a sky region - cubeviz_helper.app.session.edit_subset_mode.mode = AndMode - cubeviz_helper.app.get_viewer('flux-viewer').apply_roi(CircularROI(30, 30, 10)) + subset_plugin.combination_mode.selected = 'and' + subset_plugin.import_region(CircularROI(30, 30, 10)) subsets = cubeviz_helper.app.get_subsets(include_sky_region=True) assert len(subsets['Subset 1']) == 2 @@ -859,7 +861,8 @@ def test_get_regions_from_subsets_imviz(self, imviz_helper, spectral_cube_wcs): imviz_helper.load_data(data) # basic test, a single circular region - imviz_helper.app.get_viewer('imviz-0').apply_roi(CircularROI(25, 25, 10)) + subset_plugin = imviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(25, 25, 10)) subsets = imviz_helper.app.get_subsets(include_sky_region=True) sky_region = subsets['Subset 1'][0]['sky_region'] assert isinstance(sky_region, CircleSkyRegion) @@ -868,8 +871,8 @@ def test_get_regions_from_subsets_imviz(self, imviz_helper, spectral_cube_wcs): assert_allclose(sky_region.radius.arcsec, 28001.08106569353) # now test a composite subset, each component should have a sky region - imviz_helper.app.session.edit_subset_mode.mode = AndMode - imviz_helper.app.get_viewer('imviz-0').apply_roi(CircularROI(30, 30, 10)) + subset_plugin.combination_mode.selected = 'and' + subset_plugin.import_region(CircularROI(30, 30, 10)) subsets = imviz_helper.app.get_subsets(include_sky_region=True) assert len(subsets['Subset 1']) == 2 @@ -891,16 +894,17 @@ def test_no_wcs_sky_regions(self, imviz_helper): data = NDData(np.ones((40, 40)) * u.nJy) imviz_helper.load_data(data) - imviz_helper.app.get_viewer('imviz-0').apply_roi(CircularROI(25, 25, 10)) + subset_plugin = imviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(CircularROI(25, 25, 10)) subsets = imviz_helper.app.get_subsets(include_sky_region=True) assert subsets['Subset 1'][0]['sky_region'] is None def test_subset_renaming(self, specviz_helper, spectrum1d): specviz_helper.load_data(spectrum1d, 'myfile') - spectrum_viewer_name = specviz_helper._default_spectrum_viewer_reference_name - viewer = specviz_helper.app.get_viewer(spectrum_viewer_name) - viewer.apply_roi(XRangeROI(6200, 7200)) + subset_plugin = specviz_helper.plugins['Subset Tools']._obj + subset_plugin.import_region(SpectralRegion(6200 * spectrum1d.spectral_axis.unit, + 7200 * spectrum1d.spectral_axis.unit)) get_data_no_sub = specviz_helper.get_data('myfile') get_data_1 = specviz_helper.get_data('myfile', spectral_subset='Subset 1') diff --git a/notebooks/CubevizExample.ipynb b/notebooks/CubevizExample.ipynb index 32956991bb..c87bf2393c 100644 --- a/notebooks/CubevizExample.ipynb +++ b/notebooks/CubevizExample.ipynb @@ -164,7 +164,7 @@ "my_reg = CirclePixelRegion(center=PixCoord(x=35, y=35), radius=10)\n", "\n", "my_regions = [my_aper, my_reg]\n", - "cubeviz.load_regions(my_regions)" + "cubeviz.plugins['Subset Tools']._obj.import_region(my_regions, combination_mode='new')" ] }, { @@ -225,7 +225,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/ImvizDitheredExample.ipynb b/notebooks/ImvizDitheredExample.ipynb index a8312d8ef2..6b50b6d93e 100644 --- a/notebooks/ImvizDitheredExample.ipynb +++ b/notebooks/ImvizDitheredExample.ipynb @@ -339,7 +339,7 @@ "my_reg_sky = CircleSkyRegion(c, Angle(2, u.arcsec))\n", "\n", "my_regions = [my_aper, my_aper_sky, my_reg, my_reg_sky]\n", - "imviz.load_regions(my_regions)" + "imviz.plugins['Subset Tools']._obj.import_region(my_reigons, combination_mode='new')" ] }, { @@ -682,7 +682,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/ImvizExample.ipynb b/notebooks/ImvizExample.ipynb index 0400156230..f43b999e8f 100644 --- a/notebooks/ImvizExample.ipynb +++ b/notebooks/ImvizExample.ipynb @@ -375,7 +375,7 @@ "my_reg_sky = CircleSkyRegion(c, Angle(2, u.arcsec))\n", "\n", "my_regions = [my_aper, my_aper_sky, my_reg, my_reg_sky]\n", - "imviz.load_regions(my_regions)" + "imviz.plugins['Subset Tools']._obj.import_region(my_reigons, combination_mode='new')" ] }, { @@ -702,7 +702,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.0" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/concepts/RampvizExample.ipynb b/notebooks/concepts/RampvizExample.ipynb index 20da627259..3c849460f0 100644 --- a/notebooks/concepts/RampvizExample.ipynb +++ b/notebooks/concepts/RampvizExample.ipynb @@ -101,7 +101,7 @@ "from regions import CirclePixelRegion, PixCoord\n", "\n", "region = CirclePixelRegion(center=PixCoord(1797.2, 2051.2), radius=2)\n", - "rampviz.load_regions(region)" + "rampviz.plugins['Subset Tools']._obj.import_region(region)" ] }, { @@ -200,7 +200,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/concepts/cubeviz_aperture_photometry.ipynb b/notebooks/concepts/cubeviz_aperture_photometry.ipynb index fe9ff0d58c..255f852783 100644 --- a/notebooks/concepts/cubeviz_aperture_photometry.ipynb +++ b/notebooks/concepts/cubeviz_aperture_photometry.ipynb @@ -140,7 +140,7 @@ "metadata": {}, "outputs": [], "source": [ - "cubeviz.load_regions(aper)" + "cubeviz.plugins['Subset Tools']._obj.import_region(aper)" ] }, { @@ -523,7 +523,7 @@ "source": [ "aper2 = RectanglePixelRegion(center=PixCoord(x=1, y=3), width=1, height=1)\n", "bg2 = RectanglePixelRegion(center=PixCoord(x=0, y=2), width=1, height=1)\n", - "cubeviz2.load_regions([aper2, bg2])" + "cubeviz2.plugins['Subset Tools'].import_region([aper2, bg2])" ] }, { @@ -622,7 +622,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/concepts/imviz_advanced_aper_phot.ipynb b/notebooks/concepts/imviz_advanced_aper_phot.ipynb index cb5e10a1f9..1aa820adc2 100644 --- a/notebooks/concepts/imviz_advanced_aper_phot.ipynb +++ b/notebooks/concepts/imviz_advanced_aper_phot.ipynb @@ -108,7 +108,7 @@ "metadata": {}, "outputs": [], "source": [ - "imviz.load_regions(regions)" + "imviz.plugins['Subset Tools']._obj.import_region(reigons, combination_mode='new')" ] }, { @@ -353,7 +353,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/concepts/imviz_color_display.ipynb b/notebooks/concepts/imviz_color_display.ipynb index fd82b3cb1c..315a6b9041 100644 --- a/notebooks/concepts/imviz_color_display.ipynb +++ b/notebooks/concepts/imviz_color_display.ipynb @@ -137,7 +137,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -151,7 +151,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.3" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/concepts/imviz_colorbar_mpl.ipynb b/notebooks/concepts/imviz_colorbar_mpl.ipynb index aadbb892cf..864466e558 100644 --- a/notebooks/concepts/imviz_colorbar_mpl.ipynb +++ b/notebooks/concepts/imviz_colorbar_mpl.ipynb @@ -284,7 +284,7 @@ "metadata": {}, "outputs": [], "source": [ - "imviz.load_regions(reg)" + "imviz.plugins['Subset Tools']._obj.import_region(reg)" ] }, { @@ -393,7 +393,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.0" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/concepts/imviz_edit_subset_programmatic.ipynb b/notebooks/concepts/imviz_edit_subset_programmatic.ipynb index f968529226..98e3bc9656 100644 --- a/notebooks/concepts/imviz_edit_subset_programmatic.ipynb +++ b/notebooks/concepts/imviz_edit_subset_programmatic.ipynb @@ -68,31 +68,21 @@ { "cell_type": "code", "execution_count": null, - "id": "2030727b", - "metadata": {}, - "outputs": [], - "source": [ - "imviz.load_regions([rect, circ])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08eab464", + "id": "bfaa6bb9", "metadata": {}, "outputs": [], "source": [ - "imviz.default_viewer.zoom_level = 5" + "subset_tool = imviz.plugins['Subset Tools']._obj" ] }, { "cell_type": "code", "execution_count": null, - "id": "bfaa6bb9", + "id": "2030727b", "metadata": {}, "outputs": [], "source": [ - "subset_tool = imviz.plugins['Subset Tools']" + "subset_tool.import_region([rect, circ], combination_mode='new')" ] }, { @@ -154,7 +144,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/notebooks/concepts/imviz_simple_aper_phot.ipynb b/notebooks/concepts/imviz_simple_aper_phot.ipynb index 4bb1a1d63a..7570bf2548 100644 --- a/notebooks/concepts/imviz_simple_aper_phot.ipynb +++ b/notebooks/concepts/imviz_simple_aper_phot.ipynb @@ -155,7 +155,7 @@ "viewer.zoom_level = my_zoom\n", "\n", "# Click on image to finalize selection.\n", - "imviz.load_regions([my_aper, my_bg])" + "imviz.plugins['Subset Tools']._obj.import_region([my_aper, my_bg], combination_mode='new')" ] }, { @@ -223,7 +223,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.7" + "version": "3.10.14" } }, "nbformat": 4,