Public
Edited
Jun 6
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// style
// css style definition

html`<style>
body {
font-family: sans-serif;
margin: 0;
overflow: hidden;
}
.tick text {
font-size: 20px;
}
</style>`

// .tick text is a css selector, it selects tick elements and then look for children of that element of type 'text'
Insert cell
// our scatterplot component, it is a function that returns a function (?)
// is going to be used as aa d3 access
// 'my' is the instance of the chart

scatterPlot = () => {
let width; // default value, can be overridden
let height = 500;
let data;
let xValue;
let yValue;
let margin;
let radius;
const my = (selection) => {
const x = d3.scaleLinear()
.domain(d3.extent(data, xValue))
.range([margin.left, width-margin.right]);
const y = d3.scaleLinear()
.domain(d3.extent(data, yValue))
.range([height-margin.bottom, margin.top]);
const marks = data.map(d => ({
x: x(xValue(d)),
y: y(yValue(d)),
}));
selection
.selectAll('circle')
.data(marks)
.join('circle')
.attr('cx', (d) => d.x)
.attr('cy', (d) => d.y)
.attr('r', radius)
.attr('stroke', 'black');

selection.append('g')
.attr(
'transform',
`translate(${margin.left}, 0)`)
.call(d3.axisLeft(y));
selection.append('g')
.attr(
'transform',
`translate(0, ${height-margin.bottom})`)
.call(d3.axisBottom(x));
}

// Getter-setter for width (width is a property)
// if it's invoked with no args then it returns the default width
my.width = function (_) {
return arguments.length ? ((width = +_), my) : width; // +_ make the api more robust, it is called defensive programming
};

// Getter-setter for height
my.height = function (_) {
return arguments.length ? ((height = +_), my) : height;
};

// Getter-setter for data
my.data = function (_) {
return arguments.length ? ((data = _), my) : data;
};

// Getter-setter for xValue
my.xValue = function (_) {
return arguments.length ? ((xValue = _), my) : xValue;
};

// Getter-setter for yValue
my.yValue = function (_) {
return arguments.length ? ((yValue = _), my) : yValue;
};

// Getter-setter for margin
my.margin = function (_) {
return arguments.length ? ((margin = _), my) : margin;
};

// Getter-setter for radius
my.radius = function (_) {
return arguments.length ? ((radius = +_), my) : radius;
};
return my;
}
Insert cell
// much more concise

{
const width = 960;
const height = 500;
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

const csvUrl = [
'https://gist.githubusercontent.com/',
'curran/', // user
'a08a1080b88344b0c8a7/', // id of the gist
'raw/0e7a9b0a5d22642a06d3d5b9bcbad9890c8ee534/', // commit
'iris.csv' // file name
].join('');
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 main = async () => {
svg.call(
scatterPlot() // constructor of the scatterplot
.width(width)
//.height(height) // example
.data(await d3.csv(csvUrl, parseRow)) // we fetch the data here
.xValue((d) => d.petal_width) // pass a function
.yValue((d) => d.petal_length)
.radius(5)
.margin({
top: 20,
right: 20,
bottom: 70,
left: 70
})
);
};
main();

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