@@ -1447,6 +1447,98 @@ def convfunc(img, **kwargs):
14471447 accepts_chunks = True ,
14481448 ** kwargs ).with_beam (beam , raise_error_jybm = False )
14491449
1450+ def reproject (self , header , order = 'bilinear' , use_memmap = False ,
1451+ filled = True , ** kwargs ):
1452+ """
1453+ Spatially reproject the cube into a new header. Fills the data with
1454+ the cube's ``fill_value`` to replace bad values before reprojection.
1455+
1456+ If you want to reproject a cube both spatially and spectrally, you need
1457+ to use `spectral_interpolate` as well.
1458+
1459+ .. warning::
1460+ The current implementation of ``reproject`` requires that the whole
1461+ cube be loaded into memory. Issue #506 notes that this is a
1462+ problem, and it is on our to-do list to fix.
1463+
1464+ Parameters
1465+ ----------
1466+ header : `astropy.io.fits.Header`
1467+ A header specifying a cube in valid WCS
1468+ order : int or str, optional
1469+ The order of the interpolation (if ``mode`` is set to
1470+ ``'interpolation'``). This can be either one of the following
1471+ strings:
1472+
1473+ * 'nearest-neighbor'
1474+ * 'bilinear'
1475+ * 'biquadratic'
1476+ * 'bicubic'
1477+
1478+ or an integer. A value of ``0`` indicates nearest neighbor
1479+ interpolation.
1480+ use_memmap : bool
1481+ If specified, a memory mapped temporary file on disk will be
1482+ written to rather than storing the intermediate spectra in memory.
1483+ filled : bool
1484+ Fill the masked values with the cube's fill value before
1485+ reprojection? Note that setting ``filled=False`` will use the raw
1486+ data array, which can be a workaround that prevents loading large
1487+ data into memory.
1488+ kwargs : dict
1489+ Passed to `reproject.reproject_interp`.
1490+ """
1491+
1492+ try :
1493+ from reproject .version import version
1494+ except ImportError :
1495+ raise ImportError ("Requires the reproject package to be"
1496+ " installed." )
1497+
1498+ reproj_kwargs = kwargs
1499+ # Need version > 0.2 to work with cubes, >= 0.5 for memmap
1500+ from distutils .version import LooseVersion
1501+ if LooseVersion (version ) < "0.5" :
1502+ raise Warning ("Requires version >=0.5 of reproject. The current "
1503+ "version is: {}" .format (version ))
1504+ elif LooseVersion (version ) >= "0.6" :
1505+ pass # no additional kwargs, no warning either
1506+ else :
1507+ reproj_kwargs ['independent_celestial_slices' ] = True
1508+
1509+ from reproject import reproject_interp
1510+
1511+ # TODO: Find the minimal subcube that contains the header and only reproject that
1512+ # (see FITS_tools.regrid_cube for a guide on how to do this)
1513+
1514+ newwcs = wcs .WCS (header )
1515+ shape_out = tuple ([header ['NAXIS{0}' .format (i + 1 )] for i in
1516+ range (header ['NAXIS' ])][::- 1 ])
1517+
1518+ def reproject_interp_wrapper (img_slice ):
1519+ # What exactly is the wrapper getting here?
1520+ # I think it is given a _cube_ that is a cutout?
1521+ if filled :
1522+ data = img_slice .filled_data [:]
1523+ else :
1524+ data = img_slice ._data
1525+ return reproject_interp ((data , img_slice .header ),
1526+ newwcs , shape_out = shape_out , ** kwargs )
1527+
1528+ newcube , newcube_valid = self .apply_function_parallel_spatial (
1529+ reproject_interp_wrapper ,
1530+ accepts_chunks = True ,
1531+ order = order ,
1532+ ** reproj_kwargs )
1533+
1534+ return self ._new_cube_with (data = newcube ,
1535+ wcs = newwcs ,
1536+ mask = BooleanArrayMask (newcube_valid .astype ('bool' ),
1537+ newwcs ),
1538+ meta = self .meta ,
1539+ )
1540+
1541+
14501542
14511543class DaskVaryingResolutionSpectralCube (DaskSpectralCubeMixin , VaryingResolutionSpectralCube ):
14521544
@@ -1632,90 +1724,3 @@ def _mask_include(self):
16321724 chunks = self ._data .chunksize ),
16331725 wcs = self .wcs ,
16341726 shape = self .shape )
1635-
1636- def reproject (self , header , order = 'bilinear' , use_memmap = False ,
1637- filled = True , ** kwargs ):
1638- """
1639- Spatially reproject the cube into a new header. Fills the data with
1640- the cube's ``fill_value`` to replace bad values before reprojection.
1641-
1642- If you want to reproject a cube both spatially and spectrally, you need
1643- to use `spectral_interpolate` as well.
1644-
1645- Parameters
1646- ----------
1647- header : `astropy.io.fits.Header`
1648- A header specifying a cube in valid WCS
1649- order : int or str, optional
1650- The order of the interpolation (if ``mode`` is set to
1651- ``'interpolation'``). This can be either one of the following
1652- strings:
1653-
1654- * 'nearest-neighbor'
1655- * 'bilinear'
1656- * 'biquadratic'
1657- * 'bicubic'
1658-
1659- or an integer. A value of ``0`` indicates nearest neighbor
1660- interpolation.
1661- use_memmap : bool
1662- If specified, a memory mapped temporary file on disk will be
1663- written to rather than storing the intermediate spectra in memory.
1664- filled : bool
1665- Fill the masked values with the cube's fill value before
1666- reprojection? Note that setting ``filled=False`` will use the raw
1667- data array, which can be a workaround that prevents loading large
1668- data into memory.
1669- kwargs : dict
1670- Passed to `reproject.reproject_interp`.
1671- """
1672-
1673- try :
1674- from reproject .version import version
1675- except ImportError :
1676- raise ImportError ("Requires the reproject package to be"
1677- " installed." )
1678-
1679- reproj_kwargs = kwargs
1680- # Need version > 0.2 to work with cubes, >= 0.5 for memmap
1681- from distutils .version import LooseVersion
1682- if LooseVersion (version ) < "0.5" :
1683- raise Warning ("Requires version >=0.5 of reproject. The current "
1684- "version is: {}" .format (version ))
1685- elif LooseVersion (version ) >= "0.6" :
1686- pass # no additional kwargs, no warning either
1687- else :
1688- reproj_kwargs ['independent_celestial_slices' ] = True
1689-
1690- from reproject import reproject_interp
1691-
1692- # TODO: Find the minimal subcube that contains the header and only reproject that
1693- # (see FITS_tools.regrid_cube for a guide on how to do this)
1694-
1695- newwcs = wcs .WCS (header )
1696- shape_out = tuple ([header ['NAXIS{0}' .format (i + 1 )] for i in
1697- range (header ['NAXIS' ])][::- 1 ])
1698-
1699- def reproject_interp_wrapper (img_slice ):
1700- # What exactly is the wrapper getting here?
1701- # I think it is given a _cube_ that is a cutout?
1702- if filled :
1703- data = img_slice .filled_data [:]
1704- else :
1705- data = img_slice ._data
1706- return reproject_interp ((data , img_slice .header ),
1707- newwcs , shape_out = shape_out , ** kwargs )
1708-
1709- newcube , newcube_valid = self .apply_function_parallel_spatial (
1710- reproject_interp_wrapper ,
1711- accepts_chunks = True ,
1712- order = order ,
1713- ** reproj_kwargs )
1714-
1715- return self ._new_cube_with (data = newcube ,
1716- wcs = newwcs ,
1717- mask = BooleanArrayMask (newcube_valid .astype ('bool' ),
1718- newwcs ),
1719- meta = self .meta ,
1720- )
1721-
0 commit comments