Repository navigation
Data mismatch when converting FITS random group data to binary table - #3561
Conversation
See astropy/astropy#3561 for why I was going crazy for several hours
|
Interesting--normally that should work fine, though it's not the first time there have been bugs involving random groups data, as the feature is just not as well tested. If I repeat a similar use case, but using a normal binary table as the original file, this works as it should. So it seems somewhere along the way it's byte swapping when it shouldn't be. |
|
I think I see now. This actually doesn't have to do with it being random groups data for once, and has to do with the fact that it uses TDIMn, and that is going down a code path that's resulting in an unnecessary byte swap in this particular case. |
|
Glad to hear you're narrowing it down! To add a related enhancement idea: shouldn't the column constructor be able to figure out the I'm currently figuring these out with this code (which probably has a nicer equivalent in the bowels of pyfits): def fits_format_code_lookup(numpy_dtype, numpy_shape):
""" Return a FITS format code from a given numpy dtype
Parameters
----------
numpy_dtype: a numpy dtype object
Numpy dtype to lookup
numpy_shape: tuple
shape of data array to be converted into a FITS format
Returns
-------
fmt_code: string
FITS format code, e.g. 8A for character string of length 8
fits_dim: string or None
Returns fits dimension for TDIM keyword
Notes
-----
FITS format code Description 8-bit bytes
--------------------------------------------------------------------
L logical (Boolean) 1
X bit *
B Unsigned byte 1
I 16-bit integer 2
J 32-bit integer 4
K 64-bit integer 4
A character 1
E single precision floating point 4
D double precision floating point 8
C single precision complex 8
M double precision complex 16
P array descriptor 8
Q array descriptor 16
"""
np_type = numpy_dtype.type
# Get length of array last axis
fmt_len = 1
if len(numpy_shape) > 1:
for ii in numpy_shape[1:]:
fmt_len *= ii
#fmt_len = numpy_shape[-1]
else:
fmt_len = 1
if np_type is np.string_ or "string" in str(np_type):
fits_dim = None
if numpy_dtype.itemsize == 1:
fits_fmt = "A"
else:
fits_fmt = '%iA' % numpy_dtype.itemsize
return fits_fmt, fits_dim
else:
#TODO: handle special case of uint16,32,64, requires BZERO / scale
dtype_dict = {
np.uint8: 'B',
np.uint16: 'J', # No native FITS equivalent
np.uint32: 'K',
np.uint64: 'K',
np.int8: 'I', # No native FITS equivalent
np.int16: 'I',
np.int32: 'J',
np.int64: 'K',
np.float16: 'E', # No native FITS equivalent
np.float32: 'E',
np.float64: 'D',
np.complex64: 'C',
np.complex128: 'M',
np.bool_: 'L'
}
fmt_code = dtype_dict.get(np_type)
if fmt_len > 1:
fmt_code = "%i%s" % (fmt_len, fmt_code)
if len(numpy_shape) == 1:
fits_dim = None
else:
#NOTE: Needs to be flipped to be FORTRAN order
# From FITS spec: The value field of this indexed keyword shall contain a
# character string describing how to interpret the contents of field n as
# a multi-dimensional array with a format of “(l, m, n ...)” where l, m, n, ...
# are the dimensions of the array. The data are ordered such that the array index
# of the first dimension given (l) is the most rapidly varying and that of the last
# dimension given is the least rapidly varying.
fits_dim = str(numpy_shape[1:][::-1])
return fmt_code, fits_dimProbably not the most concise, but if you agree that being able to deduce |
|
For the most part it does do this internally. You can, for example, eschew the The old |
|
Relatedly, see #3552 |
|
Ah, thanks for pointing me toward the structured array route; I suspected that I was probably reinventing the wheel when I wrote it. |
|
It's a shame that isn't better documented--that much should be fixed,. |
…special case for string types where the string lengths don't match up (i.e. we are cramming a 2x2 array of 2 character strings into a single 8 character string). It shouldn't apply to numeric types, and the 'view' here also just screws up byteorder
… summarize for the changelog =_=
|
Fix for the underlying bug reported in this issue attached (the existing workaround should still be considered preferable to the original use case in the first place though). |
Data mismatch when converting FITS random group data to binary table
… summarize for the changelog =_=
Data mismatch when converting FITS random group data to binary table
Hi -- was trying to convert a FITS random group into a binary table, and I went a bit crazy because the data in wasn't the same as the data out.
Here's a script that will reproduce what I was seeing (it will wget a small file from the fits registry):
The print outputs are:
It seems to be related with endianess, as if I change the line to say
d_in = a[0].data["DATA"].astype('<f4')everything is dandy.
I would have thought that this kind of thing should be handled transparently?
PS: I'm running Python 2.7.6 on Mac yosemite, with astropy 1.0, numpy 1.9.2.