GithubHelp home page GithubHelp logo

spacetelescope / gwcs Goto Github PK

View Code? Open in Web Editor NEW
45.0 13.0 47.0 1.38 MB

Generalized World Coordinate System: provides tools for managing WCS in a general way

Home Page: https://gwcs.readthedocs.io/en/latest/

Python 100.00%
wcs astropy astronomy

gwcs's Introduction

GWCS - Generalized World Coordinate System

CI Status Documentation Status Code coverage Powered by Astropy Badge Powered by STScI Badge

Generalized World Coordinate System (GWCS) is an Astropy affiliated package providing tools for managing the World Coordinate System of astronomical data.

GWCS takes a general approach to the problem of expressing transformations between pixel and world coordinates. It supports a data model which includes the entire transformation pipeline from input coordinates (detector by default) to world coordinates. It is tightly integrated with Astropy.

  • Transforms are instances of astropy.Model. They can be chained, joined or combined with arithmetic operators using the flexible framework of compound models in astropy.modeling.
  • Celestial coordinates are instances of astropy.SkyCoord and are transformed to other standard celestial frames using astropy.coordinates.
  • Time coordinates are represented by astropy.Time and can be further manipulated using the tools in astropy.time
  • Spectral coordinates are astropy.Quantity objects and can be converted to other units using the tools in astropy.units.

For complete features and usage examples see the documentation site.

Installation

To install:

pip install gwcs

To clone from github and install the master branch:

git clone https://github.com/spacetelescope/gwcs.git
cd gwcs
python setup.py install

Contributing Code, Documentation, or Feedback

We welcome feedback and contributions to the project. Contributions of code, documentation, or general feedback are all appreciated. Please follow the contributing guidelines to submit an issue or a pull request.

We strive to provide a welcoming community to all of our users by abiding to the Code of Conduct.

Citing GWCS

If you use GWCS, please cite the package via its Zenodo record.

gwcs's People

Contributors

bernie-simon avatar bmorris3 avatar braingram avatar bsipocz avatar cadair avatar cdeil avatar chris-simpson avatar cshanahan1 avatar drdavella avatar dstansby avatar eslavich avatar eteq avatar jdavies-st avatar jhunkeler avatar larrybradley avatar mcara avatar mdboom avatar nden avatar nmearl avatar olebole avatar perrygreenfield avatar pllim avatar williamjamieson avatar zacharyburnett avatar zanecodes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gwcs's Issues

New release?

Hi,

since a month (Python) ASDF version 2.0 is available. gwcs does not work properly with that version since it still relies (at least) on some code which later was moved to gwcs; see c183ca6.

This affects the Debian package of gwcs, which cannot be rebuilt anymore (and may be therefore temporarily removed from Debian testing at some point), but will also make it difficult to install gwcs from Pypi.

Would you consider to release a new gwcs version that works with asdf? There was an alpha release in February already.

0.5.1 release

There is a python 3 compatibility issue in 0.5.1 related with the import of ConfigParser and the tests do not pass because of the pyasdf rename and the problem reported in #55. Are there any plans to have a 0.5.2 maintenance release to solve these issues?

convert a FITS WCS object to a GWCS object

Provide a way to convert an astropy.wcs object to a gwcs.WCS object. I'm not sure we need to go the opposite direction even when it's possible. Comments on this welcome.

YAML serialization

Another suggestion coming out of PIA17 unconference (via @Cadair and @astrofrog and @perrygreenfield ): gwcs representations should be serializable as standard YAML (which is very close to asdf, but not quite the same, and should be named as such and so on).

In many cases no "data" is needed, so that can just be straight-YAML (not asdf). When data is needed, maybe that can be asdf only, or asdf as one option and something like byte-encoded binary that fits into a YAML file as the other? (didn't decide for sure on that)

Using a non-tuple sequence for multidimensional indexing is deprecated in numpy

The following warning came from running the JWST calibration pipeline regression tests:

jwst/tests_nightly/general/pipelines/test_mrs_spec3.py::test_spec3_pipeline1
  /Users/jdavies/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/gwcs/selector.py:194: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
    result = self._mapper[args[::-1]]

So it looks like a 1-line change in the LabelMapperArray.evaluate() method.

Desired examples

As part of PIA17, we had an unconference session on what will make using gwcs easier. A lot of people agreed "documentation with some practical examples".

this google doc has a brainstormed list of what kinds of examples might be good. (After the unconference - May 10, 2017 - we should move the list to this issue)

Declare dependency on pyasdf

Is pyasdf a required or optional dependency for gwcs?

If it's required, it should be declared in setup.py so that pip will install it.
If it's optional, the tests requiring it should be conditionally skipped.

Currently I see this:

$ pip install --user gwcs
Collecting gwcs
  Downloading gwcs-0.5.tar.gz (300kB)
    100% |████████████████████████████████| 303kB 1.7MB/s 
Requirement already satisfied (use --upgrade to upgrade): astropy in /Users/deil/code/astropy (from gwcs)
Requirement already satisfied (use --upgrade to upgrade): numpy>=1.6.0 in /opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages (from astropy->gwcs)
Installing collected packages: gwcs
  Running setup.py install for gwcs
Successfully installed gwcs-0.5

$ python -c 'import gwcs; gwcs.test()'
============================================================================== test session starts ===============================================================================
platform darwin -- Python 3.5.1 -- py-1.4.30 -- pytest-2.7.3
rootdir: /Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs, inifile: 

Running tests with gwcs version 0.5.
Running tests in /Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs.

Platform: Darwin-15.2.0-x86_64-i386-64bit

Executable: /opt/local/bin/python

Full Python Version: 
3.5.1 (default, Dec 10 2015, 22:28:35) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)]

encodings: sys: utf-8, locale: UTF-8, filesystem: utf-8
byteorder: little
float info: dig: 15, mant_dig: 15

Numpy: 1.10.2
Scipy: 0.16.1
Matplotlib: 1.5.0
Astropy: 1.0.5
pyasdf: not available

collected 47 items / 1 errors 

../../Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs/tests/test_coordinate_systems.py ...............
../../Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs/tests/test_region.py .......
../../Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs/tests/test_separable.py .......
../../Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs/tests/test_utils.py ...
../../Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs/tests/test_wcs.py ...............

===================================================================================== ERRORS =====================================================================================
__________________________________________________________________ ERROR collecting tags/tests/test_selector.py __________________________________________________________________
_pytest.runner:149: in __init__
    ???
_pytest.main:437: in _memocollect
    ???
_pytest.main:314: in _memoizedcall
    ???
_pytest.main:437: in <lambda>
    ???
_pytest.python:492: in collect
    ???
_pytest.python:1753: in parsefactories
    ???
_pytest.python:276: in fget
    ???
_pytest.python:489: in _getobj
    ???
_pytest.main:314: in _memoizedcall
    ???
_pytest.python:498: in _importtestmodule
    ???
py._path.local:650: in pyimport
    ???
/Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs/tags/__init__.py:5: in <module>
    from .selectortags import *
/Users/deil/Library/Python/3.5/lib/python/site-packages/gwcs/tags/selectortags.py:12: in <module>
    from pyasdf import yamlutil
E   ImportError: No module named 'pyasdf'
======================================================================= 47 passed, 1 error in 1.11 seconds =======================================================================

Read a GWCS object from a FITS file

Something like this (in a function or method):

from asdf.fits_embed import AsdfInFits

fa = AsdfInFits.open('miri_assign_wcs.fits')
wcsobj = fa.tree['meta']['wcs']
data = fa.tree['data']

@pllim

Add a statement to the docs that GWCS works with 0-based pixel coordinates

The documentation needs to clearly state that GWCS works with 0-based pixel coordinates.

In the doc, "To convert a pixel (x, y) = (1, 2) to sky coordinates, call the WCS object as a function..." Is this (1, 2) index number or IRAF-like pixel location? I saw there was a similar question in #49 but I still don't understand. In that issue, it says GWCS is 0-based but behaves like FITS WCS 1-based, which really confused me.

gwcs broken with Astropy 2.0

Currently, gwcs does not work well with Astropy 2.0; one of the unit test fails:

=================================== FAILURES ===================================
____________________________ test_from_fiducial_sky ____________________________

    def test_from_fiducial_sky():
        sky = coord.SkyCoord(1.63 * u.radian, -72.4 * u.deg, frame='fk5')
        tan = models.Pix2Sky_TAN()
>       w = wcs_from_fiducial(sky, projection=tan)

/usr/lib/python3/dist-packages/gwcs/tests/test_wcs.py:153:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _
/usr/lib/python3/dist-packages/gwcs/wcstools.py:62: in wcs_from_fiducial
    fiducial_transform = _sky_transform(fiducial, projection)
/usr/lib/python3/dist-packages/gwcs/wcstools.py:112: in _sky_transform
    sky_rotation = models.RotateNative2Celestial(lon, lat, lon_pole)
