diff --git a/docs/data/income-histogram-historical.parquet b/docs/data/income-histogram-historical.parquet
new file mode 100644
index 0000000..fda4df1
Binary files /dev/null and b/docs/data/income-histogram-historical.parquet differ
diff --git a/docs/income.md b/docs/income.md
new file mode 100644
index 0000000..497ac87
--- /dev/null
+++ b/docs/income.md
@@ -0,0 +1,82 @@
+---
+toc: false
+---
+
+```js
+import {DuckDBClient} from "npm:@observablehq/duckdb";
+const db = DuckDBClient.of({income: FileAttachment("data/income-histogram-historical.parquet")});
+```
+
+```js
+const uniqueYears = await db.query("SELECT DISTINCT year FROM income ORDER BY year").then(data => data.map(d => d.year));
+const yearRange = [uniqueYears[0], uniqueYears[uniqueYears.length - 1]]; // Min and Max years
+const yearInput = Inputs.range(yearRange, {step: 1, value: 0, width: 150});
+const selectedYear = Generators.input(yearInput);
+yearInput.querySelector("input[type=number]").remove();
+```
+
+```js
+const mostRecentYear = uniqueYears[uniqueYears.length - 1];
+const income = await db.query(`
+ SELECT income, count, sector FROM income
+ WHERE year = ${mostRecentYear}
+`);
+```
+
+```js
+// Order the sectors by mean income
+const mostRecentYear = uniqueYears[uniqueYears.length - 1];
+const orderSectors = await db.query(`
+ SELECT sector, SUM(income * count) / SUM(count) AS mean_income
+ FROM income
+ WHERE year = ${mostRecentYear}
+ GROUP BY sector
+ ORDER BY mean_income DESC
+`).then(data => data.map(d => d.sector));
+```
+
+```js
+function incomeChart(db, selectedYear, width) {
+ const income = db.query(`
+ SELECT income, count, sector FROM income
+ WHERE year = ${selectedYear}
+ `);
+
+ // Create a histogram with a logarithmic base.
+ return Plot.plot({
+ width,
+ marginLeft: 60,
+ x: { type: "log" },
+ color: { legend: "swatches", columns: 6, domain: orderSectors },
+ marks: [
+ Plot.rectY(
+ income,
+ Plot.binX(
+ { y: "sum" },
+ {
+ x: "income",
+ y: "count",
+ fill: "sector",
+ order: orderSectors,
+ thresholds: d3
+ .ticks(Math.log10(2_000), Math.log10(1_000_000), 40)
+ .map((d) => +(10 ** d).toPrecision(3)),
+ tip: true,
+ }
+ )
+ ),
+ ],
+ });
+}
+```
+
+
+
The sectors in which people earn the most money have shifted over the past two decades
+
How much income per year people reported earning in the 2000–2022 American Community Surveys, categorized by their sector of employment.
+
+
+
${selectedYear}
+ ${yearInput}
+
+ ${resize((width) => incomeChart(db, selectedYear, width))}
+
diff --git a/docs/index.md b/docs/index.md
index 5c4661c..ab18bd5 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -52,7 +52,6 @@ This is a testbed of visualizing the Census Bureau's American Community Survey d
```js
const income = FileAttachment("data/income-histogram.parquet").parquet();
-const rent = FileAttachment("data/rent-histogram.parquet").parquet();
```
```js
@@ -92,6 +91,10 @@ function incomeChart(income, width) {
}
```
+```js
+const rent = FileAttachment("data/rent-histogram.parquet").parquet();
+```
+
```js
function rentChart(rent, width) {
// Order the regions by mean rent
diff --git a/yarn.lock b/yarn.lock
index 68548d7..880bfab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3,9 +3,9 @@
"@clack/core@^0.3.3":
- version "0.3.3"
- resolved "https://registry.yarnpkg.com/@clack/core/-/core-0.3.3.tgz#233ccebf779aa5a66fc68ee48df5e58cd226fd94"
- integrity sha512-5ZGyb75BUBjlll6eOa1m/IZBxwk91dooBWhPSL67sWcLS0zt9SnswRL0l26TVdBhb0wnWORRxUn//uH6n4z7+A==
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/@clack/core/-/core-0.3.4.tgz#375e82fc8fe46650b37cab2f2ea8752c6b7f0450"
+ integrity sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==
dependencies:
picocolors "^1.0.0"
sisteransi "^1.0.5"
@@ -978,6 +978,11 @@ is-stream@^3.0.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
+is-unicode-supported@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz#d824984b616c292a2e198207d4a609983842f714"
+ integrity sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==
+
is-wsl@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
@@ -1129,9 +1134,9 @@ npm-run-path@^4.0.1:
path-key "^3.0.0"
npm-run-path@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955"
- integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f"
+ integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==
dependencies:
path-key "^4.0.0"
@@ -1382,9 +1387,9 @@ statuses@2.0.1:
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
streamx@^2.15.0:
- version "2.16.0"
- resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.16.0.tgz#b52e204b4e14c9225cb53f87e9e95bf5169c7cb8"
- integrity sha512-a7Fi0PoUeusrUcMS4+HxivnZqYsw2MFEP841TIyLxTcEIucHcJsk+0ARcq3tGq1xDn+xK7sKHetvfMzI1/CzMA==
+ version "2.16.1"
+ resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.16.1.tgz#2b311bd34832f08aa6bb4d6a80297c9caef89614"
+ integrity sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==
dependencies:
fast-fifo "^1.1.0"
queue-tick "^1.0.1"