Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4d1c5a0
modified images to ccds and minor changes in tests
siddharthlal25 Aug 6, 2020
2870b0c
added filename generating functions and tests
siddharthlal25 Aug 6, 2020
19351d9
added `write_data` and tests
siddharthlal25 Aug 6, 2020
7c52f82
minor fix in `ccds`
siddharthlal25 Aug 6, 2020
436c58e
added more documentation
siddharthlal25 Aug 6, 2020
80aca63
added saving version of `ccds` and minor modifications
siddharthlal25 Aug 9, 2020
246dc16
added tests for saving `ccds` and `write_data`
siddharthlal25 Aug 9, 2020
9451ad2
remove files generated during testing
siddharthlal25 Aug 9, 2020
ef44964
added saving version of `filenames`
siddharthlal25 Aug 9, 2020
73f72c8
added tests for saving version of `filenames`
siddharthlal25 Aug 9, 2020
76664d4
added saving version of `arrays`
siddharthlal25 Aug 9, 2020
b6964d9
added tests for saving version of `arrays`
siddharthlal25 Aug 9, 2020
b807465
fixed documentation
siddharthlal25 Aug 9, 2020
3016deb
renamed write_data to writefits
siddharthlal25 Aug 10, 2020
a63b3ff
modified default value of save keyword
siddharthlal25 Aug 11, 2020
3f933cd
modified docs and changed variable names
siddharthlal25 Aug 11, 2020
32644f2
some doc fix and minor indentation fix
siddharthlal25 Aug 17, 2020
98aa01e
modify save functionality to accomodate path = nothing
siddharthlal25 Aug 19, 2020
31859f7
Update src/collection.jl
siddharthlal25 Aug 19, 2020
e4088e0
doc fix
siddharthlal25 Aug 19, 2020
fe5c750
doc fix and added hdr, data in exported list
siddharthlal25 Aug 24, 2020
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
2 changes: 1 addition & 1 deletion src/CCDReduction.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export subtract_bias,
fitscollection,
arrays,
filenames,
images,
ccds,
CCDData

include("ccddata.jl")
Expand Down
281 changes: 264 additions & 17 deletions src/collection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,67 @@ end

parse_name(filename, ext, ::Val{true}) = filename

# utility function for generating filename
function generate_filename(path, save_location, save_prefix, save_suffix, save_delim, ext)
# get the filename
filename = basename(path)

# splitting name and extension
modified_name, extension = parse_name_ext(filename, "." * ext)

# adding prefix and suffix with delimiter
if !isnothing(save_prefix)
modified_name = string(save_prefix, save_delim, modified_name)
end
if !isnothing(save_suffix)
modified_name = string(modified_name, save_delim, save_suffix)
end

# adding extension to modified_name
file_path = joinpath(save_location, modified_name * extension)
return file_path
end


# utility function to return filename and extension separately
# returns extension including "." at the beginning
function parse_name_ext(filename, ext)
idxs = findall(ext, filename)
length(idxs) == 0 && return (filename, "")
breaking_index = first(last(idxs))
return filename[1:breaking_index - 1], filename[breaking_index:end]
end


"""
writefits(file_path, data; header = nothing)
writefits(file_path, ccd::CCDData)

Writes `data`/`ccd` in FITS format at `file_path`.

`FITSIO` takes over memory write in by `cfitsio`, which writes in row-major form, whereas when Julia gives that memory, it is assumed as column major.
Therefore all data written by [`FITSIO.write`](http://juliaastro.github.io/FITSIO.jl/latest/api.html#Base.write-Tuple{FITS,Dict{String,V}%20where%20V}) is transposed. This function allows the user to write the data in a consistent way to FITS file by transposing before writing.
"""
function writefits(file_path, data; header = nothing)
d = ndims(data)
transposed_data = permutedims(data, d:-1:1)
FITS(file_path, "w") do fh
write(fh, transposed_data; header = header)
end
end

