【发布时间】:2014-03-30 14:53:51
【问题描述】:
工作解决方案:现在我正在设计样式并解决一些与我创建由具有值跟踪的多数据系列组成的图表有关的问题。如果有人遇到与我相同或相似的问题,我会尽快给你一个工作代码示例,可以以此为基础。目前我使用的大部分技巧都在下面的 cmets 中。
这将是我在 StackOverflow 上的第一个问题,我期待看到您可能对我的问题有什么答案。
最近我有一个项目,我必须编写 Javascript 代码来生成图表,并且我可以同时从图表的每一行读取 Y 值。我对 D3 框架非常陌生,现在我能够读取 csv 数据、创建多系列图表以及跟踪和读取 Y 值,但只有当我从单个数据系列创建图表时。我试图创建多个类似的函数来跟踪来自不同系列数据的数据,但它不起作用,并且在控制台中我看到 Y 显示为空值。我正在使用 D3 网站上的示例来尝试学习它,现在代码将与这些示例非常相似。
稍后我需要用它做一些其他的事情,但我认为在解决了这个问题之后我将能够继续前进。会有这样的:
- 通过代码从 csv 中减少数据,因为我需要删除标头信息
- 更改图表的视觉样式并编辑轴缩放
现在我有类似的东西。对不起,如果它有点乱,但我仍在学习和尝试很多不同的事情。我还添加了对我来说看起来像的屏幕截图以及我可以获得的一些控制台信息。我希望它能帮助你们了解我做错了什么以及我需要学习什么。这也不是我唯一的方法,展示它们太长了。
编辑:我正在尝试一些不同的方法。在页面底部,我将展示我现在所做的。
EDIT2:对不起,如果我对我的目标不够精确。我想要做的是我希望能够在一个 X 轴值上同时读取绘制线的所有 Y 轴值(它将是其中的 4 个)。我添加了第二个代码的屏幕截图,其中我只能读取一个 Y 轴值而无法读取超过一个。
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
</style>
<body>
<script src="d3.min.js"></script>
<script>
var margin = {top: 20, right: 80, bottom: 30, left: 200},
//-margin.left
width = 960 - margin.right,
height = 750 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%M-%d %H:%M").parse,
//dodane do sledzenia myszy i rysowania kuleczek
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) { return "$" + formatValue(d); };
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.transfers); });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("data2.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var bitrates = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, transfers: +d[name]};
})
};
});
console.log(bitrates);
//data.sort(function(a, b) {
//return a.date - b.date;
//});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(bitrates, function(c) { return d3.min(c.values, function(v) { return v.transfers; }); }),
d3.max(bitrates, function(c) { return d3.max(c.values, function(v) { return v.transfers; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Transfers");
var chart = svg.selectAll(".chart")
.data(bitrates)
.enter().append("g")
.attr("class", "chart");
chart.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
//.attr("d", line);
.style("stroke", function(d) { return color(d.name); });
chart.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.transfers) + ")"; })
.attr("x", 3)
.attr("dy", ".35em");
//.text(function(d) { return d.name; });
//sledzenie myszy i rysowanie kuleczek
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("g").append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
focus.select("text").text(formatCurrency(d.value));
}
});
</script>
在我看来是这样的: Generated chart CSV 数据文件如下所示:
date,Średni wych.:,Średni wch.:,Maks. wych.:,Maks. wch.:
2014-02-14 15:40,86518717581,101989990772,88304882317,108036052338
2014-02-14 16:00,85739038102,98312113056,87060053514,107154908503
我在试图了解问题时检查了一些过度信息:
[Object, Object, Object, Object]
0: Object
name: "Średni wych.:"
values: Array[504]
__proto__: Object
1: Object
2: Object
name: "Maks. wych.:"
values: Array[504]
[0 … 99]
[100 … 199]
100: Object
date: Thu Jan 16 2014 01:00:00 GMT+0100 (Środkowoeuropejski czas stand.)
transfers: 49305177944
__proto__: Object
101: Object
date: Thu Jan 16 2014 01:20:00 GMT+0100 (Środkowoeuropejski czas stand.)
transfers: 42169641572
__proto__: Object
102: Object
date: Thu Jan 16 2014 01:40:00 GMT+0100 (Środkowoeuropejski czas stand.)
transfers: 39400112189
__proto__: Object
103: Object
104: Object
105: Object
106: Object
107: Object
108: Object
109: Object
110: Object
非常感谢您的帮助。我知道一些面向对象的编程、HTML、CSS,但现在我并没有真正使用任何框架,学习起来很有趣,但另一方面,在试图弄清楚我在做什么的时候可能真的很沮丧错了。
编辑
现在我正在尝试分别绘制两条线。它工作得很好,它可以让我以后更容易改变线条样式。现在我需要对这些行中的每一行使用 mousemove 函数。然后将读取的值传递给一些变量并在某个框或其他东西中显示它们会相当容易。
这是我第二次尝试的代码(对不起,帖子变长了):
Screenshot for the second code is called Chart2.jpg
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: none;
stroke: steelblue;
}
</style>
<body>
<script src="d3.js"></script>
<script>
var margin = {top: 20, right: 50, bottom: 30, left: 100},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) { return "$" + formatValue(d); };
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.open); });
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
d.open = +d['open data'];
});
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain([data[0].date, data[data.length - 1].date]);
y.domain([0, d3.max(data, function(d) { return Math.max(d.close, d.open); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
svg.append("path")
.datum(data)
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline2);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove1)
.on("mousemove", mousemove2);
function mousemove1() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus = focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select("text").text(formatCurrency(d.close));
}
function mousemove2() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus = focus.attr("transform", "translate(" + x(d.date) + "," + y(d.open) + ")");
focus.select("text").text(formatCurrency(d.open));
}
});
</script>
【问题讨论】:
-
我发布了一种不同的方法,可以帮助我解决这个问题。如果有人对下一步做什么有建议,我将不胜感激。
-
我不太确定你的问题是什么?您是否需要一个工具提示来显示与鼠标具有相同 x 值的所有行的 y 值?您应该能够使用您拥有的 mousemove 功能来做到这一点。还是您只想要鼠标下特定行的值?在这种情况下,您将 (a) 需要将数据数组绑定到
<path>元素或其父<g>元素(您的第二个代码示例执行此操作),并且 (b) 接受该数据数组作为 mousemove 的参数函数:`function mousemove(pathData){... var d0=pathData[i - 1]; ...}。 -
是的。在一个 X 轴值上读取所有 Y 轴值是我想要做的。对此感到抱歉。我试图将 b) 解决方案应用于我的第一个代码,但我无法使其工作,第二个代码仅读取一个 Y 轴值。我会尝试找出它有什么问题,但我会很感激更多的建议。我花了大约 5 天的时间来解决这个问题,此时我觉得我真的陷入了困境。
标签: javascript csv svg charts d3.js