Public
Edited
Feb 20
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
addLabels = (node, labels, rotate = 0) =>
node
.append("g")
.selectAll("text")
.data(labels)
.join("text")
.attr("transform", (d) => `translate(${d.coords})rotate(${rotate})`)
.attr("text-anchor", "middle")
.attr("stroke", "ghostwhite")
.attr("stroke-width", 4)
.attr("paint-order", "stroke")
.attr("alignment-baseline", "middle")
.attr("font-size", 13)
.selectAll("tspan")
.data((d) => d.label.split(/\n/g))
.join("tspan")
.attr("x", 0)
.attr("y", (d, i, D) => `${(i === D.length - 1) * 0.3 + i * 0.9}em`)
.text((d) => d)
Insert cell
qapTernaryPlot = ternaryPlot(qapBarycentric)
.radius(radius)
.labels(["Quartz"]) //["Alkali", "Plagioclase"
.labelAngles([0, 0, 0])
.labelOffsets([45, 50, 80])
Insert cell
fpaTernaryPlot = ternaryPlot(fpaBarycentric)
.radius(radius)
.labels(["Feldspar", "",""]) // ["Feldspar", "Plagioclase", "Alkali"]
.tickAngles([180, 60, -60])
.tickTextAnchors(["end", "end", "end"])
.labelAngles([180, 60, -60])
Insert cell
Insert cell
Insert cell
qapBarycentric = barycentric()
.a((d) => d.quartz)
.b((d) => d.alkali)
.c((d) => d.plagioclase)
Insert cell
fpaBarycentric = barycentric()
.a((d) => d.feldspar)
.b((d) => d.plagioclase)
.c((d) => d.alkali)
Insert cell
fpaTernaryLines = makeTernaryLines(fpaLines, fpaTernaryPlot)
Insert cell
qapTernaryLines = makeTernaryLines(qapLines, qapTernaryPlot)
Insert cell
makeTernaryLines = (lines, ternaryPlot) =>
lines.map((d) => {
const coords = d.values.map(ternaryPlot);

return { ...d, coords };
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
height = 640
Insert cell
radius = Math.min(width, height) / 2
Insert cell
// to keep the triangle centered
yOffset = radius / 4
Insert cell
Insert cell
ticks = (g) =>
g
.selectAll("g")
.data(
(d) => d,
(d) => d.tick
)
.join(
(enter) => {
const tickGroups = enter
.append("g")
.attr("class", "tick")
.attr("transform", (tick) => `translate(${tick.position})`);

tickGroups
.append("text")
.attr("text-anchor", (tick) => tick.textAnchor)
.attr("transform", (tick) => `rotate(${tick.angle})`)
.attr(
"dx",
(tick) => (-tick.size - 5) * (tick.textAnchor === "start" ? -1 : 1)
)
.attr("dy", ".5em")
.text((tick) => tick.tick);

tickGroups
.append("line")
.attr("transform", (d) => `rotate(${d.angle + 90})`)
.attr(
"y2",
(tick) => tick.size * (tick.textAnchor === "start" ? -1 : 1)
)
.attr("stroke", "grey");

return tickGroups;
},
(update) =>
update.attr("transform", (tick) => `translate(${tick.position})`),
(exit) => exit.attr("opacity", 0.0001).remove()
)
Insert cell
import { valuesTable, grid, axisLabels } from "@julesblm/d3-ternary"
Insert cell
d3Ternary = import("d3-ternary")
Insert cell
barycentric = d3Ternary.barycentric
Insert cell
ternaryPlot = d3Ternary.ternaryPlot
Insert cell
d3 = require('d3@v6')
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