/usr/lib/python3/dist-packages/astropy/modeling/rotations.py:231: in __init__
    super(RotateNative2Celestial, self).__init__(lon, lat, lon_pole, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __ _ _ _

self = <[AttributeError("lon") raised in repr()] RotateNative2Celestialobject at 0x7f4499dd52e8>
lon = <Longitude 93.39212060632418 deg>, lat = <Latitude -72.4 deg>
lon_pole = 180, kwargs = {}, qs = [True, True, False]

    def __init__(self, lon, lat, lon_pole, **kwargs):
        qs = [isinstance(par, u.Quantity) for par in [lon, lat, lon_pole]]
        if any(qs) and not all(qs):
>           raise TypeError("All parameters should be of the same type - float or Quantity.")
E           TypeError: All parameters should be of the same type - float

Full test log here. There is also a Debian bug #868115.

It seems that gwcs.util does not use units in _compute_lon_pole(); I am however unsure about side effects when just adding u.deg there.

grid_from_bounding_box should have a default step that works with bounding boxes with ndim > 1

The default step in grid_from_bounding_box is step=1. But if the bounding box has more than 1 dimension, this produces an error.

The function should first check and make sure the dimensions are the same. If the bounding box has ndim > 1 and step ndim = 1, then assume the step is the same in all dimensions and proceed accordingly. In other words, the default should be step=1 for all dimensions of the input bounding box.

The following code should work:

from gwcs import wcstools

bounding_box = ((0, 2047), (0, 51))
grid = wcstools.grid_from_bounding_box(bounding_box)

bounding_box does not work correctly for 1D models

Model.bounding_box is a tuple for 1d models, and tuple of tuples for nd models. The1D model case does not work in gwcs. This shoul dbe fixed in the WCS.bounding_box property and in grid_from_bounding_box.

Update the help

Tyler Desjardins mentions that we should consider moving emails from help[at]stsci.edu to point to the web portal where possible and appropriate. For HST (or any non-JWST), it is https://hsthelp.stsci.edu . For JWST, it is https://jwsthelp.stsci.edu . Please update info in setup.py, setup.cfg, documentation, etc as appropriate.

Please close this issue if it is irrelevant to your repository. This is an automated issue. If this is opened in error, please let pllim know!

xref spacetelescope/hstcal#317

gwcs tries to import pytest_remotedata from asdf

ImportError Traceback (most recent call last)
in ()
13 NIRISSForwardRowGrismDispersion,
14 NIRISSBackwardGrismDispersion)
---> 15 from jwst.datamodels.wcs_ref_models import NIRISSGrismModel
16 from jwst.datamodels import image
17
~/miniconda3/envs/jwstdev/lib/python3.5/site-packages/jwst-0.9.3a0.dev85-py3.5-macosx-10.7-x86_64.egg/jwst/datamodels/init.py in ()
36 from . import ndmodel
37
---> 38 from .model_base import DataModel
39 from .amilg import AmiLgModel
40 from .asn import AsnModel
~/miniconda3/envs/jwstdev/lib/python3.5/site-packages/jwst-0.9.3a0.dev85-py3.5-macosx-10.7-x86_64.egg/jwst/datamodels/model_base.py in ()
30 from .extension import BaseExtension
31 from jwst.transforms.jwextension import JWSTExtension
---> 32 from gwcs.extension import GWCSExtension
33
34
~/miniconda3/envs/jwstdev/lib/python3.5/site-packages/gwcs/extension.py in ()
3 from asdf import util
4 from asdf.extension import BuiltinExtension
----> 5 from .tags.wcs import * # noqa
6 from .tags.selectortags import * # noqa
7
~/miniconda3/envs/jwstdev/lib/python3.5/site-packages/gwcs/tags/init.py in ()
2 # -- coding: utf-8 --
3
----> 4 from .wcs import *
5 from .selectortags import *
~/miniconda3/envs/jwstdev/lib/python3.5/site-packages/gwcs/tags/wcs.py in ()
6
7 from asdf import yamlutil
----> 8 from asdf.tests import helpers
9 from ..gwcs_types import GWCSType
10 from ..coordinate_frames import (Frame2D, CoordinateFrame, CelestialFrame,
~/miniconda3/envs/jwstdev/lib/python3.5/site-packages/asdf/tests/helpers.py in ()
22 else:
23 import pytest
---> 24 from pytest_remotedata.disable_internet import INTERNET_OFF
25 remote_data = pytest.mark.remote_data
ImportError: No module named 'pytest_remotedata'

Enable asdf serialization of subclasses

A subclass of wcs.WCS will not roundtrip serialization unless a tag and possibly a schema for the subclass is written. Provide an esay way to do this. As a minimum document how to do it with an example.

Make an example (and functionality?) for building wcs from stars world coordinates and pixel coordinates

This is obviously a big task with a lot of details I'm glossing over, but prompted by @perrygreenfield's suggestion at the spectroscopy workshop, I thought it would be good to get it in here.

Basically, the following sort of thing should be possible:

star_sc = SkyCoord(ra_stars, dec_stars) #lets not worry about how you decided which star is which
star_pixels = np.array(x_stars, y_stars)
wcs = gwcs.wcs_from_matches(star_sc, star_pixels)
assert wcs.pixel_to_world(x_stars, ystars) == star_sc.ra, star_sc.dec # this isn't exactly right but hope gets the idea across

Does the basic task there make sense? Ideally this would be a part of a tutorial that combines with photutils or similar to show the real use case of "I have an image from a telescope with only very rough WCS, and want to get a better one by matching to something else". Although that tutorial might be better in astropy-tutorials rather than in gwcs proper.

Support for appending new frames to a WCS chain

Currently the WCS class allows (per the docs) inserting new transforms between existing frames, but not adding new frames after instantiation. There also seems to be no trivial way to create a new WCS object from an existing one, with or without modifications. As discussed with @nden, it would be useful to have an interface for appending one or more frame & transform pairs to the "wcs pipeline" as data calibration progresses and the corresponding transforms become defined (perhaps not always in an identical sequence). Ideally, one would also be able to insert new frames & transforms at the start of the pipeline (or perhaps even in the middle, though that could be more dangerous), but the main use case I'd envisage is "append".

At the moment, one has to do something like this to make a new WCS object from an old one, appending a new frame and transform (which, amongst other things, is not very self-explanatory):

def wcs_append(wcs_obj, forward_transform, output_frame):
    pipeline = [(getattr(wcs_obj, f) or f, m) for f, m in wcs_obj.pipeline]
    pipeline[-1] = (pipeline[-1][0], forward_transform)
    pipeline.append((output_frame, None))
    return wcs.WCS(pipeline)

Thanks!

James.

pixel_to_skycoord and skycoord_to_pixel

Astropy has two nice convenience functions for converting between pixels and SkyCoord objects (i.e. with a coordinate frame):

It would be nice if gwcs had similar functions. Ideally, the existing astropy functions would be able to work with gwcs objects, so perhaps this issue falls under the "unified wcs" initiative.

Can't initialize an SkyOffsetFrame without origin= keyword

As seen in https://travis-ci.org/spacetelescope/gwcs/jobs/143127054

gwcs/tags/tests/test_selector.py .....

gwcs/tests/test_coordinate_systems.py .....................F

gwcs/tests/test_region.py .......

gwcs/tests/test_separable.py .......

gwcs/tests/test_utils.py ...

gwcs/tests/test_wcs.py ...................

=================================== FAILURES ===================================

_______________________ test_attributes[SkyOffsetFrame] ________________________

frame = 'SkyOffsetFrame'

    @pytest.mark.parametrize(('frame'), coord_frames)

    def test_attributes(frame):

        """

        Test getting default values for  CoordinateFrame attributes from reference_frame.

        """

>       cel = cf.CelestialFrame(reference_frame=getattr(coord, frame)())

gwcs/tests/test_coordinate_systems.py:91: 

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'astropy.coordinates.builtin_frames.skyoffset.SkyOffsetFrame'>

args = (), kwargs = {}

    def __new__(cls, *args, **kwargs):

        # We don't want to call this method if we've already set up

        # an skyoffset frame for this class.

        if not (issubclass(cls, SkyOffsetFrame) and cls is not SkyOffsetFrame):

            # We get the origin argument, and handle it here.

            try:

                origin_frame = kwargs['origin']

            except KeyError:

>               raise TypeError("Can't initialize an SkyOffsetFrame without origin= keyword.")

E               TypeError: Can't initialize an SkyOffsetFrame without origin= keyword.

/home/travis/miniconda/envs/test/lib/python3.5/site-packages/astropy/coordinates/builtin_frames/skyoffset.py:196: TypeError

===================== 1 failed, 62 passed in 2.17 seconds ======================

set_transform apparently does not work (but appears to work)

I am trying to change the value of a parameter in a WCS transformation. In large, I am following the examples from http://gwcs.readthedocs.org/en/latest/gwcs/create_wcs.html#create-the-wcs-object an then I try to modify a parameter in the transformation from the focal frame to celestial frame.

>>> from astropy.modeling.models import (Shift, Scale, Rotation2D, Pix2Sky_TAN, RotateNative2Celestial, Mapping, Polynomial2D, AffineTransformation2D)
>>> import gwcs
>>> from gwcs import coordinate_frames as cf
>>> import numpy as np
>>> from astropy import coordinates as coord
>>> 
>>> CRPIX1 = 2048.0
>>> CRPIX2 = 1024.0
>>> CRVAL1 = 5.63056810618
>>> CRVAL2 = -72.0545718428
>>> LONPOLE = 180
>>> PC1_1 =  1.29058668e-05
>>> PC1_2 = 5.95320246e-06
>>> PC2_1 = 5.02215196e-06
>>> PC2_2 = -1.26450104e-05
>>> CTYPE1 = 'RA---TAN'
>>> CTYPE2 = 'DEC---TAN'
>>> dist_x = Polynomial2D(2, c0_0=0.0013, c1_0=0.5, c2_0=0, c0_1=0.823, c0_2=1.4, c1_1=1.7, name='x_distortion')
>>> dist_y = Polynomial2D(2, c0_0=0.03, c1_0=0.25, c2_0=1.2, c0_1=0.3, c0_2=0.4, c1_1=0.7, name='y_distortion')
>>> distortion = dist_x & dist_y
>>> distortion_mapping = Mapping((0, 1, 0, 1), name='distortion_mapping')
>>> distortion = distortion_mapping | dist_x & dist_y
>>> shift = Shift(CRPIX1, name="crpix1") & Shift(CRPIX2, name="crpix2")
>>> plane_rotation = AffineTransformation2D(matrix=np.array([[PC1_1, PC1_2], [PC2_1, PC2_2]]))
>>> tangent = Pix2Sky_TAN()
>>> sky_rotation = RotateNative2Celestial(CRVAL1, CRVAL2, LONPOLE)
>>> focal2sky = shift | plane_rotation | tangent | sky_rotation
>>> 
>>> inframe = cf.Frame2D(name='detector')
>>> focal = cf.Frame2D(name='focal')
>>> outframe = cf.CelestialFrame(reference_frame=coord.ICRS(), name='CelestialFrame')
>>> pipeline = [(inframe, distortion), (focal, focal2sky), (outframe, None)]
>>> memw = gwcs.wcs.WCS(pipeline)
>>> 
>>> memw(1,1)
(5.736394270266226, -72.0572205208842)
>>> tr = memw.get_transform('focal', 'CelestialFrame')
>>> tr
<CompoundModel6(offset_0=2048.0, offset_1=1024.0, matrix_2=[[ 0.00001291, 0.00000595], [ 0.00000502,-0.00001265]], translation_2=[ 0., 0.], lon_4=5.63056810618, lat_4=-72.0545718428, lon_pole_4=180.0)>
>>> tr(1,1)
(5.7362144489763285, -72.05721404287078)
>>> tr['crpix1'].offset=0
>>> tr
<CompoundModel6(offset_0=0.0, offset_1=1024.0, matrix_2=[[ 0.00001291, 0.00000595], [ 0.00000502,-0.00001265]], translation_2=[ 0., 0.], lon_4=5.63056810618, lat_4=-72.0545718428, lon_pole_4=180.0)>
>>> tr(1,1)
(5.650428514863572, -72.0675269477636)
>>>
>>> # memw before replacing focal->celestial transformation:
>>> memw
<WCS(output_frame=CelestialFrame, input_frame=detector, forward_transform=Model: CompoundModel11
Inputs: ('x0', 'x1')
Outputs: (u'alpha_C', u'delta_C')
Model set size: 1
Expression: [0] | [1] & [2] | [3] & [4] | [5] | [6] | [7]
Components: 
    [0]: <Mapping((0, 1, 0, 1), name=distortion_mapping)>

    [1]: <Polynomial2D(2, c0_0=0.0013, c1_0=0.5, c2_0=0.0, c0_1=0.823, c0_2=1.4, c1_1=1.7, name='x_distortion')>

    [2]: <Polynomial2D(2, c0_0=0.03, c1_0=0.25, c2_0=1.2, c0_1=0.3, c0_2=0.4, c1_1=0.7, name='y_distortion')>

    [3]: <Shift(offset=2048.0, name='crpix1')>

    [4]: <Shift(offset=1024.0, name='crpix2')>

    [5]: <AffineTransformation2D(matrix=[[ 0.00001291, 0.00000595], [ 0.00000502,-0.00001265]], translation=[ 0., 0.])>

    [6]: <Pix2Sky_Gnomonic()>

    [7]: <RotateNative2Celestial(lon=5.63056810618, lat=-72.0545718428, lon_pole=180.0)>
Parameters:
    c0_0_1 c1_0_1 c2_0_1 c0_1_1 c0_2_1 c1_1_1 c0_0_2 c1_0_2 c2_0_2 c0_1_2 c0_2_2 c1_1_2 offset_3 offset_4           matrix_5 [2,2]          translation_5 [2]     lon_7         lat_7      lon_pole_7
    ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ -------- -------- --------------------------------- ----------------- ------------- -------------- ----------
    0.0013    0.5    0.0  0.823    1.4    1.7   0.03   0.25    1.2    0.3    0.4    0.7   2048.0   1024.0 1.29058668e-05 .. -1.26450104e-05        0.0 .. 0.0 5.63056810618 -72.0545718428      180.0)>
>>> memw(1,1)
(5.736394270266226, -72.0572205208842)
>>>
>>> # Now replace focal->celestial using the modified 'tr' which we have checked above that it works:
>>> memw.set_transform('focal', 'CelestialFrame', tr)
>>> memw(1,1)
(5.736394270266226, -72.0572205208842)
>>> # Above result is identical to the result obtained before WCS was modified.
>>>
>>> # Let's check that focal->celestial transformation in the WCS is the one that we just set:
>>> memw.get_transform('focal', 'CelestialFrame')
<CompoundModel6(offset_0=0.0, offset_1=1024.0, matrix_2=[[ 0.00001291, 0.00000595], [ 0.00000502,-0.00001265]], translation_2=[ 0., 0.], lon_4=5.63056810618, lat_4=-72.0545718428, lon_pole_4=180.0)>
>>> # Indeed, this is identical to 'tr':
>>> tr
<CompoundModel6(offset_0=0.0, offset_1=1024.0, matrix_2=[[ 0.00001291, 0.00000595], [ 0.00000502,-0.00001265]], translation_2=[ 0., 0.], lon_4=5.63056810618, lat_4=-72.0545718428, lon_pole_4=180.0)>
>>>
>>> # However, wcs object itself (full forward transformation) does not show modified 'CRPIX' value:
>>> memw
<WCS(output_frame=CelestialFrame, input_frame=detector, forward_transform=Model: CompoundModel14
Inputs: ('x0', 'x1')
Outputs: (u'alpha_C', u'delta_C')
Model set size: 1
Expression: [0] | [1] & [2] | [3] & [4] | [5] | [6] | [7]
Components: 
    [0]: <Mapping((0, 1, 0, 1), name=distortion_mapping)>

    [1]: <Polynomial2D(2, c0_0=0.0013, c1_0=0.5, c2_0=0.0, c0_1=0.823, c0_2=1.4, c1_1=1.7, name='x_distortion')>

    [2]: <Polynomial2D(2, c0_0=0.03, c1_0=0.25, c2_0=1.2, c0_1=0.3, c0_2=0.4, c1_1=0.7, name='y_distortion')>

    [3]: <Shift(offset=2048.0, name='crpix1')>

    [4]: <Shift(offset=1024.0, name='crpix2')>

    [5]: <AffineTransformation2D(matrix=[[ 0.00001291, 0.00000595], [ 0.00000502,-0.00001265]], translation=[ 0., 0.])>

    [6]: <Pix2Sky_Gnomonic()>

    [7]: <RotateNative2Celestial(lon=5.63056810618, lat=-72.0545718428, lon_pole=180.0)>
Parameters:
    c0_0_1 c1_0_1 c2_0_1 c0_1_1 c0_2_1 c1_1_1 c0_0_2 c1_0_2 c2_0_2 c0_1_2 c0_2_2 c1_1_2 offset_3 offset_4           matrix_5 [2,2]          translation_5 [2]     lon_7         lat_7      lon_pole_7
    ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ -------- -------- --------------------------------- ----------------- ------------- -------------- ----------
    0.0013    0.5    0.0  0.823    1.4    1.7   0.03   0.25    1.2    0.3    0.4    0.7   2048.0   1024.0 1.29058668e-05 .. -1.26450104e-05        0.0 .. 0.0 5.63056810618 -72.0545718428      180.0)>

change argument name: "output" --> "with_units"

Currently one needs to pass output=numericals_plus to the __call__ function in order to have it return SkyCoord or Quantity objects. It's clearer to use a boolean keyword with_units.

However, #96 is also relevant for this issue.

fits files not containing WCSAXES crash read_wcs_from_header()

I get the following error when reading a file with a WCS that doesn't have the WCSAXES keyword:

{{{
/Users/parejkoj/lsst/lsstsw/miniconda/lib/python2.7/site-packages/gwcs/utils.pyc in read_wcs_from_header(header)
97 keys = ctypes.keys()
98 for key in keys[::-1]:
---> 99 if p.split(k)[-1] != "":
100 keys.remove(k)
101 wcs_info['WCSAXES'] = len(keys)
}}}

The k there should be key. Though it's potentially dangerous to loop over the keys and remove them as you go...

issues using gwcs with units

[ ] fix wcs_from_fiducial to work with SkyCoord objects.

Before units in modeling worked gwcs did the following when inputs were quantities or SkyCoord objects:

  • Converted the inputs to the expected units in the input coordinate frame
  • Stripped the units off
  • Evaluated the transform using numbers
  • Attached the units of the output frame to the result

With units available we have now more use cases to consider:

  1. Transforms were initialized with quantities
    1.1 Inputs are quantities and are passed through the entire transform
    1.2 Inputs are numbers - make them quantities using the units in the input coordinate frame.
    This assumes the numbers are in the expected units but that's a valid assumption in all cases.

  2. Transforms were not initialized with quantities
    2.1 Inputs are quantities - we can do what we did before (if there's a way to find out whether the
    model was initialized with quantities or not).
    2.2 Inputs are numbers - use numbers as inputs.

2.1 raises the question of how to distinguish if a transform was initialized with quantities or not. @perrygreenfield suggested requiring a transform to have input_units if it was initialized with quantities. This sounds reasonable to me. So in this case, this is what needs to change

When a GWCS object is initialized:

  • If forward_transform.input_units exists check that the transform input units are the same as input_coordinate_frame.unit and raise an error if not.
  • Perform the same check for transform.return_units and output_frame.unit

When evaluating the WCS and inputs are quantities:
If all transforms have input_units:

  • pass inputs as quantities
    else:
  • convert to units of input_frame
  • strip units
  • evaluate
  • attach units of output_frame

@Cadair Does this make sense?

improve documentation

This is a list of "desired" examples which came from Python in Astronomy meeting in Leiden.

  • An example of separating optical distortion from atmospheric effects
  • An example of “I have stars at pixel positions x, y (arrays), and I know they are at the SkyCoord(ra, dec). Give me the gWCS of the transformation to model that.”
  • I have a FITS file with a header with FITS WCS - how do I read it in and inspect the gWCS object?
  • I have a gWCS for a spectral cube, how do I check if the spectral axis is separable, and if so can I get a pure-spectral gWCS?
  • Manual construction of a simple WCS pipeline.
  • Augmenting (array) columns in FITS tables with WCS.
  • I have a gWCS object for a time-dependent spectral cube, how do I find out what the order of the dimensions are? (e.g. longitude, time, latitude, spectral)
  • Easily change WCS projections (automatic determination of new grid boundary, etc.)
  • I have a gWCS object with distortions, how do I get one without distortions?
  • A comparison of how to use gWCS versus FITS WCS (as implemented in astropy.wcs)
  • I have a gWCS object for an image, and want to extract a cutout of the image, how do I get the gWCS of the cutout?
  • I have a gWCS, how do I export it to a FITS file?
  • Serialize a gWCS pipeline into yaml / asdf
  • How to deal with different coordinate systems (J2000, B1950, Galactic, etc.)

grid_from_bounding_box() step default value

Using gwcs.wcstools.grid_from_bounding_box() and only passing the bounding box as the argument:

  File "/Users/jdavies/dev/jwst/jwst/resample/gwcs_drizzle.py", line 495, in dodrizzle
    pixmap = resample_utils.calc_gwcs_pixmap(input_wcs, output_wcs)
  File "/Users/jdavies/dev/jwst/jwst/resample/resample_utils.py", line 135, in calc_gwcs_pixmap
    grid = wcstools.grid_from_bounding_box(in_wcs.bounding_box)
  File "/Users/jdavies/anaconda/envs/dev_b7/lib/python3.5/site-packages/gwcs/wcstools.py", line 225, in grid_from_bounding_box
    for d, s in zip(bb, step):
TypeError: zip argument #2 must support iteration

I think it is a problem with the default step=1. I believe it should be step=(1, 1), or perhaps step=None with some logic inside the function to turn None into a tuple of ones of the same size as the number of dimensions of the bounding box? Not sure what the other use cases are for this function.

This is not urgent. I can work around it by calling the function and explicitly setting step=(1, 1), it works as expected.

Release 0.1?

@nden – Can you cut a gwcs release in the near future?

Or is something holding this back or do you have plans to put this in the Astropy core directly?

There is https://pypi.python.org/pypi/gwcs/0.1.dev44 but no tarball and pip install gwcs currently doesn't work:

$ pip install gwcs
Collecting gwcs
  Could not find a version that satisfies the requirement gwcs (from versions: )
No matching distribution found for gwcs

`separable` attribute error with astropy 3.0

Hi,

since we switched to astropy 3.0, we get the following error during the tests:

==================================== ERRORS ====================================
________________ ERROR collecting gwcs/tests/test_separable.py _________________
gwcs/tests/test_separable.py:30: in <module>
    sh1.separable = True
E   AttributeError: can't set attribute
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.60 seconds ============================

This happens with 0.7 as well as with 0.8. I found #123, but this doesn't enlight me.

Is there a simple workaround?

GWCS transformations lose accuracy near CRVAL and/or CRPIX (or near native poles)

Quite possible this issue may be related to issue #49. First of all, based on my tests, it appears that GWCS has extremely limited accuracy of inverse transformations (and possible forward too). This low accuracy makes GWCS unusable for chained transformations from one WCS to another (=re-projections).

Here is an example of a case when accuracy is lost and I also compare the results from GWCS with results from FITS WCS:

>>> # Define FITS WCS:
>>> from astropy import wcs
>>> fwi = wcs.WCS()
>>> fwi.wcs.pc = [[-1.666667E-05, 0], [0, 1.666667E-05]]
>>> fwi.wcs.cdelt = [1, 1]
>>> fwi.wcs.crpix = [4100.5, -8157.5]
>>> fwi.wcs.crval = [150.1163213, 2.200973097]
>>> fwi.wcs.ctype=['RA---TAN','DEC--TAN']
>>> fwi.wcs.radesys='ICRS'
>>> fwi.wcs.set()
>>> 
>>> # Define "similar" GWCS:
>>> import gwcs
>>> from astropy.modeling.models import (Shift, Scale, RotateNative2Celestial,
...                                      AffineTransformation2D, Rotation2D, Pix2Sky_TAN )
>>> from astropy import coordinates as coord
>>> sky_frame = gwcs.coordinate_frames.CelestialFrame(reference_frame=coord.ICRS(),name='icrs')
>>> transform = (Shift(-fwi.wcs.crpix[0]) & Shift(-fwi.wcs.crpix[1]) |
...              AffineTransformation2D(matrix=fwi.wcs.pc, translation=[0, 0]) |
...              Scale(fwi.wcs.cdelt[0]) & Scale(fwi.wcs.cdelt[1]) |
...              Pix2Sky_TAN() |
...              RotateNative2Celestial(fwi.wcs.crval[0], fwi.wcs.crval[1], 180))
>>> gwi = gwcs.WCS(forward_transform=transform, output_frame=sky_frame)
>>> 
>>> # Check that RA, DEC at CRPIX is identical to CRVAL:
>>> gwi(*fwi.wcs.crpix)
(150.1163213, 2.2009730969999963)
>>> gwi(*fwi.wcs.crpix) - fwi.wcs.crval
array([  0.00000000e+00,  -3.55271368e-15])
>>> 
>>> # Now convert (inverse transform) CRVAL to image coordinates and compare with CRPIX:
>>> gwi.invert(*gwi(*fwi.wcs.crpix)) - fwi.wcs.crpix
array([ 0.        , -0.05122641])
>>> # This is a very large error!!!
>>>
>>> # Compare previous result with the results from the same transformations
>>> # performed with FITS WCS:
>>> fwi.wcs_world2pix(fwi.wcs_pix2world([fwi.wcs.crpix], 1), 1) - fwi.wcs.crpix
array([[  0.00000000e+00,  -2.10093276e-10]])
>>> fwi.wcs_world2pix(fwi.wcs_pix2world([fwi.wcs.crpix], 0), 0) - fwi.wcs.crpix
array([[  6.74845069e-10,  -8.70386430e-10]])
>>> # Notice that FITS WCS is 8 orders of magnitude more accurate than GWCS *regardless* of
>>> # "origin" setting (as it should be)!

Inconsistency in WCS transformations between FITS WCS and GWCS (pixel CS origin)

There is something weird going on related to the "origin" of the coordinate system used for the "image"/pixel coordinates. Specifically, my understanding is that pixels are counted using numpy convention, that is first pixel in a 2D array has "coordinates" (0,0) (unlike (1,1) in DS9). However, my computations show that transformations performed by GWCS correspond to computations performed by analogous functions in FITS WCS when origin is set to 1:

>>> from astropy import wcs as fitswcs
>>> fits_wcs = fitswcs.WCS()
>>> fits_wcs.wcs.pc = [[1,0], [0,1]]
>>> fits_wcs.wcs.cdelt = [1e-5, 1e-5]
>>> fits_wcs.wcs.crpix = [100, 100]
>>> fits_wcs.wcs.crval = [250, 2]
>>> fits_wcs.wcs.ctype=['RA---TAN','DEC--TAN']
>>> fits_wcs.wcs.set()
>>> 
>>> import gwcs
>>> from astropy.modeling.models import ( Shift, Scale, RotateNative2Celestial, AffineTransformation2D, Rotation2D, Pix2Sky_TAN )
>>> from gwcs import coordinate_frames
>>> from astropy import coordinates as coord
>>> transform = Shift(-100) & Shift(-100) | Rotation2D(0) | Scale(1e-5) & Scale(1e-5) | Pix2Sky_TAN() | RotateNative2Celestial(250, 2, 180)
>>> sky_frame = coordinate_frames.CelestialFrame(reference_frame=coord.ICRS(), name='icrs')
>>> w = gwcs.WCS(forward_transform=transform, output_frame=sky_frame)
>>> 
>>> w(150,50)
(250.0005003046197, 1.9994999999238419)
>>> fits_wcs.wcs_pix2world([[150,50]], 0)
array([[ 250.00051031,    1.99951   ]])
>>> fits_wcs.wcs_pix2world([[150,50]], 1)
array([[ 250.0005003,    1.9995   ]])
>>> 
>>> # it may be easier to see the differences:
>>> wp = w(150,50)
>>> fits_wcs.wcs_pix2world([[150,50]], 0) - wp
array([[  1.00060955e-05,   9.99999694e-06]])
>>> fits_wcs.wcs_pix2world([[150,50]], 1) - wp
array([[ -2.84217094e-14,   6.43929354e-15]])

Am I doing something wrong?

Forward (and possibly inverse) transforms do not work with arbitrarily shaped inputs

I need to convert pixel coordinates of 3D images (cubes) to world coordinates. The forward transformation crashes when input coordinates are 3D arrays (NOTE: cube is a cube model):

>>> ind = np.indices((372,32,34))[::-1]
>>> cube.meta.wcs(*ind) 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../lib/python2.7/site-packages/gwcs/wcs.py", line 228, in __call__
    result = self.forward_transform(*args)
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 386, in __call__
    __call__, args, [('model_set_axis', None)])
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 382, in __call__
    return super(cls, self).__call__(*inputs, **kwargs)
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 687, in __call__
    outputs = self.evaluate(*chain(inputs, parameters))
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 2459, in evaluate
    return self.__class__.evaluate(*args)
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 1929, in evaluate
    result = cls._evaluate(inputs, params)
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 1755, in <lambda>
    return (lambda inputs, params: (f[0](inputs[:f[1]], params) +
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 1744, in <lambda>
    return (lambda inputs, params: g[0](f[0](inputs, params), params),
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 1744, in <lambda>
    return (lambda inputs, params: g[0](f[0](inputs, params), params),
  File "/.../lib/python2.7/site-packages/astropy/modeling/core.py", line 2374, in <lambda>
    evaluate(*chain(inputs, islice(params, n_params)))
  File "/.../lib/python2.7/site-packages/astropy/modeling/rotations.py", line 206, in evaluate
    phi, theta, psi)
  File "/.../lib/python2.7/site-packages/astropy/modeling/rotations.py", line 170, in _evaluate
    lon_pole, self.axes_order)
  File "/.../lib/python2.7/site-packages/astropy/modeling/rotations.py", line 88, in evaluate
    result = np.dot(matrix, inp)
ValueError: shapes (3,3) and (3,372,32,34) not aligned: 3 (dim 1) != 32 (dim 2)

Cube file will be e-mailed to @nden

Citable record?

We're planning to reference and cite all Astropy affiliated packages in the upcoming Astropy v2.0 paper. I couldn't find a citable record for this package - are you interested in creating one so that we can cite it? For example, you can create a zenodo record and just comment back here to let me know that it's done. Please also let me know if you'd like to opt out of a citation and we'll just link to the package. Thanks!

Celestial frame hardcoded to 2 axes?

I don't know if this is a bug or not, but it's come up in the work to serialize frames to/from ASDF.

If I assign a reference_frame on a CelestialFrame to a coordinate that has inherently 3 axes, it doesn't complain, but then len(axes_names) != naxes.

In [17]: import gwcs

In [18]: x = gwcs.CelestialFrame(reference_frame=coordinates.Galactic())

In [19]: x.axes_names
Out[19]: [u'lon', u'lat', u'distance']

In [20]: x.naxes
Out[20]: 2

Handle units on input

The gwcs.WCS.__call__ function has a with_units parameter that can be used to return an astropy.coordinates.SkyCoord object with units.

But if one tries to round trip this by taking this astropy.coordinates.SkyCoord object and feed it back into the backward_transform, then it fails, as it's expecting N inputs, where N is the number of dimensions inside the SkyCoord object.

Following the example from the docs, we construct a simplified gwcs.WCS object:

import numpy as np
from astropy.modeling.models import (Shift, Scale, Rotation2D,
      Pix2Sky_TAN, RotateNative2Celestial)
det2sky = (Shift(-10.5) & Shift(-13.2) | Rotation2D(0.0023) |
           Scale(.01) & Scale(.04) | Pix2Sky_TAN() |
           RotateNative2Celestial(5.6, -72.05, 180)).rename("det2sky")

from astropy import units as u
from astropy import coordinates as coord
from gwcs import coordinate_frames as cf
detector_frame = cf.Frame2D(name="detector", unit=(u.pix, u.pix))
sky_frame = cf.CelestialFrame(reference_frame=coord.ICRS(), name='icrs')

from gwcs import wcs
pipeline = [(detector_frame, det2sky),
            (sky_frame, None)
            ]
wcsobj = wcs.WCS(pipeline)

And then test it out:

In [12]: wcsobj(1, 1)
Out[12]: (5.599990008144789, -71.73800308407476)

In [13]: wcsobj(1, 1, with_units=True)
Out[13]: 
<SkyCoord (ICRS): (ra, dec) in deg
    (5.59999001, -71.73800308)>

In [14]: w = wcsobj(1, 1, with_units=True)

In [15]: wcsobj.backward_transform(w, with_units=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-23-fb3d7869d5a0> in <module>()
----> 1 wcsobj.backward_transform(w, with_units=True)

TypeError: __call__() got an unexpected keyword argument 'with_units'

In [16]: wcsobj.backward_transform(w)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-99c2ede38a9c> in <module>()
----> 1 wcsobj.backward_transform(w)

TypeError: __call__() missing 1 required positional argument: 'delta_C'

Now, one can decompose the SkyCoord object by hand, but even here we have to be careful.

In [34]: w.ra
Out[34]: <Longitude 5.28344155 deg>

In [35]: w.dec
Out[35]: <Latitude -72.53775313 deg>

In [36]: wcsobj.backward_transform(w.ra, w.dec)
---------------------------------------------------------------------------
UnitsError                                Traceback (most recent call last)
<ipython-input-36-3d1c306b417f> in <module>()
----> 1 wcsobj.backward_transform(w.ra, w.dec)

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in __call__(self, alpha_C, delta_C, model_set_axis, with_bounding_box, fill_value, equivalencies)
    380                                      ('with_bounding_box', False),
    381                                      ('fill_value', np.nan),
--> 382                                      ('equivalencies', None)])
    383 
    384             # The following makes it look like __call__ was defined in the class

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in __call__(self, *inputs, **kwargs)
    361             def __call__(self, *inputs, **kwargs):
    362                 """Evaluate this model on the supplied inputs."""
--> 363                 return super(cls, self).__call__(*inputs, **kwargs)
    364 
    365             # When called, models can take two optional keyword arguments:

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in __call__(self, *inputs, **kwargs)
    813                     outputs = [np.asarray(r) for r in result]
    814         else:
--> 815             outputs = self.evaluate(*chain(inputs, parameters))
    816         if self.n_outputs == 1:
    817             outputs = (outputs,)

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in evaluate(self, *args)
   2919     @sharedmethod
   2920     def evaluate(self, *args):
-> 2921         return self.__class__.evaluate(*args)
   2922 
   2923     # TODO: The way this works is highly inefficient--the inverse is created by

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in evaluate(cls, *args)
   2360         inputs = args[:cls.n_inputs]
   2361         params = iter(args[cls.n_inputs:])
-> 2362         result = cls._evaluate(inputs, params)
   2363         if cls.n_outputs == 1:
   2364             return result[0]

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in <lambda>(inputs, params)
   2192     #
   2193     # and similarly for g
-> 2194     return (lambda inputs, params: g[0](f[0](inputs, params), params),
   2195             f[1], g[2])
   2196 

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in <lambda>(inputs, params)
   2192     #
   2193     # and similarly for g
-> 2194     return (lambda inputs, params: g[0](f[0](inputs, params), params),
   2195             f[1], g[2])
   2196 

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in <lambda>(inputs, params)
   2192     #
   2193     # and similarly for g
-> 2194     return (lambda inputs, params: g[0](f[0](inputs, params), params),
   2195             f[1], g[2])
   2196 

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in <lambda>(inputs, params)
   2192     #
   2193     # and similarly for g
-> 2194     return (lambda inputs, params: g[0](f[0](inputs, params), params),
   2195             f[1], g[2])
   2196 

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in <lambda>(inputs, params)
   2203     #
   2204     # and similarly for g
-> 2205     return (lambda inputs, params: (f[0](inputs[:f[1]], params) +
   2206                                     g[0](inputs[f[1]:], params)),
   2207             f[1] + g[1], f[2] + g[2])

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in f(inputs, params)
   2800             def f(inputs, params):
   2801                 param_values = tuple(islice(params, n_params))
-> 2802                 return evaluate_wrapper(model, inputs, param_values)
   2803         else:
   2804             # Where previously model was a class, now make an instance

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/core.py in evaluate_wrapper(model, inputs, param_values)
   2792         def evaluate_wrapper(model, inputs, param_values):
   2793             inputs = model._validate_input_units(inputs)
-> 2794             outputs = model.evaluate(*inputs, *param_values)
   2795             if n_outputs == 1:
   2796                 outputs = (outputs,)

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/modeling/functional_models.py in evaluate(x, offset)
    479     def evaluate(x, offset):
    480         """One dimensional Shift model function"""
--> 481         return x + offset
    482 
    483     @staticmethod

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/units/quantity.py in __array_ufunc__(self, function, method, *inputs, **kwargs)
    618         # consistent units between two inputs (e.g., in np.add) --
    619         # and the unit of the result (or tuple of units for nout > 1).
--> 620         converters, unit = converters_and_unit(function, method, *inputs)
    621 
    622         out = kwargs.get('out', None)

~/anaconda3/envs/jwst_dev/lib/python3.6/site-packages/astropy/units/quantity_helper.py in converters_and_unit(function, method, *args)
    565                                      "argument is not a quantity (unless the "
    566                                      "latter is all zero/infinity/nan)"
--> 567                                      .format(function.__name__))
    568             except TypeError:
    569                 # _can_have_arbitrary_unit failed: arg could not be compared

UnitsError: Can only apply 'add' function to dimensionless quantities when other argument is not a quantity (unless the latter is all zero/infinity/nan)

One can jettison the units altogether, and it eventually works.

In [37]: wcsobj.backward_transform(w.ra.value, w.dec.value)
Out[37]: (0.999999999999897, 0.9999999999997442)

But the with_units parameter only seems defined on the WCS.__call__ method, not WCS.forward_transform or WCS.backward_transform.

In [38]: wcsobj.backward_transform(w.ra.value, w.dec.value, with_units=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-38-72f326c8ef7a> in <module>()
----> 1 wcsobj.backward_transform(w.ra.value, w.dec.value, with_units=True)

TypeError: __call__() got an unexpected keyword argument 'with_units'

This is mostly to document this behavior to take into account any changes to the calling API that might be made in the future.

Change RTD domain name

Change all references of readthedocs.org to readthedocs.io. For example, the link to asdf, etc. This is not urgent but should happen eventually.

Astropy Affiliated Package Review

This package has been re-reviewed by the Astropy coordination committee in relation to the Astropy affiliated package ecosystem.

We have adopted a review process for affiliated package that includes assigning quantitative ‘scores’ (red/orange/green) for different categories of review. You can read up more about this process here. (This document, currently in Google Docs, will be moved to the documentation in the near future.) For each of the categories below we have listed the score and have included some comments when the score is not green.

Functionality/ScopeGeneral%20package
No further comments
Integration with Astropy ecosystemGood
No further comments
DocumentationPartial
The documentation could be more beginner-friendly and include more examples, in particular for how gWCS would be used with a traditional FITS WCS for example. We know this is on the roadmap, but just wanted to mention it here for the record.
TestingPartial
Test coverage appears to be around 76%, which is a little under our target for a package to be considered 'green' (~90% or more)
Development statusGood
No further comments
Python 3 compatibilityGood
No further comments

Summary/Decision: Things are looking good! There are a few areas where things could be improved as described above. However, these aren't critical and this package still meets the criteria to be an affiliated package. Keep up the good work!

If you agree with the above review, please feel free to close this issue. If you have any follow-up questions or disagree with any of the comments above, leave a comment and we can discuss it here. At any point in future you can request a re-review of the package if you believe any of the scores should be updated - contact the coordination committee, and we’ll do a new review. Note that we are in the process of redesigning the http://affiliated.astropy.org page to show these scores (but not the comments). Finally, please keep the title of this issue as-is (“Astropy Affiliated Package Review”) to make it easy to search for affiliated package reviews in future.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.