writefits(file_path, ccd::CCDData) = writefits(file_path, ccd.data; header = ccd.hdr)

#---------------------------------------------------------------------------------------
@doc raw"""
fitscollection(dir; recursive=true, abspath=true, keepext=true, ext=r"fits(\.tar\.gz)?", exclude=nothing, exclude_dir=nothing, exclude_key = ("", "HISTORY"))
fitscollection(dir;
recursive=true,
abspath=true,
keepext=true,
ext=r"fits(\.tar\.gz)?",
exclude=nothing,
exclude_dir=nothing,
exclude_key=("", "HISTORY"))

Walk through `dir` collecting FITS files, scanning their headers, and culminating into a `DataFrame` that can be used with the generators for iterating over many files and processing them. If `recursive` is false, no subdirectories will be walked through.

Expand Down Expand Up @@ -60,7 +118,7 @@ function fitscollection(basedir::String;
exclude = nothing,
exclude_dir = nothing,
exclude_key = ("", "HISTORY"))
df = DataFrame()
collection = DataFrame()

for (root, dirs, files) in walkdir(basedir)
# recursive searching functionality
Expand Down Expand Up @@ -88,25 +146,46 @@ function fitscollection(basedir::String;
# filtering out comment columns
_keys = filter(k -> k ∉ exclude_key, keys(header_data))
_values = (header_data[k] for k in _keys)
push!(df, (path = path, name = name, hdu = index, zip(Symbol.(_keys), _values)...); cols = :union)
push!(collection, (path = path, name = name, hdu = index, zip(Symbol.(_keys), _values)...); cols = :union)
end
close(fits_data)
end
end
return df
return collection
end


"""
arrays(df::DataFrame)
arrays(collection)

Generator for arrays of images of entries in data frame.

Iterates over `collection` using each `path` and `hdu` to load data using [`CCDReduction.getdata`](@ref) into an `Array`.

# Examples
```julia
collection = fitscollection("~/data/tekdata")
data = arrays(collection) |> collect
```
This returns all image arrays present in `collection`. This can also be used via a for-loop
```julia
collection = fitscollection("~/data/tekdata")
for arr in arrays(collection)
@assert arr isa Array
println(size(arr))
end

# output
(1048, 1068)
(1048, 1068)
...
```
"""
function arrays end

# generator for image arrays specified by data frames (i.e. path of file, hdu etc.)
@resumable function arrays(df::DataFrame)
for row in eachrow(df)
@resumable function arrays(collection)
for row in eachrow(collection)
fh = FITS(row.path)
@yield getdata(fh[row.hdu])
close(fh)
Expand All @@ -115,30 +194,198 @@ end


"""
filenames(df::DataFrame)
filenames(collection)

Generator for filenames of entries in data frame.

Iterates over `collection` using each `path`.

# Examples
```julia
collection = fitscollection("~/data/tekdata")
for path in filenames(collection)
@assert path isa String
println(path)
end

# output
"~/data/tekdata/tek001.fits"
"~/data/tekdata/tek002.fits"
...
```
"""
function filenames end

# generator for filenames specified by data frame (i.e. path of file, hdu etc.)
@resumable function filenames(df::DataFrame)
for row in eachrow(df)
@resumable function filenames(collection)
for row in eachrow(collection)
@yield row.path
end
end


"""
images(df::DataFrame)
ccds(collection)

Generator for `ImageHDU`s of entries in data frame.
Generator for `CCDData`s of entries in data frame.

