D3.js 图表转换错误
D3.js Chart Transition Erroring
我正在尝试刷#histogram1 并重绘子图表#histogram2。
在我的示例中,重绘工作不正常,在第 113 行左右。
控制台偶尔会在 "height" 和 "y" 属性上显示错误 -
Error: <rect> attribute height: Expected length, "NaN".
Error: <rect> attribute y: Expected length, "NaN".
我无法确定错误值的来源?
有人可以帮助我理解我做错了什么吗?
谢谢
var data = [
{"yr":1940,"type":"E","rate":40},{"yr":1947,"type":"A","rate":20},{"yr":1943,"type":"B","rate":30},{"yr":1950,"type":"B","rate":25},
{"yr":1943,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},{"yr":1945,"type":"E","rate":40},{"yr":1948,"type":"A","rate":20},
{"yr":1947,"type":"B","rate":30},{"yr":1950,"type":"B","rate":25},{"yr":1945,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},
{"yr":1944,"type":"B","rate":10},{"yr":1949,"type":"C","rate":20},{"yr":1940,"type":"E","rate":10},{"yr":1940,"type":"E","rate":40},
{"yr":1940,"type":"E","rate":40},{"yr":1947,"type":"A","rate":20},{"yr":1943,"type":"B","rate":30},{"yr":1950,"type":"B","rate":25},
{"yr":1943,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},{"yr":1945,"type":"E","rate":40},{"yr":1948,"type":"A","rate":20},
{"yr":1947,"type":"B","rate":30},{"yr":1950,"type":"D","rate":25},{"yr":1945,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},
{"yr":1944,"type":"B","rate":10},{"yr":1949,"type":"C","rate":20},{"yr":1940,"type":"E","rate":10},{"yr":1947,"type":"E","rate":40}
];
// CROSSFILTER Dimensions //
var cfdata = crossfilter(data)
, all = cfdata.groupAll()
, year = cfdata.dimension(function(d) {return d.yr;})
, type = cfdata.dimension(function(d) {return d.type;})
, years= year.group()
, types= type.group().reduceCount()
, typeKeys = types.all()
, keyMap = typeKeys.map (function(d) {return d.key}) ;
// General CHART Dimensions //
var margin = {top: 10, right: 20, bottom: 10, left: 10}
, height = 200 - margin.top - margin.bottom
, width = 400 - margin.left - margin.right
, barPadding = 5 ;
// Setup TOOLTIPS //
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d){return d.value});
// HISTOGRAM 1 : TOTAL BY YEAR //
var min1 = d3.min(years.all(), function(d) {return d.key;})
, max1 = d3.max(years.all(), function(d) {return d.key;})
, range1 = max1 - min1 ;
var xScale1 = d3.scale.linear()
.domain([min1, max1])
.range([0, width]) ;
var yScale1 = d3.scale.linear()
.domain([0, d3.max(years.all(), function(d) {return d.value;})])
.range([height / 2, 0]) ;
var xAxis1 = d3.svg.axis()
.scale(xScale1)
.ticks(5).tickFormat(d3.format("d"))
.orient("bottom") ;
var histogram1 = d3.select("#histogram1").append("svg:svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g");
histogram1.call(tip);
histogram1.append("g")
.attr("class", "axis")
.call(xAxis1)
.attr("transform", "translate(" + margin.left + "," + height / 2 + ")") ;
histogram1.selectAll("rect")
.data(years.all())
.enter().append("rect")
.attr("x", function(d) {return xScale1(d.key) + 0.5 * (width / range1)})
.attr("width", width / range1)
.attr("y", function(d) {return yScale1(d.value);})
.attr("height", function(d) {return (height / 2 - yScale1(d.value));})
.attr("fill", "green")
.attr("stroke", "white")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var brush = d3.svg.brush()
.x(xScale1)
.extent([1945, 1946])
.on("brush", brushmove) ;
var brushg = histogram1.append("g")
.attr("class", "brush")
.call(brush) ;
brushg.selectAll("rect")
.attr("height", height / 2) ;
brushg.selectAll(".resize")
.append("path")
.attr("d", resizePath) ;
function brushmove() {
var s = brush.extent()
, lower = parseInt(s[0])
, upper = parseInt(s[1]);
histogram1.selectAll("rect")
.style("opacity", function(d) {return lower <= d.key && d.key <= upper ? "1" : ".2";}) ;
var filt = year.filterRange([lower,upper]);
console.log(filt.top(Infinity));
histogram2.selectAll("rect")
.data(filt.top(Infinity))
.transition()
.attr("y", function(d){ return height - yScale2(d); })
.attr("height", function(d){ return yScale2(d); })
};
// HISTOIGRAM 2 : TOTAL BY TYPE //
var keys2 = typeKeys.map(function(d) {return d.key;})
, min2 = d3.min(types, function(d) {return d.key;})
, max2 = d3.max(types, function(d) {return d.key;})
var xScale2 = d3.scale.ordinal()
.domain(keys2)
.rangeBands([0, width]);
var yScale2 = d3.scale.linear()
.domain([0, d3.max(types.all(), function(d) {return d.value;})])
.range([height / 2, 0]);
var xAxis2 = d3.svg.axis()
.scale(xScale2)
.orient("bottom");
var histogram2 = d3.select("#histogram2").append("svg:svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g");
histogram2.call(tip);
histogram2.append("g")
.attr("class", "axis")
.call(xAxis2)
.attr("transform", "translate(0," + height + ")")
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {return "rotate(-65)"});
histogram2.selectAll("rect")
.data(types.all())
.enter().append("rect")
.attr("x", function(d) {return xScale2(d.key);})
.attr("width", width / keyMap.length - barPadding)
.attr("y", function(d) {return yScale2(d.value); })
.attr("height", function(d) {return height - yScale2(d.value);})
.attr("fill", "steelblue")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
function resizePath(d) {
var e = +(d == "e")
, x = e ? 1 : -1
, y = height / 4;
return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y) + "Z" + "M" + (2.5 * x) + "," + (y + 8) + "V" + (2 * y - 8) + "M" + (4.5 * x) + "," + (y + 8) + "V" + (2 * y - 8);
}
/*** d3-tip styles */
.d3-tip {
line-height: 1.5;
padding: 8px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 0px;
text-align: center;
}
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "BC";
position: absolute;
text-align: center;
}
.d3-tip.n:after {
top: 100%;
left: 0;
margin: -1px 0 0;
}
/*** D3 brush */
.brush .extent {
stroke: #222;
fill-opacity: .125;
shape-rendering: crispEdges;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
<div id="histogram1"></div>
<div id="histogram2"></div>
您在响应画笔更新第二个直方图时使用的数据与您最初绘制图表时不同。通常,您会希望在这两种情况下使用同一组的数据 (.all()
)。
特别是,
.data(filt.top(Infinity))
将为图表提供数据的原始行,
.attr("y", function(d){ return height - yScale2(d); })
.attr("height", function(d){ return yScale2(d); })
然后,当秤需要一个数字时,将尝试将这些行对象传递给秤。 (一个对象字面意思是"Not a Number"。)
当您应用过滤器时
year.filterRange([lower,upper]);
这将导致关联交叉过滤器中的所有组重新过滤和重新聚合。 (这在很大程度上是命令式的,而不是函数式编程,接口。filter
方法只是 returns 相同的维度对象。)
如果你更新 y
和 height
完全按照你最初画的那样:
.attr("y", function(d){ return height - yScale2(d.value); })
.attr("height", function(d){ return yScale2(d.value); })
然后转瞬即逝!它过滤。
Fiddle 更正代码:http://jsfiddle.net/gordonwoodhull/hjL6rf9u/5/
我正在尝试刷#histogram1 并重绘子图表#histogram2。
在我的示例中,重绘工作不正常,在第 113 行左右。
控制台偶尔会在 "height" 和 "y" 属性上显示错误 -
Error: <rect> attribute height: Expected length, "NaN".
Error: <rect> attribute y: Expected length, "NaN".
我无法确定错误值的来源?
有人可以帮助我理解我做错了什么吗?
谢谢
var data = [
{"yr":1940,"type":"E","rate":40},{"yr":1947,"type":"A","rate":20},{"yr":1943,"type":"B","rate":30},{"yr":1950,"type":"B","rate":25},
{"yr":1943,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},{"yr":1945,"type":"E","rate":40},{"yr":1948,"type":"A","rate":20},
{"yr":1947,"type":"B","rate":30},{"yr":1950,"type":"B","rate":25},{"yr":1945,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},
{"yr":1944,"type":"B","rate":10},{"yr":1949,"type":"C","rate":20},{"yr":1940,"type":"E","rate":10},{"yr":1940,"type":"E","rate":40},
{"yr":1940,"type":"E","rate":40},{"yr":1947,"type":"A","rate":20},{"yr":1943,"type":"B","rate":30},{"yr":1950,"type":"B","rate":25},
{"yr":1943,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},{"yr":1945,"type":"E","rate":40},{"yr":1948,"type":"A","rate":20},
{"yr":1947,"type":"B","rate":30},{"yr":1950,"type":"D","rate":25},{"yr":1945,"type":"C","rate":20},{"yr":1941,"type":"A","rate":30},
{"yr":1944,"type":"B","rate":10},{"yr":1949,"type":"C","rate":20},{"yr":1940,"type":"E","rate":10},{"yr":1947,"type":"E","rate":40}
];
// CROSSFILTER Dimensions //
var cfdata = crossfilter(data)
, all = cfdata.groupAll()
, year = cfdata.dimension(function(d) {return d.yr;})
, type = cfdata.dimension(function(d) {return d.type;})
, years= year.group()
, types= type.group().reduceCount()
, typeKeys = types.all()
, keyMap = typeKeys.map (function(d) {return d.key}) ;
// General CHART Dimensions //
var margin = {top: 10, right: 20, bottom: 10, left: 10}
, height = 200 - margin.top - margin.bottom
, width = 400 - margin.left - margin.right
, barPadding = 5 ;
// Setup TOOLTIPS //
var tip = d3.tip()
.attr('class', 'd3-tip')
.html(function(d){return d.value});
// HISTOGRAM 1 : TOTAL BY YEAR //
var min1 = d3.min(years.all(), function(d) {return d.key;})
, max1 = d3.max(years.all(), function(d) {return d.key;})
, range1 = max1 - min1 ;
var xScale1 = d3.scale.linear()
.domain([min1, max1])
.range([0, width]) ;
var yScale1 = d3.scale.linear()
.domain([0, d3.max(years.all(), function(d) {return d.value;})])
.range([height / 2, 0]) ;
var xAxis1 = d3.svg.axis()
.scale(xScale1)
.ticks(5).tickFormat(d3.format("d"))
.orient("bottom") ;
var histogram1 = d3.select("#histogram1").append("svg:svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g");
histogram1.call(tip);
histogram1.append("g")
.attr("class", "axis")
.call(xAxis1)
.attr("transform", "translate(" + margin.left + "," + height / 2 + ")") ;
histogram1.selectAll("rect")
.data(years.all())
.enter().append("rect")
.attr("x", function(d) {return xScale1(d.key) + 0.5 * (width / range1)})
.attr("width", width / range1)
.attr("y", function(d) {return yScale1(d.value);})
.attr("height", function(d) {return (height / 2 - yScale1(d.value));})
.attr("fill", "green")
.attr("stroke", "white")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
var brush = d3.svg.brush()
.x(xScale1)
.extent([1945, 1946])
.on("brush", brushmove) ;
var brushg = histogram1.append("g")
.attr("class", "brush")
.call(brush) ;
brushg.selectAll("rect")
.attr("height", height / 2) ;
brushg.selectAll(".resize")
.append("path")
.attr("d", resizePath) ;
function brushmove() {
var s = brush.extent()
, lower = parseInt(s[0])
, upper = parseInt(s[1]);
histogram1.selectAll("rect")
.style("opacity", function(d) {return lower <= d.key && d.key <= upper ? "1" : ".2";}) ;
var filt = year.filterRange([lower,upper]);
console.log(filt.top(Infinity));
histogram2.selectAll("rect")
.data(filt.top(Infinity))
.transition()
.attr("y", function(d){ return height - yScale2(d); })
.attr("height", function(d){ return yScale2(d); })
};
// HISTOIGRAM 2 : TOTAL BY TYPE //
var keys2 = typeKeys.map(function(d) {return d.key;})
, min2 = d3.min(types, function(d) {return d.key;})
, max2 = d3.max(types, function(d) {return d.key;})
var xScale2 = d3.scale.ordinal()
.domain(keys2)
.rangeBands([0, width]);
var yScale2 = d3.scale.linear()
.domain([0, d3.max(types.all(), function(d) {return d.value;})])
.range([height / 2, 0]);
var xAxis2 = d3.svg.axis()
.scale(xScale2)
.orient("bottom");
var histogram2 = d3.select("#histogram2").append("svg:svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g");
histogram2.call(tip);
histogram2.append("g")
.attr("class", "axis")
.call(xAxis2)
.attr("transform", "translate(0," + height + ")")
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {return "rotate(-65)"});
histogram2.selectAll("rect")
.data(types.all())
.enter().append("rect")
.attr("x", function(d) {return xScale2(d.key);})
.attr("width", width / keyMap.length - barPadding)
.attr("y", function(d) {return yScale2(d.value); })
.attr("height", function(d) {return height - yScale2(d.value);})
.attr("fill", "steelblue")
.on("mouseover", tip.show)
.on("mouseout", tip.hide);
function resizePath(d) {
var e = +(d == "e")
, x = e ? 1 : -1
, y = height / 4;
return "M" + (.5 * x) + "," + y + "A6,6 0 0 " + e + " " + (6.5 * x) + "," + (y + 6) + "V" + (2 * y - 6) + "A6,6 0 0 " + e + " " + (.5 * x) + "," + (2 * y) + "Z" + "M" + (2.5 * x) + "," + (y + 8) + "V" + (2 * y - 8) + "M" + (4.5 * x) + "," + (y + 8) + "V" + (2 * y - 8);
}
/*** d3-tip styles */
.d3-tip {
line-height: 1.5;
padding: 8px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 0px;
text-align: center;
}
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "BC";
position: absolute;
text-align: center;
}
.d3-tip.n:after {
top: 100%;
left: 0;
margin: -1px 0 0;
}
/*** D3 brush */
.brush .extent {
stroke: #222;
fill-opacity: .125;
shape-rendering: crispEdges;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-tip/0.7.1/d3-tip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.12/crossfilter.min.js"></script>
<div id="histogram1"></div>
<div id="histogram2"></div>
您在响应画笔更新第二个直方图时使用的数据与您最初绘制图表时不同。通常,您会希望在这两种情况下使用同一组的数据 (.all()
)。
特别是,
.data(filt.top(Infinity))
将为图表提供数据的原始行,
.attr("y", function(d){ return height - yScale2(d); })
.attr("height", function(d){ return yScale2(d); })
然后,当秤需要一个数字时,将尝试将这些行对象传递给秤。 (一个对象字面意思是"Not a Number"。)
当您应用过滤器时
year.filterRange([lower,upper]);
这将导致关联交叉过滤器中的所有组重新过滤和重新聚合。 (这在很大程度上是命令式的,而不是函数式编程,接口。filter
方法只是 returns 相同的维度对象。)
如果你更新 y
和 height
完全按照你最初画的那样:
.attr("y", function(d){ return height - yScale2(d.value); })
.attr("height", function(d){ return yScale2(d.value); })
然后转瞬即逝!它过滤。
Fiddle 更正代码:http://jsfiddle.net/gordonwoodhull/hjL6rf9u/5/