Skip to content

Instantly share code, notes, and snippets.

@davidherczeg
Last active April 3, 2018 06:32
Show Gist options
  • Save davidherczeg/f86d0f35ad9c75235df7935db787cb30 to your computer and use it in GitHub Desktop.
Save davidherczeg/f86d0f35ad9c75235df7935db787cb30 to your computer and use it in GitHub Desktop.
D3 Notebook: Playing With Bubble Charts
license: mit
name calories protein fat sodium fiber carbohydrates sugars potassium vitamins
100% Bran 70 4 1 130 10 5 6 280 25
100% Natural Bran 120 3 5 15 2 8 8 135 0
All-Bran 70 4 1 260 9 7 5 320 25
All-Bran with Extra Fiber 50 4 0 140 14 8 0 330 25
Almond Delight 110 2 2 200 1 14 8 -1 25
Apple Cinnamon Cheerios 110 2 2 180 1.5 10.5 10 70 25
Apple Jacks 110 2 0 125 1 11 14 30 25
Basic 4 130 3 2 210 2 18 8 100 25
Bran Chex 90 2 1 200 4 15 6 125 25
Bran Flakes 90 3 0 210 5 13 5 190 25
Cap'n'Crunch 120 1 2 220 0 12 12 35 25
Cheerios 110 6 2 290 2 17 1 105 25
Cinnamon Toast Crunch 120 1 3 210 0 13 9 45 25
Clusters 110 3 2 140 2 13 7 105 25
Cocoa Puffs 110 1 1 180 0 12 13 55 25
Corn Chex 110 2 0 280 0 22 3 25 25
Corn Flakes 100 2 0 290 1 21 2 35 25
Corn Pops 110 1 0 90 1 13 12 20 25
Count Chocula 110 1 1 180 0 12 13 65 25
Cracklin' Oat Bran 110 3 3 140 4 10 7 160 25
Cream of Wheat (Quick) 100 3 0 80 1 21 0 -1 0
Crispix 110 2 0 220 1 21 3 30 25
Crispy Wheat & Raisins 100 2 1 140 2 11 10 120 25
Double Chex 100 2 0 190 1 18 5 80 25
Froot Loops 110 2 1 125 1 11 13 30 25
Frosted Flakes 110 1 0 200 1 14 11 25 25
Frosted Mini-Wheats 100 3 0 0 3 14 7 100 25
Fruitful Bran 120 3 0 240 5 14 12 190 25
Fruity Pebbles 110 1 1 135 0 13 12 25 25
Golden Crisp 100 2 0 45 0 11 15 40 25
Golden Grahams 110 1 1 280 0 15 9 45 25
Grape Nuts Flakes 100 3 1 140 3 15 5 85 25
Grape-Nuts 110 3 0 170 3 17 3 90 25
Great Grains Pecan 120 3 3 75 3 13 4 100 25
Honey Graham Ohs 120 1 2 220 1 12 11 45 25
Honey Nut Cheerios 110 3 1 250 1.5 11.5 10 90 25
Honey-comb 110 1 0 180 0 14 11 35 25
Just Right Crunchy Nuggets 110 2 1 170 1 17 6 60 100
Just Right Fruit & Nut 140 3 1 170 2 20 9 95 100
Kix 110 2 1 260 0 21 3 40 25
Life 100 4 2 150 2 12 6 95 25
Lucky Charms 110 2 1 180 0 12 12 55 25
Maypo 100 4 1 0 0 16 3 95 25
Mueslix Crispy Blend 160 3 2 150 3 17 13 160 25
Multi-Grain Cheerios 100 2 1 220 2 15 6 90 25
Nut&Honey Crunch 120 2 1 190 0 15 9 40 25
Nutri-Grain Almond-Raisin 140 3 2 220 3 21 7 130 25
Nutri-grain Wheat 90 3 0 170 3 18 2 90 25
Oatmeal Raisin Crisp 130 3 2 170 1.5 13.5 10 120 25
Post Nat. Raisin Bran 120 3 1 200 6 11 14 260 25
Product 19 100 3 0 320 1 20 3 45 100
Puffed Rice 50 1 0 0 0 13 0 15 0
Puffed Wheat 50 2 0 0 1 10 0 50 0
Quaker Oat Squares 100 4 1 135 2 14 6 110 25
Quaker Oatmeal 100 5 2 0 2.7 -1 -1 110 0
Raisin Bran 120 3 1 210 5 14 12 240 25
Raisin Nut Bran 100 3 2 140 2.5 10.5 8 140 25
Raisin Squares 90 2 0 0 2 15 6 110 25
Rice Chex 110 1 0 240 0 23 2 30 25
Rice Krispies 110 2 0 290 0 22 3 35 25
Shredded Wheat 80 2 0 0 3 16 0 95 0
Shredded Wheat 'n'Bran 90 3 0 0 4 19 0 140 0
Shredded Wheat spoon size 90 3 0 0 3 20 0 120 0
Smacks 110 2 1 70 1 9 15 40 25
Special K 110 6 0 230 1 16 3 55 25
Strawberry Fruit Wheats 90 2 0 15 3 15 5 90 25
Total Corn Flakes 110 2 1 200 0 21 3 35 100
Total Raisin Bran 140 3 1 190 4 15 14 230 100
Total Whole Grain 100 3 1 200 3 16 3 110 100
Triples 110 2 1 250 0 21 3 60 25
Trix 110 1 1 140 0 13 12 25 25
Wheat Chex 100 3 1 230 3 17 3 115 25
Wheaties 100 3 1 200 3 17 3 110 25
Wheaties Honey Gold 110 2 1 200 1 16 8 60 25
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
.buttons {
margin: 40px;
}
circle {
fill: rgb(0, 153, 255);
fill-opacity: 0.25;
stroke: rgb(177, 208, 229);
stroke-width: 4px;
}
text {
text-anchor: middle;
font-family: sans-serif;
}
</style>
</head>
<body>
<div class="container">
<div class="buttons">
<input type="radio" id="calories" name="property" value="calories" onclick="bubbleChart('calories')">
<label for="calories">Calories</label>
<input type="radio" id="protein" name="property" value="protein" onclick="bubbleChart('protein')">
<label for="protein">Protein</label>
<input type="radio" id="fat" name="property" value="fat" onclick="bubbleChart('fat')">
<label for="fat">Fat</label>
<input type="radio" id="sodium" name="property" value="sodium" onclick="bubbleChart('sodium')">
<label for="sodium">Sodium</label>
<input type="radio" id="fiber" name="property" value="fiber" onclick="bubbleChart('fiber')">
<label for="fiber">Fiber</label>
<input type="radio" id="carbohydrates" name="property" value="carbohydrates" onclick="bubbleChart('carbohydrates')">
<label for="carbohydrates">Carbohydrates</label>
<input type="radio" id="sugars" name="property" value="sugars" onclick="bubbleChart('sugars')">
<label for="sugars">Sugars</label>
<input type="radio" id="potassium" name="property" value="potassium" onclick="bubbleChart('potassium')">
<label for="potassium">Potassium</label>
<input type="radio" id="vitamins" name="property" value="vitamins" onclick="bubbleChart('vitamins')">
<label for="vitamins">Vitamins</label>
</div>
<div class="visual">
</div>
</div>
<script>
let width = window.innerWidth;
let height = window.innerHeight;
let svg = d3.select('.visual').append('svg')
.attr('width', width)
.attr('height', height);
function bubbleChart(property) {
let pack = d3.pack()
.size([width, height])
.padding(8);
let units = ['', '', 'g', 'g', 'mg', 'g', 'g', 'g', 'mg', '%']
let duration = 1000;
let delay = 10;
d3.csv('cereal.csv', function(d) {
if (!isNaN(parseFloat(d[property])) && isFinite(d[property])){
d[property] = +d[property];
} else {
throw 'Property value isn\'t a number or doesn\'t exist';
}
return d;
}, function(error, objects) {
if (error) throw error;
let index = objects.columns.indexOf(property)
let root = d3.hierarchy({children: objects})
.sum(d => d[property])
.sort((a, b) => b.value - a.value);
let nodes = svg.selectAll('.node').data([]).exit().remove();
nodes = svg.selectAll('.node')
.data(pack(root).leaves())
.enter().append('g')
.attr('class', 'node')
.attr('transform', d => 'translate(' + d.x + ',' + d.y + ')');
nodes.append('title')
.text(d => '\"' + d.data.name + '\"\n'
+ property.replace(property[0], l => l.toUpperCase())
+ ': ' + d.value + units[index]);
nodes.append('circle')
.transition()
.duration(duration)
.delay((d, i) => i * delay)
.attr('r', d => d.r);
nodes.append("text")
.transition()
.duration(duration)
.delay((d, i) => i * delay)
.attr('font-size', (d) => d.r / 5)
.text(d => d.data.name.substring(0, d.r / 3));
});
}
bubbleChart('calories');
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment