Public
Edited
Apr 3, 2023
Insert cell
Insert cell
{
const z = zip();
for (const extract of _EXTRACTS_FINAL) {
const directory = DIRECTORY_FOR({ extract });
EXPORT_AS_TEXT({ extract, property: 'text', filename: `${directory}/OriginalPrompt.txt` });
EXPORT_AS_TEXT({ extract, property: 'prompt', filename: `${directory}/Prompt.txt` });
EXPORT_AS_TEXT({ extract, property: 'date', filename: `${directory}/Date.txt` });
EXPORT_AS_TEXT({ extract, property: 'medium', filename: `${directory}/Medium.txt` });
EXPORT_AS_TEXT({ extract, property: 'discussion', filename: `${directory}/Discussion.txt` });
EXPORT_AS_TEXT({ extract, property: 'backstory', filename: `${directory}/Backstory.txt` });

z.file(`${directory}/Metadata.json`, JSON.stringify({
name: extract.name,
text: extract.text,
prompt: extract.prompt,
date: extract.date,
medium: extract.medium,
discussion: extract.discussion,
backstory: extract.backstory,
entities: Array.from(extract.entities).reduce((acc, [key, val]) => {
acc[key] = val;
return acc;
}, {}),
}, true, 2));
}

const blob = await z.generateAsync({ type: 'blob' });
return DOM.download(blob, `Sol LeWitt Data Set.zip`, `Download Sol LeWitt Data Set.zip`);

function DIRECTORY_FOR({ extract }) {
const { filename } = extract;
return filename.split('.', 2)[0];
}

function EXPORT_AS_TEXT({ extract, property, filename }) {
z.file(filename, extract[property]);
}
}
Insert cell
{
const extracts = _EXTRACTS_FINAL;
return Inputs.textarea({ rows: 24, cols: 24, value: extracts.map(({ prompt }) => prompt).join('\n\n') })
}
Insert cell
mutable _EXTRACTS_FINAL = null
Insert cell
{
const iter = EXTRACTS();
for (;;) {
const { value, done } = await iter.next();
if (!done) {
yield value;
} else {
mutable _EXTRACTS_FINAL = value;
break;
}
}
}
Insert cell
async function *EXTRACTS() {
const details = htl.html`<details>`;
const extracts = [];
yield VIEW();

let filenames = solLewitt1.filenames;
filenames = [...filenames];
filenames.sort((a, b) => {
a = +a.match(/\d+/)[0];
b = +b.match(/\d+/)[0];
return a - b;
});
for (let i=0, n=filenames.length; i<n; ++i) {
const filename = filenames[i];
const extract = await EXTRACT(filename);
extracts.push(extract);
yield VIEW();
}
return extracts;

function VIEW() {
details.replaceChildren(htl.html.fragment`
<summary>${extracts.length} drawings</summary>
${extracts.map((extract) => extract.view())}
`/* htl.html.fragment */);
return details;
}
}
Insert cell
async function EXTRACT(filename) {
const name = filename.split('/')[1].split('.')[0];
const number = name.split('Wall Drawing ', 2)[1];
const file = solLewitt1.file(filename);
let text = await file.text();
for (const x of ['', '', '', '', '', '\r']) {
text = text.replaceAll(x, '');
}

const originalText = text;

let entities = new Map();
const entityRegex = [];
entityRegex.push( new RegExp(String.raw`_(Wall Drawing ${number}[^_]*)_`/* String.raw */, 'g') );
entityRegex.push( /(Sol LeWitt)/g );
entityRegex.push( /(LeWitt)/g );
entityRegex.push( /\b([A-Z][a-zA-Z]+(?:\s+[A-Z][a-zA-Z]+)+)\b/g );
entityRegex.push( /_([^_]+)_/g );
for (const re of entityRegex) {
for (const match of text.matchAll(re)) {
const entity = match[1];
if (entity === 'Wall Drawings') continue;
if (!entities.has(entity)) {
entities.set(entity, `$${entities.size+1}`);
}
}
}

for (const [entity, replacement] of entities.entries()) {
text = text.replaceAll(`_${entity}_`, replacement);
text = text.replaceAll(`${entity}`, replacement);
}

entities = new Map(Array.from(entities.entries()).map(([k, v]) => ([v, k])));

let backstory;
[text, backstory] = text.split('**Backstory**', 2);
let lines = text.split('\n\n');
// lines = lines.filter((d) => !d.includes('- Sol LeWitt'));
// lines = lines.filter((d) => !d.includes('Yale University'));
// lines = lines.filter((d) => !d.includes('First Installation'));
// lines = lines.filter((d) => !d.includes('First Drawn By'));
// lines = lines.filter((d) => !d.includes('Collection '));
// lines = lines.filter((d) => !d.includes(' Collection'));
// lines = lines.filter((d) => !d.includes('MoCA'));

const prompt = lines[0].trim();
const date = lines[1].trim();
const medium = lines[2].trim();
const discussion = lines.slice(3).join('\n\n').trim();
backstory = (backstory || '').trim();
return Object.assign({ entities, name, filename, prompt, date, medium, discussion, backstory, lines, text: originalText }, {
view() {
return htl.html`
<details>
<summary>${name}</summary>
<dl>
${['entities', 'prompt', 'date', 'medium', 'discussion', 'backstory'].map((d) => htl.html.fragment`
<dt>${d}
<dd><textarea rows=${d==='discussion'||d==='backstory' ? 8 : 1} cols=80>${d==='entities' ? Array.from(entities.entries()).map(([k, v]) => `${k}: ${v}`).join('\n') : this[d]}
`/* htl.html.fragment */)}
<dt>Inspect
<dd>${inspect(this)}
`/* htl.html */;
},
});
}
Insert cell
solLewitt1 = FileAttachment("Sol LeWitt@2.zip").zip()
Insert cell
import {inspect} from "@observablehq/inspector"
Insert cell
import {zip} from "@fil/jszip"
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