Built with blockbuilder.org
xxxxxxxxxx
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
padding: 10px;
}
.axis,
.frame {
shape-rendering: crispEdges;
}
.axis line {
stroke: #ddd;
}
.axis path {
display: none;
}
.cell text {
font-weight: bold;
text-transform: capitalize;
}
.frame {
fill: none;
stroke: #aaa;
}
circle {
fill-opacity: .7;
}
circle.hidden {
fill: #ccc !important;
}
.extent {
fill: #000;
fill-opacity: .125;
stroke: #fff;
}
div.tooltip {
position: absolute;
text-align: center;
width: 100px;
height: 150;
padding: 2px;
font: 12px sans-serif;
background: lightgrey;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script>
d3.helper = {};
d3.helper.tooltip = function () {
var tooltipDiv;
var bodyNode = d3.select('body').node();
function tooltip(selection) {
selection.on('mouseover.tooltip', function (point) {
// Clean up lost tooltips
d3.select('body').selectAll('div.tooltip').remove();
// Append tooltip
tooltipDiv = d3.select('body')
.append('div')
.attr('class', 'tooltip');
var absoluteMousePos = d3.mouse(bodyNode);
tooltipDiv
.style('left', (absoluteMousePos[0] + 10) + 'px')
.style('top', (absoluteMousePos[1] - 30) + 'px');
var line = '';
_.each(d3.keys(point), function (key, index) {
if (index != d3.keys(point).length - 1) {
if(index == 0) {
line += key + ': ' + point[key] + '</br>';
} else {
line += key + ': ' + "$" + point[key] + '</br>';
}
} else {
line += key + ': ' + "$" + point[key];
}
});
tooltipDiv.html(line);
})
.on('mousemove.tooltip', function () {
// Move tooltip
var absoluteMousePos = d3.mouse(bodyNode);
tooltipDiv
.style("left", (absoluteMousePos[0] + 10) + 'px')
.style("top", absoluteMousePos[1] < 80 ? absoluteMousePos[1] + 10 :(absoluteMousePos[1] - 70) + 'px');
})
.on('mouseout.tooltip', function () {
// Remove tooltip
tooltipDiv.remove();
});
}
tooltip.attr = function (_x) {
if (!arguments.length) return attrs;
attrs = _x;
return this;
};
tooltip.style = function (_x) {
if (!arguments.length) return styles;
styles = _x;
return this;
};
return tooltip;
};
var width = 600,
size = 200,
padding = 30;
var x = d3.scaleLinear().rangeRound([padding / 2, size - padding / 2]);
var y = d3.scaleLinear().rangeRound([size - padding / 2, padding / 2]);
var xAxis = d3.axisBottom()
.scale(x)
.ticks(4)
.tickFormat(function (d) {
if (d >=1000 && d<1000000) {
d = d / 1000 + "K";
}
if (d >=1000000) {
d = d / 1000000 + "M";
}
return d;
});
var yAxis = d3.axisLeft()
.scale(y)
.ticks(4)
.tickFormat(function (d) {
if (d >=1000 && d<1000000) {
d = d / 1000 + "K";
}
if (d >=1000000) {
d = d / 1000000 + "M";
}
return d;
});
var color = d3.scaleOrdinal(d3.schemeCategory10);
d3.csv("Patients.csv", function (data) {
data = _.chain(data).map(function (data) {
var obj = {};
_.each(d3.keys(data).filter(function(d) { return d!="TotalDischarges"}), function (key) {
obj[key] = data[key];
});
return obj;
}).value();
// transfer value from string to number
_.each(data, function (ele) {
_.each(Object.keys(ele), function (key) {
if (key != 'State') {
ele[key] = +ele[key];
}
});
});
var attr2Domain = {},
attrs = _.filter(d3.keys(data[0]), function (key) {
return key !== "State";
}),
n = attrs.length;
_.each(attrs, function (attr) {
attr2Domain[attr] = d3.extent(data, function (ele) {
return ele[attr];
});
});
xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);
var brush = d3.brush(x, y)
.extent([[padding / 2, padding / 2], [size - padding / 2, size - padding / 2]]) // brush will out beyond this extent
.on("start", brushStart)
.on("brush", brushMove)
.on("end", brushEnd);
var svg = d3.select("body")
.append("svg")
.attr("width", size * n + padding)
.attr("height", size * n + padding)
.append("g")
.attr("transform", "translate(" + padding + "," + padding / 2 + ")");
svg.selectAll(".x.axis")
.data(attrs)
.enter().append("g")
.attr("class", "x axis")
.attr("transform", function (d, i) {
return "translate(" + (n - i - 1) * size*0.9 + ",0)";
})
.each(function (d) {
x.domain(attr2Domain[d]);
d3.select(this).call(xAxis);
});
svg.selectAll(".y.axis")
.data(attrs)
.enter().append("g")
.attr("class", "y axis")
.attr("transform", function (d, i) {
return "translate(0," + i * size*0.9 +")";
})
.each(function (d) {
y.domain(attr2Domain[d]);
d3.select(this).call(yAxis);
});
svg.append("text")
.attr("id", "title")
.attr("transform", "translate(125, 1)")
.style("font-size", 14)
.text("Discharge Payments per State in the U.S. for 2011");
var cell = svg.selectAll(".cell")
.data(cross(attrs, attrs))
.enter()
.append("g")
.attr("class", "cell")
.attr("transform", function (d) {
return "translate(" + (n - d.i - 1) * size *0.9 + "," + d.j * size*0.9 + ")";
});
// Titles for the diagonal.
cell.filter(function (d) {
return d.i === d.j;
})
.append("text")
.attr("x", padding*.9)
.attr("y", padding*.9)
.attr("dy", ".71em")
.style("fill", "black")
.text(function (d) {
return d.x;
});
cell.call(brush);
cell.each(plot);
// plot each cell
function plot(p) {
var cell = d3.select(this);
x.domain(attr2Domain[p.x]);
y.domain(attr2Domain[p.y]);
cell.append("rect")
.attr("class", "frame")
.attr("x", padding / 2)
.attr("y", padding / 2)
.attr("width", size - padding)
.style("pointer-events", "none")
.attr("height", size - padding);
var circles = cell.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function (d) {
return x(d[p.x]);
})
.attr("cy", function (d) {
return y(d[p.y]);
})
.attr("r", 4)
.call(d3.helper.tooltip())
.style("fill", function (d) {
return color(d.State);
});
circles.on('mousedown', function () {
});
}
var brushCell;
var legendRectSize = 10;
var legendSpacing = 10;
var legend = svg.append("g")
.selectAll("g")
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function (d, i) {
var height = legendRectSize;
var x = n * size;
var y = (i * height) + 25;
return 'translate(' + x + ',' + y + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color)
.on("mouseover", function(d) {
svg.selectAll("circle").classed("hidden", true);
});
legend.append('text')
.attr('x', -legendRectSize+7)
.attr('y', legendSpacing-3)
.style("font-size", 7)
.style("text-anchor", "end")
.text(function (d) {
return d;
})
.on("mouseover", function(d) {
svg.selectAll("circle").style("opacity", 0)
svg.selectAll("circle").filter(function(c) {return c.State == d}).style("opacity", 1);
})
.on("mouseout", function(d) {
svg.selectAll("circle").style("opacity", 1);
});
// Clear the previously-active brush, if any.
function brushStart(p) {
if (brushCell !== this) {
d3.select(brushCell).call(brush.move, null); // clear the brush
x.domain(attr2Domain[p.x]);
y.domain(attr2Domain[p.y]);
brushCell = this;
}
}
// Highlight the selected circles.
function brushMove(p) {
var s = d3.event.selection;
if (s) {
// translate selection area
var e = [_.map(s[0], x.invert)[0], _.map(s[1], x.invert)[0], _.map(s[1], y.invert)[1], _.map(s[0], y.invert)[1]];
// hide circles outside of selection
svg.selectAll("circle").classed("hidden", function (d) {
return e[0] > d[p.x] || d[p.x] > e[1]
|| e[2] > d[p.y] || d[p.y] > e[3];
});
}
}
// If the brush is empty, highlight all circles.
function brushEnd() {
if (!d3.event.selection) svg.selectAll(".hidden").classed("hidden", false);
}
});
function cross(a, b) {
var c = [], n = a.length, m = b.length, i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++) {
c.push({x: a[i], i: i, y: b[j], j: j});
}
}
return c;
}
</script>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js