Reputation: 804
I'm working with a modified version of Mike Bostock's Calendar Heatmap (https://bl.ocks.org/mbostock/4063318). In this version, I rotated the calendar and I'm just focusing on a few months (this was helpful: Tweak D3 calendar view example to be vertical with days be ordered left to right, then top to bottom?). See the attached image.
Does anyone have ideas on how to add small font day numbers to each of the day rectangles? They would be font size 8, and in the corners of each day's rectangle. I've been fiddling with it for hours and haven't gotten anywhere.
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var width = 550,
height = 750,
cellSize = 45;
var formatPercent = d3.format(".1%");
var color = d3.scaleQuantize()
.domain([0, 100])
.range(["#ffffff","#e6f7ff","#b3e6ff","#99ddff","#66ccff","#4dc3ff","#1ab2ff","#0077b3","#004466"]);
var month_strings = ["January", "February", "March"]
var svg = d3.select("body")
.selectAll("svg")
.data([2018])
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 5) / 2) + "," + (height - cellSize * 16 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-10," + cellSize * 3 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text(month_strings[0]);
svg.append("text")
.attr("transform", "translate(-10," + cellSize * 7 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text(month_strings[1]);
svg.append("text")
.attr("transform", "translate(-10," + cellSize * 11 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text(month_strings[2]);
var rect = svg.append("g")
.attr("fill", "none")
.attr("stroke", "#d2d4d8")
.selectAll("rect")
.data(function(d) { return d3.timeDays(new Date(2018, 0, 1), new Date(2018, 3, 1)); })
.enter().append("rect")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("class", "hour bordered")
.attr("rx", 4)
.attr("ry", 4)
//.attr("x", function(d) { return d3.timeWeek.count(d3.timeYear(d), d) * cellSize; })
//.attr("y", function(d) { return d.getDay() * cellSize; })
.attr("x", function(d) { return d.getDay() * cellSize;})
.attr("y", function(d) { return d3.timeWeek.count(d3.timeYear(d), d) * cellSize; })
.datum(d3.timeFormat("%Y-%m-%d"));
svg.append("g")
.attr("fill", "none")
.attr("stroke", "#000")
.selectAll("path")
.data(function(d) { return d3.timeMonths(new Date(2018, 0, 1), new Date(2018, 3, 1)); })
.enter().append("path")
.attr("d", pathMonth);
d3.csv("static/test.csv", function(error, csv) {
if (error) throw error;
var data = d3.nest()
.key(function(d) { return d.Date; })
.rollup(function(d) { return (d[0].Close - d[0].Open) / d[0].Open; })
.object(csv);
rect.filter(function(d) { return d in data; })
.attr("fill", function(d) { return color(data[d]); })
.append("title")
.text(function(d) { return d + ": " + formatPercent(data[d]); });
});
function pathMonth(t0) {
var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
d0 = t0.getDay(), w0 = d3.timeWeek.count(d3.timeYear(t0), t0),
d1 = t1.getDay(), w1 = d3.timeWeek.count(d3.timeYear(t1), t1);
return "M" + d0 * cellSize + "," + (w0) * cellSize
+ "H" + 7 * cellSize + "V" + (w1) * cellSize
+ "H" + (d1 + 1) * cellSize + "V" + (w1 + 1) * cellSize
+ "H" + 0 + "V" + (w0 + 1) * cellSize + "H"
+ d0 * cellSize + "Z";
}
var start_box = svg.append("rect")
.attr("x", 225)
.attr("y", 45)
.attr("width", cellSize)
.attr("height", cellSize)
.attr("rx", 4)
.attr("ry", 4)
.attr("class", "hour bordered")
.style("fill", "#FFD700");
</script>
Here is the CSV:
Date,Weekday,Open,Close
2018-01-01,0,1,0
2018-01-02,1,1,1
2018-01-03,2,1,2
2018-01-04,3,1,3
2018-01-05,4,1,4
2018-01-06,5,1,1
2018-01-07,6,1,1
2018-01-08,0,1,7
2018-01-09,1,1,8
2018-01-10,2,1,9
2018-01-11,3,1,10
2018-01-12,4,1,11
2018-01-13,5,1,1
2018-01-14,6,1,1
2018-01-15,0,1,14
2018-01-16,1,1,15
2018-01-17,2,1,16
2018-01-18,3,1,17
2018-01-19,4,1,18
2018-01-20,5,1,1
2018-01-21,6,1,1
2018-01-22,0,1,21
2018-01-23,1,1,22
2018-01-24,2,1,23
2018-01-25,3,1,24
2018-01-26,4,1,25
2018-01-27,5,1,1
2018-01-28,6,1,1
2018-01-29,0,1,28
2018-01-30,1,1,29
2018-01-31,2,1,30
2018-02-01,3,1,31
2018-02-02,4,1,32
2018-02-03,5,1,1
2018-02-04,6,1,1
2018-02-05,0,1,35
2018-02-06,1,1,36
2018-02-07,2,1,37
2018-02-08,3,1,38
2018-02-09,4,1,39
2018-02-10,5,1,1
2018-02-11,6,1,1
2018-02-12,0,1,42
2018-02-13,1,1,43
2018-02-14,2,1,44
2018-02-15,3,1,45
2018-02-16,4,1,46
2018-02-17,5,1,1
2018-02-18,6,1,1
2018-02-19,0,1,49
2018-02-20,1,1,50
2018-02-21,2,1,51
2018-02-22,3,1,52
2018-02-23,4,1,53
2018-02-24,5,1,1
2018-02-25,6,1,1
2018-02-26,0,1,56
2018-02-27,1,1,57
2018-02-28,2,1,58
2018-03-01,3,1,59
2018-03-02,4,1,60
2018-03-03,5,1,1
2018-03-04,6,1,1
2018-03-05,0,1,63
2018-03-06,1,1,64
2018-03-07,2,1,65
2018-03-08,3,1,66
2018-03-09,4,1,67
2018-03-10,5,1,1
2018-03-11,6,1,1
2018-03-12,0,1,70
2018-03-13,1,1,71
2018-03-14,2,1,72
2018-03-15,3,1,73
2018-03-16,4,1,74
2018-03-17,5,1,1
2018-03-18,6,1,1
2018-03-19,0,1,77
2018-03-20,1,1,78
2018-03-21,2,1,79
2018-03-22,3,1,80
2018-03-23,4,1,81
2018-03-24,5,1,1
2018-03-25,6,1,1
2018-03-26,0,1,84
2018-03-27,1,1,85
2018-03-28,2,1,86
2018-03-29,3,1,87
2018-03-30,4,1,88
2018-03-31,5,1,1
Upvotes: 1
Views: 1153
Reputation: 108512
I'd do it like this:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var width = 550,
height = 750,
cellSize = 45;
var formatPercent = d3.format(".1%");
var color = d3.scaleQuantize()
.domain([0, 100])
.range(["#ffffff", "#e6f7ff", "#b3e6ff", "#99ddff", "#66ccff", "#4dc3ff", "#1ab2ff", "#0077b3", "#004466"]);
var month_strings = ["January", "February", "March"]
var svg = d3.select("body")
.selectAll("svg")
.data([2018])
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 5) / 2) + "," + (height - cellSize * 16 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-10," + cellSize * 3 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text(month_strings[0]);
svg.append("text")
.attr("transform", "translate(-10," + cellSize * 7 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text(month_strings[1]);
svg.append("text")
.attr("transform", "translate(-10," + cellSize * 11 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 20)
.attr("text-anchor", "middle")
.text(month_strings[2]);
var g = svg.append("g")
.attr("fill", "none")
.attr("stroke", "#d2d4d8")
.selectAll("g")
.data(function(d) {
return d3.timeDays(new Date(2018, 0, 1), new Date(2018, 3, 1));
})
.enter()
.append("g")
.attr("transform", function(d){
var x = d.getDay() * cellSize,
y = d3.timeWeek.count(d3.timeYear(d), d) * cellSize;
return "translate(" + x + "," + y + ")";
})
g.append("rect")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("class", "hour bordered")
.attr("rx", 4)
.attr("ry", 4)
.datum(d3.timeFormat("%Y-%m-%d"));
g.append("text")
.text(function(d){
return d.getDate();
})
.attr("y", cellSize)
.style("font-family", "arial")
.style("font-size", "8pt")
svg.append("g")
.attr("fill", "none")
.attr("stroke", "#000")
.selectAll("path")
.data(function(d) {
return d3.timeMonths(new Date(2018, 0, 1), new Date(2018, 3, 1));
})
.enter().append("path")
.attr("d", pathMonth);
d3.csv("static/test.csv", function(error, csv) {
if (error) throw error;
var data = d3.nest()
.key(function(d) {
return d.Date;
})
.rollup(function(d) {
return (d[0].Close - d[0].Open) / d[0].Open;
})
.object(csv);
rect.filter(function(d) {
return d in data;
})
.attr("fill", function(d) {
return color(data[d]);
})
.append("title")
.text(function(d) {
return d + ": " + formatPercent(data[d]);
});
});
function pathMonth(t0) {
var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0),
d0 = t0.getDay(),
w0 = d3.timeWeek.count(d3.timeYear(t0), t0),
d1 = t1.getDay(),
w1 = d3.timeWeek.count(d3.timeYear(t1), t1);
return "M" + d0 * cellSize + "," + (w0) * cellSize + "H" + 7 * cellSize + "V" + (w1) * cellSize + "H" + (d1 + 1) * cellSize + "V" + (w1 + 1) * cellSize + "H" + 0 + "V" + (w0 + 1) * cellSize + "H" + d0 * cellSize + "Z";
}
var start_box = svg.append("rect")
.attr("x", 225)
.attr("y", 45)
.attr("width", cellSize)
.attr("height", cellSize)
.attr("rx", 4)
.attr("ry", 4)
.attr("class", "hour bordered")
.style("fill", "#FFD700");
</script>
</body>
</html>
Upvotes: 3