Public
Edited
Aug 5, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
maplesRaw = FileAttachment("w1_acsa_seed_physical.txt").csv({typed: true})
Insert cell
Insert cell
Insert cell
Insert cell
maplesRaw
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
validate = v => v < 0 ? null : v;
Insert cell
maples = maplesRaw.map(d => ({
year: d.Year,
watershed: d.Watershed,
stemLength: validate(d.StemLength),
leafMass: validate(d.LeafDryMass),
stemMass: validate(d.StemDryMass),
leafArea: validate(d.CorrectedLeafArea)
}))
Insert cell
maples2003 = maples.filter(f => f.year === 2003)
Insert cell
maples2004 = maples.filter(f => f.year === 2004).map(({leafArea, ...rest}) => ({...rest})) //the entire empty column needs to be removed for PCA to work
Insert cell
maples
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
maples
X
leafArea
Y
Color
watershed
Size
Facet X
year
Facet Y
watershed
Mark
Auto
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import {PlotMatrix as PM2003} with {maples2003 as data} from "@observablehq/autoplot-matrix"
Insert cell
import {PlotMatrix as PM2004} with {maples2004 as data} from "@observablehq/autoplot-matrix"
Insert cell
PM2003()
Insert cell
PM2004()
Insert cell
Insert cell
Insert cell
Insert cell
ML = require("https://www.lactame.com/lib/ml/6.0.0/ml.min.js")
Insert cell
import {scale, asMatrix} from "@chrispahm/hierarchical-clustering"
Insert cell
mapleScaled2003 = scale(maples2003.map(({year, watershed, ...rest}) => rest))
Insert cell
mapleScaled2004 = scale(maples2004.map(({year, watershed, ...rest}) => rest))
Insert cell
maplePCA = ({
y2003: new ML.PCA(mapleScaled2003.map(Object.values)),
y2004: new ML.PCA(mapleScaled2004.map(Object.values))
})
Insert cell
explainedVariance = maplePCA.y2003.getExplainedVariance().map((d, i) => ({year: 2003, v: d, pc: i+1}))
.concat(maplePCA.y2004.getExplainedVariance().map((d, i) => ({year: 2004, v: d, pc: i+1})))
Insert cell
Insert cell
import {viewof loadings as loadings2003} with {mapleScaled2003 as food_scaled} from "@chrispahm/principal-component-analysis"
Insert cell
import {viewof loadings as loadings2004} with {mapleScaled2004 as food_scaled} from "@chrispahm/principal-component-analysis"
Insert cell
import {viewof scores as scores2003} with {mapleScaled2003 as food_scaled, maples2003 as food} from "@chrispahm/principal-component-analysis"
Insert cell
import {viewof scores as scores2004} with {mapleScaled2004 as food_scaled, maples2004 as food} from "@chrispahm/principal-component-analysis"
Insert cell
loadingsAndScores = {
const scoresCombined2003 = scores2003.map((d, i) => ({year: maples2003[i].year, watershed: maples2003[i].watershed, ...d}));
const scoresCombined2004 = scores2004.map((d, i) => ({year: maples2004[i].year, watershed: maples2004[i].watershed, ...d}));
const scoresCombined = scoresCombined2003.concat(scoresCombined2004);
const loadings = loadings2003.map(d => ({year: 2003, ...d})).concat(loadings2004.map(d => ({year: 2004, ...d})))

//putting loadings and scores together in one array is an ugly hack that allows facets to work in a chart below
//would appreciate a hint to a more elegant solution
return loadings.concat(scoresCombined);
}
Insert cell
chart = Plot.plot({
width: 900,
facet: {
data: loadingsAndScores,
x: "year"
},
x: { domain: [-4, 4] },
y: { domain: [-4, 4] },
color: { legend: true },
marks: [
Plot.density(loadingsAndScores, {
x: "PC1",
y: "PC2",
fill: "watershed",
stroke: "watershed",
fillOpacity: (d) => (d.watershed ? 0.02 : 0),
strokeOpacity: (d) => (d.watershed ? 0.8 : 0),
tip: true
}),
Plot.ruleX([0], { stroke: "lightgrey" }),
Plot.ruleY([0], { stroke: "lightgrey" }),
Plot.arrow(loadingsAndScores, {
x1: 0,
x2: (d) => d.PC1 * scalingFactor,
y1: 0,
y2: (d) => d.PC2 * scalingFactor,
opacity: (d) => (d.Variable ? 1 : 0)
}),
Plot.text(loadingsAndScores, {
x: (d) => d.PC1 * scalingFactor * 1.3,
y: (d) => d.PC2 * scalingFactor * 1.1,
text: "Variable",
opacity: (d) => (d.Variable ? 1 : 0)
})
]
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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