Public
Edited
Jul 31, 2023
Insert cell
Insert cell
viewof height = Inputs.range([1, 2000], {label: "Chart height", step: 1, value: 200})
Insert cell
viewof shapeSize = Inputs.range([1, 2000], {label: "Chart height", step: 1, value: 10})
Insert cell
viewof row1 = Inputs.range([1, 20], {label: "Chart rows", step: 1, value: 10})
Insert cell
viewof col1 = Inputs.range([1, 20], {label: "Chart cols", step: 1, value: 10})
Insert cell
Math.floor(height/2/row1)
Insert cell
grid = {
const width = height/2;
const chartHeight = height + margin.top * 2;
let svg = DOM.svg(width, chartHeight);
let activeFill = '#3dbd5d';
let passiveFill = '#d8d8d8';
const scaleX = d3.scaleLinear()
.domain([0, Math.floor(width/col1)])
.range([0, width])

const scaleY = d3.scaleLinear()
.domain([0, Math.floor(chartHeight/row1)])
.range([0, chartHeight])
const g = d3.select(svg)
.selectAll('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)

const render = g.selectAll(shape)
.data(d3.range(100))
.join('circle')
.attr('stroke-width', 1)
.attr('stroke', 'white')
// note < not <= as counting from 0
.attr('fill', (d, i) => (i < value) ? activeFill : passiveFill)
return svg;

}
Insert cell
Insert cell
waffle2(value, {
bind: d3.select(vis), // pass in the selection
activeFill: '#3dbd5d',
shapeSize: shape,
shape: 'rect',
})
Insert cell
vis = html`<div class="vis-cc"></div>`
Insert cell
viewof value = Inputs.range([1, 100], {label: "Pct", step: 1, value: 45})
Insert cell
viewof test = Inputs.range([1, 20], {label: "Sizes", step: 1, value: 10})
Insert cell
viewof shape = Inputs.range([1, 20], {label: "Sizes", step: 1, value: 5})
Insert cell
function waffle2 (value = 90, {
bind = null, // pass in a d3 selection i.e d3.select('class/div')
shape = 'circle', // 'circle' 'rect'
activeFill = '#008cbc', // colour of the square or circle
passiveFill = '#e5e7de', // when there is no value
strokeCol = '#666666',
shapeSize = 20,
strokeWidth = 0,
margin = {
top: shapeSize,
right: shapeSize,
bottom: shapeSize,
left: shapeSize,
}
} = {}) {

const size = (shapeSize + (strokeWidth * 2)) * test

// append the svg if first render
if (bind.select('svg').empty()) {
bind
.append('svg')
.attr('width', width)//size + margin.left + margin.right)
.attr('height', size + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
.call(grid10by10)
}

function grid10by10 (sel) {
const scaleX = d3.scaleLinear()
.domain([0, 9])
.range([0, shapeSize * test])

const scaleY = d3.scaleLinear()
.domain([0, 9])
.range([shapeSize * test, 0])

const render = sel.selectAll(shape)
.data(d3.range(100))
.join(shape)
.attr('stroke-width', strokeWidth)
.attr('stroke', strokeCol)
// note < not <= as counting from 0
.attr('fill', (d, i) => (i < value) ? activeFill : passiveFill)

if (shape === 'rect') {
render
.attr('x', (d, i) => {
const n = i % test
return scaleX(n)
})
.attr('y', (d, i) => {
const n = Math.floor(i / test)
return scaleY(n)
})
.attr('width', shapeSize)
.attr('height', shapeSize)
} else {
render
.attr('cx', (d, i) => {
const n = i % test
return scaleX(n)
})
.attr('cy', (d, i) => {
const n = Math.floor(i / test)
return scaleY(n)
}).attr('r', shapeSize / 2)
}
}

return bind.select('svg g').call(grid10by10)

}
Insert cell
Insert cell
margin = ({left: 10, top: 10})
Insert cell
n = 1000
Insert cell
rows = Math.round(n / cols)
Insert cell
td = [...Array(n).keys()];
Insert cell
scaleX = d3.scaleBand().domain(d3.range(rows)).range([margin.left, chartWidth * sCW])
Insert cell
scaleY = d3.scaleBand().domain(d3.range(cols)).range([margin.top, radius * rows + padding * (rows)])
Insert cell
viewof sCW = Inputs.range([0, 1], {value: 0.15, step: 0.1, label: "Sectioning"})
Insert cell
viewof cols = Inputs.range([0, 200], {value: 2, step: 1, label: "Columns"})
Insert cell
viewof radius = Inputs.range([0, 20], {value: 2, step: 0.1, label: "Radius"})
Insert cell
viewof padding = Inputs.range([0, 50], {value: 10, step: 0.1, label: "Padding"})
Insert cell
block(2000)
Insert cell
Insert cell
viewof scale = Inputs.range([0, 1], {value: 0.3, step: 0.1, label: "Scale"})
Insert cell
waffle(data, 2012)
Insert cell
waffle(data, 2011)
Insert cell
waffle(data, 2016)
Insert cell
function waffle(data, year) {
const svg = DOM.svg(width, chartHeight);
let nRow = 0;

let subdf = data.filter(row => row.Year === year);
// console.log('!!!', subdf);

let objs = [];
for (let j in subdf) {
let row = subdf[j];
let num = row['nCase'];
if (num > 0) {
for (let k in d3.range(num)){
objs.push({Status: row['Status'], Category: row['Category'], Number: k})
}
}
}
const g = d3.select(svg)
.selectAll('g')
g.data(objs)
.enter()
.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`)
.attr('id', (d, i) => `circle-${i}`)
.attr('transform', (d, i) => {
return `translate(${scaleX(i%cols)}, ${scaleY(Math.floor(i/cols))}) scale(${scale})`
})
.append('path')
.attr('d', d => pathScale[d.Category])
.attr('fill', d => colorScale(d.Category));
// .attr('r', radius);

return svg;

}
Insert cell
pathScale = ({'Successful': diamondSVG, 'Unsuccessful': circleSVG, 'Pending': squareSVG, 'Unsure': petalSVG})
Insert cell
colorScale = d3.scaleOrdinal().domain(['Successful', 'Unsuccesful', 'Pending', 'Unsure']).range(d3.schemeSet3);
Insert cell
diamondSVG = "M0,0 C-1,-15 -25,-30 -10,-50 C-10,-40 10,-40 10,-50 C25,-30 1,-15 0,0"
Insert cell
circleSVG = "M 0,0 C -10,-20 -20,-30 0,-50 C 20,-30 10,-20 0,0"
Insert cell
squareSVG = "M 0,0 C -10,-10 -30,-50 0,-50 C 30,-50 10,-10 0,0"
Insert cell
petalSVG = 'M 0,0 C -40,-10 -20,-40 0,-50 C 20,-40 40,-10 0,0';
Insert cell
radius
Insert cell
html `<svg width="${50}" height="${50}"><path transform="translate(25,50)" d="${diamondSVG}"></svg>`
Insert cell
html `<svg width="${50}" height="${50}"><path transform="translate(25,50)" d="${circleSVG}"></svg>`
Insert cell
html `<svg width="${50}" height="${50}"><path transform="translate(25,50)" d="${squareSVG}"></svg>`
Insert cell
html `<svg width="${50}" height="${50}"><path transform="translate(25,50)" d="${petalSVG}"></svg>`
Insert cell
Insert cell
Insert cell
svgSize = 50
Insert cell
Insert cell
xAxis = g => g
.attr("transform", `translate(0, ${chartHeight - 50})`)
.style("font-size", "1.4em")
.call(d3.axisBottom(xScale)
.tickValues(xAxisTicks)
.tickFormat(d3.format('d')))
Insert cell
xAxisTicks = xScale.ticks()
.filter(tick => Number.isInteger(tick));
Insert cell
xScale = d3.scaleLinear()
.domain(d3.extent(data, d => d.Year))
.range([20, chartWidth - 30])
Insert cell
waffleWidth = chartWidth / data.length
Insert cell
chartHeight = 300
Insert cell
chartWidth = 900
Insert cell
Insert cell
Insert cell
Insert cell
nData = {
for (let i in data){
data[i]['nCase'] = Math.round(data[i]['Cases']/10)
}

return data;

}
Insert cell
Insert cell
years = [...new Set(data.map(row=> row.Year))]//.sort()
Insert cell
data = FileAttachment("annulment-nullity-transposed.csv").csv({typed: true})
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