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.

+

Code for data transform

+
+

${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"