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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more