Public
Edited
Jan 30, 2023
1 star
Insert cell
Insert cell
viewof chart = {
const width = 600;
const height = 600;
const csvUrl = 'https://gist.githubusercontent.com/curran/a08a1080b88344b0c8a7/raw/0e7a9b0a5d22642a06d3d5b9bcbad9890c8ee534/iris.csv';
const parseRow = (d) => {
d.sepal_length = +d.sepal_length;
d.sepal_width = +d.sepal_width;
d.petal_length = +d.petal_length;
d.petal_width = +d.petal_width;
return d;
};

const svg = d3.create("svg")
.attr('width', width)
.attr('height', height);

svg.call(
scatterPlot()
.width(width)
.height(height)
.data(await d3.csv(csvUrl, parseRow))
.xValue((d) => d.petal_width)
.yValue((d) => d.sepal_length)
.xLabel('Petal width')
.yLabel('Sepal length')
.title('Iris: petal width and sepal length')
.margin({
top: 70,
right: 70,
bottom: 70,
left: 70,
})
.radius(5)
);

return svg.node();
};
Insert cell
scatterPlot = () => {
// configuration
let width;
let height;
let data; // data as a list of objects
let xValue; // x-axis value accessor function
let yValue; // y-axis value accessor function
let xLabel;
let yLabel;
let title;
let margin;
let radius;
// closure
const my = (selection) => {
const x = d3.scaleLinear()
.domain(d3.extent(data, xValue)).nice()
.range([margin.left, width - margin.right]);

const y = d3.scaleLinear()
.domain(d3.extent(data, yValue)).nice()
.range([height - margin.bottom, margin.top]);

const markerData = data.map((d) => ({
x: x(xValue(d)),
y: y(yValue(d))
}));

selection
.selectAll('circle')
.data(markerData)
.join('circle')
.attr('cx', (d) => d.x)
.attr('cy', (d) => d.y)
.attr('r', radius);

selection
.selectAll('.y-axis')
.data([null])
.join('g')
.attr('class', 'y-axis')
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(y));

selection
.selectAll('.y-axis-label')
.data([null])
.join('text')
.attr('class', 'y-axis-label')
.text(yLabel)
.attr('text-anchor', 'middle')
.attr('transform', 'rotate(-90)')
.attr('x', -height / 2)
.attr('y', margin.left / 2);

selection
.selectAll('.x-axis')
.data([null])
.join('g')
.attr('class', 'x-axis')
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));

selection
.selectAll('.x-axis-label')
.data([null])
.join('text')
.attr('class', 'x-axis-label')
.attr('text-anchor', 'middle')
.attr('x', width / 2)
.attr('y', height - margin.bottom / 2)
.text(xLabel);

selection
.selectAll('.title')
.data([null])
.join('text')
.attr('class', 'title')
.text(title)
.attr('text-anchor', 'middle')
.attr('x', width / 2)
.attr('y', margin.top / 2);
};

// getter-setter methods
my.width = function (_) {
return arguments.length ? ((width = +_), my) : width;
}

my.height = function (_) {
return arguments.length ? ((height = +_), my) : height;
}

my.data = function (_) {
return arguments.length ? ((data = _), my) : data;
}

my.xValue = function (_) {
return arguments.length ? ((xValue = _), my) : xValue;
}

my.yValue = function (_) {
return arguments.length ? ((yValue = _), my) : yValue;
}

my.xLabel = function (_) {
return arguments.length ? ((xLabel = _), my) : xLabel;
}

my.yLabel = function (_) {
return arguments.length ? ((yLabel = _), my) : yLabel;
}

my.title = function (_) {
return arguments.length ? ((title = _), my) : title;
}

my.margin = function (_) {
return arguments.length ? ((margin = _), my) : margin;
}

my.radius = function (_) {
return arguments.length ? ((radius = +_), my) : radius;
}

return my;
}
Insert cell
Insert cell
Insert cell
(1, 2, 3)
Insert cell
{
let x;
const y = (x = 5, 3);
return [x, y];
}
Insert cell
Insert cell
noArguments = (_) => {
return arguments; // Oops!
}
Insert cell
yesArguments = function (_) {
return arguments;
}
Insert cell
yesArguments("param")
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