Public
Edited
Feb 20
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
lines = [
{
name: "Transitional Arc/Dissected Arc",
values: [
{ quartz: 17.1, feldspar: 70.1, lithic: 100 - 17.1 - 70.1 },
{ quartz: 33.47, feldspar: 12.51, lithic: 54.01 }
// { quartz: 37, feldspar: 0, lithic: 100 - 37 }, //full
]
},
{
name: "Undissected Arc/Transitional Arc",
values: [
{ quartz: 25, feldspar: 0, lithic: 75 },
{ quartz: 0, feldspar: 50, lithic: 50 }
]
},
{
name: "Basement Uplift/Transitional Continental",
values: [
{ quartz: 55, feldspar: 45, lithic: 0 },
intersection
// { quartz: 25, feldspar: 0, lithic: 75 }
]
},
{
name: "Transitional Continental/Craton Interior",
values: [
{ quartz: 100 - 18, feldspar: 18, lithic: 0 },
{ quartz: 79.71, feldspar: 15.38, lithic: 4.91 }
]
}
]
Insert cell
Insert cell
qtflBarycentric = barycentric()
.a(d => d.quartz)
.b(d => d.feldspar)
.c(d => d.lithic)
Insert cell
qtflTernaryPlot = ternaryPlot(qtflBarycentric)
.radius(radius)
.labels(["Q", "F", "L"])
Insert cell
drawTernaryPlot = (someTernaryPlot) => {
const node = DOM.svg(width, height);
const svg = d3.select(node);

const radius = someTernaryPlot.radius();

const chart = svg
.append("g")
.attr("transform", `translate(${width / 2} ${height / 2 + yOffset})`)
.attr("height", 300)
.attr("font-family", "sans-serif")
.attr("id", "chart")
.on("mousemove", handleMouseMove);

const defs = chart.append("defs");

const clipPath = defs
.append("clipPath")
.attr("id", "trianglePath")
.append("path")
.attr("d", someTernaryPlot.triangle());

const axisLabelsGroup = chart
.append("g")
.attr("class", "axis-labels")
.call(axisLabels, someTernaryPlot.axisLabels());

const gridLinesPaths = someTernaryPlot
.gridLines()
.map((axisGrid) => axisGrid.map(d3.line()).join(" "));

const gridGroup = chart
.append("g")
.attr("class", "grid")
.call(grid, gridLinesPaths);

const axisTicksGroups = chart
.append("g")
.attr("class", "ternary-ticks")
.attr("font-size", 10)
.selectAll("g")
.data(someTernaryPlot.ticks())
.join("g")
.attr("class", "axis-ticks");

axisTicksGroups.call(ticks);

const trianglePath = chart
.append("path")
.attr("d", someTernaryPlot.triangle())
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 2);

chart
.append("g")
.attr("class", "divisions")
.selectAll("path")
.data(ternaryDivisions.map((d) => d.coords))
.join("path")
.attr("d", closedLine)
.attr("fill", "none")
.attr("stroke", "black")
// .attr("stroke-opacity", 0.4)
.attr("stroke-width", 1)
.append("title")
.text((d) => d.texture);

chart
.append("g")
.attr("class", "lines")
.selectAll("path")
.data(ternaryLines.map((d) => d.coords))
.join("path")
.attr("d", openLine)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-dasharray", "4 1")
.attr("stroke-width", 1);

if (toggle) {
chart
.append("g")
.selectAll("text")
.data(ternaryDivisions)
.join("text")
.attr("transform", (d) => `translate(${d.centroid})`)
.attr("text-anchor", "middle")
.attr("stroke", "ghostwhite")
.attr("stroke-width", 2)
.attr("paint-order", "stroke")
.attr("alignment-baseline", "middle")
.attr("font-size", 16)
.text((d) => d.source);
}

const labels = chart
.append("g")
.selectAll("text")
.data(ternaryLabels)
.join("text")
.attr("transform", (d) => `translate(${d.coords})rotate(${d.rotation})`)
.attr("text-anchor", "middle")
.attr("stroke", "ghostwhite")
.attr("fill", "dimgray")
.attr("stroke-width", 2)
.attr("paint-order", "stroke")
.attr("alignment-baseline", "middle")
.attr("font-size", 12)
.text((d) => d.name);

function handleMouseMove(d) {
const xy = d3.pointer(d);
const inverse = someTernaryPlot.invert(xy);

node.dispatchEvent(new CustomEvent("input"), { bubbles: true });
node.value = inverse;
}

return svg.node();
}
Insert cell
closedLine = d3.line().curve(d3.curveLinearClosed)
Insert cell
openLine = d3.line().curve(d3.curveLinear)
Insert cell
divisions = [
{
source: "Craton",
rotation: 0,
values: [
{ quartz: 100, feldspar: 0, lithic: 0 },
{ quartz: 97, feldspar: 0, lithic: 3 },
{ quartz: 0, feldspar: 85, lithic: 15 },
{ quartz: 0, feldspar: 100, lithic: 0 }
]
},
{
source: "Recycled Orogon",
rotation: 0,
values: [
{ quartz: 97, feldspar: 0, lithic: 3 },
{ quartz: 25, feldspar: 0, lithic: 75 },
intersection
]
},
{
source: "Magmatic Arcs",
rotation: 0,
values: [
intersection,
{ quartz: 0, feldspar: 85, lithic: 15 },
{ quartz: 0, feldspar: 0, lithic: 100 },
{ quartz: 25, feldspar: 0, lithic: 75 }
]
}
]
Insert cell
labels = [
{
name: "Recycled Orogenic",
value: { quartz: 60, feldspar: 16, lithic: 24 },
rotation: 0
},
{
name: "Dissected Arc",
value: { quartz: 35, feldspar: 42, lithic: 23 },
rotation: 0
},
{
name: "Transitional Arc",
value: { quartz: 15, feldspar: 41, lithic: 43 },
rotation: 0
},
{
name: "Undissected Arc",
value: { quartz: 7, feldspar: 13, lithic: 80 },
rotation: 0
},
{
name: "Transitional Continental",
value: { quartz: 47, feldspar: 30, lithic: -10 },
rotation: 0 //-64
},
{
name: "Craton Interior",
value: { quartz: 70, feldspar: 16, lithic: -8 },
rotation: 0 //-62
},
{
name: "Basement Uplift",
value: { quartz: 30, feldspar: 77, lithic: -11 },
rotation: 0 //-63
}
]
Insert cell
intersection = ({
quartz: intersectionValues[0],
feldspar: intersectionValues[1],
lithic: intersectionValues[2]
})
Insert cell
ternaryLines = lines.map((d) => {
const coords = d.values.map(qtflTernaryPlot);

return { ...d, coords };
})
Insert cell
ternaryDivisions = divisions.map((d) => {
const coords = d.values.map(qtflTernaryPlot);

const centroid = d3.polygonCentroid(coords);

return { ...d, coords, centroid };
})
Insert cell
format = d3.format(".2%")
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
a = [
{ quartz: 97, feldspar: 0, lithic: 3 },
{ quartz: 0, feldspar: 85, lithic: 15 }
].map((e) => [qtflBarycentric(e)[0] * radius, qtflBarycentric(e)[1] * radius])
Insert cell
b = [
{ quartz: 55, feldspar: 45, lithic: 0 },
{ quartz: 25, feldspar: 0, lithic: 75 }
].map((e) => [qtflBarycentric(e)[0] * radius, qtflBarycentric(e)[1] * radius])
Insert cell
intersectionValues = qtflTernaryPlot
.invert(intersect(a[0], a[1], b[0], b[1]))
.map((d) => d * 100)
Insert cell
Insert cell
Insert cell
d3 = require('d3@v6')
Insert cell
mathjs = require("https://unpkg.com/mathjs@4.0.0/dist/math.min.js")
Insert cell
ternaryPlot = d3Ternary.ternaryPlot
Insert cell
barycentric = d3Ternary.barycentric
Insert cell
d3Ternary = import("d3-ternary")
Insert cell
import {
valuesTable,
grid,
axisLabels,
ticks
} from "@julesblm/d3-ternary"
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