A Marimekko Chart, inspired by Freakalytics. Thanks to Noah Iliinsky for the suggestion. Jason Davies has published an even-simpler interactive implementation using the “slice-dice” treemap layout algorithm!
Last active
February 26, 2019 22:38
-
-
Save mbostock/1005090 to your computer and use it in GitHub Desktop.
Marimekko Chart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: gpl-3.0 | |
redirect: https://observablehq.com/@d3/d3-marimekko-chart |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<title>Marimekko Chart</title> | |
<style> | |
body { | |
font: 10px sans-serif; | |
} | |
rect { | |
stroke: #000; | |
} | |
svg { | |
shape-rendering: crispEdges; | |
} | |
</style> | |
<body> | |
<script src="//d3js.org/d3.v3.min.js"></script> | |
<script> | |
var width = 960, | |
height = 500, | |
margin = 20; | |
var x = d3.scale.linear() | |
.range([0, width - 3 * margin]); | |
var y = d3.scale.linear() | |
.range([0, height - 2 * margin]); | |
var z = d3.scale.category10(); | |
var n = d3.format(",d"), | |
p = d3.format("%"); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height) | |
.append("g") | |
.attr("transform", "translate(" + 2 * margin + "," + margin + ")"); | |
d3.json("marimekko.json", function(error, data) { | |
if (error) throw error; | |
var offset = 0; | |
// Nest values by segment. We assume each segment+market is unique. | |
var segments = d3.nest() | |
.key(function(d) { return d.segment; }) | |
.entries(data); | |
// Compute the total sum, the per-segment sum, and the per-market offset. | |
// You can use reduce rather than reduceRight to reverse the ordering. | |
// We also record a reference to the parent segment for each market. | |
var sum = segments.reduce(function(v, p) { | |
return (p.offset = v) + (p.sum = p.values.reduceRight(function(v, d) { | |
d.parent = p; | |
return (d.offset = v) + d.value; | |
}, 0)); | |
}, 0); | |
// Add x-axis ticks. | |
var xtick = svg.selectAll(".x") | |
.data(x.ticks(10)) | |
.enter().append("g") | |
.attr("class", "x") | |
.attr("transform", function(d) { return "translate(" + x(d) + "," + y(1) + ")"; }); | |
xtick.append("line") | |
.attr("y2", 6) | |
.style("stroke", "#000"); | |
xtick.append("text") | |
.attr("y", 8) | |
.attr("text-anchor", "middle") | |
.attr("dy", ".71em") | |
.text(p); | |
// Add y-axis ticks. | |
var ytick = svg.selectAll(".y") | |
.data(y.ticks(10)) | |
.enter().append("g") | |
.attr("class", "y") | |
.attr("transform", function(d) { return "translate(0," + y(1 - d) + ")"; }); | |
ytick.append("line") | |
.attr("x1", -6) | |
.style("stroke", "#000"); | |
ytick.append("text") | |
.attr("x", -8) | |
.attr("text-anchor", "end") | |
.attr("dy", ".35em") | |
.text(p); | |
// Add a group for each segment. | |
var segments = svg.selectAll(".segment") | |
.data(segments) | |
.enter().append("g") | |
.attr("class", "segment") | |
.attr("xlink:title", function(d) { return d.key; }) | |
.attr("transform", function(d) { return "translate(" + x(d.offset / sum) + ")"; }); | |
// Add a rect for each market. | |
var markets = segments.selectAll(".market") | |
.data(function(d) { return d.values; }) | |
.enter().append("a") | |
.attr("class", "market") | |
.attr("xlink:title", function(d) { return d.market + " " + d.parent.key + ": " + n(d.value); }) | |
.append("rect") | |
.attr("y", function(d) { return y(d.offset / d.parent.sum); }) | |
.attr("height", function(d) { return y(d.value / d.parent.sum); }) | |
.attr("width", function(d) { return x(d.parent.sum / sum); }) | |
.style("fill", function(d) { return z(d.market); }); | |
}); | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{"market": "Auburn, AL", "segment": "Almond lovers", "value": 3840}, | |
{"market": "Auburn, AL", "segment": "Berry buyers", "value": 1920}, | |
{"market": "Auburn, AL", "segment": "Carrots-n-more", "value": 960}, | |
{"market": "Auburn, AL", "segment": "Delicious-n-new", "value": 400}, | |
{"market": "Birmingham, AL", "segment": "Almond lovers", "value": 1600}, | |
{"market": "Birmingham, AL", "segment": "Berry buyers", "value": 1440}, | |
{"market": "Birmingham, AL", "segment": "Carrots-n-more", "value": 960}, | |
{"market": "Birmingham, AL", "segment": "Delicious-n-new", "value": 400}, | |
{"market": "Gainesville, FL", "segment": "Almond lovers", "value": 640}, | |
{"market": "Gainesville, FL", "segment": "Berry buyers", "value": 960}, | |
{"market": "Gainesville, FL", "segment": "Carrots-n-more", "value": 640}, | |
{"market": "Gainesville, FL", "segment": "Delicious-n-new", "value": 400}, | |
{"market": "Durham, NC", "segment": "Almond lovers", "value": 320}, | |
{"market": "Durham, NC", "segment": "Berry buyers", "value": 480}, | |
{"market": "Durham, NC", "segment": "Carrots-n-more", "value": 640}, | |
{"market": "Durham, NC", "segment": "Delicious-n-new", "value": 400} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment