Iam new to D3.i just want to draw a line chart.For that i just put the static values ,its working fine,But when i fetch data from server db graph is not getting properly.Problem iam getting is x and y axis with values are getting.But not getting the line graph.here is the code
// Line chart creation....................................................
var deviceTime = 0;
var margin = { top: 20, right: 80, bottom: 30, left: 50 };
var da = '<%=#display.to_json(:only => [:DeviceTime, :Speed])%>'
var margin = { top: 20, right: 80, bottom: 30, left: 50 };
var dataset=JSON.parse(da.replace(/"/g,'"'));
//test code TODO :need to move somewhere else
var data = [];
for (var vAlue in dataset[0]) {
var tempData = d3.values(dataset[0][vAlue]);
data.push(tempData[1]);
}
// test end
var yExtents = d3.extent(d3.merge(dataset), function (d) { return d.Speed; });
var xExtents = d3.extent(d3.merge(dataset), function (d) { return d.DeviceTime; });
//alert("xevents[0]-------"+xExtents[0] "xevents[1]-------"+xExtents[1]);
var w = 900;
var h = 400;
var padding = 30;
deviceTime = xExtents[1];
//Create scale functions
var xScale = d3.scale.linear()
.domain([xExtents[0], xExtents[1]])
.range([padding, w - padding * 2]);
var yScale = d3.scale.linear()
.domain([0, yExtents[1]])
//.domain([0, 160])
.range([h - padding, padding]);
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10);
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
///////////////// need to remove
var line = d3.svg.line()
.x(function (d, i) { return xScale(i); })
.y(function (d, i) { return yScale(d); });
//Create SVG element
var svg = d3.select("#bar-demo")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Create X axis
var hh = svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
var path = svg.append("g")
//.attr("clip-path", "url(#clip)")
.append("path")
.data([data])
.attr("class", "line")
.attr("transform", "translate(" + 102 + ",0)")
.attr("d", line);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0-margin.left+10)
.attr("x",0-h/2)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Speed km/h");
svg.append("text")
.attr("y", h)
.attr("x", h)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Time Stamp");
Related
Adapting a histogram with D3 (v3) I find two problems to solve (original code here):
<script type="text/javascript">
var faithfulData = [20,21,26,18,24,24,25,25,21,20,20,18,28,23,17,26,27,27,20,28,23,26,];
var datos_unicos = Array.from(new Set(faithfulData))
var margin = {top: 4, right: 10, bottom: 40, left: 40},
width = 360 - margin.left - margin.right,
height = 180 - margin.top - margin.bottom;
var cant_ticks = datos_unicos.length;
var edad_min = Math.min.apply(Math, datos_unicos) - 3;
var edad_max = Math.max.apply(Math, datos_unicos) + 3;
var vartickValues = []
var tope = (edad_max)+1;
for (var i =edad_min; i< tope; i++) {
vartickValues.push(i);
}
var x = d3.scale.linear()
.domain([edad_min, edad_max])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, .1])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickValues(vartickValues)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format("%"));
var line = d3.svg.line()
.x(function(d) { return x(d[0]); })
.y(function(d) { return y(d[1]); });
var histogram = d3.layout.histogram()
.frequency(false)
.bins(cant_ticks);
var svg = d3.select("#plantel_distribucion").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 + ")");
svg.append("g")
.attr("class", "x plantel_axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", 34)
.style("text-anchor", "end")
.text("Edad de las jugadoras");
svg.append("g")
.attr("class", "y plantel_axis")
.call(yAxis);
var data = histogram(faithfulData),
kde = kernelDensityEstimator(epanechnikovKernel(7), x.ticks(100));
svg.selectAll(".plantel_bar")
.data(data)
.enter().insert("rect", ".axis")
.attr("class", "plantel_bar")
.attr("x", function(d) { return x(d.x) + 1; })
.attr("y", function(d) { return y(d.y); })
.attr("width", x(data[0].dx + data[0].x) - x(data[0].x) - 1)
.attr("height", function(d) { return height - y(d.y); });
svg.append("path")
.datum(kde(faithfulData))
.attr("class", "plantel_line")
.attr("d", line);
//});
function kernelDensityEstimator(kernel, x) {
return function(sample) {
return x.map(function(x) {
return [x, d3.mean(sample, function(v) { return kernel(x - v); })];
});
};
}
function epanechnikovKernel(scale) {
return function(u) {
return Math.abs(u /= scale) <= 1 ? .75 * (1 - u * u) / scale : 0;
};
}
</script>
1) How to place the labels on the x axis in the center of the bin? In other words, the tick mark and its label on the center of the bar.
2) How do I place the quantity (frequency) of each bin above its bar?
I appreciate your comments and leave an image with the current development:
Thanks
For question1, if you just want to add some ticks at the center of each bin, there are x and dx attributes in histogram that indicate the position and step of each bin. You can compute the x tick by xtick = x + dx / 2.
For question2, I think you can draw a line chart above the histogram, and set the z-index to be 2.
I hope the above helps. :)
I know this is easy and I saw some examples in this forum as well as other websites as well, but I simple can't figure it out.
I'm new in using D3 library to generate the charts. I'm trying to learn by creating bar chart.
My question is how to add the Data Labels into the chart?
Below is the codes I have.
then I have my JS:
var chartwidth = 800;
var chartheight = 600;
var data = [
{"Start_Dt":"Jan 15","UnitName":"Unit 1","ProgramName":"ProgramName 1","AttendCnt":159,"NewcomerCnt":10}
, {"Start_Dt":"Jan 22","UnitName":"Unit 2","ProgramName":"ProgramName 2","AttendCnt":178,"NewcomerCnt":5}
, {"Start_Dt":"Feb 14","UnitName":"Unit 2","ProgramName":"ProgramName 3","AttendCnt":240,"NewcomerCnt":46}
, {"Start_Dt":"Feb 19","UnitName":"Unit 1","ProgramName":"ProgramName 4","AttendCnt":201,"NewcomerCnt":10}
, {"Start_Dt":"Feb 26","UnitName":"Unit 2","ProgramName":"ProgramName 5","AttendCnt":177,"NewcomerCnt":7}
, {"Start_Dt":"Mar 12","UnitName":"Unit N","ProgramName":"ProgramName N","AttendCnt":184,"NewcomerCnt":3}
];
var margin = {top: 20, right: 20, bottom: 300, left: 40},
width = chartwidth - margin.left - margin.right,
height = chartheight - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var formatTime = d3.time.format("%e %B");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x2 = d3.scale.ordinal()
.rangeBands([0, width], 0);
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 svg = d3.select(".chart").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 + ")");
data.forEach(function(d) {
d.AttendCnt = +d.AttendCnt;
});
x.domain(data.map(function(d) { return d.Start_Dt + " " + d.ProgramName; }));
y.domain([0, d3.max(data, function(d) { return d.AttendCnt; })]);
//Create X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)" )
.append("text")
.attr("y", 25)
.attr("x",x.rangeBand()/2 )
.style("text-anchor", "middle")
.style("font-size", "20px")
.style("color", "black")
.text(function(d,i) { return "xxx"; });
//Create Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Attendance");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.Start_Dt + " " + d.ProgramName); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.AttendCnt); })
.attr("height", function(d) { return height - y(d.AttendCnt); });
Before
After
How to modify the codes to get the result I wanted? Tks
i haven't tested the code but it could be something like this :
svg.selectAll(".barText")
.data(data)
.enter().append("text")
.attr("class", "barText")
.attr("x", function(d) { return x(d.Start_Dt + " " + d.ProgramName); })
.attr("y", function(d) { return height - y(d.AttendCnt); })
.text(function(d) { return d.AttendCnt; })
;
Hope it helps
I'm learning d3js using various examples found online.
I've been trying to plot a chart with dual Y axis and an X-axis. The Y axis on the left side would plot a bar chart against the X-axis and the Y-axis on the right side would plot a line chart against X-axis. The Bar graph plots as exactly as required but the line graph does not. The X-axis is date (2015-10-15 04:10). Following this example.
The code I wrote
var margin = {top: 50, right: 50, bottom: 100, left: 50},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%m/%d/%Y %H:%M:%S").parse;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var yTxnVol = d3.scale.linear().range([height, 0]);
var yResTime = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(yTxnVol)
.orient("left")
var yAxis2 = d3.svg.axis()
.scale(yResTime)
.orient("right")
.ticks(10);
var svg = d3.selectAll("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("../res/data.csv", function(error, data) {
data.forEach(function(d) {
d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
d.TXN_VOL = +d.TXN_VOL;
});
x.domain(data.map(function(d) { return d.TYM; }));
yTxnVol.domain([0, d3.max(data, function(d) { return d.TXN_VOL+50; })]);
yResTime.domain([0, d3.max(data, function(d) { return d.AVRG_RESP_TIME+50; })]);
var minDate = d3.min(data, function(d){return d.TYM});
var maxDate = d3.max(data, function(d){ return d.TYM});
var xScale = d3.time.scale().range([0,width]);//.domain([minDate, maxDate]);
xScale.domain(d3.extent(data, function(d) { return new Date(d.TYM); }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("g")
.attr("class","y axis")
.attr("transform","translate("+width+ ", 0)")
.call(yAxis2)
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "yhover")
.attr("x", function(d) { return x(d.TYM); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return yTxnVol(d.TXN_VOL); })
.attr("height", function(d) { return height - yTxnVol(d.TXN_VOL); })
var line = d3.svg.line()
.x(function(d) { return xScale(new Date(d.TYM));})
.y(function(d) { return d.AVRG_RESP_TIME; });
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
});
The Output Trying to make this to a meaningful line graph. Got NaN error while formatting the dates.
Could someone help me to make this a proper line graph ?
The csv data sample
TYM, AVRG_RESP_TIME, TXN_VOL
2015-10-15 04:00:00, 12, 170
2015-10-15 04:10:00, 18, 220
2015-10-15 04:20:00, 28, 251
2015-10-15 05:00:00, 19, 100
First, fix your csv file. It is improperly formatted and should not have spaces after the comma.
Second, You are trying to mix an ordinal scale and a time scale for you xAxis. This isn't going to work. For your use case, just stick with time.
Here's a reworking of your code with explanatory comments:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>
<body>
<script>
var margin = {
top: 50,
right: 50,
bottom: 100,
left: 50
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
// x scale should be time and only time
var x = d3.time.scale().range([0, width]);
var yTxnVol = d3.scale.linear().range([height, 0]);
var yResTime = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(yTxnVol)
.orient("left")
var yAxis2 = d3.svg.axis()
.scale(yResTime)
.orient("right")
.ticks(10);
var svg = d3.selectAll("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) {
var data = [{"TYM":"2015-10-15 04:00:00","AVRG_RESP_TIME":"12","TXN_VOL":"170"},{"TYM":"2015-10-15 04:10:00","AVRG_RESP_TIME":"18","TXN_VOL":"220"},{"TYM":"2015-10-15 04:20:00","AVRG_RESP_TIME":"28","TXN_VOL":"251"},{"TYM":"2015-10-15 05:00:00","AVRG_RESP_TIME":"19","TXN_VOL":"100"}];
// just make TYM a date and keep it as a date
data.forEach(function(d) {
d.TYM = parseDate(d.TYM);
d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
d.TXN_VOL = +d.TXN_VOL;
});
// get our min and max date in milliseconds
// set a padding around our domain of 15%
var minDate = d3.min(data, function(d){
return d.TYM;
}).getTime();
var maxDate = d3.max(data, function(d){
return d.TYM;
}).getTime();
var padDate = (maxDate - minDate) * .15;
x.domain([new Date(minDate - padDate), new Date(maxDate + padDate)]);
yTxnVol.domain([0, d3.max(data, function(d) {
return d.TXN_VOL + 50;
})]);
yResTime.domain([0, d3.max(data, function(d) {
return d.AVRG_RESP_TIME + 50;
})]);
// set an intelligent bar width
var barWidth = (width / x.ticks().length) - 20;
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis2)
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "yhover")
.attr("x", function(d) {
// center bar on time
return x(d.TYM) - (barWidth / 2);
})
.attr("width", barWidth)
.attr("y", function(d) {
return yTxnVol(d.TXN_VOL);
})
.attr("height", function(d) {
return height - yTxnVol(d.TXN_VOL);
})
.style("fill","orange");
var line = d3.svg.line()
.x(function(d) {
return x(d.TYM);
})
.y(function(d) {
return d.AVRG_RESP_TIME;
});
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.style("fill","none")
.style("stroke","steelblue")
.style("stoke-width","3px");
// });
</script>
</body>
</html>
The issue with the line graph filling with black was due to improper css. The new css property.
.line {
fill: none;
stroke: darkgreen;
stroke-width: 2.5px;
}
For the dates I formatted it to (%Y-%m-%d %H:%M) format and it worked.
Trying to develop a stacked chart plugin.
This was the basic version
http://jsfiddle.net/NYEaX/131/
this is my current plugin
http://jsfiddle.net/NYEaX/149/
_ there are issues though with a) having more than one chart b) updating the chart(s)
I've tried breaking up the code required to build the chart and update it/handle the block/morphs. I think I need to add transitions - enter/exit/remove on the code responsible for adding the stacked chart blocks.
buildChart: function(data, w, h, yLabel){
var that = this;
var margin = {top: 30, right: 55, bottom: (h * 0.56), left: 95},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
this.x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
this.y = d3.scale.linear()
.rangeRound([height, 0]);
var colorArray = ["#538ed5", "#953735", "#e46d0a", "#75923c", "#b2a1c7", "#dc143c", "#87cefa", "#90ee90", "#add8e6", "#d3d3d3", "#cf1256", "#12cf5e"];
this.color = d3.scale.ordinal()
.range(colorArray);
var xAxis = d3.svg.axis()
.scale(this.x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(this.y)
.orient("left")
//.tickFormat(d3.format(".2s"));
var chartWidth = parseInt(width + margin.left + margin.right,10);
var chartHeight = parseInt(height + margin.top + margin.bottom,10);
var svg = d3.select(methods.el["selector"])
.append("svg")
.attr("class", "stackedchart")
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr('viewBox', "0 0 "+chartWidth+" "+chartHeight)
.attr('perserveAspectRatio', "xMinYMid")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
this.color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Label"; }));
data.forEach(function(d) {
var y0 = 0;
d.blocks = that.color.domain().map(function(name) {
return {name: name, values: d[name], y0: y0, y1: y0 += +d[name]};
});
d.total = d.blocks[d.blocks.length - 1].y1;
});
this.x.domain(data.map(function(d) { return d.Label; }));
this.y.domain([0, d3.max(data, function(d) { return d.total; })]);
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", "-3.5em")
.style("text-anchor", "end")
.text(yLabel);
var xlabels = svg.selectAll(".x.axis text")
.attr("transform", "rotate(-60) translate(-10,-10)")
that.manageStack(svg, data);
that.buildLegend();
//that.resizeChart();
}
I'm new to D3 charts and I'm getting an error saying 'Error: Problem Parsing' when trying to run my code. The code and error can be seen below. I have no idea what the problem is except it has something to do with parsing the 'd.value'. Both X and Y axis show up as well as the X axis dates. But there are no lines. The value coming in is already a number, but I've tried to use parseFloat, parseInt, and parseDouble to make it work. I'm out of ideas.
Error: Problem parsing d="M0,NaNL0.47187163062091714,NaNL0.9437432612418343,NaNL1.4156148918627514,NaNL1.8874865224836685,NaNL2.3593581531045857,NaNL2.8312297837255027, etc. etc.
function drawLineChart(element, chartData){
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 380 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var parseDateD3 = d3.time.format("%d-%m-%y").parse;
var defaultMax = 50;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.ticks(6)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.ticks(6)
.orient("left");
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
var svg = d3.selectAll(element).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("margin", "auto")
.style("background-color", "white")
.style("border", "2px solid white")
.style("border-radius", "25px")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//d3.tsv("/resources/sampledata/data.tsv", function(error, data) {
chartData.forEach(function(d) {
var day = JSON.stringify(d.day.date);
var month = JSON.stringify(d.day.month);
var year = JSON.stringify(d.day.year);
if(day < 10) day = "0" + day;
if(month < 10) month = "0" + month;
year = year.substring(1, year.length);
d.date = parseDateD3(day + "-" + month + "-" + year);
var NUMBER = parseInt(d.value);
d.number = +NUMBER;
});
x.domain(d3.extent(chartData, function(d,i) { return d.date; }));
y.domain(d3.extent(chartData, function(d) { return d.number; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("path")
.datum(chartData)
.attr("class", "line")
.attr("d", line);
svg.append("rect")
.attr("class", "goal")
.style("opacity", 0.2)
.attr("width", width)
.attr("height", height - defaultMax)
.attr("transform", "translate(0," + defaultMax + ")");
}
In the definition of your line, you should have
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.number); });
instead of
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
The code was referencing .close and you're setting and using .number elsewhere.