Include Json In This D3.js Calendar View?
Solution 1:
There are a few changes needed for your code to work. These are mostly related to the use of data
instead of nest
, and a minor change (for which I cannot find information on) in d3 v4 as compared with d3 v3.
Filter
Firstly, you are not filtering your data correctly:
You do not want to filter like this:
return d indata;
The in
operator is for properties of an object, data
is an array.
You want to filter by your nest (as in the example):
return d in nest;
Secondly, at least in my brief testing, d3.nest behaves slightly differently in d3 v4 (this might be dependent on version, I've used 4.9.1 (min) in the snippet below). When using keys that begin with numbers, d3 seems to be appending a dollar sign at the beginning of each key when using d3.nest:
D3v4 example:
data = [{
"date": "2017-01-04", "open": 10430.69
}, {
"date": "2017-01-05", "open": 10584.56
}];
var nest = d3.nest()
.key(function(d) { return d.date; })
.map(data);
console.log(nest);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
Compared with D3v3:
data = [{
"date": "2017-01-04", "open": 10430.69
}, {
"date": "2017-01-05", "open": 10584.56
}];
var nest = d3.nest()
.key(function(d) { return d.date; })
.map(data);
console.log(nest);
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
If you are seeing this behaviour, you'll need to change your filter accordingly:
return ("$" + d) in nest;
Accessing Nest Properties
Thirdly, as data
is just an array, data[d]
is not likely to get desired results as d
will be a date string, you need to access the nest
object. Logging nest
might help in finding the proper properties. Instead of:
return color(data[d]);
Try:
return color(nest[("$" + d)][0].open);
Which is very similar to the linked example in the question (with the exception of that dollar sign thing again).
Optimization
Related to your other recent question, this code
var date = "2017-01-02";
var dateParse = d3.timeFormat("%Y-%m-%d");
console.log(dateParse(newDate(date)));
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
does nothing. It takes a string representing a date and converts it to a date object, then converts it back into the same string representation you started with. You can drop this portion of the code, it was used in the linked example because it was converting from a m/d/Y date string to a date object, and then to a Y-m-d date string. Your initial date format is already in the format you want, so there is no need to modify it. Use just:
var nest = d3.nest()
.key(function(d) {
return d.date;
})
.map(data);
Rather than:
data.forEach(function(d) {
d.dd = dateParse(d.date);
});
var nest = d3.nest()
.key(function(d) {
return d.dd;
})
.map(data);
Result
These changes (I've stripped out the text to make the example simpler, removed the external file reference, etc) result in:
var width = 960,
height = 136,
cellSize = 17;
var color = d3.scaleQuantize()
.domain([9000, 12000])
.range(["Blue", "Red", "Green", "Yellow", "Purple", "Black"]);
var dateFormat = d3.timeFormat("%Y-%m-%d");
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(2017, 2018))
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
var rect = svg.append("g")
.attr("fill", "none")
.attr("stroke", "#ccc")
.selectAll("rect")
.data(function(d) {
return d3.timeDays(newDate(d, 0, 1), newDate(d + 1, 0, 1));
})
.enter().append("rect")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) {
return d3.timeWeek.count(d3.timeYear(d), d) * cellSize;
})
.attr("y", function(d) {
return d.getDay() * cellSize;
})
.datum(dateFormat);
svg.append("g")
.attr("fill", "none")
.attr("stroke", "#000")
.selectAll("path")
.data(function(d) {
return d3.timeMonths(newDate(d, 0, 1), newDate(d + 1, 0, 1));
})
.enter().append("path")
.attr("d", pathMonth);
data = [{
"date": "2017-01-04",
"open": 10430.69
}, {
"date": "2017-01-05",
"open": 10584.56
}];
var nest = d3.nest()
.key(function(d) {
return d.date;
})
.map(data);
rect.filter(function(d) {
return ("$" + d) in nest;
})
.attr("fill", function(d) {
returncolor(nest[("$" + d)][0].open);
})
functionpathMonth(t0) {
var t1 = newDate(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" + (w0 + 1) * cellSize + "," + d0 * cellSize +
"H" + w0 * cellSize + "V" + 7 * cellSize +
"H" + w1 * cellSize + "V" + (d1 + 1) * cellSize +
"H" + (w1 + 1) * cellSize + "V" + 0 +
"H" + (w0 + 1) * cellSize + "Z";
}
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
Solution 2:
Looks like you were forgetting to declare dateParse (and using it wrong).
var dateParse = d3.timeParse("%Y-%m-%d");
var width = 960,
height = 136,
cellSize = 17;
var color = d3.scaleQuantize()
.domain([9000, 12000])
.range(["Blue", "Red", "Green", "Yellow", "Purple", "Black"]);
var dateParse = d3.timeParse("%Y-%m-%d");
var svg = d3.select("body")
.selectAll("svg")
.data(d3.range(2017, 2018))
.enter().append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + ((width - cellSize * 53) / 2) + "," + (height - cellSize * 7 - 1) + ")");
svg.append("text")
.attr("transform", "translate(-6," + cellSize * 3.5 + ")rotate(-90)")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.attr("text-anchor", "middle")
.text(function(d) {
return d;
});
var rect = svg.append("g")
.attr("fill", "none")
.attr("stroke", "#ccc")
.selectAll("rect")
.data(function(d) {
return d3.timeDays(newDate(d, 0, 1), newDate(d + 1, 0, 1));
})
.enter().append("rect")
.attr("width", cellSize)
.attr("height", cellSize)
.attr("x", function(d) {
return d3.timeWeek.count(d3.timeYear(d), d) * cellSize;
})
.attr("y", function(d) {
return d.getDay() * cellSize;
})
.datum(d3.timeFormat("%Y-%m-%d"));
svg.append("g")
.attr("fill", "none")
.attr("stroke", "#000")
.selectAll("path")
.data(function(d) {
return d3.timeMonths(newDate(d, 0, 1), newDate(d + 1, 0, 1));
})
.enter().append("path")
.attr("d", pathMonth);
d3.json("data3.json", function(error, data) {
//populating data since i don't have the file
data = [{
"date": "2017-01-04",
"open": 10430.69
}, {
"date": "2017-01-05",
"open": 10584.56
}];
data.forEach(function(d) {
d.dd = dateParse(d.date);
console.log(d.dd);
});
var nest = d3.nest()
.key(function(d) {
return d.dd;
})
.map(data);
rect.filter(function(d) {
return d in data;
})
.attr("fill", function(d) {
returncolor(data[d]);
})
.append("title")
.text(function(d) {
return d + ": " + data[d];
});
});
functionpathMonth(t0) {
var t1 = newDate(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" + (w0 + 1) * cellSize + "," + d0 * cellSize +
"H" + w0 * cellSize + "V" + 7 * cellSize +
"H" + w1 * cellSize + "V" + (d1 + 1) * cellSize +
"H" + (w1 + 1) * cellSize + "V" + 0 +
"H" + (w0 + 1) * cellSize + "Z";
}
<scriptsrc="http://d3js.org/d3.v4.min.js"></script>
Post a Comment for "Include Json In This D3.js Calendar View?"