Public
Edited
Jul 12, 2023
12 stars
Insert cell
Insert cell
Insert cell
Insert cell
lol_dataset
Insert cell
{
const svg = d3.create('svg').attr('viewBox', [0,0,width, height]).style('background', "#463152")

const wrapper = svg.append('g').attr("transform", `translate(${margin.left},${margin.top})`)

const node = wrapper.selectAll('g').data(lol_dataset.nodes).join('g').attr('transform', function(d) { return `translate(${d.x},${ d.y})`}).call(create_node)

// init simulation
const simulation = d3.forceSimulation();
simulation.nodes(lol_dataset.nodes);

// annotations and descriptions
const desc_group = svg.append('g').attr('transform', `translate(30,30)`)
desc_group.append('text').text("Red side vs Blue Side Pick Rate, Patch(11.13 and 11.14)").attr('fill', "white")
desc_group.append('text').attr('transform', `translate(${0}, ${30})`).text(`Region ${curr_region}`).attr('fill', "white").attr('font-size', 30)
wrapper.append("g").attr('transform', `translate(${0},${margin.top})`).call(xAxis)
wrapper.append('line')
.attr('stroke', 'white')
.attr('opacity', 0.8)
.style('stroke-dasharray', '5,5')
.attr('fill', 'white')
.attr('x1', x(0.5))
.attr('y1', 0)
.attr('x2', x(0.5))
.attr('y2', innerHeight)
wrapper.append('text').attr('transform', `translate(${x(0.5)}, ${40})`).text('50% pickrate').attr('fill', 'white').attr('align-text', 'center')

// simulation force
simulation.force("charge", d3.forceManyBody())
.force('y', d3.forceY().y(y('All')).strength(0.1))
.force('x', d3.forceX().x(d => x(parseFloat(d.data[curr_region].red_weight))).strength(1))
.force('collide',d3.forceCollide().radius(function(d) { return r(d.data[curr_region].totalpickrate) + 15}))
simulation.alpha(1).alphaDecay(0.01).velocityDecay(0.36)
simulation.on('tick', () => {
node.transition().duration(700).ease(d3.easeLinear).attr('transform', function(d) {
return `translate(${d.x},${ d.y})`})
})
return Object.assign(svg.node(), {
update(curr_region) {
simulation.alpha(1).alphaDecay(0.01).velocityDecay(0.36 ).restart()
}
});
}

Insert cell
lol_dataset
Insert cell
Insert cell
create_node = (node) => {
node.append('defs').append("clipPath") // define a clip path
.attr("id", d => `circle-clip-${d.champion}`) // give the clipPath an ID
.append("rect") // shape it as an ellipse
.attr("x", v => r(v.data[curr_region].totalpickrate) - 1 * r(v.data[curr_region].totalpickrate) * 2 * calculate_circular_segment(v.data[curr_region].red_weight)) // position the x-centre
.attr("y", v => {return (-r(v.data[curr_region].totalpickrate))}) // position the y-centre
.attr("width", v => calculate_circular_segment(v.data[curr_region].red_weight) * r(v.data[curr_region].totalpickrate) * 2) // set the x radius
.attr("height", v => r(v.data[curr_region].totalpickrate) * 2)
node.append('circle').attr('r', v => r(v.data[curr_region].totalpickrate)).attr('fill', "#5496d0")
node.append('circle').attr('r', v => r(v.data[curr_region].totalpickrate)).attr('clip-path', d => `url(#circle-clip-${d.champion})`).attr('fill', "#f51641")
node.append('text').attr('text-anchor', 'middle').text(v => v.champion).attr('font-size', 15).attr('y', v => r(v.data[curr_region].totalpickrate) > 10 ? 0 : -12).attr('fill', "whitesmoke")

node.attr('opacity', 0.9)
}
Insert cell
calculate_circular_segment = (f) => {
// From Mike Bostock Wonderful Notebook https://observablehq.com/@mbostock/circular-segment
let h = f;
if (h > 0 && h < 1) {
let t0,
t1 = Math.pow(12 * h * Math.PI, 1 / 3);
for (let i = 0; i < 10; ++i) {
t0 = t1;
t1 =
(Math.sin(t0) - t0 * Math.cos(t0) + 2 * h * Math.PI) /
(1 - Math.cos(t0));
}
h = (1 - Math.cos(t1 / 2)) / 2;
}
return h;
}
Insert cell
lol_dataset = FileAttachment("lol_dataset.json").json()
Insert cell
Insert cell
margin = ({"top":50, "bottom":50, "left":150, "right":150})
Insert cell
height = 1200
Insert cell
width = 800
Insert cell
innerHeight = height-margin.top-margin.bottom
Insert cell
innerWidth = width-margin.left-margin.right
Insert cell
y = d3.scaleBand().domain(["All"]).range([0, innerHeight]).padding(1)
Insert cell
r = d3.scaleLinear().domain([0,1]).range([5, width/20])
Insert cell
x = d3.scaleLinear()
.domain([0,1])
.range([0, innerWidth])

Insert cell
Insert cell
xAxis = g => g
.call(d3.axisTop(x).ticks(0))
.call(g => g.select('.text').remove())
.call(g => g.selectAll('.tick line').remove())
.call(g => g.select('.domain').remove())
.call(g => g.append('text')
.attr('x', -10)
.attr('y', 0)
.attr('font-weight', 'bold')
.attr('font-size', "0.65rem")
.attr('fill', 'white')
.attr('text-anchor', 'end')
.text('← Blue Pick Rate'))
.call(g => g.append('text')
.attr('x', x(1)+10)
.attr('y', 0)
.attr('font-weight', 'bold')
.attr('font-size', "0.65rem")
.attr('fill', 'white')
.attr('text-anchor', 'start')
.text('Red Pick Rate →'))


Insert cell
yAxis = g => g
.call(d3.axisLeft(y) .tickFormat(d => `${d} `).ticks(0))
.call(g => g.select('.text').remove())
.call(g => g.append('text')
.attr('x', 0)
.attr('y', 0)
.attr('font-weight', 'bold')
.attr('font-size', "0.87rem")
.attr('fill', 'white')
.attr('text-anchor', 'start')
.text('50% Pick Rate'))
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