Public
Edited
Jun 8, 2023
1 star
Insert cell
Insert cell
ZIP = await FileAttachment("Nuclear Decay Data - Cleaned HTML.zip").zip()
Insert cell
NAMES = (await ZIP.file('names.txt').text())
.split('\n')
.filter((line) => line !== '')
.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], [])
Insert cell
viewof NAME = Inputs.input('22Mg')
Insert cell
Inputs.bind(Inputs.text({ datalist: NAMES }), viewof NAME, invalidation)
Insert cell
NAME
Insert cell
async function MAKE_TEXT(zip, name) {
return await zip.file(`${name}.html`).text();
}
Insert cell
viewof TEXT = Inputs.textarea({
rows: 24,
value: await MAKE_TEXT(ZIP, NAME),
submit: true,
})
Insert cell
TEXT
Insert cell
viewof HTML = Inputs.input(MAKE_HTML(TEXT))
Insert cell
function MAKE_HTML(text) {
return new DOMParser().parseFromString(text, 'text/html');
}
Insert cell
viewof DATA = Inputs.input(MAKE_DATA(HTML))
Insert cell
function MAKE_DATA(html) {
const debug = [];

const state = {};

let datasets, dataset, measurements, measurement;
datasets = {};
dataset = null;
for (let el=html.querySelector(':scope body').firstChild; el.nextSibling; el = el.nextSibling) {
const { tagName, textContent } = el;
debug.push({ tagName, textContent });

if (tagName === 'P') {
let match;
if (match = textContent.match(/^\s*(?<name>.+)\s*:\s*$/)) {
const { name } = match.groups;
debug.push({ name });

if (name.startsWith('Results')) {
continue;

} else if (name.startsWith('Dataset ')) {
measurements = {};
measurement = null;
dataset = { name, measurements };
datasets[name] = dataset;
} else {
measurement = { name };
measurements[name] = measurement;
}
}
} else if (tagName === 'TABLE') {
const rows = [];
debug.push({ el });
for (const tr of el.querySelectorAll(':scope > tbody > tr')) {
debug.push({ tr });
const row = [];
for (const td of tr.querySelectorAll(':scope > td')) {
debug.push({ td });
const { textContent } = td;
const text = textContent;
const parsed = text
.trim()
.replaceAll(/\s*%\s*/g, ' ')
.split(/\s*,\s*/g)
.map((v) => {
const parts = v.trim().split(/\s+/g);
if (parts.length === 1) {
let [value] = parts;
value = Number.parseFloat(value);
return { value };
} else if (parts.length === 2) {
let [value, sigdig] = parts;
value = Number.parseFloat(value);
sigdig = Number.parseInt(sigdig, 10);
return { value, sigdig };
}
});

if (text.match(/^\s*$/)) {
continue;
}

row.push({ text, parsed });
}

if (row.length > 0) {
rows.push(row);
}
}

const [columns] = rows.splice(0, 1);
if (columns.length === rows[0].length - 1) {
columns.unshift('name');
}

Object.assign(measurement, {
columns,
rows,
});
}
}
// return htl.html`${debug.find(({ el }) => !!el).el}`;
// return debug;
return datasets;
}
Insert cell
Inputs.textarea({
rows: 24,
value: JSON.stringify(DATA, true, 2),
})
Insert cell
DATAS = {
const zip = ZIP;
const names = NAMES;

const datas = {};
for (const name of names) {
const text = await MAKE_TEXT(zip, name);
if (!text) {
continue;
}
const html = MAKE_HTML(text);
try {
const data = MAKE_DATA(html);
if (JSON.stringify(data) === '{}') {
continue;
}
datas[name] = data;
} catch (e) {
throw `${e}: ${name}`;
}
}

return datas;
}
Insert cell
import {zip} from "@fil/jszip"
Insert cell
{
const names = NAMES;
const datas = DATAS;
const z = new zip();
for (const name of names) {
const data = datas[name];
if (!data) {
continue;
}

z.file(`${name}.json`, JSON.stringify(data, true, 2)); // prettify
}
const blob = await z.generateAsync({ type: 'blob' });
return DOM.download(blob, `Nuclear Decay Data - Parsed.zip`);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more