java - 尝试用 Java 编写 FITS BinaryTable(或 AsciiTable)时出现奇怪的维度
问题描述
第一个功能是直接从 nom-tam-fits 网站窃取的:https ://nom-tam-fits.github.io/nom-tam-fits/intro.html
private static void dataTableToBinaryFitsDummy() throws Exception {
BufferedFile bf = new BufferedFile("table.fits", "rw");
BasicHDU.getDummyHDU().write(bf); // Write an initial null HDU
double[] ra = {1.};
double[] dec = {2.};
String[] name = {" "}; // maximum length will be 10 characters
Object[] row = {ra, dec, name};
long rowSize = ArrayFuncs.computeLSize(row);
BinaryTable table = new BinaryTable();
table.addRow(row);
Header header = new Header();
table.fillHeader(header);
BinaryTableHDU bhdu = new BinaryTableHDU(header, table);
bhdu.setColumnName(0, "ra", null);
bhdu.setColumnName(1, "dec", null);
bhdu.setColumnName(2, "name", null);
bhdu.getHeader().setNaxis(2, 1000); // set the header to the actual number of rows we write
bhdu.getHeader().write(bf);
ByteBuffer buffer = ByteBuffer.allocate((int) rowSize);
for (int event = 0; event < 1000; event ++){
buffer.clear();
// update ra, dec and name here
buffer.putDouble(event);
buffer.putDouble(dec[0]);
buffer.put(("event "+event).getBytes());
buffer.flip();
bf.write(buffer.array());
}
FitsUtil.pad(bf, rowSize * 1000);
bf.close();
}
作为起点,我希望能够传入原始双精度数组的任意集合。这是我的尝试,IMO 不应该与原来的特别不同。
private static void dataTableToBinaryFitsDummyWithArgsDoublesOnlyWrapper() {
int nRows = 100;
double [] rowA = new double[nRows];
double [] rowB = new double[nRows];
double [] rowC = new double[nRows];
double [] rowD = new double[nRows];
Random random = new Random();
for (int i=0;i<nRows;i++) {
rowA[i] = i;
rowB[i] = 2*i;
rowC[i] = random.nextGaussian();
rowD[i] = rowC[i] * -1;
}
ImmutableList<double[]> columns = ImmutableList.of(rowA, rowB, rowC, rowD);
ImmutableList<String> names = ImmutableList.of("ints", "double ints", "randos", "neg randos");
try {
dataTableToBinaryFitsDummyWithArgsDoublesOnly(columns, names, 4, nRows);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void dataTableToBinaryFitsDummyWithArgsDoublesOnly(ImmutableList<double[]> columns,
ImmutableList<String> names, int nCols, int nRows) throws Exception {
BufferedFile bf = new BufferedFile("tableWithArgs.fits", "rw");
BasicHDU.getDummyHDU().write(bf); // Write an initial null HDU
Object[] row = new Object[nCols];
for (int i=0;i<nCols;i++) {
row[i] = columns.get(i);
}
long rowSize = ArrayFuncs.computeLSize(row);
BinaryTable table = new BinaryTable();
table.addRow(row);
Header header = new Header();
table.fillHeader(header);
BinaryTableHDU bhdu = new BinaryTableHDU(header, table);
for (int i=0;i<nCols;i++) {
bhdu.setColumnName(i, names.get(i), null);
}
bhdu.getHeader().setNaxis(2, nRows);
bhdu.getHeader().write(bf);
ByteBuffer buffer = ByteBuffer.allocate((int) rowSize);
for (int i = 0; i < nRows; i ++){
buffer.clear();
// update ra, dec and name here
for (double[] column : columns) {
buffer.putDouble(column[i]);
}
buffer.flip();
bf.write(buffer.array());
}
FitsUtil.pad(bf, rowSize * nRows);
bf.close();
}
但是,我得到的看起来非常不同。我希望行看起来像
ints, double ints, randos, neg randos
0.0, 0.0, 0.66938, -0.66938
1.0, 2.0, 0.53482, -0.53482
2.0, 4.0, 0.66825, -0.66825
...
但相反我得到
ints, double ints, randos, neg randos
(0.0, 0.0, 0.66938, -0.66938, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...)
(1.0, 2.0, 0.53482, -0.53482, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...), (0.0, 0.0, 0.0, 0.0, ...)
看起来我没有得到 4 列和 100 行的数字,而是得到 4 列和 100 行的 100 个数字列表。我尽可能地遵循规范示例,为什么会发生这种情况?
虽然我在这里,但我也希望这是一个 AsciiTable 和 AsciiTableHDU,但我看到的唯一示例是 BinaryTables、BinaryTableHDUs 和 ByteBuffers。
解决方案
我不是很熟悉nom.tam.fits
,但根据文档BinaryTable.addRow采用基元数组数组(这是因为 FITS 二进制表的单个单元格中的数据本身可以是多维数组)。
这就是您引用的原始示例从 1 元素数组的数组中创建一行的原因:
double[] ra = {1.};
double[] dec = {2.};
String[] name = {" "}; // maximum length will be 10 characters
Object[] row = {ra, dec, name};
在您的代码中,您似乎混淆了行和列:
double [] rowA = new double[nRows];
double [] rowB = new double[nRows];
double [] rowC = new double[nRows];
double [] rowD = new double[nRows];
在这里,这些数组中的每一个都代表一整列数据(这就是它们的长度为 的原因nRows
)。
那么这里
Object[] row = new Object[nCols];
for (int i=0;i<nCols;i++) {
row[i] = columns.get(i);
}
您创建一个“行”,其中包含该行中整个列的值。您缺少一些外部 for 循环 over nRows
。
还有一个BinaryTable.addColumn
可能更有效地一次添加整个列(特别是如果您预先指定列的数量和类型)。
原始示例的主要用例(一次写入一行)可能是如果您有一些长时间运行的观察或事件记录过程,其中一行以流方式一次附加到表中。
推荐阅读
- machine-learning - 无法将 NumPy 数组转换为张量?
- python - 为什么 PyScripter 控制台中的输出不同?
- java - 在使用 Spring Boot 执行 @WebMvcTest 时,有没有办法在自定义 bean 验证器中注入 EntityManager 的实例?
- python - Plotly Dash:实时烛台图错误?
- html - 如何根据媒体查询使用 colspan/rowspan 创建不同的类似表格的布局?
- bash - 从两个列表中删除重复的单词
- purescript - 尝试解除 Aff 响应时没有类型类实例错误
- c# - Discord 机器人在调试时断开连接
- typescript - 类型 'string' 不能分配给 typrscript 中的类型 'number'
- r - 使用 Chebyshev 的 P(4 < X <12) 与模拟值不一致