我正在使用 jmeter 在网站上执行负载测试。Jmeter 以 CSV 文件的形式生成输出。
我想使用这个 CSV 文件生成条形图。为了生成图表,我使用 D3 和 Crossfilter。
为此,我参考了http://square.github.io/crossfilter/ 并根据我的 CSV 文件要求通过编辑使用了相同的代码。
它显示以下错误:-
Error: Problem parsing d="M230,100V50h9V100MNaN,100V0h9V100" index.html:1
2
Error: Problem parsing d="M230,100V100h9V100MNaN,100V100h9V100" d3.v3.min.js:1
46
Error: Problem parsing d="M230,100V100h9V100MNaN,100V100h9V100" d3.v3.min.js:1
114
Error: Problem parsing d="M230,100V100h9V100MNaN,100V0h9V100" d3.v3.min.js:1
30
我的 CSV 文件是:
timeStamp,elapsed,label,responseCode,responseMessage,threadName,dataType,success,bytes,grpThreads,allThreads,Latency,Hostname
12/25/2012 0:02,2417,/ratings/rate.php,200,OK,Thread Group 1-1,text,TRUE,1067,1,1,2417,PRAVIN-PC
12/25/2012 0:02,3784,/ratings/rate.php,200,OK,Thread Group 1-1,text,TRUE,913,1,1,3783,PRAVIN-PC
12/25/2012 0:12,3121,/gampad/ads,200,OK,Thread Group 1-1,text,TRUE,1214,1,1,3121,PRAVIN-PC
`
我的 HTML 文件代码是:
<style>
body {
font-family: "Helvetica Neue";
margin: 40px auto;
width: 960px;
min-height: 2000px;
}
#body {
position: relative;
}
footer {
padding: 2em 0 1em 0;
font-size: 12px;
}
h1 {
font-size: 96px;
margin-top: .3em;
margin-bottom: 0;
}
h1 + h2 {
margin-top: 0;
}
h2 {
font-weight: 400;
font-size: 28px;
}
h1, h2 {
font-family: "Yanone Kaffeesatz";
text-rendering: optimizeLegibility;
}
#body > p {
line-height: 1.5em;
width: 640px;
text-rendering: optimizeLegibility;
}
#charts {
padding: 10px 0;
}
.chart {
display: inline-block;
height: 151px;
margin-bottom: 20px;
}
.reset {
padding-left: 1em;
font-size: smaller;
color: #ccc;
}
.background.bar {
fill: #ccc;
}
.foreground.bar {
fill: steelblue;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text {
font: 10px sans-serif;
}
.brush rect.extent {
fill: steelblue;
fill-opacity: .125;
}
.brush .resize path {
fill: #eee;
stroke: #666;
}
#hour-chart {
width: 260px;
}
#delay-chart {
width: 230px;
}
#distance-chart {
width: 420px;
}
#date-chart {
width: 920px;
}
#flight-list {
min-height: 1024px;
}
#flight-list .date,
#flight-list .day {
margin-bottom: .4em;
}
#flight-list .flight {
line-height: 1.5em;
background: #eee;
width: 640px;
margin-bottom: 1px;
}
#flight-list .time {
color: #999;
}
#flight-list .flight div {
display: inline-block;
width: 100px;
}
#flight-list div.distance,
#flight-list div.delay {
width: 160px;
padding-right: 10px;
text-align: right;
}
#flight-list .early {
color: green;
}
aside {
position: absolute;
left: 740px;
font-size: smaller;
width: 220px;
}
</style>
<div id="body">
<div id="charts">
<div id="hour-chart" class="chart">
<div class="title">Time of Day</div>
</div></br>
<div id="delay-chart" class="chart">
<div class="title">Page Load Time (ms.)</div>
</div>
<!-- <div id="distance-chart" class="chart">
<div class="title">Visit Time (mi.)</div>
</div>
<div id="date-chart" class="chart">
<div class="title">Date</div>
</div>-->
</div>
<aside id="totals"><span id="active">-</span> of <span id="total">-</span> Visits selected.</aside>
<div id="lists">
<div id="flight-list" class="list"></div>
</div>
<footer>
<span style="float:right;">
Released under the <a href="http://www.apache.org/licenses/LICENSE- 2.0.html">Apache License 2.0</a>.
</span>
Copyright 2012 <a href="http://squareup.com">Square, Inc.</a>
</footer>
</div>
<script src="crossfilter.min.js"></script>
<script src="d3.v3.min.js"></script>
<script>
// (It's CSV, but GitHub Pages only gzip's JSON at the moment.)
d3.csv("resultofcommandline.csv", function(flights) {
// A nest operator, for grouping the flight list.
var nestByDate = d3.nest()
.key(function(d) { return d3.time.day(d.date); });
// A little coercion, since the CSV is untyped.
flights.forEach(function(d, i) {
d.index = i;
d.timeStamp = parseDate(d.timeStamp);
d.Latency = +d.Latency;
});
// Create the crossfilter for the relevant dimensions and groups.
var flight = crossfilter(flights),
all = flight.groupAll(),
hour = flight.dimension(function(d) { return d.timeStamp.getHours() + d.timeStamp.getMinutes() / 60; }),
hours = hour.group(Math.floor),
latency = flight.dimension(function(d) {return Math.min(1999, d.Latency);}),
latencys = latency.group(function (d){ return Math.floor(d/50)*50 ;});
var charts = [
barChart()
.dimension(latency)
.group(latencys)
.x(d3.scale.linear()
.domain([0, 2000])
.rangeRound([0, 10 * 40])),
barChart()
.dimension(hour)
.group(hours)
.x(d3.scale.linear()
.domain([0, 24])
.rangeRound([0, 10 * 24]))
];
// Given our array of charts, which we assume are in the same order as the
// .chart elements in the DOM, bind the charts to the DOM and render them.
// We also listen to the chart's brush events to update the display.
var chart = d3.selectAll(".chart")
.data(charts)
.each(function(chart) { chart.on("brush", renderAll).on("brushend", renderAll); });
renderAll();
// Renders the specified chart or list.
function render(method) {
d3.select(this).call(method);
}
// Whenever the brush moves, re-rendering everything.
function renderAll() {
chart.each(render);
}
// Like d3.time.format, but faster.
function parseDate(d) {
return new Date(d.substring(6,10),
d.substring(0, 2) - 1,
d.substring(3, 5),
d.substring(11, 13),
d.substring(14, 16));
}
window.filter = function(filters) {
filters.forEach(function(d, i) { charts[i].filter(d); });
renderAll();
};
window.reset = function(i) {
charts[i].filter(null);
renderAll();
};
function barChart() {
if (!barChart.id) barChart.id = 0;
var margin = {top: 10, right: 10, bottom: 20, left: 10},
x,
y = d3.scale.linear().range([100, 0]),
id = barChart.id++,
axis = d3.svg.axis().orient("bottom"),
brush = d3.svg.brush(),
brushDirty,
dimension,
group,
round;
function chart(div) {
var width = x.range()[1],
height = y.range()[0];
y.domain([0, group.top(1)[0].value]);
div.each(function() {
var div = d3.select(this),
g = div.select("g");
// Create the skeletal chart.
if (g.empty()) {
div.select(".title").append("a")
.attr("href", "javascript:reset(" + id + ")")
.attr("class", "reset")
.text("reset")
.style("display", "none");
g = div.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 + ")");
g.append("clipPath")
.attr("id", "clip-" + id)
.append("rect")
.attr("width", width)
.attr("height", height);
g.selectAll(".bar")
.data(["background", "foreground"])
.enter().append("path")
.attr("class", function(d) { return d + " bar"; })
.datum(group.all());
g.selectAll(".foreground.bar")
.attr("clip-path", "url(#clip-" + id + ")");
g.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(axis);
// Initialize the brush component with pretty resize handles.
var gBrush = g.append("g").attr("class", "brush").call(brush);
gBrush.selectAll("rect").attr("height", height);
gBrush.selectAll(".resize").append("path").attr("d", resizePath);
}
// Only redraw the brush if set externally.
if (brushDirty) {
brushDirty = false;
g.selectAll(".brush").call(brush);
div.select(".title a").style("display", brush.empty() ? "none" : null);
if (brush.empty()) {
g.selectAll("#clip-" + id + " rect")
.attr("x", 0)
.attr("width", width);
}
else {
var extent = brush.extent();
g.selectAll("#clip-" + id + " rect")
.attr("x", x(extent[0]))
.attr("width", x(extent[1]) - x(extent[0]));
}
}
g.selectAll(".bar").attr("d", barPath);
});
function barPath(groups) {
var path = [],
i = -1,
n = groups.length,
d;
while (++i < n) {
d = groups[i];
path.push("M", x(d.key), ",", height, "V", y(d.value), "h9V", height);
}
return path.join("");
}
function resizePath(d) {
var e = +(d == "e"),
x = e ? 1 : -1,
y = height / 3;
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);
}
}
brush.on("brushstart.chart", function() {
var div = d3.select(this.parentNode.parentNode.parentNode);
div.select(".title a").style("display", null);
});
brush.on("brush.chart", function() {
var g = d3.select(this.parentNode),
extent = brush.extent();
if (round) g.select(".brush")
.call(brush.extent(extent = extent.map(round)))
.selectAll(".resize")
.style("display", null);
g.select("#clip-" + id + " rect")
.attr("x", x(extent[0]))
.attr("width", x(extent[1]) - x(extent[0]));
dimension.filterRange(extent);
});
brush.on("brushend.chart", function() {
if (brush.empty()) {
var div = d3.select(this.parentNode.parentNode.parentNode);
div.select(".title a").style("display", "none");
div.select("#clip-" + id + " rect").attr("x", null).attr("width", "100%");
dimension.filterAll();
}
});
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.x = function(_) {
if (!arguments.length) return x;
x = _;
axis.scale(x);
brush.x(x);
return chart;
};
chart.y = function(_) {
if (!arguments.length) return y;
y = _;
return chart;
};
chart.dimension = function(_) {
if (!arguments.length) return dimension;
dimension = _;
return chart;
};
chart.filter = function(_) {
if (_) {
brush.extent(_);
dimension.filterRange(_);
} else {
brush.clear();
dimension.filterAll();
}
brushDirty = true;
return chart;
};
chart.group = function(_) {
if (!arguments.length) return group;
group = _;
return chart;
};
chart.round = function(_) {
if (!arguments.length) return round;
round = _;
return chart;
};
return d3.rebind(chart, brush, "on");
}
});
</script>