Iterates over `collection` using each `path` and `hdu` to load data using [`FITSIO.FITS`](http://juliaastro.github.io/FITSIO.jl/latest/api.html#FITSIO.FITS) into a [`CCDData`](@ref).

# Examples
```julia
collection = fitscollection("~/data/tekdata")
for hdu in ccds(collection)
@assert hdu isa CCDData
end
```
"""
function images end
function ccds end

# generator for ImageHDU specified by data frame (i.e. path of file, hdu etc.)
@resumable function images(df::DataFrame)
for row in eachrow(df)
@yield FITS(row.path)[row.hdu]
# generator for CCDData specified by data frame (i.e. path of file, hdu etc.)
@resumable function ccds(collection)
for row in eachrow(collection)
@yield CCDData(row.path; hdu = row.hdu)
end
end


"""
ccds(f, collection; save = any(!isnothing, (save_prefix, path, save_suffix)), path = nothing, save_prefix = nothing, save_suffix = nothing, save_delim = "_", ext = r"fits(\\.tar\\.gz)?"i, kwargs...)

Iterates over the `CCDData`s of the collection applying function `f` at each step.

It returns an array of output values of function `f` applied on `CCDData`s.
In addition to applying function `f`, the outputs can be saved. If `save = true`, it enables programmatical saving of returned value of the function `f` using [`CCDReduction.writefits`](@ref). File is saved at `path` specified by the user.
Suffix and prefix can be added to filename of newly created files by modifying `save_suffix` and `save_prefix`, `save_delim` is used as delimiter.
`ext` is the extension of files in collection, by default it is set to `r"fits(\\.tar\\.gz)?"i`.

# Example
```julia
collection = fitscollection("~/data/tekdata")
processed_images = map(ccds(collection)) do img
trim(img, (:, 1040:1059))
end
```
The above generates `processed_images` which consists of trimmed versions of images present in `collection`.

For saving the `processed_images` simultaneously with the operations performed
```julia
processed_images = map(ccds(collection; save = true, path = "~/data/tekdata", save_prefix = "trimmed")) do img
trim(img, (:, 1040:1059))
end
```
The trimmed images are saved as `trimmed_(original_name)` (FITS files) at `path = "~/data/tekdata"` as specified by the user.

Mapping version of `ccds` function is interfaced on iterative version of `images`, any valid parameter can be passed into iterative version as `kwargs`.
"""
function ccds(f, collection; save = any(!isnothing, (save_prefix, path, save_suffix)), path = nothing, save_prefix = nothing, save_suffix = nothing, save_delim = "_", ext = r"fits(\.tar\.gz)?"i, kwargs...)
image_iterator = ccds(collection; kwargs...)
locations = collection.path

processed_images = map(zip(locations, image_iterator)) do (location, output)
processed_image = f(output)
if save
save_path = generate_filename(location, path, save_prefix, save_suffix, save_delim, ext)
writefits(save_path, processed_image)
end
processed_image
end

return processed_images
end


"""
filenames(f, collection; save = any(!isnothing, (save_prefix, path, save_suffix)), path = nothing, save_prefix = nothing, save_suffix = nothing, save_delim = "_", ext = r"fits(\\.tar\\.gz)?"i, kwargs...)

Iterates over the file paths of the collection applying function `f` at each step.

It returns an array of output values of function `f` applied on file paths.
In addition to applying function `f`, the outputs can be saved. If `save = true`, it enables programmatical saving of returned value of the function `f` using [`CCDReduction.writefits`](@ref). File is saved at `path` specified by the user.
Suffix and prefix can be added to filename of newly created files by modifying `save_suffix` and `save_prefix`, `save_delim` is used as delimiter.
`ext` is the extension of files in collection, by default it is set to `r"fits(\\.tar\\.gz)?"i`.

# Examples
```julia
collection = fitscollection("~/data/tekdata")
data = map(filenames(collection)) do path
fh = FITS(path)
data = getdata(fh[1]) # assuming all 1-hdu are ImageHDUs
close(fh)
data
end
```
The above generates `data` which consists of image arrays corresponding to 1st hdu of FITS file paths present in `collection`.
For saving the `data` simultaneously with the operations performed
```julia
data = map(filenames(collection; save = true, path = "~/data/tekdata", save_prefix = "retrieved_from_filename")) do img
fh = FITS(path)
data = getdata(fh[1]) # assuming all 1-hdu are ImageHDUs
close(fh)
data
end
```
The retrieved data is saved as `retrieved_from_filename_(original_name)` (FITS files) at `path = "~/data/tekdata"` as specified by the user.

Mapping version of `filenames` function is interfaced on iterative version of `filenames`, any valid parameter can be passed into iterative version as `kwargs`.
"""
function filenames(f, collection; save = any(!isnothing, (save_prefix, path, save_suffix)), path = nothing, save_prefix = nothing, save_suffix = nothing, save_delim = "_", ext = r"fits(\.tar\.gz)?"i, kwargs...)
path_iterator = filenames(collection; kwargs...)
locations = collection.path

processed_images = map(zip(locations, path_iterator)) do (location, output)
processed_image = f(output)
if save
save_path = generate_filename(location, path, save_prefix, save_suffix, save_delim, ext)
writefits(save_path, processed_image)
end
processed_image
end

return processed_images
end


"""
arrays(f, collection; save = any(!isnothing, (save_prefix, path, save_suffix)), path = nothing, save_prefix = nothing, save_suffix = nothing, save_delim = "_", ext = r"fits(\\.tar\\.gz)?"i, kwargs...)

Iterates over the image arrays of the collection applying function `f` at each step.

It returns an array of output values of function `f` applied on image arrays.
In addition to applying function `f`, the outputs can be saved. If `save = true`, it enables programmatical saving of returned value of the function `f` using [`CCDReduction.writefits`](@ref). File is saved at `path` specified by the user.
Suffix and prefix can be added to filename of newly created files by modifying `save_suffix` and `save_prefix`, `save_delim` is used as delimiter.
`ext` is the extension of files in collection, by default it is set to `r"fits(\\.tar\\.gz)?"i`.

# Examples
```julia
collection = fitscollection("~/data/tekdata")
processed_images = map(arrays(collection)) do arr
trim(arr, (:, 1040:1059))
end
```
The above generates `processed_images` which consists of trimmed versions of image arrays present in `collection`.
For saving the `processed_images` simultaneously with the operations performed
```julia
processed_images = map(arrays(collection; save = true, path = "~/data/tekdata", save_prefix = "trimmed")) do img
trim(img, (:, 1040:1059))
end
```
The trimmed image arrays are saved as `trimmed_(original_name)` (FITS files) at `path = "~/data/tekdata"` as specified by the user.

Mapping version of `arrays` function is interfaced on iterative version of `arrays`, any valid parameter can be passed into iterative version as `kwargs`.
"""
function arrays(f, collection; save = any(!isnothing, (save_prefix, path, save_suffix)), path = nothing, save_prefix = nothing, save_suffix = nothing, save_delim = "_", ext = r"fits(\.tar\.gz)?"i, kwargs...)
array_iterator = arrays(collection; kwargs...)
locations = collection.path

processed_images = map(zip(locations, array_iterator)) do (location, output)
processed_image = f(output)
if save
save_path = generate_filename(location, path, save_prefix, save_suffix, save_delim, ext)
writefits(save_path, processed_image)
end
processed_image
end

return processed_images
end
14 changes: 8 additions & 6 deletions src/fits.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# helper functions

#=
FITSIO.jl takes over memory read in by cfitsio, which reads in row-major form,
whereas when Julia takes that memory, it is assumed as column major.
Therefore all data read by `read` is transposed.
Related comment: https://github.com/JuliaAstro/CCDReduction.jl/pull/16#issuecomment-638492572
=#
"""
getdata(::FITSIO.ImageHDU)
Loads image array form `ImageHDU`
FITSIO.jl takes over memory read in by cfitsio, which reads in row-major form, whereas when Julia takes that memory, it is assumed as column major.
Therefore all data read by [`FITSIO.read`](http://juliaastro.github.io/FITSIO.jl/latest/api.html#Base.read-Tuple{ImageHDU}) is transposed. This function allows the user to read data in a consistent way to `Array` by transposing after reading.
"""
function getdata(hdu::ImageHDU)
data = read(hdu)
d = ndims(data)
Expand Down
Loading