Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve show(); reorganize files #38

Merged
merged 5 commits into from
May 31, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
v0.7.0 (unreleased)
===================

## New Features
## New Features & Improvements

- Read and write variable length columns in binary tables.
- New function `FITSIO.libcfitsio_version()` (unexported) returns CFITSIO
library version.
- Improved `show` methods give more and better information
for `FITS` and `HDU` types.
- Write name and version of HDU when creating a new HDU with `hduname` and
`hduver` keywords.

## Deprecations

Expand Down
13 changes: 7 additions & 6 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ File operations
- ``endof(f::FITS)`` Same as length.
- ``f[i]`` Return the ``i``-th HDU.
- ``f[name]`` or ``f[name, ver]`` Return the HDU containing the
given the given HDUNAME (EXTNAME) keyword (an ASCIIString), and
optionally the given HDUVER (EXTVER) number (an Integer).
given the given EXTNAME (or HDUNAME) keyword (an ASCIIString), and
optionally the given EXTVER (or HDUVER) number (an Integer).

.. function:: close(f::FITS)

Expand Down Expand Up @@ -67,7 +67,7 @@ Header operations
Image operations
----------------

.. function:: write(f::FITS, data::Array; header=nothing)
.. function:: write(f::FITS, data::Array; header=nothing, name=nothing, ver=nothing)

Add a new ImageHDU to the file. The following array element types
are supported: ``UInt8``, ``Int8``, ``UInt16``, ``Int16``,
Expand Down Expand Up @@ -121,7 +121,7 @@ Image operations
Table Operations
----------------

.. function:: write(f::FITS, data::Dict; hdutype=TableHDU, extname=nothing, header=nothing, units=nothing, varcols=nothing)
.. function:: write(f::FITS, data::Dict; hdutype=TableHDU, name=nothing, ver=nothing, header=nothing, units=nothing, varcols=nothing)

Create a new table extension and write data to it. If the FITS file
is currently empty then a dummy primary array will be created
Expand All @@ -137,7 +137,8 @@ Table Operations

- ``hdutype``: Type of table extension to create. Can be either
``TableHDU`` (binary table) or ``ASCIITableHDU`` (ASCII table).
- ``extname``: Name of extension.
- ``name``: Name of extension.
- ``ver``: Version of extension (Int).
- ``header``: FITSHeader instance to write to new extension.
- ``units``: Dictionary mapping column name to units (as a string).
- ``varcols``: An array giving the column names or column indicies to
Expand All @@ -157,7 +158,7 @@ Table Operations
potentially non-uniform element types (which would not be
writable as a FITS table column).

.. function:: write(f::FITS, colnames, coldata; hdutype=TableHDU, extname=nothing, header=nothing, units=nothing, varcols=nothing)
.. function:: write(f::FITS, colnames, coldata; hdutype=TableHDU, name=nothing, ver=nothing, header=nothing, units=nothing, varcols=nothing)

Same as ``write(f::FITS, data::Dict; ...)`` but providing column
names and column data as a separate arrays. This is useful for
Expand Down
113 changes: 109 additions & 4 deletions src/FITSIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,116 @@ export FITS,
set_comment!,
copy_section

import Base: getindex, setindex!, length, show, read, write, close, ndims,
size, endof, haskey, keys, values
import Base: getindex,
setindex!,
length,
show,
read,
write,
close,
ndims,
size,
endof,
haskey,
keys,
values

# Libcfitsio submodule
include("libcfitsio.jl")

using .Libcfitsio

# There are a few direct `ccall`s to libcfitsio in this module. For this, we
# need a few non-exported things from Libcfitsio: the shared library handle,
# and a helper function for raising errors. TYPE_FROM_BITPIX is awkwardly
# defined in Libcfitsio, even though it is not used there.
import .Libcfitsio: libcfitsio,
fits_assert_ok,
TYPE_FROM_BITPIX

# HDU Types
abstract HDU

type ImageHDU <: HDU
fitsfile::FITSFile
ext::Int
end

type TableHDU <: HDU
fitsfile::FITSFile
ext::Int
end

type ASCIITableHDU <: HDU
fitsfile::FITSFile
ext::Int
end

# FITS
#
# The FITS type represents a FITS file. It holds a reference to a
# FITSFile object (basically the low-level CFITSIO pointer). It also
# holds a reference to all of the previously accessed HDU
# objects. This is so that only a single HDU object is created for
# each extension in the file. It also allows a FITS object to tell
# previously created HDUs about events that happen to the file, such
# as deleting extensions. This could be done by, e.g., setting ext=-1
# in the HDU object.
type FITS
fitsfile::FITSFile
filename::String
mode::String
hdus::Dict{Int, HDU}

function FITS(filename::String, mode::String="r")
f = (mode == "r" ? fits_open_file(filename, 0) :
mode == "r+" && isfile(filename)? fits_open_file(filename, 1) :
mode == "r+" ? fits_create_file(filename) :
mode == "w" ? fits_create_file("!"*filename):
error("invalid open mode: $mode"))

new(f, filename, mode, Dict{Int, HDU}())
end
end

