Skip to content

Commit

Permalink
improve default templates (#693)
Browse files Browse the repository at this point in the history
* improve default templates

* fix test, docs
  • Loading branch information
mbostock authored Feb 7, 2024
1 parent ab7b242 commit 7366a0e
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 163 deletions.
4 changes: 2 additions & 2 deletions templates/default/README.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ A typical Framework project looks like this:
│ ├─ components
│ │ └─ timeline.js # an importable module
│ ├─ data
│ │ ├─ launchHistory.csv.js # a data loader
│ │ └─ spaceHistory.json # a static data file
│ │ ├─ launches.csv.js # a data loader
│ │ └─ events.json # a static data file
│ ├─ example-dashboard.md # a page
│ ├─ example-report.md # another page
│ └─ index.md # the home page
Expand Down
33 changes: 9 additions & 24 deletions templates/default/docs/components/timeline.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,16 @@
import * as Plot from "npm:@observablehq/plot";
import * as d3 from "npm:d3";

export function timeline(events) {
export function timeline(events, {width, height} = {}) {
return Plot.plot({
insetTop: 30,
insetBottom: 10,
insetRight: 10,
height: 250,
x: {
domain: d3.extent(events, (d) => d["year"]),
label: "Year",
nice: true,
},
y: { axis: null },
width,
height,
marginTop: 30,
x: {nice: true, label: null, tickFormat: ""},
y: {axis: null},
marks: [
Plot.axisX({tickFormat: d3.format(".0f")}),
Plot.ruleX(events, {x: "year", y: "y", stroke: "#eee", strokeWidth: 2}),
Plot.ruleY([0], {stroke: "#eee"}),
Plot.dot(events, {x: "year", y: "y", fill: "currentColor", r: 5}),
Plot.text(events, {
x: "year",
y: "y",
text: "name",
dy: -20,
lineWidth: 10,
fontSize: 12,
}),
Plot.ruleX(events, {x: "year", y: "y", markerEnd: "dot", strokeWidth: 2.5}),
Plot.ruleY([0]),
Plot.text(events, {x: "year", y: "y", text: "name", lineAnchor: "bottom", dy: -10, lineWidth: 10, fontSize: 12})
]
});
}
8 changes: 8 additions & 0 deletions templates/default/docs/data/events.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{"name": "Sputnik 1", "year": 1957, "y": 10},
{"name": "Apollo 11", "year": 1969, "y": 20},
{"name": "Viking 1 and 2", "year": 1975, "y": 30},
{"name": "Space Shuttle Columbia", "year": 1981, "y": 40},
{"name": "Hubble Space Telescope", "year": 1990, "y": 50},
{"name": "ISS Construction", "year": 1998, "y": 60}
]
52 changes: 0 additions & 52 deletions templates/default/docs/data/launchHistory.csv.js

This file was deleted.

61 changes: 61 additions & 0 deletions templates/default/docs/data/launches.csv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {csvFormat, tsvParse} from "d3-dsv";
import {utcParse} from "d3-time-format";

async function text(url) {
const response = await fetch(url);
if (!response.ok) throw new Error(`fetch failed: ${response.status}`);
return response.text();
}

// “Top” vehicles
const TOP_LAUNCH_VEHICLES = new Set([
"Falcon9",
"R-7",
"R-14",
"Thor",
"DF5",
"R-36",
"Proton",
"Titan",
"Zenit",
"Atlas"
]);

// “Top” launching states
const TOP_STATES_MAP = new Map([
["US", "United States"],
["SU", "Soviet Union"],
["RU", "Russia"],
["CN", "China"]
]);

// Load and parse launch vehicles.
const launchVehicles = tsvParse(await text("https://planet4589.org/space/gcat/tsv/tables/lv.tsv"));

// Construct map to lookup vehicle family from name.
const launchVehicleFamilyMap = new Map(launchVehicles.map((d) => [d["#LV_Name"], d.LV_Family.trim()]));

// Reduce cardinality by mapping smaller states to “Other”.
function normalizeState(d) {
return TOP_STATES_MAP.get(d) ?? "Other";
}

// Reduce cardinality by mapping smaller launch families to “Other”.
function normalizeFamily(d) {
const family = launchVehicleFamilyMap.get(d);
return TOP_LAUNCH_VEHICLES.has(family) ? family : "Other";
}

// Parse dates!
const parseDate = utcParse("%Y %b %_d");

// Load and parse launch-log and trim down to smaller size.
const launchHistory = tsvParse(await text("https://planet4589.org/space/gcat/tsv/derived/launchlog.tsv"), (d) => ({
date: parseDate(d.Launch_Date.slice(0, 11)),
state: normalizeState(d.LVState),
stateId: d.LVState,
family: normalizeFamily(d.LV_Type)
})).filter((d) => d.date != null);

// Write out csv formatted data.
process.stdout.write(csvFormat(launchHistory));
32 changes: 0 additions & 32 deletions templates/default/docs/data/spaceHistory.json

This file was deleted.

102 changes: 56 additions & 46 deletions templates/default/docs/example-dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,84 +6,94 @@ toc: false

# Rocket launches 🚀

<!-- load and transform the data -->
<!-- Load and transform the data -->

```js
const launchHistory = await FileAttachment("data/launchHistory.csv")
.csv({typed: true});
const launches = FileAttachment("data/launches.csv").csv({typed: true});
```

const format = d3.format(",");
function launches(id) {
return format(launchHistory.filter((d) => d.stateId === id).length);
}
<!-- A shared color scale for consistency, sorted by the number of launches -->

```js
const color = Plot.scale({
color: {
type: "categorical",
domain: d3.groupSort(launches, (D) => -D.length, (d) => d.state).filter((d) => d !== "Other"),
unknown: "var(--theme-foreground-muted)"
}
});
```

<!-- cards with big numbers -->
<!-- Cards with big numbers -->

<div class="grid grid-cols-4">
<div class="card">
<h2>United States</h2>
<span class="big">${launches("US")}</span>
<h2>United States 🇺🇸</h2>
<span class="big">${launches.filter((d) => d.stateId === "US").length.toLocaleString("en-US")}</span>
</div>
<div class="card">
<h2>Soviet Union</h2>
<span class="big">${launches("SU")}</span>
<h2>Russia 🇷🇺 <span class="muted">/ Soviet Union</span></h2>
<span class="big">${launches.filter((d) => d.stateId === "SU" || d.stateId === "RU").length.toLocaleString("en-US")}</span>
</div>
<div class="card">
<h2>Russia</h2>
<span class="big">${launches("RU")}</span>
<h2>China 🇨🇳</h2>
<span class="big">${launches.filter((d) => d.stateId === "CN").length.toLocaleString("en-US")}</span>
</div>
<div class="card">
<h2>China</h2>
<span class="big">${launches("CN")}</span>
<h2>Other</h2>
<span class="big">${launches.filter((d) => d.stateId !== "US" && d.stateId !== "SU" && d.stateId !== "RU" && d.stateId !== "CN").length.toLocaleString("en-US")}</span>
</div>
</div>

<!-- plot of launch history -->
<!-- Plot of launch history -->

<div class="card grid grid-cols-8">
${resize((width) => Plot.plot({
width,
```js
function launchTimeline(data, {width} = {}) {
return Plot.plot({
title: "Launches over the years",
width,
height: 300,
x: {label: null, interval: "year"},
y: {grid: true, label: "Launches"},
color: {legend: true, label: "State"},
color: {...color, legend: true},
marks: [
Plot.barY(
launchHistory,
Plot.groupX(
{y: "count"},
{x: d => new Date(d.date), fill: "state", tip: {format: {x: false}}}
)
),
Plot.rectY(data, Plot.binX({y: "count"}, {x: "date", fill: "state", interval: "year", tip: true})),
Plot.ruleY([0])
]
}))}
});
}
```

<div class="grid grid-cols-1">
<div class="card">
${resize((width) => launchTimeline(launches, {width}))}
</div>
</div>

<!-- plot of launch vehicles -->
<!-- Plot of launch vehicles -->

<div class="card grid grid-cols-8">
${resize((width) => Plot.plot({
```js
function vehicleChart(data, {width}) {
return Plot.plot({
title: "Popular launch vehicles",
width,
title: "Popular Launch Vehicles",
marginLeft: 65,
height: 300,
x: { grid: true, label: "Launches" },
y: { label: "Vehicle Family" },
color: { legend: true, label: "State" },
marginTop: 0,
marginLeft: 50,
x: {grid: true, label: "Launches"},
y: {label: null},
color: {...color, legend: true},
marks: [
Plot.barX(
launchHistory,
Plot.groupY(
{ x: "count" },
{ y: "family", fill: "state", tip: true, sort: { y: "x", reverse: true }}
)
),
Plot.rectX(data, Plot.groupY({x: "count"}, {y: "family", fill: "state", tip: true, sort: {y: "-x"}})),
Plot.ruleX([0])
]
}))}
});
}
```

<div class="grid grid-cols-1">
<div class="card">
${resize((width) => vehicleChart(launches, {width}))}
</div>
</div>

Data: Jonathan C. McDowell, [General Catalog of Artificial Space Objects](https://planet4589.org/space/gcat)
8 changes: 4 additions & 4 deletions templates/default/docs/example-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ This led to the launch of the first artificial satellite, Sputnik 1, and the cre
## The Space Shuttle era

```js
const events = FileAttachment("./data/spaceHistory.json").json();
import {timeline} from "./components/timeline.js";
```

```js
import {timeline} from "./components/timeline.js";
const events = FileAttachment("./data/events.json").json();
```

```js
display(timeline(events));
timeline(events, {height: 300})
```

### Sputnik 1 (1957)
Expand All @@ -48,7 +48,7 @@ The first orbital space shuttle mission, STS-1, launched the Space Shuttle Colum

The Hubble Space Telescope has provided unparalleled images and data, revolutionizing our understanding of the universe and contributing to countless astronomical discoveries.

### International Space Station (ISS) Construction (1998—2011)
### International Space Station (ISS) construction (1998—2011)

The ISS, a collaborative effort involving multiple space agencies, began construction with the launch of its first module, Zarya, in 1998. Over the following years, various modules were added, making the ISS a symbol of international cooperation in space exploration.

Expand Down
4 changes: 3 additions & 1 deletion templates/default/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"observable": "observable"
},
"dependencies": {
"@observablehq/framework": "https://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@github.com/observablehq/framework#main"
"@observablehq/framework": "https://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@github.com/observablehq/framework#main",
"d3-dsv": "^3.0.1",
"d3-time-format": "^4.1.0"
}
}
4 changes: 2 additions & 2 deletions test/create-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ describe("create", async () => {
new Set([
"template-test/.gitignore",
"template-test/docs/components/timeline.js",
"template-test/docs/data/launchHistory.csv.js",
"template-test/docs/data/spaceHistory.json",
"template-test/docs/data/launches.csv.js",
"template-test/docs/data/events.json",
"template-test/docs/example-dashboard.md",
"template-test/docs/example-report.md",
"template-test/docs/index.md",
Expand Down

0 comments on commit 7366a0e

Please sign in to comment.