Published
Edited
Apr 27, 2021
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);

svg.append("g")
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", xScale(0))
.attr("y", (d, i) => yScale(i))
.attr("height", yScale.bandwidth())
.attr("width", width - margin.left - margin.right)
.attr("fill", "rgba(0,0,0,0.1)");
svg.append("g")
.selectAll("rect")
.data(data)
.join("rect")
.attr("x", xScale(0))
.attr("y", (d, i) => yScale(i))
.attr("height", yScale.bandwidth())
.attr("width", (d,i) => crosstabWidth + barScale(d))
.attr("fill", "rgba(0,0,0,0.2)");
// Inner rectangles and assigning colors by their percentages
data.map((datum, index) => svg.append("g")
.selectAll("rect")
.data(innerRectData)
.join("rect")
.attr("x", (d,i) => innerXScale(i))
.attr("y", (d, i) => yScale(index) + 10)
.attr("height", yScale.bandwidth() - 20)
.attr("width", innerRectWidth)
.attr("fill", (d,i) => getColor(d)));
// Adding text to inner rectangles
data.map((datum, index) => svg.append("g")
.selectAll("text")
.data(innerRectData)
.join('text')
.attr("x", (d,i) => innerXScale(i) + innerRectWidth)
.attr("y", yScale(index) + yScale.bandwidth() - innerPadding * 2)
.attr("dx", "-2.6rem")
.attr("dy", "0.7rem")
.text((d) => `${d}%`)
.style("font-weight", '600')
.attr("fill-opacity", "0.9")
.style('fill', 'white'));
// Bottom labels for categories
svg.append("g")
.selectAll("text")
.data(labelsY)
.join('text')
.attr("x", (d,i) => innerXScale(i) + yScale.bandwidth() / 2)
.attr("y", height - margin.top + 10)
.text((d) => d.label)
.attr("font-weight", '600')
.style("color", 'rgba(0,0,0,0.38)')
.attr("text-anchor", "middle")
.attr("fill-opacity", "0.6")
.style("font-size", '14px');
// Right side labels
svg.append("g")
.selectAll("text")
.data(rightLabelOptions)
.join('text')
.attr("x", (d,i) => width-margin.right)
.attr("y", (d,i) => yScale(i) + yScale.bandwidth())
.attr("dx", "-0.8rem")
.attr("dy", "-2rem")
.text((d) => d.perc)
.attr("font-weight", '600')
.attr("fill-opacity", "0.85")
.style("color", 'rgba(0,0,0,0.38)')
.attr("text-anchor", "end")
.append('tspan')
.text(d => d.label)
.attr("x", (d,i) => width-margin.right)
.attr("y", (d,i) => yScale(i) + yScale.bandwidth())
.attr("dx", "-0.8rem")
.attr("dy", "-0.8rem")
.attr("text-anchor", "end")
.attr("fill-opacity", "0.6")
// Top title
svg.append("text")
.attr("x", margin.left)
.attr("y", margin.top)
.attr("dy", ".35em")
.attr("text-anchor", "start")
.attr("font-weight", '600')
.style("color", 'rgba(0,0,0,0.38)')
.style("font-size", '20px')
.text(chartTitle);
return svg.node();
}
Insert cell
// Functions
Insert cell
xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d)])
.range([margin.left, innerWidth])
Insert cell
yScale = d3.scaleBand()
.domain(d3.range(data.length))
.rangeRound([margin.top, height - margin.bottom])
.padding(0.1)
Insert cell
barScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d)])
.range([0, maxBarWidth])
Insert cell
innerXScale = d3.scaleLinear()
.domain([0, data.length])
.range([margin.left + innerPadding, crosstabWidth])
Insert cell
getColor = d3.scaleThreshold()
.domain([10, 20, 30, 40, 50, 60, 70, 80, 90])
.range(innerRectColors)
Insert cell
// Change raw data here
Insert cell
labelsY = [
{
label: 'Transportation',
perc: '50%',
},
{
label: 'Accommodation',
perc: '50%',
},
{
label: 'Food',
perc: '50%',
},
{
label: 'Recreation',
perc: '50%',
},
{
label: 'Travel',
perc: '50%',
},
];
Insert cell
rightLabelOptions = [
{
label: 'Government',
perc: '10%',
},
{
label: 'Tourism board',
perc: '39%',
},
{
label: 'Unions & Associations',
perc: '19%',
},
{
label: 'Shareholders',
perc: '21%',
},
{
label: 'Friends & family',
perc: '11%',
},
];
Insert cell
data = [100, 300, 200, 400, 500]
Insert cell
innerRectData = [10, 39, 19, 21, 11]
Insert cell
innerRectColors = [
'#F7DEE0',
'#EFBDC1',
'#E79CA4',
'#DF7C86',
'#D75B67',
'#CF3A49',
'#B52C39',
'#94242F',
'#731C25',
]
Insert cell
// Change parameters here
Insert cell
chartTitle = "Who do you think will be your biggest support in recovery?"
Insert cell
crosstabWidth = data.length * innerRectWidth + (data.length + 1) * innerPadding
Insert cell
maxBarWidth = 150
Insert cell
innerHeight = height - margin.top - margin.bottom
Insert cell
innerWidth = width - margin.left - margin.right
Insert cell
innerRectWidth = 100
Insert cell
innerPadding = 17
Insert cell
width=1000
Insert cell
height = 700
Insert cell
selectedFont = "Roboto"
Insert cell
margin = ({top: 30, right: 0, bottom: 30, left: 40})
Insert cell
// Styles
Insert cell
style = html`
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${selectedFont}:ital@0;1&display=swap;wght:400,700">

<style>
body, svg {
font-family: '${selectedFont}', serif;
}
</style>
`
Insert cell
d3 = require("d3@6")
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