Skip to content

Instantly share code, notes, and snippets.

@nanu146
Last active April 1, 2017 21:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nanu146/df39c69d1d0cb1b71429b2cd47e2a189 to your computer and use it in GitHub Desktop.
Save nanu146/df39c69d1d0cb1b71429b2cd47e2a189 to your computer and use it in GitHub Desktop.
Heatmap using d3.js
license: gpl-3.0
height: 900
x y value
France Apricot 2.3129545439964723
France Avocado 3.1610140317890965
France Lemon 0.9075695440623942
France Date 1.1296454803177811
France Strawberry
France Mandarin 2.6193568568512493
France Chestnut 0.08748279136251946
France Nuts 2.943858242639327
France Olive 1.3356914547843943
France Mirabelle 0.31390905400247027
France Orange 0.5709024568447734
France Fig 0.8689875977541086
France Raisin
France Pear
France Potato
France Khaki
France Kiwi 6.026783469350332
France Pumpkin 0.5472217416389179
France Mango
France Cherry 1.9472375734686518
Italy Apricot 2.250335336990016
Italy Avocado 1.4472931892677967
Italy Lemon 1.7163168911863054
Italy Date 0.6222770814456479
Italy Strawberry
Italy Mandarin 1.9378611429750559
Italy Goyave
Italy Chestnut 0.35446193006796944
Italy Nuts 0.37199215156032084
Italy Olive 1.05979039016384
Italy Orange 1.9087621718437413
Italy Fig 4.632439392448328
Italy Raisin
Italy Pear
Italy Potato
Italy Khaki
Italy Banana
Italy Blackcurrant
Italy Kiwi 1.673923311217576
Italy Pumpkin 0.8029920360319587
Italy Cherry 1.9453249240219272
Germany Apricot 0.24786564820472912
Germany Avocado 1.13545847239482
Germany Lemon 0.6388067539810734
Germany Date 1.626323182055196
Germany Strawberry
Germany Mandarin 0.4239980281990543
Germany Chestnut 1.4341389749588975
Germany Nuts 0.7392983316104583
Germany Olive 1.6630071601899028
Germany Mirabelle 4.759329801939115
Germany Orange 3.718673834416696
Germany Fig 2.458679694479642
Germany Raisin
Germany Pear
Germany Potato
Germany Prune
Germany Khaki
Germany Banana
Germany Ananas
Germany Kiwi 1.3234705953824204
Germany Pumpkin 0.0770059996293927
Germany Cherry 1.7111604775075815
United Kingdom Apricot 0.17924671480874477
United Kingdom Avocado 0.022885648078082133
United Kingdom Lemon 1.7152082470441878
United Kingdom Date 1.752070575653172
United Kingdom Mandarin 3.4281163770331387
United Kingdom Goyave
United Kingdom Chestnut 0.19739811992921974
United Kingdom Nuts 1.0070422960846344
United Kingdom Olive 2.228287010523628
United Kingdom Orange 0.9304979227921532
United Kingdom Fig 0.5953329645659061
United Kingdom Cerise
United Kingdom Raisin
United Kingdom Potato
United Kingdom Prune
United Kingdom Khaki
United Kingdom Ananas
United Kingdom Kiwi 3.9494022464067755
United Kingdom Pumpkin 2.2009939178127476
United Kingdom Mango
United Kingdom Cherry 0.20063602688693316
Spain Apricot 0.9989751140631283
Spain Avocado 1.3798561037495776
Spain Lemon 4.621063369745371
Spain Date 2.715496746864414
Spain Strawberry
Spain Mandarin 4.655686656785712
Spain Chestnut 2.0830024325290624
Spain Nuts 3.8907348191368603
Spain Olive 0.4593907900702838
Spain Mirabelle 0.8657861030686699
Spain Orange 3.431725506748977
Spain Fig 6.387945884767135
Spain Raisin
Spain Pear
Spain Potato
Spain Khaki
Spain Kiwi 1.1520183768223036
Spain Pumpkin 1.9614971869756583
Spain Cherry 1.7489279548209826
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.heatmap{
top:110px;
position: relative;
}
</style>
<div class="heatmap"></div>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
/*
negative color scales in increasing magnitude
#EF9FAE, #C76475, #781426
positive color scales in increasing magnitude
#ABDB92, #77B75B, #2E6E12
*/
/* supporting functions */
// Standard deviation
function RMS(arr){
return Math.pow(arr.reduce(function(acc,pres){
return acc+ Math.pow(pres,2);
})/arr.length,.5)
}
// mean
function mean(arr){
return arr.reduce(function(acc,prev){
return acc+prev;
})/arr.length;
}
var lPatchWidth=200;
var itemSize = 22,
cellSize = itemSize - 3,
margin = {top: 50, right: 20, bottom: 120, left: 110};
var data;
var width = 750 - margin.right - margin.left,
height = 300 - margin.top - margin.bottom;
var colorScale;
colorHold=["#781426","#C76475","#EF9FAE","#ABDB92","#77B75B","#2E6E12"]
colorLText=["< -66%","-66% to -33%","-33% to 0%","0% to 33%","33% to 66%","> 66%"]
function bandClassifier(val,multiplier)
{
if(val>=0)
{
return (Math.floor((val*multiplier)/(.33*multiplier))+1)>3?3:Math.floor((val*multiplier)/(.33*multiplier))+1
}
else{
return (Math.floor((val*multiplier)/(.33*multiplier)))<-3?-3:Math.floor((val*multiplier)/(.33*multiplier))
}
}
window.onload=function(){
d3.csv('data.csv', function ( response ) {
data = response.map(function( item ) {
var newItem = {};
newItem.country = item.x;
newItem.product = item.y;
newItem.value = +item.value;
return newItem;
})
invertcolors=0;
// Inverting color scale
if(invertcolors){
colorHold.reverse();
}
var x_elements = d3.set(data.map(function( item ) { return item.product; } )).values(),
y_elements = d3.set(data.map(function( item ) { return item.country; } )).values();
var xScale = d3.scaleBand()
.domain(x_elements)
.range([0, x_elements.length * itemSize])
.paddingInner(20).paddingOuter(cellSize/2)
var xAxis = d3.axisBottom()
.scale(xScale)
.tickFormat(function (d) {
return d;
});
var yScale = d3.scaleBand()
.domain(y_elements)
.range([0, y_elements.length * itemSize])
.paddingInner(.2).paddingOuter(.2);
var yAxis = d3.axisLeft()
.scale(yScale)
.tickFormat(function (d) {
return d;
});
// Finding the mean of the data
var mean=window.mean(data.map(function(d){return +d.value}));
//setting percentage change for value w.r.t average
data.forEach(function(d){
d.perChange=(d.value-mean)/mean
})
colorScale = d3.scaleOrdinal()
.domain([-3,-2,-1,1,2,3])
.range(colorHold);
var rootsvg = d3.select('.heatmap')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
var svg=rootsvg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// tooltip
tooltip=d3.select("body").append("div").style("width","80px").style("height","40px").style("background","#C3B3E5")
.style("opacity","1").style("position","absolute").style("visibility","hidden").style("box-shadow","0px 0px 6px #7861A5").style("padding","10px");
toolval=tooltip.append("div");
var cells = svg.selectAll('rect')
.data(data)
.enter().append('g').append('rect')
.attr('class', 'cell')
.attr('width', cellSize)
.attr('height', cellSize)
.attr('y', function(d) { return yScale(d.country); })
.attr('x', function(d) { return xScale(d.product)-cellSize/2; })
.attr('fill', function(d) { return colorScale(window.bandClassifier(d.perChange,100));})
.attr("rx",3)
.attr("ry",3)
.on("mouseover",function(d){
console.log(d);
//d3.select(this).attr("fill","#655091");
d3.select(this).style("stroke","orange").style("stroke-width","3px")
d3.select(".trianglepointer").transition().delay(100).attr("transform","translate("+(-((lPatchWidth/colorScale.range().length)/2+(colorScale.domain().indexOf(bandClassifier(d.perChange,100))*(lPatchWidth/colorScale.range().length) )))+",0)");
d3.select(".LegText").select("text").text(colorLText[colorScale.domain().indexOf(bandClassifier(d.perChange,100))])
})
.on("mouseout",function(){
//d3.select(this).attr('fill', function(d) { return colorScale(window.bandClassifier(d.perChange,100));});
d3.select(this).style("stroke","none");
tooltip.style("visibility","hidden");
})
.on("mousemove",function(d){
tooltip.style("visibility","visible")
.style("top",(d3.event.pageY-30)+"px").style("left",(d3.event.pageX+20)+"px");
console.log(d3.mouse(this)[0])
tooltip.select("div").html("<strong>"+d.product+"</strong><br/> "+(+d.value).toFixed(2))
})
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.selectAll('text')
.attr('font-weight', 'normal');
svg.append("g")
.attr("class", "x axis")
.attr("transform","translate(0,"+(y_elements.length * itemSize +cellSize/2)+")")
.call(xAxis)
.selectAll('text')
.attr('font-weight', 'normal')
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.5em")
.attr("transform", function (d) {
return "rotate(-65)";
});
// Legends section
legends=svg.append("g").attr("class","legends")
.attr("transform","translate("+((width+margin.right)/2-lPatchWidth/2 -margin.left/2)+","+(height+margin.bottom-35-20)+")");
// Legend traingle pointer generator
var symbolGenerator = d3.symbol()
.type(d3.symbolTriangle)
.size(64);
legends.append("g").attr("transform","rotate(180)").append("g").attr("class","trianglepointer")
.attr("transform","translate("+(-lPatchWidth/colorScale.range().length)/2+")")
.append("path").attr("d",symbolGenerator());
//Legend Rectangels
legends.append("g").attr("class","LegRect")
.attr("transform","translate(0,"+15+")")
.selectAll("rect").data(colorScale.range()).enter()
.append("rect").attr("width",lPatchWidth/colorScale.range().length+"px").attr("height","10px").attr("fill",function(d){ return d})
.attr("x",function(d,i){ return i*(lPatchWidth/colorScale.range().length) })
// legend text
legends.append("g").attr("class","LegText")
.attr("transform","translate(0,45)")
.append("text")
.attr("x",lPatchWidth/2)
.attr('font-weight', 'normal')
.style("text-anchor", "middle")
.text(colorLText[0])
// Heading
rootsvg.append("g")
.attr("transform","translate(0,30)")
.append("text")
.attr("x",(width+margin.right+margin.left)/2)
.attr('font-weight', 'bold')
.attr('font-size', '22px')
.attr('font-family', 'Segoe UI bold')
.style("text-anchor", "middle")
.text("Sales Heatmap")
});
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment