Published
Edited
Dec 28, 2021
Fork of Challenge 4
Insert cell
Insert cell
Insert cell
{
const features = ["sepalLength", "sepalWidth", "petalLength", "petalWidth"];
const subGraphSize = 200;
const margin = { left: 125, right: 0, top: 20, bottom: 20 };

const width = margin.left + margin.right + features.length * subGraphSize;
const height = margin.top + margin.bottom + features.length * subGraphSize;

const buffer = 50;

const svg = d3
.create("svg")
.attr("viewbox", [0, 0, width, height])
.style("height", `${height}px`)
.style("width", `${width}px`);

const legend = svg.append("g").attr("transform", "translate(0, 0)");
const entries = legend.selectAll("g").data(features).join("g"); // how to pass our text titles?

/////////////////////////////////////////
// Call functions to build our subgraphs!

for (let i = 0; i < features.length; ++i) {
// Iterate over the features only once & manually put the label in both desired locations
svg
.append("text")
.attr("text-anchor", "middle")
.style("font-weight", "bold")
.style("font-size", "12px")
.attr("x", margin.left / 2 - 10)
.attr("y", margin.top + i * subGraphSize + (subGraphSize - buffer) / 2)
.text(features[i]);

svg
.append("text")
.attr("text-anchor", "middle")
.style("font-weight", "bold")
.style("font-size", "12px")
.attr("x", margin.left + i * subGraphSize + (subGraphSize - buffer) / 2)
.attr("y", height - margin.bottom / 2 - margin.top)
.text(features[i]);

for (let j = 0; j < features.length; ++j) {
// go down the columns
if (j >= i) {
let g = make_scatterplot(
svg,
irisData,
features[i], // on the x axis
features[j], // on the y axis
subGraphSize - buffer
);

// Subgraph positioning
const graph_x_pos = margin.left + i * subGraphSize;
const graph_y_pos = margin.top + j * subGraphSize;

g.attr("transform", `translate(${graph_x_pos}, ${graph_y_pos})`);
}
}
}

/////////////////////////////
// FUNCTION SPACE

// Function to build our scatterplot
function make_scatterplot(svg, data, fieldX, fieldY, graphSize) {
// Make subgraph scales
const x = d3
.scaleLinear()
.range([0, graphSize]) // understand spacing later
.domain([0, d3.extent(data, (d) => d[fieldX])[1]]);

const y = d3
.scaleLinear()
.range([graphSize, 0]) // understand spacing later
.domain([0, d3.extent(data, (d) => d[fieldY])[1]]);

// Add in color
const color = d3
.scaleOrdinal()
.range(d3.schemeCategory10)
.domain(data.map((d) => d.species));

// Declare a g for our subgraph & add the circles onto it
const subgraph = svg.append("g");

subgraph
.selectAll("circle")
.data(data)
.join("circle")
.attr("cx", (d) => x(d[fieldX])) // will fieldX and fieldY get properly evaluated here?
.attr("cy", (d) => y(d[fieldY]))
.attr("r", 3) // fixed radius
.style("fill", (d) => color(d.species))
.style("opacity", 0.8);

// Add axes
subgraph
.append("g")
.call(d3.axisBottom(x).ticks(6))
.attr("transform", `translate(0, ${graphSize})`); // xAxis

subgraph.append("g").call(d3.axisLeft(y).ticks(6)); // yAxis

return subgraph;
}

return svg.node();
}
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