Public
Edited
Nov 7, 2023
Insert cell
Insert cell
vis = html`<div class="vis-cc"></div>`
Insert cell
concentricPctLines(value, {
bind: d3.select(vis), // pass in the selection
modulus: 5, // i.e each circle is 5%
scaleSqrt: scaleToggle
})
Insert cell
Insert cell
Insert cell
function concentricPctLines (datum, {
bind = null, // pass in a d3 selection i.e d3.select('class/div')
margin = {top: 10, right: 10, bottom: 30, left: 10},
circleSize = 100,
width = (circleSize * 2) + (margin.left + margin.right),
height = circleSize * 1.8 + (margin.top + margin.bottom),
modulus = 5, // what % each circle represents
col = {
active: '#1b3644',
passive: '#ffa6d9'
},
strokeWidth = 1,
domain = [0, 100],
range = [0, circleSize],
scaleSqrt = true // if to use scaleSqrt scale or even distribution
} = {}) {

// set the dimensions and margins of the graph
const w = width - margin.left - margin.right
const h = height - margin.top - margin.bottom
bind.selectAll('svg').remove();
const sel = bind.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);

const scale = (scaleSqrt)? d3.scaleSqrt() : d3.scaleLinear();
scale.domain(domain).range(range);

const r = scale(circleSize); // radius of full circle
const translate = `translate(${width / 2},${(height - margin.bottom) / 2 })`;

const passive = sel.append('g')
.attr('class', 'g-passive-wrap')
.attr('transform', translate);

const active = sel.append('g')
.attr('class', 'g-active-wrap')
.attr('transform', translate);

// passive (background) circle(s)
passive.selectAll('circle')
.data(d3.range(domain[1]))
.join('circle')
.attr('r', d => {
if ((d % modulus) == 0){
return scale(d + 1)
} else {
return 0
}
})
.attr('fill', 'transparent')
.attr('stroke', col.passive)
.style('opacity', 0.4)
.attr('stroke-width', strokeWidth);

// active circle(s)
active.selectAll('circle')
.data(d3.range(datum))
.join('circle')
.attr('r', d => {
if ((d % modulus) == 0){
return scale(d + 1)
} else {
return 0
}
})
.attr('fill', 'transparent')
.attr('stroke', col.active)
.attr('stroke-width', strokeWidth);
// show pct
active.append('text')
.attr('class', 'percent-label')
.attr('y', r)
.attr('dy', 15)
.style('text-anchor', 'middle')
.text(datum + '%');

return sel;

}
Insert cell
Insert cell
Insert cell
Insert cell
visWrap = html`<div class="vis-1 flex flex-wrap "></div>`
Insert cell
[30, 45, 25, 80, 60, 5, 20, 25, 15, 10, 90, 50].forEach((d, i) => {
const div = d3.select(visWrap).append('div').attr('class', 'ref-' + i)
concentricPctLines(d, {
bind: d3.select(visWrap).select('.ref-' + i),
margin: {top: 30, right: 30, bottom: 50, left: 10},
modulus: 5, // i.e each circle is 5%
scaleSqrt: scaleToggle,
col: {
active: '#ed3d66',
passive: '#33ff7d'
}
})
})
Insert cell
<hr>
<link href="https://fonts.googleapis.com/css?family=Space+Mono" rel="stylesheet">
<link href="https://unpkg.com/basscss@8.0.2/css/basscss.min.css" rel="stylesheet">
<style>
text {
font-family:'Space Mono',monospace;
fill: #130C0E;
font-size: 11px;
}
</style>
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