def test_clone_wcs_link(): # Make sure that WCSLink can be serialized/deserialized wcs1 = WCS(naxis=2) wcs1.wcs.ctype = 'DEC--TAN', 'RA---TAN' wcs1.wcs.set() data1 = Data(label='Data 1') data1.coords = WCSCoordinates(wcs=wcs1) data1['x'] = np.ones((2, 3)) wcs2 = WCS(naxis=3) wcs2.wcs.ctype = 'GLON-CAR', 'FREQ', 'GLAT-CAR' wcs2.wcs.set() data2 = Data(label='Data 2') data2.coords = WCSCoordinates(wcs=wcs2) data2['x'] = np.ones((2, 3, 4)) link1 = WCSLink(data1, data2) link2 = clone(link1) assert isinstance(link2, WCSLink) assert link2.data1.label == 'Data 1' assert link2.data2.label == 'Data 2'
def setup_method(self, method): # Set up simple spectral WCS wcs_1d = WCS(naxis=1) wcs_1d.wcs.ctype = ['VELO-LSR'] wcs_1d.wcs.set() # Set up a spectral cube WCS wcs_3d = WCS(naxis=3) wcs_3d.wcs.ctype = ['RA---TAN', 'DEC--TAN', 'VELO-LSR'] wcs_3d.wcs.set() # Set up glue Coordinates object coords_1d = WCSCoordinates(wcs=wcs_1d) coords_3d = WCSCoordinates(wcs=wcs_3d) self.data_1d = Data(label='spectrum', coords=coords_1d) self.data_3d = Data(label='spectrum', coords=coords_3d) # FIXME: there should be an easier way to do this in glue x = np.array([3.4, 2.3, -1.1, 0.3]) y = np.array([3.2, 3.3, 3.4, 3.5]) self.data_1d.add_component(Component(x, units='Jy'), 'x') self.data_1d.add_component(Component(y, units='Jy'), 'y') self.data_3d.add_component(Component(np.broadcast_to(x, (6, 5, 4)), units='Jy'), 'x') self.data_3d.add_component(Component(np.broadcast_to(x, (6, 5, 4))), 'y') self.app = GlueApplication() self.session = self.app.session self.hub = self.session.hub self.data_collection = self.session.data_collection self.data_collection.append(self.data_1d) self.data_collection.append(self.data_3d)
def test_link_editor(): # Make sure that the WCSLink works property in the link editor and is # returned unmodified. The main way to check that is just to make sure that # the link round-trips when going through EditableLinkFunctionState. wcs1 = WCS(naxis=2) wcs1.wcs.ctype = 'DEC--TAN', 'RA---TAN' wcs1.wcs.set() data1 = Data(label='Data 1') data1.coords = WCSCoordinates(wcs=wcs1) data1['x'] = np.ones((2, 3)) wcs2 = WCS(naxis=3) wcs2.wcs.ctype = 'GLON-CAR', 'FREQ', 'GLAT-CAR' wcs2.wcs.set() data2 = Data(label='Data 2') data2.coords = WCSCoordinates(wcs=wcs2) data2['x'] = np.ones((2, 3, 4)) link1 = WCSLink(data1, data2) link2 = EditableLinkFunctionState(link1).link assert isinstance(link2, WCSLink) assert link2.data1.label == 'Data 1' assert link2.data2.label == 'Data 2'
def setup_method(self, method): self.coords = MyCoords() self.image1 = Data(label='image1', x=[[1, 2], [3, 4]], y=[[4, 5], [2, 3]]) self.image2 = Data(label='image2', a=[[3, 3], [2, 2]], b=[[4, 4], [3, 2]], coords=self.coords) self.catalog = Data(label='catalog', c=[1, 3, 2], d=[4, 3, 3]) self.hypercube = Data(label='hypercube', x=np.arange(120).reshape((2, 3, 4, 5))) # Create data versions with WCS coordinates self.image1_wcs = Data(label='image1_wcs', x=self.image1['x'], coords=WCSCoordinates(wcs=WCS(naxis=2))) self.hypercube_wcs = Data(label='hypercube_wcs', x=self.hypercube['x'], coords=WCSCoordinates(wcs=WCS(naxis=4))) self.application = GlueApplication() self.session = self.application.session self.hub = self.session.hub self.data_collection = self.session.data_collection self.data_collection.append(self.image1) self.data_collection.append(self.image2) self.data_collection.append(self.catalog) self.data_collection.append(self.hypercube) self.data_collection.append(self.image1_wcs) self.data_collection.append(self.hypercube_wcs) self.viewer = self.application.new_data_viewer(ImageViewer) self.data_collection.register_to_hub(self.hub) self.viewer.register_to_hub(self.hub) self.options_widget = self.viewer.options_widget()
def on_finished(self, data, unit=None): """ Called when the `QThread` has finished performing the operation on the `SpectralCube` object. Parameters ---------- data : ndarray The result of the operation performed on the `SpectralCube` object. """ component_name = "{} {}".format(self._component_id, self._operation_name) comp_count = len([x for x in self._data.component_ids() if component_name in str(x)]) if comp_count > 0: component_name = "{} {}".format(component_name, comp_count) if data.ndim == 2: coords = WCSCoordinates(wcs=self._data.coords.wcs.celestial) self._data.container_2d = Data(label=self._data.label + " [2d]", coords=coords) self._data.container_2d.add_component(data, component_name) # self._layout.session.data_collection.append(self._data.container_2d) self._layout.add_overlay(data, component_name, display_now=True) else: component = Component(data, units=unit) self._data.add_component(component, component_name) super(SpectralOperationHandler, self).accept()
def load_stacked_sequence(self, raster_data): for window, window_data in raster_data.items(): w_data = Data(label=f"{window.replace(' ', '_')}") w_data.coords = WCSCoordinates(wcs=window_data.wcs) w_data.add_component(Component(window_data.data), f"{window}") self.datasets.append(w_data)
def import_iris_obs(): caption = "Select a directory containing files from one IRIS OBS, and stack all raster scans." data_path = Path(pick_directory(caption)) rasters = list(data_path.glob("*raster*")) sji = list(data_path.glob("*SJI*")) sji_data = [] for s in sji: sji_data.append(load_sji_fits(s)) raster_data = read_iris_spectrograph_level2_fits(rasters, spectral_windows=['Mg II k 2796'], memmap=False, uncertainty=False) raster_data = {window: stack_spectrogram_sequence(seq) for window, seq in raster_data.data.items()} result = [] for window, window_data in raster_data.items(): w_data = Data(label=f"{window.replace(' ', '_')}") w_data.coords = WCSCoordinates(wcs=window_data.wcs) w_data.add_component(Component(window_data.data), f"{window}") result.append(w_data) return result + sji_data
def test_to_spectrum1d(): # Set up simple spectral WCS wcs = WCS(naxis=1) wcs.wcs.ctype = ['VELO-LSR'] wcs.wcs.set() coords = WCSCoordinates(wcs=wcs) data = Data(label='spectrum', coords=coords) data.add_component(Component(np.array([3.4, 2.3, -1.1, 0.3]), units='Jy'), 'x') spec = data.get_object(Spectrum1D, attribute=data.id['x']) assert_quantity_allclose(spec.spectral_axis, [1, 2, 3, 4] * u.m / u.s) assert_quantity_allclose(spec.flux, [3.4, 2.3, -1.1, 0.3] * u.Jy) data.add_subset(data.id['x'] > 1, label='bright') spec_subset = data.get_subset_object(cls=Spectrum1D, subset_id=0, attribute=data.id['x']) assert_quantity_allclose(spec_subset.spectral_axis, [1, 2, 3, 4] * u.m / u.s) assert_quantity_allclose(spec_subset.flux, [3.4, 2.3, np.nan, np.nan] * u.Jy) assert_equal(spec_subset.mask, [1, 1, 0, 0])
def test_wcs_autolink_emptywcs(): # No links should be found because the WCS don't actually have well defined # physical types. data1 = Data() data1.coords = WCSCoordinates(wcs=WCS(naxis=1)) data1['x'] = [1, 2, 3] data2 = Data() data2.coords = WCSCoordinates(wcs=WCS(naxis=1)) data2['x'] = [4, 5, 6] dc = DataCollection([data1, data2]) links = wcs_autolink(dc) assert len(links) == 0
def test_component_unit_header(tmpdir): from astropy import units as u filename = tmpdir.join('test3.fits').strpath data = Data(x=np.arange(6).reshape(2, 3), y=(np.arange(6) * 2).reshape(2, 3), z=(np.arange(6) * 2).reshape(2, 3)) wcs = WCS() data.coords = WCSCoordinates(wcs=wcs) unit1 = data.get_component("x").units = u.m / u.s unit2 = data.get_component("y").units = u.Jy unit3 = data.get_component("z").units = "" fits_writer(filename, data) with fits.open(filename) as hdulist: assert len(hdulist) == 3 bunit = hdulist['x'].header.get('BUNIT') assert u.Unit(bunit) == unit1 bunit = hdulist['y'].header.get('BUNIT') assert u.Unit(bunit) == unit2 bunit = hdulist['z'].header.get('BUNIT') assert bunit == unit3
def load_sequence(self, raster_data): for window, window_data in raster_data.items(): for i, scan_data in enumerate(window_data): w_data = Data(label=f"{window.replace(' ', '_')}-scan-{i}") w_data.coords = WCSCoordinates(wcs=scan_data.wcs) w_data.add_component(Component(scan_data.data), f"{window}-scan-{i}") w_data.meta = scan_data.meta self.datasets.append(w_data)
def to_data(self, obj): if obj.wcs is None: coords = None else: coords = WCSCoordinates(wcs=obj.wcs) data = Data(coords=coords) data['data'] = obj.data data.get_component('data').units = str(obj.unit) data.meta.update(obj.meta) return data
def load_sji(self, sji): with fits.open(sji) as hdul: hdul.verify("fix") label = hdul[0].header['TDESC1'] data = Data(label=label) data.coords = WCSCoordinates(hdul[0].header) data.meta = hdul[0].header data.add_component(Component(hdul[0].data), label) self.datasets.append(data)
def _parse_iris_raster(data, label): result = [] for window, window_data in data.data.items(): for i, scan_data in enumerate(window_data): w_data = Data(label=f"{window.replace(' ', '_')}-scan-{i}") w_data.coords = WCSCoordinates(wcs=scan_data.wcs) w_data.add_component(Component(scan_data.data), f"{window}-scan-{i}") w_data.meta = scan_data.meta result.append(w_data) return result
def load_sji_fits(filename): with fits.open(filename) as hdul: hdul.verify("fix") sji = hdul[0] label = sji.header['TDESC1'] data = Data(label=label) data.coords = WCSCoordinates(sji.header) data.meta = sji.header data.add_component(Component(sji.data), label) return data
def test_hypercube_world(self): # Check defaults when we add data wcs = WCS(naxis=4) hypercube2 = Data() hypercube2.coords = WCSCoordinates(wcs=wcs) hypercube2.add_component(np.random.random((2, 3, 4, 5)), 'a') self.data_collection.append(hypercube2) self.viewer.add_data(hypercube2)
def _parse_iris_raster(data, label): result = [] for window, window_data in data.items(): for i, scan_data in enumerate(window_data): w_data = Data(label=f"{window.replace(' ', '_')}-scan-{i}") w_data.coords = WCSCoordinates(scan_data.header) w_data.add_component(Component(scan_data.data), f"{window}-scan-{i}") w_data.meta = scan_data.meta w_data.style = VisualAttributes(color='#5A4FCF') result.append(w_data) return result
def test_wcs_autolink_spectral_cube(): # This should link all coordinates wcs1 = WCS(naxis=3) wcs1.wcs.ctype = 'DEC--TAN', 'FREQ', 'RA---TAN' wcs1.wcs.set() data1 = Data() data1.coords = WCSCoordinates(wcs=wcs1) data1['x'] = np.ones((2, 3, 4)) pz1, py1, px1 = data1.pixel_component_ids wcs2 = WCS(naxis=3) wcs2.wcs.ctype = 'GLON-CAR', 'GLAT-CAR', 'FREQ' wcs2.wcs.set() data2 = Data() data2.coords = WCSCoordinates(wcs=wcs2) data2['x'] = np.ones((2, 3, 4)) pz2, py2, px2 = data2.pixel_component_ids dc = DataCollection([data1, data2]) links = wcs_autolink(dc) assert len(links) == 1 link = links[0] assert isinstance(link, MultiLink) assert len(link) == 6 assert link[0].get_to_id() == pz2 assert link[0].get_from_ids() == [pz1, py1, px1] assert link[1].get_to_id() == py2 assert link[1].get_from_ids() == [pz1, py1, px1] assert link[2].get_to_id() == px2 assert link[2].get_from_ids() == [pz1, py1, px1] assert link[3].get_to_id() == pz1 assert link[3].get_from_ids() == [pz2, py2, px2] assert link[4].get_to_id() == py1 assert link[4].get_from_ids() == [pz2, py2, px2] assert link[5].get_to_id() == px1 assert link[5].get_from_ids() == [pz2, py2, px2]
def load_sji(self, sji): with fits.open(sji) as hdul: hdul.verify("fix") label = hdul[0].header['TDESC1'] + hdul[0].header['OBSID'] data = Data(label=label) data.coords = WCSCoordinates(hdul[0].header) data.meta = hdul[0].header preferred_cmap_name = 'IRIS ' + hdul[0].header['TDESC1'].replace( '_', ' ') data.style = VisualAttributes(preferred_cmap=preferred_cmap_name) data.add_component(Component(hdul[0].data), label) self.datasets.append(data)
def test_celestial_with_unknown_axes(): # Regression test for a bug that caused n-d datasets with celestial axes # and axes with unknown physical types to not even be linked by celestial # axes. wcs1 = WCS(naxis=3) wcs1.wcs.ctype = 'DEC--TAN', 'RA---TAN', 'SPAM' wcs1.wcs.set() data1 = Data() data1.coords = WCSCoordinates(wcs=wcs1) data1['x'] = np.ones((2, 3, 4)) pz1, py1, px1 = data1.pixel_component_ids wcs2 = WCS(naxis=3) wcs2.wcs.ctype = 'GLON-CAR', 'FREQ', 'GLAT-CAR' wcs2.wcs.set() data2 = Data() data2.coords = WCSCoordinates(wcs=wcs2) data2['x'] = np.ones((2, 3, 4)) pz2, py2, px2 = data2.pixel_component_ids dc = DataCollection([data1, data2]) links = wcs_autolink(dc) assert len(links) == 1 link = links[0] assert isinstance(link, MultiLink) assert len(link) == 4 assert link[0].get_to_id() == px2 assert link[0].get_from_ids() == [px1, py1] assert link[1].get_to_id() == pz2 assert link[1].get_from_ids() == [px1, py1] assert link[2].get_to_id() == px1 assert link[2].get_from_ids() == [px2, pz2] assert link[3].get_to_id() == py1 assert link[3].get_from_ids() == [px2, pz2]
def _parse_iris_raster(data, label): """ Parse IRIS Level 2 raster files so that it can be loaded by glue. """ w_dataset = [] for window, window_data in data.items(): for i, scan_data in enumerate(window_data): w_data = Data(label=f"{window.replace(' ', '_')}-{scan_data.meta['OBSID']}-scan-{i}") w_data.coords = WCSCoordinates(scan_data.wcs.to_header()) w_data.add_component(Component(scan_data.data), f"{window.replace(' ', '_')}-{scan_data.meta['OBSID']}-scan-{i}") w_data.meta = scan_data.meta w_data.style = VisualAttributes(color='#5A4FCF') w_dataset.append(w_data) return w_dataset
def test_wcs_autolink_dimensional_mismatch(): # No links should be found because the WCS don't actually have well defined # physical types. wcs1 = WCS(naxis=1) wcs1.wcs.ctype = ['FREQ'] wcs1.wcs.set() data1 = Data() data1.coords = WCSCoordinates(wcs=wcs1) data1['x'] = [1, 2, 3] wcs2 = WCS(naxis=3) wcs2.wcs.ctype = 'DEC--TAN', 'FREQ', 'RA---TAN' wcs2.wcs.set() data2 = Data() data2.coords = WCSCoordinates(wcs=wcs2) data2['x'] = np.ones((2, 3, 4)) dc = DataCollection([data1, data2]) links = wcs_autolink(dc) assert len(links) == 0
def test_to_spectrum1d_from_3d_cube(): # Set up simple spectral WCS wcs = WCS(naxis=3) wcs.wcs.ctype = ['RA---TAN', 'DEC--TAN', 'VELO-LSR'] wcs.wcs.set() coords = WCSCoordinates(wcs=wcs) data = Data(label='spectral-cube', coords=coords) data.add_component(Component(np.ones((3, 4, 5)), units='Jy'), 'x') spec = data.get_object(Spectrum1D, attribute=data.id['x'], statistic='sum') assert_quantity_allclose(spec.spectral_axis, [1, 2, 3] * u.m / u.s) assert_quantity_allclose(spec.flux, [20, 20, 20] * u.Jy)
def test_to_spectrum1d_unitless(): # Set up simple spectral WCS wcs = WCS(naxis=1) wcs.wcs.ctype = ['VELO-LSR'] wcs.wcs.set() coords = WCSCoordinates(wcs=wcs) data = Data(label='spectrum', coords=coords) data.add_component(Component(np.array([3.4, 2.3, -1.1, 0.3])), 'x') spec = data.get_object(Spectrum1D, attribute=data.id['x']) assert_quantity_allclose(spec.spectral_axis, [1, 2, 3, 4] * u.m / u.s) assert_quantity_allclose(spec.flux, [3.4, 2.3, -1.1, 0.3] * u.one)
def add_to_2d_container(cubeviz_layout, data, component_data, label): """ Given the cubeviz layout, a data object, a new 2D layer and a label, add the 2D layer to the data object and update the cubeviz layout accordingly. This creates the 2D container dataset if needed. """ # If the 2D container doesn't exist, we create it here. This container is # basically just a Data object but we keep it in an attribute # ``container_2d`` on its parent dataset. if getattr(data, 'container_2d', None) is None: # For now, we assume that the 2D maps are always computed along the # spectral axis, so that the resulting WCS is always celestial coords = WCSCoordinates(wcs=data.coords.wcs.celestial) data.container_2d = Data(label=data.label + " [2d]", coords=coords) data.container_2d.add_component(component_data, label) cubeviz_layout.session.data_collection.append(data.container_2d) # NOTE: the following is disabled for now but can be uncommented once # we are ready to use the glue overlay infrastructure. # Set up pixel links so that selections in the image plane propagate # between 1D and 2D views. Again this assumes as above that the # moments are computed along the spectral axis # link1 = LinkSame(data.pixel_component_ids[2], # data.container_2d.pixel_component_ids[1]) # link2 = LinkSame(data.pixel_component_ids[1], # data.container_2d.pixel_component_ids[0]) # cubeviz_layout.session.data_collection.add_link(link1) # cubeviz_layout.session.data_collection.add_link(link2) for helper in cubeviz_layout._viewer_combo_helpers: helper.append_data(data.container_2d) for viewer in cubeviz_layout.cube_views: viewer._widget.add_data(data.container_2d) else: # Make sure we don't add duplicate data components if label in data.container_2d.component_ids(): raise ValueError("Data component with label '{}' already exists, " "and cannot be created again".format(label)) data.container_2d.add_component(component_data, label)
def test_conversion_utils_3d(): # Set up simple spectral WCS wcs = WCS(naxis=3) wcs.wcs.ctype = ['RA---TAN', 'DEC--TAN', 'VELO-LSR'] wcs.wcs.set() # Set up glue Coordinates object coords = WCSCoordinates(wcs=wcs) data = Data(label='spectral-cube', coords=coords) data.add_component(Component(np.ones((3, 4, 5)), units='Jy'), 'x') assert glue_data_has_spectral_axis(data) spec = glue_data_to_spectrum1d(data, data.id['x'], statistic='sum') assert_quantity_allclose(spec.spectral_axis, [1, 2, 3] * u.m / u.s) assert_quantity_allclose(spec.flux, [20, 20, 20] * u.Jy)
def test_conversion_utils_1d(): # Set up simple spectral WCS wcs = WCS(naxis=1) wcs.wcs.ctype = ['VELO-LSR'] wcs.wcs.set() # Set up glue Coordinates object coords = WCSCoordinates(wcs=wcs) data = Data(label='spectrum', coords=coords) data.add_component(Component(np.array([3.4, 2.3, -1.1, 0.3]), units='Jy'), 'x') assert glue_data_has_spectral_axis(data) spec = glue_data_to_spectrum1d(data, data.id['x']) assert_quantity_allclose(spec.spectral_axis, [1, 2, 3, 4] * u.m / u.s) assert_quantity_allclose(spec.flux, [3.4, 2.3, -1.1, 0.3] * u.Jy)
def add_to_2d_container(cubeviz_layout, data, component_data, label): """ Given the cubeviz layout, a data object, a new 2D layer and a label, add the 2D layer to the data object and update the cubeviz layout accordingly. This creates the 2D container dataset if needed. """ # If the 2D container doesn't exist, we create it here. This container is # basically just a Data object but we keep it in an attribute # ``container_2d`` on its parent dataset. if getattr(data, 'container_2d', None) is None: # For now, we assume that the 2D maps are always computed along the # spectral axis, so that the resulting WCS is always celestial coords = WCSCoordinates(wcs=data.coords.wcs.celestial) data.container_2d = Data(label=data.label + " [2d]", coords=coords) data.container_2d.add_component(component_data, label) cubeviz_layout.session.data_collection.append(data.container_2d) # Set up pixel links so that selections in the image plane propagate # between 1D and 2D views. Again this assumes as above that the # moments are computed along the spectral axis link1 = LinkSame(data.pixel_component_ids[2], data.container_2d.pixel_component_ids[1]) link2 = LinkSame(data.pixel_component_ids[1], data.container_2d.pixel_component_ids[0]) cubeviz_layout.session.data_collection.add_link(link1) cubeviz_layout.session.data_collection.add_link(link2) for helper in cubeviz_layout._viewer_combo_helpers: helper.append_data(data.container_2d) for viewer in cubeviz_layout.all_views: viewer._widget.add_data(data.container_2d) else: data.container_2d.add_component(component_data, label)
def put_data_cb(self): if self.glue_app is None: self.error_no_glue() return channel = self.fv.get_current_channel() if channel is None: self.fv.show_error("No active channel!") return image = channel.get_current_image() if image is None: self.fv.show_error("No data in channel '%s'" % (channel.name)) return data_np = image.get_data() name = image.get('name', 'noname') kwargs = {name: data_np} try: # Pass in WCS for image. if isinstance(image, AstroImage.AstroImage): gdata = Data(**kwargs) h = image.get_header() w = WCS(h) gdata.coords = WCSCoordinates(h, wcs=w) self.glue_app.add_data(**{name: gdata}) # Table data else: self.glue_app.add_data(**kwargs) self.glue_app.raise_() except Exception as e: self.fv.show_error("Error sending data to Glue: %s" % (str(e))) self.error_no_glue()