-
-
Notifications
You must be signed in to change notification settings - Fork 18
Generalized WCS #10
base: master
Are you sure you want to change the base?
Generalized WCS #10
Conversation
|
Thanks. I'll also ask @dsberry to take a look. |
|
@timj Yes, please. I couldn't find his github tag. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would choose a different name for this method or describe it more completely; I'm not entirely clear what scan is supposed to do. Maybe create_mask?
Should the returned mask be a boolean array, or is it, e.g., an array with 0's and, say, 5's?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name is influenced by the algorithm I used which scans the region line by line to find the pixels included. But you are right, it may not be a good name in the context of WCS.
The returned mask is a byte array with region labels and 0's for pixels which are not in any region. The region labels may be int or str.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, that makes some sense. What is the input mask? Is it like the example below (line 107)? That one seems like it should be the output of scan.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, line 107 is the output mask. The scan method is used by the create_regions_mask function which takes the shape of the science data array and the JSON file with regions definitions. It creates the byte array with 0's initially and for each region uses its scan method to find which science array pixels it contains and sets those values in the mask to the region's label.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I think I get it:
R = Region(3, coordsys)
assert R.__contains__(1,1) # just to show that 1,1 is in the region, nothing else is...
mask = [[0,0,0],[0,0,0],[0,0,0]]
newmask = R.scan(mask)
newmask
[[0,0,0],[0,3,0],[0,0,0]]
So if, say, I wanted a mask that selects all pixels in a given region, I'd do:
region3_mask = (R.scan(blank_mask)==3)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the input mask modified and returned?
Or is the returned mask a new mask or copy of the input mask and only the shape of the input mask is relevant?
Shouldn't the mask have a world coordinate system attached?
Or is the region defined in pixel coordinates?
I think this is the equivalent of the region.get_mask method in pyregion?
mask = region.get_mask(shape=(300,300))
Since it's part of the API, +1 to a more explicit name for this method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that's it. And the create_mask function loops over all regions.
Once the mask is created (which is a one time operation) to get the indexes of all pixels from region 3:
mask==3
scan is a relatively expensive operation but it's done once.
A prototype implementation is here:
https://github.com/nden/code-experiments/blob/master/generalized_wcs_api/prototype/region.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cdeil The input mask is created in create_regions_mask which then loops over all regions. The individual region's scan method modifies the mask (no copy).The region has coordinate system attached to it. All regions in a mask should have the same coordinate system. The coordinate system is not limited to cartesian.
|
On a quick look, I have no strong objections except that I don't really understand what In terms of how specutils is using these, I think we want the "x axis" (called "dispersion","wavelength","frequency", etc) to have a In terms of initializing (minor: s/standart/standard/) |
|
Also, I'm pretty excited to see the region API & definitions. I think a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are rest_freq and rest_wave independent values? Or alternative views of the same thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point; I think there should just be one defined and the other should be a property. Also, consider renaming to reference_frequency or reference_wavelength - a reference is required for transformation to z or velocity, but a rest frequency isn't required for the frame definition. At least, that's how I've interpreted the use of these terms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rest Frequency is common usage. It's the FITS terminology as well. I think it would be confusing to use a different term for this than the commonly accepted name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, fair enough. In GBTIDL, at least, I've seen both being used - rest frequency referring to the vacuum frequency of the targeted line, reference frequency referring to where the spectrograph had been tuned and therefore where the default zero-velocity point will be. But since that's the FITS convention (RESTFRQ, right?), we should stick with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok , I'll make rest_frequency an attribute and rest_wavelength a property. But I think it should be an attribute and not a parameter to a transform_to_some_other_coord_system() function because the class is also meant to be an info container
|
Can you state somewhere at the top how this relates to the existing |
|
The "generalized WCS" has been discussed a lot but I don't think there's a decision about that. It may be too early to decide this. As for the relation with |
|
There's a couple of (relatively big) ideas muddled together in this PR and I suggest we discuss them separately in separate PRs:
|
|
@wkerzendorf - I disagree that Since |
|
@keflavich The API we're building is in its essence a transform between pixel and world coordinates (for the lack of a better name) and vice versa. FITS is not a language for transformation, but a storage format for data. In the case of WCS there are certain conventions how to encode certain transformations in FITS header keywords. But, you can store any transformation you like in FITS header keywords - but would need to invent your own convention. So my suggestion is to separate storage on disk and transformation. IMHO we should be implementing some of the transformation and then programming functions/methods to store these into different formats including fits. For example (as you suggested on class LinearWCS(Poly1DModel):
@classmethod
def from_fits_header(cls, fits_header):
return cls(fits_header['crval1'], fits_header['cdelt1'])
@classmethod
def from_mycustom_format(cls, fname):
offset, slope = map(float, file(fname).read().strip().split(','))
return cls(offset, slope)
def __init__(offset, slope):
self.degree = 1
self.c_0 = offset
self.c_1 = slope
def to_fits(self, fits_header):
fits_header['crval1'] = self.offset
fits_header['cdelt1'] = self.slopeIn this case you can see if you can write to fits by seeing if there's a |
|
@wkerzendorf - I think the point about FITSWCS is that various people have been referring to the current WCS standard as FITS-WCS (see e.g. Astropy paper). I think @mdboom and @perrygreenfield have been using the term for a while. However, it doesn't mean we can't find a better name. |
|
@wkerzendorf This is exactly how AST functions - it has its own rich model for representing WCS (a "FrameSet"), and also has a separate set of "Channel" classes for exporting and importing that model in various external formats. For instance, the FitsChan class can import a set of FITSWCS headers to create an AST FrameSet, and can - sometimes - export a FrameSet to create a set of FITSWCS headers. But because AST has a much richer collection of transformations than FITSWCS allows, this export operation will fail if there is no equivalent FITSWCS construct. In this case a flag is returned by the FitsChan export method indicating that the conversion was not possible. As an alternative, the FitsChan class can be told to use a set of non-standard FITS keywords that can represent any AST FrameSet. Plus there are other channel classes that convert to and from things like STC-S, etc. It all depends on whether you want to lock yourself into the limitations imposed by the FITS-WCS standard. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you also need something to indicate how the time is represented - is it an MJD, a Julian Epoch, A Besselian epoch, or what?
|
@nden - a quick question before digging too deeply: how do you envision this relating to |
|
This might sound a bit crazy, but we could consider renaming |
|
On 2 July 2013 22:37, Thomas Robitaille notifications@github.com wrote:
One thing I wished we done in AST at an early stage, but which it is now This would have made it easier to provide (for example) a class to describe David |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like one is missing, as there are only three below? Should there be one for arbitrary Frames which are neither time, spectral, or spatial?
|
@nden - sorry for the late comments! I think it would be worth trying to implement any revisions before the coordination meeting next week since I think this is one of the most important things to focus on post-0.3. Thanks for working on this! :) |
|
@nden - I meant to say, this API is looking very promising to me! I think we should actually start implementing some of the code to have some examples to play around with (maybe you have already, behind the scenes?). |
|
I think it would be nice to see more examples of using the WCS - for instance, given a WCS that maps from Equatorial to pixel coordinates, can I easily get a WCS that maps from Galactic to pixel coordinates? |
|
One request I have - it would be nice to be able to define 'Transform' objects similarly to Matplotlib in the sense that they can be easily combined. For instance, if I have a transformation from FK4 to FK5, I could do soemthing like: where EDIT - maybe this isn't necessary if one can simply call the WCS object with any coordinate object, and the WCS figures out how to get it into pixel coordinates? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment here that also applies anywhere this sort of thing is used: these sort of all-caps abbreviations I think are a bad idea. I know historically they come from situations where bytes were more precious, but here we can make a break with the past and instead use something more readable. So for example, spectral_ref_frame might instead be: ['wavelength', 'frequency', 'energy', 'wave number', 'air wavelength', 'radio velocity', 'optical velocity', 'optical z', 'relativistic v', 'relativistic beta']. (If these are actually needed to be attributes in some cases, replace the spaces with underscores)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These came from WCS Paper III. While I'm not opposed to changing them we have to consider that they are in common use now and will have to support them in some way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I agree we have to accept them as FITS/WCS header keywords, but we do not have to actually encourage their use in code. In fact, I want to make every effort to discouraging it - this isn't fortran, so we're not limited to 72 characters any more 😉
This reflects me general attitude that we are not aiming to reproduce WCS, but rather make a better and more pythonic take on WCS.
This PR is a proposal for a WCS data object.
Please take a look and comment on it. It would be very useful to get feedback about the proposed functionality in view of different instrumentation/use cases.
I am adding a few people who might be interested in case they are not watching this repository. I'm sure I'll miss many.