38 个版本 (20 个破坏性更新)
0.21.5 | 2024 年 8 月 6 日 |
---|---|
0.21.4 | 2024 年 7 月 27 日 |
0.21.2 | 2023 年 2 月 10 日 |
0.21.1 | 2022 年 12 月 23 日 |
0.1.1 | 2016 年 5 月 31 日 |
#14 in 科学
911 每月下载量
用于 12 个 Crates (10 个直接使用)
11MB
143K SLoC
fitsio
lib.rs
:
fitsio
- 对 C 库 [cfitsio
][cfitsio] 的薄包装。
- 文件访问
- 格式化打印
- HDU 访问
- 创建新的 HDU
- 创建新的图像
- 创建新的表格
- 列描述
- 将 HDU 复制到另一个文件
- 删除 HDU
- 遍历文件中的 HDU
- 一般调用行为
- 头部键
- 读取文件数据
- 读取图像
ndarray
支持- 读取表格
- 读取单元格值
- 读取行
- 遍历列
- 写入文件数据
- 写入图像
- 调整图像大小
- 写入表格
- 写入表格数据
- 插入列
- 删除列
- 原始 FITS 文件访问
- 线程安全访问
此库包装了低级 cfitsio
绑定:[fitsio-sys
][fitsio-sys],并为 Rust 用户提供了更本地的体验。
FITS 文件的主接口是 [FitsFile
][fits-file]。所有文件操作和读取都从这个类开始。
文件访问
要打开现有文件,请使用 [open][fitsfile-open] 方法。
use fitsio::FitsFile;
// let filename = ...;
let fptr = FitsFile::open(filename)?;
或者,可以使用配套方法 [create
][fits-file-create] 在磁盘上创建新文件
use fitsio::FitsFile;
// let filename = ...;
let fptr = FitsFile::create(filename).open()?;
[[code][src-rs]create[fits-file-create]] 方法返回一个 [[code][src-rs]NewFitsFile[新-fits-file]],它是磁盘上临时 FITS 文件的内部表示,在文件完全创建之前。
这种表示方法有两种方法:[open
][new-fits-file-open] 和 [with_custom_primary
][new-fits-file-with-custom-primary]。实际上,[open
][new-fits-file-open] 方法会在磁盘上创建文件,但在调用此方法之前,可以使用 [with_custom_primary
][new-fits-file-with-custom-primary] 方法添加自定义的 primary HDU。这对于图像来说非常有用。否则,会创建一个默认的 primary HDU。上面展示了不添加自定义 primary HDU 的示例。下面我们看到 [with_custom_primary
][new-fits-file-with-custom-primary] 的示例。
use fitsio::FitsFile;
use fitsio::images::{ImageType, ImageDescription};
// let filename = ...;
let description = ImageDescription {
data_type: ImageType::Double,
dimensions: &[52, 103],
};
let fptr = FitsFile::create(filename)
.with_custom_primary(&description)
.open()?;
从这一点开始,可以查询和更改当前 HDU,或者读取 fits 头卡或文件内容。
要以读/写模式打开 fits 文件(以允许更改文件),必须使用 [edit
][fits-file-edit]。这将打开一个已存在于磁盘上的文件以进行编辑。
use fitsio::FitsFile;
// let filename = ...;
let fptr = FitsFile::edit(filename)?;
格式化打印
可以使用 [pretty_print
][pretty-print] 或其更强大的同类 [pretty_write
][pretty-write] 来进行 fits 文件的 pretty-print。
use fitsio::FitsFile;
let mut fptr = FitsFile::open(filename)?;
fptr.pretty_print()?;
// or
fptr.pretty_write(&mut io::stdout())?;
遵循每次发布 fits 库时都发布 fits 摘要程序的传统,这个库包含一个二进制程序 fitssummary
,可以使用 cargo install
安装。它接受命令行上的 fits 文件并打印它们的摘要到 stdout。
$ fitssummary ../testdata/full_example.fits
file: ../testdata/full_example.fits
mode: READONLY
extnum hdutype hduname details
0 IMAGE_HDU dimensions: [100, 100], type: Long
1 BINARY_TBL TESTEXT num_cols: 4, num_rows: 50
HDU 访问
HDU 信息属于 [FitsHdu
][fits-hdu] 对象。可以通过 String
/str
或整数(0 索引)使用 [hdu
][fitsfile-hdu] 方法获取 HDU。《HduInfo》对象包含有关当前 HDU 的信息。
#
use fitsio::hdu::HduInfo;
let hdu = fptr.hdu(0)?;
// image HDU
if let HduInfo::ImageInfo { shape, .. } = hdu.info {
println!("Image is {}-dimensional", shape.len());
println!("Found image with shape {:?}", shape);
}
// tables
if let HduInfo::TableInfo { column_descriptions, num_rows, .. } = hdu.info {
println!("Table contains {} rows", num_rows);
println!("Table has {} columns", column_descriptions.len());
}
始终可以使用 FitsFile::primary_hdu
方法访问主 HDU。
创建新的 HDU
创建新的图像
使用 [create_image
][fits-file-create-image] 方法创建新的 fits 图像。此方法需要扩展名和一个 [ImageDescription
][image-description] 对象,该对象定义所需图像的形状和类型。
use fitsio::images::{ImageDescription, ImageType};
let image_description = ImageDescription {
data_type: ImageType::Float,
dimensions: &[100, 100],
};
let hdu = fptr.create_image("EXTNAME".to_string(), &image_description)?;
与 cfitsio 不同,new_size
的维度顺序遵循 C 规范,即 行主序。
创建新的表格
与创建新图像类似,使用 [create_table
][fits-file-create-table] 方法创建新表。这需要扩展名和 [ColumnDescription
][column-description]s 的切片。
use fitsio::tables::{ColumnDescription, ColumnDataType};
let first_description = ColumnDescription::new("A")
.with_type(ColumnDataType::Int)
.create()?;
let second_description = ColumnDescription::new("B")
.with_type(ColumnDataType::Long)
.create()?;
let descriptions = [first_description, second_description];
let hdu = fptr.create_table("EXTNAME".to_string(), &descriptions)?;
列描述
列使用 [ColumnDescription
][column-description] 结构描述。这封装了:列的名称和数据格式。
fits 规范允许标量或向量列,数据格式由 [ColumnDataDescription
][column-data-description] 结构描述,该结构又封装了每行元素的数量(通常是 1)、列的宽度(对于字符串)和数据类型,数据类型是 [ColumnDataType
][column-data-type] 成员之一。
对于标量列的常见情况,可以使用 scalar
方法构造 ColumnDataDescription
对象。
use fitsio::tables::{ColumnDescription, ColumnDataDescription, ColumnDataType};
let desc = ColumnDataDescription::scalar(ColumnDataType::Int);
assert_eq!(desc.repeat, 1);
assert_eq!(desc.width, 1);
可以使用 vector
方法构造向量列。
use fitsio::tables::{ColumnDataDescription, ColumnDescription, ColumnDataType};
let desc = ColumnDataDescription::vector(ColumnDataType::Int, 100);
assert_eq!(desc.repeat, 100);
assert_eq!(desc.width, 1);
这些实现 From<...> for String
,以便获得传统的 fits 列描述字符串。
use fitsio::tables::{ColumnDataDescription, ColumnDescription, ColumnDataType};
let desc = ColumnDataDescription::scalar(ColumnDataType::Int);
assert_eq!(String::from(desc), "1J".to_string());
将 HDU 复制到另一个文件
可以使用 [copy_to
][fits-hdu-copy-to] 方法将 HDU 复制到另一个打开的文件。这需要一个打开的 [FitsFile
][fits-file] 对象来复制到。
#
#
hdu.copy_to(&mut src_fptr, &mut dest_fptr)?;
删除 HDU
当前HDU可以使用[delete
][fits-hdu-delete]方法进行删除。注意:此方法会接管self
的所有权,因此在此调用之后,[FitsHdu][fits-hdu]对象将无法使用。
// let fptr = FitsFile::open(...)?;
// let hdu = fptr.hdu(0)?;
hdu.delete(&mut fptr)?;
// Cannot use hdu after this
遍历文件中的 HDU
[iter][fits-hdu-iter]方法允许遍历fits文件的HDU。
for hdu in fptr.iter() {
// Do something with hdu
}
一般调用行为
后续的所有数据访问都通过[FitsHdu][fits-hdu]对象进行。大多数方法将当前打开的[
FitsFile][fits-file]作为第一个参数。
头部键
通过[read_key][fits-hdu-read-key]函数读取头键,对实现[
ReadsKey][reads-key]特质的类型是通用的。
let int_value: i64 = fptr.hdu(0)?.read_key(&mut fptr, "INTTEST")?;
// Alternatively
let int_value = fptr.hdu(0)?.read_key::<i64>(&mut fptr, "INTTEST")?;
// Or let the compiler infer the types (if possible)
HeaderValue
也实现了[ReadsKey][reads-key]特质,并允许读取注释
let int_value_with_comment: HeaderValue<i64> = fptr.hdu(0)?.read_key(&mut fptr, "INTTEST")?;
let HeaderValue { value, comment } = int_value_with_comment;
可以通过方法[write_key][fits-hdu-write-key]写入头卡。它接受键名和值,或键名和值-注释元组。有关支持的数据类型,请参阅[
WritesKey][writes-key]特质。
fptr.hdu(0)?.write_key(&mut fptr, "foo", 1i64)?;
assert_eq!(fptr.hdu(0)?.read_key::<i64>(&mut fptr, "foo")?, 1i64);
// with comments
fptr.hdu(0)?.write_key(&mut fptr, "bar", (1i64, "bar comment"))?;
let HeaderValue { value, comment } = fptr.hdu(0)?.read_key::<HeaderValue<i64>>(&mut fptr, "bar")?;
assert_eq!(value, 1i64);
assert_eq!(comment, Some("bar comment".to_string()));
读取文件数据
接受范围的方法不包括上限值,这反映了Rust范围类型的本质。
读取图像
可以通过[read_section][fits-hdu-read-section]或[
read_region][fits-hdu-read-region]读取图像数据,前者读取从起始索引到结束索引之间的连续像素,后者从图像中读取矩形块。
// Read the first 100 pixels
let first_row: Vec<i32> = hdu.read_section(&mut fptr, 0, 100)?;
// Read a square section of the image
let xcoord = 0..10;
let ycoord = 0..10;
let chunk: Vec<i32> = hdu.read_region(&mut fptr, &[&ycoord, &xcoord])?;
与cfitsio不同,区域范围的顺序遵循C约定,即行主序。
提供了一些方便的方法来读取图像的行。这通常是有用的,因为它是一种高效的访问方法
let start_row = 0;
let num_rows = 10;
let first_few_rows: Vec<f32> = hdu.read_rows(&mut fptr, start_row, num_rows)?;
// 10 rows of 100 columns
assert_eq!(first_few_rows.len(), 1000);
也可以将整个图像读入内存
let image_data: Vec<f32> = hdu.read_image(&mut fptr, )?;
// 100 rows of 100 columns
assert_eq!(image_data.len(), 10_000);
[ndarray][ndarray]支持
当fitsio
使用array
功能编译时,图像可以读入[ndarray::ArrayD
][arrayd]类型
use fitsio::FitsFile;
use ndarray::ArrayD;
let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
let hdu = f.primary_hdu().unwrap();
let data: ArrayD<u32> = hdu.read_image(&mut f).unwrap();
let dim = data.dim();
assert_eq!(dim[0], 100);
assert_eq!(dim[1], 100);
assert_eq!(data[[20, 5]], 152);
#
有关更多详细信息,请参阅ndarray_compat
文档(仅当编译了array
功能时可用)。
读取表格
可以使用[read_col][fits-hdu-read-col]函数读取列,该函数可以即时转换数据类型。有关支持的数据类型,请参阅[
ReadsCol][reads-col]特质。
let integer_data: Vec<i32> = hdu.and_then(|hdu| hdu.read_col(&mut fptr, "intcol"))?;
读取单元格值
可以从FITS表中读取单个单元格值
let result: i64 = tbl_hdu.read_cell_value(&mut f, "intcol", 4)?;
assert_eq!(result, 16);
let result: String = tbl_hdu.read_cell_value(&mut f, "strcol", 4)?;
assert_eq!(result, "value4".to_string());
读取行
可以使用[row][fits-hdu-row]方法从FITS表中读取单行。这需要使用[
fitsio-derive][fitsio-derive] crate。
use fitsio::tables::FitsRow;
use fitsio_derive::FitsRow;
#[derive(Default, FitsRow)]
struct Row {
#[fitsio(colname = "intcol")]
intfoo: i32,
#[fitsio(colname = "strcol")]
foobar: String,
}
#
// Pick the 4th row
let row: Row = hdu.row(&mut f, 4)?;
assert_eq!(row.intfoo, 16);
assert_eq!(row.foobar, "value4");
遍历列
使用[columns][fits-hdu-columns]迭代列。
for column in hdu.columns(&mut fptr) {
// Do something with column
}
写入文件数据
接受范围的方法不包括上限值,这反映了Rust范围类型的本质。
写入图像
图像数据通过HDU对象上的三个方法写入:[write_section][fits-hdu-write-section],[
write_region][fits-hdu-write-region],和[
write_image][fits-hdu-write-image]。
[write_section][fits-hdu-write-section]需要一个起始索引、结束索引以及要写入的数据。数据参数需要是一个切片,这意味着任何连续内存存储方法(例如
Vec
)都可以传递。
#
let data_to_write: Vec<f64> = vec![1.0, 2.0, 3.0];
hdu.write_section(&mut fptr, 0, data_to_write.len(), &data_to_write)?;
[write_region][fits-hdu-write-region]接受一个范围切片,用于指定要写入的数据,以及要写入的数据。
#
let data_to_write: Vec<f64> = vec![1.0, 2.0, 3.0, 4.0];
let ranges = [&(0..1), &(0..1)];
hdu.write_region(&mut fptr, &ranges, &data_to_write)?;
与cfitsio不同,范围的顺序遵循C约定,即行主序。
[write_image][fits-hdu-write-image]将传递的所有数据(如果可能)写入图像。如果传递的数据比图像中的像素多,该方法会返回错误。
#
// Image is 3x1
assert!(hdu.write_image(&mut fptr, &[1.0, 2.0, 3.0]).is_ok());
assert!(hdu.write_image(&mut fptr, &[1.0, 2.0, 3.0, 4.0]).is_err());
调整图像大小
可以使用[resize][fits-hdu-resize]方法将图像调整到新的形状。
该方法接收打开的 [FitsFile
][fits-file] 和一个 usize
值的切片。注意:目前 fitsio
只支持长度为 2 的切片,即二维图像。[resize
][fits-hdu-resize] 取得 self
的所有权,迫使用户再次获取 HDU 对象。这确保了图像更改反映在新的 HDU 对象中。
use fitsio::hdu::HduInfo;
hdu.resize(&mut fptr, &[1024, 1024])?;
// Have to get the HDU again, to reflect the latest changes
let hdu = fptr.hdu(0)?;
match hdu.info {
HduInfo::ImageInfo { shape, .. } => {
assert_eq!(shape, [1024, 1024]);
}
_ => panic!("Unexpected hdu type"),
}
与 cfitsio 不同,new_size
的维度顺序遵循 C 规范,即 行主序。
写入表格
写入表格数据
表格数据可以由 [write_col
][fits-hdu-write-col] 或 [write_col_range
][fits-hdu-write-col-range] 编写。
[write_col
][fits-hdu-write-col] 将整个列的数据写入文件。它不会检查文件中有多少行,但如果数据长度超过表长度,则会扩展表格。
let data_to_write: Vec<i32> = vec![10101; 5];
hdu.write_col(&mut fptr, "bar", &data_to_write)?;
let data: Vec<i32> = hdu.read_col(&mut fptr, "bar")?;
assert_eq!(data, vec![10101, 10101, 10101, 10101, 10101]);
[write_col_range
][fits-hdu-write-col-range] 将数据写入表格中的行范围。范围包括上界和下界,因此 0..4
写入 5 个元素。
let data_to_write: Vec<i32> = vec![10101; 10];
hdu.write_col_range(&mut fptr, "bar", &data_to_write, &(0..5))?;
let data: Vec<i32> = hdu.read_col(&mut fptr, "bar")?;
assert_eq!(data, vec![10101, 10101, 10101, 10101, 10101]);
插入列
HDU 对象上的两种方法允许添加新列:[append_column
][fits-hdu-append-column] 和 [insert_column
][fits-hdu-insert-column]。 [append_column
][fits-hdu-append-column] 将新列作为最后一个列成员添加,通常更受青睐,因为它不需要在文件内移动数据。
use fitsio::tables::{ColumnDescription, ColumnDataType};
let column_description = ColumnDescription::new("abcdefg")
.with_type(ColumnDataType::Int)
.create()?;
hdu.append_column(&mut fptr, &column_description)?;
删除列
HDU 对象具有 [delete_column
][fits-hdu-delete-column] 方法,可删除列。列可以通过整数或名称访问
let newhdu = hdu.delete_column(&mut fptr, "bar")?;
// or
let newhdu = hdu.delete_column(&mut fptr, 0)?;
原始 FITS 文件访问
将 FitsFile
转换为原始 fitsio_sys::fitsfile
指针
如果此库不支持所需的特定用例,可以访问原始 fitsfile
指针
use fitsio::FitsFile;
let mut fptr = FitsFile::open(filename)?;
/* Find out the number of HDUs in the file