Commit df4f7ede authored by Simon Conseil's avatar Simon Conseil

Merge branch 'segmap' into 'master'

Add code to create masks from a segmap (from musex) + some utilities (isiter, progressbar, isnotebook)

See merge request !166
parents f078c725 ba2e05fe
Pipeline #3182 passed with stage
in 15 minutes and 39 seconds
This diff is collapsed.
......@@ -36,3 +36,4 @@ from .source import *
from .linelist import *
from .muselet import muselet
from .sea import *
from .segmap import *
This diff is collapsed.
import numpy as np
import pytest
from astropy.io import fits
from glob import glob
from mpdaf.obj import Image
from mpdaf.sdetect import Segmap, create_masks_from_segmap
from mpdaf.tests.utils import get_data_file
from numpy.testing import assert_array_equal
try:
import joblib # noqa
except ImportError:
HAS_JOBLIB = False
else:
HAS_JOBLIB = True
def test_segmap():
segfile = get_data_file('segmap', 'segmap.fits')
img = Image(segfile)
refdata = np.arange(14)
for arg in (segfile, img, img.data):
segmap = Segmap(arg)
assert segmap.img.shape == (90, 90)
assert str(segmap.img.data.dtype) == '>i8'
assert np.max(segmap.img._data) == 13
assert_array_equal(np.unique(segmap.img._data), refdata)
assert_array_equal(segmap.copy().img.data, segmap.img.data)
cmap = segmap.cmap()
assert cmap.N == 14 # nb of values in the segmap
def test_align_segmap():
segmap = Segmap(get_data_file('segmap', 'segmap.fits'))
ref = Image(get_data_file('segmap', 'image.fits'))
aligned = segmap.align_with_image(ref, truncate=True)
assert aligned.img.shape == ref.shape
assert (aligned.img.wcs.get_rot() - ref.wcs.get_rot()) < 1e-3
def test_cut_header():
segmap = Segmap(get_data_file('segmap', 'segmap.fits'),
cut_header_after='NAXIS2')
assert 'RADESYS' not in segmap.img.primary_header
assert 'RADESYS' not in segmap.img.data_header
@pytest.mark.skipif(not HAS_JOBLIB, reason="requires joblib")
def test_create_masks(tmpdir):
segfile = get_data_file('segmap', 'segmap.fits')
reffile = get_data_file('segmap', 'image.fits')
catalog = get_data_file('segmap', 'catalog.fits')
create_masks_from_segmap(
segfile, catalog, reffile, n_jobs=1,
masksky_name=str(tmpdir.join('mask-sky.fits')),
maskobj_name=str(tmpdir.join('mask-source-%05d.fits')),
idname='id', raname='ra', decname='dec', margin=5, mask_size=(10, 10))
assert len(glob(str(tmpdir.join('mask-source*')))) == 13
assert len(glob(str(tmpdir.join('mask-sky*')))) == 1
mask = fits.getdata(str(tmpdir.join('mask-source-00001.fits')))
assert mask.shape == (50, 50)
assert mask.sum() == 56
# test skip_existing
create_masks_from_segmap(
segfile, catalog, reffile, n_jobs=1, skip_existing=True,
masksky_name=str(tmpdir.join('mask-sky.fits')),
maskobj_name=str(tmpdir.join('mask-source-%05d.fits')),
idname='id', raname='ra', decname='dec', margin=5, mask_size=(10, 10),
convolve_fwhm=0)
# test convolve_fwhm and callables for mask filenames
masksky_func = lambda: str(tmpdir.join('mask2-sky.fits'))
maskobj_func = lambda x: str(tmpdir.join('mask2-source-%05d.fits' % x))
create_masks_from_segmap(
segfile, catalog, reffile, n_jobs=1, skip_existing=True,
masksky_name=masksky_func, maskobj_name=maskobj_func,
idname='id', raname='ra', decname='dec', margin=5, mask_size=(10, 10),
convolve_fwhm=1, psf_threshold=0.5)
mask = fits.getdata(str(tmpdir.join('mask2-source-00001.fits')))
assert mask.shape == (50, 50)
assert mask.sum() == 106
......@@ -40,10 +40,17 @@ import warnings
from astropy.utils import minversion
from mpdaf.tools.util import (chdir, deprecated, broadcast_to_cube, timeit,
timer)
timer, isiter, progressbar)
PYTEST_LT_3_3 = not minversion('pytest', '3.3')
try:
import tqdm
except ImportError:
HAS_TQDM = False
else:
HAS_TQDM = True
def test_chdir(tmpdir):
cwd = os.getcwd()
......@@ -106,3 +113,17 @@ def test_timer(caplog):
assert out == 'a'
assert re.search(r'Request took 0.1\d\d sec.', caplog.text) is not None
def test_isiter():
assert isiter([])
assert isiter((1, 2, 3))
assert not isiter(1)
assert isiter(np.array([1, 2, 3]))
@pytest.mark.skipif(not HAS_TQDM, reason="requires tqdm")
def test_progressbar():
bar = progressbar([1, 2, 3])
assert isinstance(bar, tqdm.tqdm)
assert next(iter(bar)) == 1
......@@ -48,7 +48,7 @@ from time import time
__all__ = ('MpdafWarning', 'MpdafUnitsWarning', 'deprecated', 'chdir',
'timeit', 'timer', 'broadcast_to_cube', 'LowercaseOrderedDict',
'all_subclasses')
'all_subclasses', 'isiter', 'isnotebook', 'progressbar')
# NOTE(kgriffs): We don't want our deprecations to be ignored by default,
......@@ -145,6 +145,37 @@ def all_subclasses(cls):
[s for c in cls.__subclasses__() for s in all_subclasses(c)])
def isiter(val):
"""Return True is val is iterable."""
try:
iter(val)
except TypeError:
return False
else:
return True
def isnotebook(): # pragma: no cover
"""Detect if running inside a jupyter notebook."""
try:
shell = get_ipython().__class__.__name__
if shell == 'ZMQInteractiveShell':
return True # Jupyter notebook or qtconsole
elif shell == 'TerminalInteractiveShell':
return False # Terminal running IPython
else:
return False # Other type (?)
except NameError:
return False # Probably standard Python interpreter
def progressbar(*args, **kwargs):
"""Wrapper for tqdm progress bar, with notebook detection."""
from tqdm import tqdm, tqdm_notebook
func = tqdm_notebook if isnotebook() else tqdm
return func(*args, **kwargs)
# Here we inherit unnecessarily from OrderedDict.
# This is because when merging astropy.table.Table() objects, an explicit
# check for the metadata object is a <dict> instance
......
......@@ -231,7 +231,7 @@ setup(
setup_requires=['numpy>=1.10.0'],
install_requires=['numpy>=1.10.0', 'scipy', 'matplotlib', 'astropy>=1.0'],
extras_require={
'all': ['numexpr', 'fitsio', 'adjustText'],
'all': ['numexpr', 'fitsio', 'adjustText', 'joblib', 'tqdm'],
},
tests_require=['pytest'],
package_dir={'': 'lib'},
......
......@@ -13,10 +13,12 @@ commands =
pytest --cov mpdaf --cov-report term {posargs}
deps =
cython
joblib
numexpr
py{36,37}: regions
specutils
pytest-cov
specutils
tqdm
py35: astropy>=2.0,<3.0
py35: numpy>=1.14,<1.15
py36: astropy>=3.0,<3.1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment