Skip to content

A few minor improvements to scaling and uint support - #3916

Merged
embray merged 8 commits into
astropy:masterfrom
embray:fits/scale-improvements
Jul 7, 2015
Merged

embray merged 8 commits into
astropy:masterfrom
embray:fits/scale-improvements

Conversation

@embray

@embray embray commented Jul 6, 2015

Copy link
Copy Markdown
Member

Just a grab bag of minor improvements from a branch I started but didn't do much else with yet (I think I had planned to do more but better to start fresh).

This improves somewhat on the surprising behavior that a FITS HDU's type changes after accessing the data when scaled data is present. Now, fits.info() gives more info about scaled images ahead of time.

This also enables unsigned integer support by default. The current version of the FITS standard even describes the convention of using BZERO=2**(BITPIX - 1) to represent unsigned ints. Although it is still "merely" a convention there's almost no reason not to assume this was the intent in practice. This hopefully shouldn't break anything existing, but in the odd case that it does the default can be changed via a config flag.

embray added 6 commits July 6, 2015 09:32
…n _ImageBaseHDU. In addition to being non-pep-8, they are not very meaningfully named, and apply more broadly than to just image HDUs (though in fairness they apply *mostly* to image HDUs).
…e HDU summaries for scaled images to better indicate that the data will be rescaled upon access. The behavior here is still somewhat cryptic, but at least there's better indication that *something* will happen--users can then consult the documentation for more information.
… anymore but by deprecating it we can later remove this.
…fault. This convention is documented in the current version of the FITS standard, and it is fairly unambiguous when it is intended to be used. For the sake of user-friendliness it should be assumed by default.
@embray

embray commented Jul 6, 2015

Copy link
Copy Markdown
Member Author

Incidentally, this also fixes #3766. I'm just going to cherry pick that one change out as a separate fix.

embray added a commit to embray/astropy that referenced this pull request Jul 6, 2015
@embray

embray commented Jul 6, 2015

Copy link
Copy Markdown
Member Author

Need to double check if this merits any documentation changes (including a changelog entry, of course) before merging.

…s, although they should. So I added a note explaining how FITS handles them, including how Astropy now handles them. Added a changelog entry.
@embray

embray commented Jul 6, 2015

Copy link
Copy Markdown
Member Author

Added a note in the docs about unsigned integers, as there really wasn't anything there before.

embray added a commit that referenced this pull request Jul 7, 2015
A few minor improvements to scaling and uint support
@embray
embray merged commit c8b5284 into astropy:master Jul 7, 2015
@embray
embray deleted the fits/scale-improvements branch July 7, 2015 13:40
embray added a commit to embray/astropy that referenced this pull request Jul 7, 2015
embray added a commit to embray/astropy that referenced this pull request Jul 7, 2015
embray added a commit to embray/astropy that referenced this pull request Jul 14, 2015
@mwcraig

mwcraig commented Jul 17, 2015

Copy link
Copy Markdown
Member

@embray -- what is the expected behavior of the BZERO keyword when uint=True?

If uint=False then the BZERO keyword is removed from the header after the data is accessed/scaled. That makes sense because the header is consistent with the state of the data.

With uint=True, the data is uint16, which makes sense, but the header still has BZERO=32768 (assuming BITPIX=16).

If that is the intended behavior, I can add something about it to the docs. If it is not the intended behavior, I can try to fix so that BZERO gets droped.

@embray

embray commented Jul 17, 2015

Copy link
Copy Markdown
Member Author

@mwcraig Thanks for the catch--that sounds like a regression to me.

@mwcraig

mwcraig commented Jul 17, 2015

Copy link
Copy Markdown
Member

@embray -- I see the same behaviour in 1.0.3 if I set update=True, so I don't think this PR introduced the error, it just exposed it because it changed the default.

@embray

embray commented Jul 17, 2015

Copy link
Copy Markdown
Member Author

Okay, so not technically a regression, but definitely not intentional either.

@embray

embray commented Jul 17, 2015

Copy link
Copy Markdown
Member Author

Actually, no, I stand corrected.

@mwcraig

mwcraig commented Jul 17, 2015

Copy link
Copy Markdown
Member

So it is intentional?

@embray

embray commented Jul 17, 2015

Copy link
Copy Markdown
Member Author

Sorry, it is intentional now that I think harder about it. The reason is that there is no native unsigned integer type in FITS. So when you read unsigned int data, although technically it is rescaled, it leaves BZERO in the header because "BITPIX = N" plus "BZERO = 2**(N-1)" is the only way to unambiguously write "the data currently in the .data attribute is unsigned integer data".

The difference with arbitrary BSCALE/BZERO is that the data is being rescaled from some storage values (perhaps detector counts or some other quantized data) to "physical values" via the scaling, and the implication is that unless otherwise requested the data will remain as the physical values (so as to not lose accuracy in case the data is modified in any way).

Unsigned ints on the other hand are a special case since they're using BZERO as a kludge to represent a data type that FITS doesn't already natively support :(

@embray

embray commented Jul 17, 2015

Copy link
Copy Markdown
Member Author

This should go in the docs somewhere, I guess. One day I still want a less confusing way to represent this.... (somewhere else I've mentioned wanting to make a cleaner distinction between the "logical" data (including headers) and the raw data of the FITS serialization....)

@mwcraig

mwcraig commented Jul 17, 2015

Copy link
Copy Markdown
Member

I see - so in the case when uint=False the keywords get removed not because the data have been scaled, per se, but because the data type is unambiguous (BITPIX is either 32 or 64 in that case)?

It seems like that makes the meaning of the data a little ambiguous though...how does one know whether it has already been scaled with BZERO?

It is remarkable that FITS can't represent something simple like this!

@mwcraig

mwcraig commented Jul 17, 2015

Copy link
Copy Markdown
Member

I'll poke through the docs for a place to add it. Is there a recommended way to know whether the data has been scaled?

@embray

embray commented Jul 17, 2015

Copy link
Copy Markdown
Member Author

So with uint=False you're turning off the support for this implicit convention--this is supported because in principle one could use BSCALE=1 and BZERO=32768 with no intention whatsoever for the data to be interpreted as unsigned ints; in practice this is highly unlikely, which is why I changed the default. There is no way with FITS to know, without a doubt, that the uint convention is being used. With uint=False the BZERO keyword is removed after scaling because the data is just assumed to be rescaled to floats, just as in the general case. (In both cases the reason the keywords are removed is so that what's in the .header is in sync with what's actually in the .data.)

Part of the point of this PR is that fits.info() tries to tell a little more about what's going on with data rescaling. It's still probably imperfect though. Beyond that, this is part of the intention behind the hypothetical FITSData container I've mused about before. This would be an array-like object used for FITS arrays that would include the book-keeping about things like this.

@mwcraig

mwcraig commented Jul 17, 2015

Copy link
Copy Markdown
Member

Makes sense -- so if, in a test, I want to check that data has been scaled, I could do something like ('BZERO' not in header) or (data.dtype is np.dtype(np.uint16)) ?

@embray

embray commented Jul 20, 2015

Copy link
Copy Markdown
Member Author

Of course, that would only work if you knew the data had to be rescaled in the first place. If it didn't then that test (at least when applied to floats) would result in a false-positive.

Maybe something we could do for now, until there's a better solution, is to publicly expose some of the the _ImageBaseHDU class's external bookkeeping w.r.t. scaling. Will have to think about that. I think it could help.

embray added a commit to embray/astropy that referenced this pull request Jul 20, 2015
dhomeier pushed a commit to dhomeier/astropy that referenced this pull request Aug 11, 2015
dhomeier pushed a commit to dhomeier/astropy that referenced this pull request Aug 11, 2015
mwcraig added a commit to mwcraig/msumastro that referenced this pull request Mar 14, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants