Published unlisted
Edited
Sep 25, 2020
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
main_plot = {
// our SVG element
let svg = d3.create('svg').attr('width', width).attr('height', height)
// group element to center our plot, provide margins for axes/labels -> add your elements to this <g> element
let g = svg.append('g').attr('transform', `translate(${pad},${pad})`)
let books_link = g
.selectAll('path')
.data(link_data)
.enter()
.append('path')
books_link
.attr('class', d => book_counts[d.title] >= min_weeks ? 'selectedlink' : 'backgroundlink')
.attr('d', d => link(d))
.attr('fill', 'none')
.attr('stroke', d3.hcl(0,0,80))
.attr('opacity', .4)
.attr('stroke-width', point_radius)
g.selectAll('.selectedlink')
.attr('stroke', d => d3.hcl(top_books_hues(d.title),28,45))
.attr('opacity', d => .8)
g.selectAll('.backgroundlink').lower()
let books_circle = g
.selectAll('circle')
.data(data)
.enter()
.append('circle')
books_circle
.attr('class', d => book_counts[d.title] >= min_weeks ? 'selectedcircle' : 'backgroundcircle')
.attr('cx', d => time_scale(d.date)).attr('cy', d => rank_scale(d.rank))
.attr('r', point_radius)
.attr('fill', d3.hcl(0,0,84))
.attr('stroke', d3.hcl(0,0,22)).attr('stroke-width', 1)
g.selectAll('.selectedcircle')
.attr('fill', d => d3.hcl(top_books_hues(d.title),30,66))
g.append('g').attr('class', 'left axis').attr('transform', 'translate(-5,0)')
.call(d3.axisLeft(rank_scale))
g.select('.left').selectAll('.tick').selectAll('line').remove()
g.select('.left').select('.domain').remove()
g.select('.left').selectAll('text')
.attr('fill', d3.hcl(0,0,50)).attr('font-weight', 'bold').attr('font-size', '13px')
g.append('text')
.attr('transform', `translate(-35,${plot_height/2}) rotate(270)`).attr('text-anchor', 'middle')
.text('Ranking').attr('fill', d3.hcl(0,0,35)).attr('font-weight', 'bold')
g.append('g').attr('class', 'bottom axis').attr('transform', `translate(0,${plot_height+6})`)
.call(d3.axisBottom(time_scale).ticks(5))
g.select('.bottom').selectAll('.tick').selectAll('line').remove()
g.select('.bottom').select('.domain').remove()
g.select('.bottom').selectAll('text')
.attr('fill', d3.hcl(0,0,50)).attr('font-weight', 'bold').attr('font-size', '13px')
g.append('text')
.attr('transform', `translate(${plot_width/2},${plot_height+46})`).attr('text-anchor', 'middle')
.text('Week').attr('fill', d3.hcl(0,0,35)).attr('font-weight', 'bold')
return svg.node()
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
time_scale = d3.scaleTime().domain(time_extent).range([0,plot_width])
Insert cell
Insert cell
rank_scale = d3.scalePoint().domain(ranking_extent).range([0,plot_height])
Insert cell
point_radius = rank_scale.step()/4
Insert cell
Insert cell
top_books_hues = {
let top_books = []
for(let title in book_counts) {
if(book_counts[title] >= min_weeks)
top_books.push({title:title,count:book_counts[title]})
}
top_books.sort((a,b) => b.count-a.count)
return d3.scalePoint().domain(top_books.map(d => d.title)).range([0,360]).padding(.5)
}
Insert cell
Insert cell
Insert cell
time_extent = d3.extent(data.map(d => d.date))
Insert cell
Insert cell
ranking_extent = d3.range(d3.max(data, d => d.rank)).map(d => d+1)
Insert cell
Insert cell
Insert cell
book_counts = {
let book_obj = {}
for(let i = 0; i < data.length; i++) {
if(!(data[i].title in book_obj))
book_obj[data[i].title] = 0
book_obj[data[i].title] += 1
}
return book_obj
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
n_weeks = d3.set(data, d => d.date).values().length
Insert cell
Insert cell
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