# FITSHeader
#
# An in-memory representation of the header of an HDU. It stores the
# (key, value, comment) information for each card in a header. We
# could almost just use an OrderedDict for this, but we need to store
# comments.
type FITSHeader
keys::Vector{ASCIIString}
values::Vector{Any}
comments::Vector{ASCIIString}
map::Dict{ASCIIString, Int}

function FITSHeader(keys::Vector{ASCIIString}, values::Vector,
comments::Vector{ASCIIString})
if ((length(keys) != length(values)) ||
(length(keys) != length(comments)))
error("keys, values, comments must be same length")
end
map = [keys[i]=>i for i=1:length(keys)]
new(keys, convert(Vector{Any}, values), comments, map)
end
end

include("fits.jl") # FITS methods
include("header.jl") # FITSHeader methods
include("image.jl") # ImageHDU methods
include("table.jl") # TableHDU & ASCIITableHDU methods

function libcfitsio_version()
# fits_get_version returns a float. e.g., 3.341f0. We parse that
# into a proper version number. E.g., 3.341 -> v"3.34.1"
v = convert(Int, round(1000 * fits_get_version()))
x = div(v, 1000)
y = div(rem(v, 1000), 10)
z = rem(v, 10)
VersionNumber(x, y, z)
end

include("cfitsio.jl") # Libcfitsio submodule
include("hdutypes.jl")
include("deprecations.jl")

end # module
121 changes: 121 additions & 0 deletions src/fits.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# FITS methods

const VERBOSE_MODE = @compat Dict("r"=>"read-only",
"w"=>"read-write",
"r+"=>"append")

# helper function for show()
function show_ascii_table(io, names, cols, spaces=2, indent=0)
ncols = length(cols)
ncols >= 1 || error("No columns")
nrows = length(cols[1])
length(names) == ncols || error("length of cols and names must match")
for i=1:ncols
length(cols[i]) == nrows || error("column length mismatch")
end

lengths = [max(maximum(length, cols[i]), length(names[i])) + spaces
for i=1:ncols]
for i = 1:ncols
print(io, rpad(names[i], lengths[i]))
end
print(io, "\n")
for j = 1:nrows
print(io, " "^indent)
for i=1:ncols
print(io, rpad(cols[i][j], lengths[i]))
end
print(io, "\n")
end
end

function length(f::FITS)
fits_assert_open(f.fitsfile)
@compat Int(fits_get_num_hdus(f.fitsfile))
end

endof(f::FITS) = length(f)

function show(io::IO, f::FITS)
fits_assert_open(f.fitsfile)

# Get name and type of all HDUs.
nhdu = length(f)
names = Array(ASCIIString, nhdu)
vers = Array(ASCIIString, nhdu)
types = Array(ASCIIString, nhdu)
for i = 1:nhdu
t = fits_movabs_hdu(f.fitsfile, i)
types[i] = (t == :image_hdu ? "Image" :
t == :binary_table ? "Table" :
t == :ascii_table ? "ASCIITable" :
error("unknown HDU type"))
nname = fits_try_read_extname(f.fitsfile)
names[i] = get(nname, "")
nver = fits_try_read_extver(f.fitsfile)
vers[i] = isnull(nver) ? "" : string(get(nver))
end

nums = [string(i) for i=1:nhdu]

# only display version info if present
if maximum(length, vers) > 0
dispnames = ["Num", "Name", "Ver", "Type"]
dispcols = Vector{ASCIIString}[nums, names, vers, types]
else
dispnames = ["Num", "Name", "Type"]
dispcols = Vector{ASCIIString}[nums, names, types]
end

print(io, """File: $(f.filename)
Mode: $(repr(f.mode)) ($(VERBOSE_MODE[f.mode]))
HDUs: """)
show_ascii_table(io, dispnames, dispcols, 2, 6)
end

# Returns HDU object based on extension number
function getindex(f::FITS, i::Integer)
fits_assert_open(f.fitsfile)

if haskey(f.hdus, i)
return f.hdus[i]
end

if i > length(f)
error("index out of bounds")
end
hdutype = fits_movabs_hdu(f.fitsfile, i)
f.hdus[i] = (hdutype == :image_hdu ? ImageHDU(f.fitsfile, i) :
hdutype == :binary_table ? TableHDU(f.fitsfile, i) :
hdutype == :ascii_table ? ASCIITableHDU(f.fitsfile, i) :
error("bad HDU type"))
return f.hdus[i]
end

# Returns HDU based on hduname, version
function getindex(f::FITS, name::String, ver::Int=0)
fits_assert_open(f.fitsfile)
fits_movnam_hdu(f.fitsfile, name, ver)
i = fits_get_hdu_num(f.fitsfile)

if haskey(f.hdus, i)
return f.hdus[i]
end

hdutype = fits_get_hdu_type(f.fitsfile)
f.hdus[i] = (hdutype == :image_hdu ? ImageHDU(f.fitsfile, i) :
hdutype == :binary_table ? TableHDU(f.fitsfile, i) :
hdutype == :ascii_table ? ASCIITableHDU(f.fitsfile, i) :
error("bad HDU type"))
return f.hdus[i]
end


function close(f::FITS)
fits_assert_open(f.fitsfile)
fits_close_file(f.fitsfile)
f.filename = ""
f.mode = ""
empty!(f.hdus)
nothing
end
Loading