Published
Edited
Dec 18, 2020
1 fork
4 stars
Insert cell
Insert cell
Insert cell
Insert cell
chart = {

// note: width and height are the same value
// d3.randomNormal() picks normally-distributed, random numbers
// first argument is expected value, second is std-dev
// more here: https://github.com/d3/d3-random#randomNormal
const randomGenerator = d3.randomNormal( 0, width / 8 )
const data = d3.range(0,500).map(d => ({
x: randomGenerator(),
y: randomGenerator()
}))
const xScale = d3.scaleLinear([ -width/2, width/2 ], [ -width/2, width/2 ]),
yScale = d3.scaleLinear([ -height/2, height/2 ], [ -height/2, height/2 ])
const svg = d3.create('svg')
.attr('width', width)
.attr('height', height)
// We'll be calling the brush on this <g>
// note that it's translated to the center of the viewport
const container = svg.append('g')
.attr('class', 'container')
.attr('transform', `translate(${ width/2 },${ height/2 })`)
const points = container.selectAll('circle.point')
.data( data )
.join('circle')
.attr('class', 'point')
.attr('cx', d => xScale( d.x ))
.attr('cy', d => yScale( d.y ))
.attr('r', 8)
.style('fill', color)
.style('opacity', 0.8)
// our axes - remember these?
const xAxis = d3.axisBottom( xScale )
container.append('g').call( xAxis )
const yAxis = d3.axisLeft( yScale )
container.append('g').call( yAxis )
// remove all text elements on the axes (design choice)
container.selectAll('.tick text').remove()
return svg.node()
}
Insert cell
// color set by how far from the center the point is
color = (d) => d3.interpolateViridis( Math.hypot(d.x, d.y) / Math.hypot(width/4, width/4) )
Insert cell
Insert cell
brush = d3.brush()
.extent([ [ -width/2, -width/2 ], [ width/2, width/2] ])
.on('start', brushStart)
.on('brush', brushing)
Insert cell
Insert cell
brushStart = function({selection}) {
const sameX = selection[0][0] === selection [1][0],
sameY = selection[0][1] === selection [1][1]
if(sameX && sameY) {
const points = d3.select( chart ).selectAll('circle.point')
points.style('fill', color)
}
}
Insert cell
Insert cell
brushing = function({ selection }) {
const points = d3.select( chart ).selectAll('circle.point')
// If our selection is null, there's a problem, so color all of our points in
if( selection === null ) {

points.style('fill', color)

} else {
// First get the selection x coords in one array and the selection y coords in another
const sx = [ selection[0][0], selection[1][0] ],
sy = [ selection[0][1], selection[1][1] ]
points.style('fill', d => {
// Check whether or not each point is within the x and y coordinates of the selection area
const inRangeX = d.x >= sx[0] && d.x < sx[1],
inRangeY = d.y >= sy[0] && d.y < sy[1]
if(inRangeX && inRangeY) {
// If the point is within the selection range, color it in
return color(d)
} else {
// Otherwise, it's gray
return '#ccc'
}
})
}
}

Insert cell
Insert cell
d3.select( chart )
.select('g.container')
.call( brush )
Insert cell
Insert cell
Insert cell
width = 500
Insert cell
height = 500
Insert cell
d3 = require('d3@6')
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