D3 charts - Data overlapping issue with huge data - javascript
I have generated a bar chart using D3 charts. Here is the js code
function renderChart(filename) {
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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("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 + ")");
var data = [
{"name": "india", "population": 120},
{"name": "uk", "population": 200},
{"name": "us", "population": 300},
{"name": "china", "population": 50}
];
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.population; })]);
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("Frequency");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.name); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.population); })
.attr("height", function(d) { return height - y(d.population); });
}
Here is the link to fiddle - http://jsfiddle.net/scfx9/
Here, the width of the bars increases and decreases according to the size of the data. When ever I pass huge data the bars shrink and data gets overlapped as the div size is fixed. How do I make the size of the bars constant and allow the users to use the arrow keys to move the data as in the example below
http://bl.ocks.org/mbostock/4062085
If you look at the example you posted, he is handling the keydown event for arrow keys:
d3.select(window).on("keydown", function() {
switch (d3.event.keyCode) {
case 37: year = Math.max(year0, year - 10); break;
case 39: year = Math.min(year1, year + 10); break;
}
update();
});
Your data will need to work a little bit differently but the concept of windowing is the same. Each time the arrow key is pressed your handler will produce a data array that represents the current window into the overall data. Then you will bind the array to enter new bars and exit old ones and you can decide the kind of transition you want.
One difference in your case compared with the example is that his example uses a fixed scale on his X axis, so he never needs to change the axis. In your case because you're using an ordinal scale and your values will be different for each data window, you'll need to update the domain on your X scale and redraw the axis (possible in a transition if you like).
Related
Creating a categorical line chart in D3.js (V4)
I'm relatively new to D3.js and I'm visualising the 'PassengersIn' & 'PassengersOut' values from my busdatasimple.json file. For reference, one of the JSON objects looks like this; { "BusNo": "1", "Date": "21 November 2016", "Time": "09:10:34 AM", "Destination": "Pier 50", "Longitude": "-122.383262", "Latitude": "37.773644", "PassengersIn": "8", "PassengersOut": "1" } I'm now trying to graph the PassengersIn & PassengersOut against the Destination using two lines on a line graph. I'm struggling with the axes as the x has only 2 ticks and the y is not scaling to my data. As seen below; My code is as follows. I've removed the irrelevant Google Maps and jQuery. //Setting The Dimensions Of The Canvas var margin = {top: 20, right: 20, bottom: 70, left: 40}, width = 650 - margin.left - margin.right, height = 350 - margin.top - margin.bottom; //Setting X & Y Ranges var x = d3.scaleOrdinal().range([0, width]); var y = d3.scaleLinear().range([height, 0]); //Define The Axes var xAxis = d3.axisBottom().scale(x); var yAxis = d3.axisLeft().scale(y).ticks(10); //Add The SVG Element var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right + 50) .attr("height", height + margin.top + margin.bottom + 200) .attr("class", "svg") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); //Load Data From JSON d3.json("busdatasimple.json", function(error, data) { //Functions for Y-Axis Grid Lines function yGridLines() { return d3.axisLeft().scale(y).ticks(5); } //Adding the Y-Axis Grid Lines svg.append("g") .attr("class", "grid-lines") .call(yGridLines().tickSize(-width, 0, 0).tickFormat("")); //Adding Y-Axis svg.append("g") .attr("class", "y axis").call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 5) .attr("dy", ".71em") .style("text-anchor", "end") .text("Passengers In"); //Adding X-Axis (Added to the end of the code so the label show over bottom bars) svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .selectAll("text") .style("text-anchor", "middle") //.attr("dx", "-.8em") .attr("dy", "-.55em") .attr("transform", "translate(-5, 15)") .attr("font-family", "Arial") .attr("font-weight", "bold") .attr("font-size", "1.1em"); x.domain(data.map(function(d){return d.Destination;})); y.domain([d3.min(data, function(d){return d.PassengersIn;}), d3.max(data, function(d) {return d.PassengersIn;})]); var line = d3.line() .x(function(d){return x(d.Destination);}) .y(function(d){return y(d.PassengersIn);}); svg.append("path").datum(data) .attr("class", "line") .attr("d", function(d){return d.PassengersIn;}) .attr("stroke", "green") .attr("stroke-width", 2); }); I've managed to find a few examples that use a categorical ordinal scale, however, they are all using v3 of d3.js and after reading through the v4 API countless times I still can't figure it out.
You want a categorical scale, that's right, but you don't want an ordinal scale here. There was a lot of changes from v3 to v4. In v3, you could set .rangeBands, .rangeRoundBands, .rangePoints and .rangeRoundPoints to your ordinal scale, which therefore could accept an continuous range. Not anymore: in D3 v4 you have the brand new scaleBand and scalePoint. In v4, in a regular ordinal scale (which is scaleOrdinal): If range is specified, sets the range of the ordinal scale to the specified array of values. The first element in the domain will be mapped to the first element in range, the second domain value to the second range value, and so on. If there are fewer elements in the range than in the domain, the scale will reuse values from the start of the range. (emphases mine) So, in an scaleOrdinal, the range need to have the same length (number of elements) of the domain. That being said, you want a point scale (scalePoint) here. Band scales and point scales... ...are like ordinal scales except the output range is continuous and numeric. (emphasis mine) Check this snippet, look at the console and compare the two scales: var destinations = ["foo", "bar", "baz", "foobar", "foobaz"]; var scale1 = d3.scaleOrdinal() .range([0, 100]) .domain(destinations); var scale2 = d3.scalePoint() .range([0, 100]) .domain(destinations); destinations.forEach(d=>{ console.log(d + " in an ordinal scale: " + scale1(d) + " / in a point scale: " + scale2(d)) }) <script src="https://d3js.org/d3.v4.min.js"></script> Regarding your y-axis problem: Set the domain of the y scale before calling the axis. So, instead of this: svg.append("g") .attr("class", "y axis").call(yAxis); y.domain([d3.min(data, function(d){ return d.PassengersIn; }), d3.max(data, function(d){ return d.PassengersIn; })]); Change the order: y.domain([d3.min(data, function(d){ return d.PassengersIn; }), d3.max(data, function(d){ return d.PassengersIn; })]);//set the domain first! svg.append("g") .attr("class", "y axis").call(yAxis);
Position a chart top left
I am a newbie using d3 and javascript, but have managed to cobble together some code (using borrowed code from online examples) to create a simple column chart with different colours indicating the status of a variable. Everything works well except that the chart will not position at the top left of the canvas despite adjusting the margin.top or margin.left to small values. If I adjust the browser window to portrait, the chart aligns left but with white significant amounts of white space above it. If I adjust the browser window to landscape the chart aligns to the top but with significant amounts of white space to the left of it. Can someone please advise as to where I have gone wrong. Thanks in advance. <!DOCTYPE html> <meta charset="utf-8"> <style> .axis text { font: 10px sans-serif; } </style> <svg class="chart"></svg> <script src="http://d3js.org/d3.v3.min.js"></script> <script> var data = [ { "status": "Low", "value": "20", "color": "red" }, { "status": "Marginal", "value": "10", "color": "orange" }, { "status": "High", "value": "70", "color": "green" } ]; var margin = {top: 10, right: 20, bottom: 30, left: 30}, width = 200 - margin.left - margin.right, height = 200 - margin.top - margin.bottom; var x = d3.scale.ordinal() .rangeRoundBands([0, width], .1); 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") .ticks(10); 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 + ")"); x.domain(data.map(function(d) { return d.status; })); y.domain([0, 100]); 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("Probability"); svg.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("x", function(d) { return x(d.status); }) .attr("width", x.rangeBand()) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .style("fill", function(d) { return d.color; }); function type(d) { d.frequency = +d.frequency; return d; } </script>
The problem seems to be that you have an <svg class="chart"> element, but your code appends yet another <svg> element to the page after that one, and the first one takes some space
Unneeded white space before the 1st bar in D3 bar chart
I am trying to populate a data set into D3's Bar chart data. I am using this example from the d3: http://bl.ocks.org/mbostock/3885304 Here is my sample data: var data = [{"name":"0","members_count":4},{"name":"1","members_count":1},{"name":"2","members_count":6},{"name":"3","members_count":1},{"name":"4","members_count":1},{"name":"5","members_count":2},{"name":"6","members_count":4},{"name":"7","members_count":3},{"name":"8","members_count":5},{"name":"9","members_count":1},{"name":"10","members_count":2},{"name":"11","members_count":3},{"name":"12","members_count":2},{"name":"13","members_count":0},{"name":"14","members_count":5},{"name":"15","members_count":2},{"name":"16","members_count":2},{"name":"17","members_count":4},{"name":"18","members_count":2},{"name":"19","members_count":4},{"name":"20","members_count":3},{"name":"21","members_count":5},{"name":"22","members_count":8},{"name":"23","members_count":3},{"name":"24","members_count":2},{"name":"25","members_count":3},{"name":"26","members_count":4},{"name":"27","members_count":4},{"name":"28","members_count":1},{"name":"29","members_count":1},{"name":"30","members_count":3},{"name":"31","members_count":5},{"name":"32","members_count":4},{"name":"33","members_count":3},{"name":"34","members_count":6},{"name":"35","members_count":2},{"name":"36","members_count":2},{"name":"37","members_count":7},{"name":"38","members_count":2},{"name":"39","members_count":4},{"name":"40","members_count":2},{"name":"41","members_count":1},{"name":"42","members_count":8},{"name":"43","members_count":10},{"name":"44","members_count":1},{"name":"45","members_count":5},{"name":"46","members_count":2},{"name":"47","members_count":5},{"name":"48","members_count":3},{"name":"49","members_count":1},{"name":"50","members_count":9},{"name":"51","members_count":3},{"name":"52","members_count":2},{"name":"53","members_count":8},{"name":"54","members_count":2},{"name":"55","members_count":3},{"name":"56","members_count":2},{"name":"57","members_count":2},{"name":"58","members_count":5},{"name":"59","members_count":1},{"name":"60","members_count":2},{"name":"61","members_count":4},{"name":"62","members_count":2},{"name":"63","members_count":2},{"name":"64","members_count":6},{"name":"65","members_count":6},{"name":"66","members_count":1},{"name":"67","members_count":1},{"name":"68","members_count":3},{"name":"69","members_count":5},{"name":"70","members_count":3},{"name":"71","members_count":4},{"name":"72","members_count":4},{"name":"73","members_count":1},{"name":"74","members_count":3},{"name":"75","members_count":2},{"name":"76","members_count":4},{"name":"77","members_count":5},{"name":"78","members_count":2},{"name":"79","members_count":1},{"name":"80","members_count":2},{"name":"81","members_count":1},{"name":"82","members_count":4},{"name":"83","members_count":3},{"name":"84","members_count":1},{"name":"85","members_count":4},{"name":"86","members_count":1},{"name":"87","members_count":3},{"name":"88","members_count":1},{"name":"89","members_count":8},{"name":"90","members_count":6},{"name":"91","members_count":6},{"name":"92","members_count":3},{"name":"93","members_count":4},{"name":"94","members_count":5},{"name":"95","members_count":2},{"name":"96","members_count":3},{"name":"97","members_count":2},{"name":"98","members_count":3},{"name":"99","members_count":6},{"name":"100","members_count":3},{"name":"101","members_count":1},{"name":"102","members_count":0},{"name":"103","members_count":5},{"name":"104","members_count":2},{"name":"105","members_count":1},{"name":"106","members_count":7},{"name":"107","members_count":1},{"name":"108","members_count":1},{"name":"109","members_count":7},{"name":"110","members_count":5},{"name":"111","members_count":5},{"name":"112","members_count":2},{"name":"113","members_count":6},{"name":"114","members_count":1},{"name":"115","members_count":2},{"name":"116","members_count":1},{"name":"117","members_count":1},{"name":"118","members_count":10},{"name":"119","members_count":2},{"name":"120","members_count":6},{"name":"121","members_count":1},{"name":"122","members_count":1},{"name":"123","members_count":2},{"name":"124","members_count":4},{"name":"125","members_count":5},{"name":"126","members_count":1},{"name":"127","members_count":1},{"name":"128","members_count":1},{"name":"129","members_count":3},{"name":"130","members_count":3},{"name":"131","members_count":3},{"name":"132","members_count":4},{"name":"133","members_count":3},{"name":"134","members_count":1},{"name":"135","members_count":5},{"name":"136","members_count":5},{"name":"137","members_count":1},{"name":"138","members_count":2},{"name":"139","members_count":5},{"name":"140","members_count":1},{"name":"141","members_count":1},{"name":"142","members_count":2},{"name":"143","members_count":2},{"name":"144","members_count":4},{"name":"145","members_count":4},{"name":"146","members_count":3},{"name":"147","members_count":5},{"name":"148","members_count":2},{"name":"149","members_count":1},{"name":"150","members_count":2},{"name":"151","members_count":3},{"name":"152","members_count":0},{"name":"153","members_count":3},{"name":"154","members_count":1},{"name":"155","members_count":2},{"name":"156","members_count":2},{"name":"157","members_count":1},{"name":"158","members_count":5},{"name":"159","members_count":4},{"name":"160","members_count":4},{"name":"161","members_count":5},{"name":"162","members_count":4},{"name":"163","members_count":2},{"name":"164","members_count":4},{"name":"165","members_count":2},{"name":"166","members_count":2},{"name":"167","members_count":1},{"name":"168","members_count":1},{"name":"169","members_count":10},{"name":"170","members_count":4},{"name":"171","members_count":2},{"name":"172","members_count":2},{"name":"173","members_count":1},{"name":"174","members_count":5},{"name":"175","members_count":1},{"name":"176","members_count":1},{"name":"177","members_count":5},{"name":"178","members_count":3},{"name":"179","members_count":1},{"name":"180","members_count":5},{"name":"181","members_count":8},{"name":"182","members_count":4},{"name":"183","members_count":2},{"name":"184","members_count":1},{"name":"185","members_count":3},{"name":"186","members_count":1},{"name":"187","members_count":3},{"name":"188","members_count":1},{"name":"189","members_count":1},{"name":"190","members_count":6},{"name":"191","members_count":4},{"name":"192","members_count":5},{"name":"193","members_count":1},{"name":"194","members_count":4},{"name":"195","members_count":2},{"name":"196","members_count":2},{"name":"197","members_count":2},{"name":"198","members_count":0},{"name":"199","members_count":3},{"name":"200","members_count":3},{"name":"201","members_count":1},{"name":"202","members_count":1},{"name":"203","members_count":1},{"name":"204","members_count":5},{"name":"205","members_count":1},{"name":"206","members_count":1},{"name":"207","members_count":1},{"name":"208","members_count":1},{"name":"209","members_count":1},{"name":"210","members_count":5},{"name":"211","members_count":2},{"name":"212","members_count":1},{"name":"213","members_count":5},{"name":"214","members_count":1},{"name":"215","members_count":3},{"name":"216","members_count":1},{"name":"217","members_count":1},{"name":"218","members_count":4},{"name":"219","members_count":2},{"name":"220","members_count":1},{"name":"221","members_count":3},{"name":"222","members_count":1},{"name":"223","members_count":3},{"name":"224","members_count":1},{"name":"225","members_count":2},{"name":"226","members_count":1},{"name":"227","members_count":1},{"name":"228","members_count":11},{"name":"229","members_count":9},{"name":"230","members_count":9},{"name":"231","members_count":9},{"name":"232","members_count":10},{"name":"233","members_count":10},{"name":"234","members_count":10},{"name":"235","members_count":9},{"name":"236","members_count":10},{"name":"237","members_count":10},{"name":"238","members_count":10},{"name":"239","members_count":10},{"name":"240","members_count":9},{"name":"241","members_count":9},{"name":"242","members_count":9},{"name":"243","members_count":10},{"name":"244","members_count":10},{"name":"245","members_count":9},{"name":"246","members_count":2},{"name":"247","members_count":1},{"name":"248","members_count":2},{"name":"249","members_count":2},{"name":"250","members_count":1},{"name":"251","members_count":2},{"name":"252","members_count":1},{"name":"253","members_count":5},{"name":"254","members_count":1},{"name":"255","members_count":1},{"name":"256","members_count":1},{"name":"257","members_count":1},{"name":"258","members_count":1},{"name":"259","members_count":1},{"name":"260","members_count":2},{"name":"261","members_count":1},{"name":"262","members_count":1},{"name":"263","members_count":2},{"name":"264","members_count":1},{"name":"265","members_count":1},{"name":"266","members_count":1},{"name":"267","members_count":1},{"name":"268","members_count":2},{"name":"269","members_count":2},{"name":"270","members_count":1},{"name":"271","members_count":1},{"name":"272","members_count":0},{"name":"273","members_count":2},{"name":"274","members_count":1},{"name":"275","members_count":2},{"name":"276","members_count":2},{"name":"277","members_count":1},{"name":"278","members_count":3},{"name":"279","members_count":1},{"name":"280","members_count":1},{"name":"281","members_count":1},{"name":"282","members_count":1},{"name":"283","members_count":1},{"name":"284","members_count":1},{"name":"285","members_count":1},{"name":"286","members_count":1},{"name":"287","members_count":1},{"name":"288","members_count":1},{"name":"289","members_count":1},{"name":"290","members_count":1},{"name":"291","members_count":1},{"name":"292","members_count":1},{"name":"293","members_count":1},{"name":"294","members_count":1},{"name":"295","members_count":1},{"name":"296","members_count":1},{"name":"297","members_count":2},{"name":"298","members_count":2},{"name":"299","members_count":1},{"name":"300","members_count":1},{"name":"301","members_count":1},{"name":"302","members_count":1},{"name":"303","members_count":1},{"name":"304","members_count":1},{"name":"305","members_count":1},{"name":"306","members_count":1},{"name":"307","members_count":1},{"name":"308","members_count":1},{"name":"309","members_count":1},{"name":"310","members_count":1},{"name":"311","members_count":1},{"name":"312","members_count":1},{"name":"313","members_count":0},{"name":"314","members_count":1}] This is chart's drawing code. var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = (960 - margin.left - margin.right) * data.length/50, height = 500 - margin.top - margin.bottom; var x = d3.scale.ordinal() .domain([0,1]) .rangeRoundBands([0, width], 0.1); 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") .ticks(10, "%"); 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 + ")"); x.domain(data.map(function(d) { return d.name; })); y.domain([0, d3.max(data, function(d) { return d.members_count; })]); 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("Frequency"); svg.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("fill","green") .attr("x", function(d) { return x(d.name); }) .attr("width", x.rangeBand()) .attr("y", function(d) { return y(d.members_count); }) .attr("height", function(d) { return height - y(d.members_count); }); This issue I am getting is that I have some white space which looks ugly. This space come before the 1st bar and also after the last bar of the chart. I have tried tweaking the x value of the bar, But I think that is not a good way to do. This space does not come when the data set is small. But when dataset is large then this space comes up. How can I remove this space from the start and from end.
The problem is with this line in scale: .rangeRoundBands([0, width], 0.1); When there is not specified the third parameter outerPadding it adds before and after the chart extra space produced by the padding parameter for each bar. You have set the padding to 0.1. To solve this problem set the outerPadding parameter: var x = d3.scale.ordinal() .domain([0,1]) .rangeRoundBands([0, width], 0.1, 0); Here is updated your code: http://jsfiddle.net/ojntup1a/
JSON keys for x axis, values for y
Basically, I am trying to recreate this graph which was created in Excel: My code so far is this... var theData = [ { 'FB':4, 'Mv':4, 'CB':5, 'SL':3, 'CH':2, 'OT':2, 'Ctrl':6, 'Cmd':6, 'Del':5, 'AA':6, }, { 'FB':2, 'Mv':3, 'CB':4, 'SL':5, 'CH':4, 'OT':3, 'Ctrl':5, 'Cmd':6, 'Del':6, 'AA':5, }, etc... ]; var margin = {top:10, right:10, bottom:30, left:40}, width = 600 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; var x = d3.scale.ordinal() .domain(d3.keys(theData[0])) .rangeRoundBands([0, width]); var y = d3.scale.linear() .domain([2,8]) .range([height,0]); var xAx = d3.svg.axis() .scale(x) .orient('bottom') var yAx = d3.svg.axis() .scale(y) .orient('left') .ticks(3); var svgContainer = d3.select('#d3Stuff').append('svg') .attr('width',width + margin.left + margin.right) .attr('height',height + margin.top + margin.bottom) .style('border','1px solid black') .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svgContainer.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAx) .append("text") .attr("class", "label") .attr("x", width) .attr("y", -6) .style("text-anchor", "end"); svgContainer.append("g") .attr("class", "y axis") .call(yAx) .append("text") .attr("class", "label") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end"); I'm having problems trying to get circles to appear for the values in the data object. I would like them to line up with the x axis keys, obviously. If I can at least get the initial values to show, I can calculate the min/max/avg later. Here is what the code creates so far: Any help would be awesome!
You can use the ordinal scale to find the x position of any circle using the key (since the ordinal domain is made up of keys). For example x("FB"), x("Mv"), etc. To create the circles, you need to bind to an array, in the typical d3 fashion, using the enter, update, exit stuff. Since your data is a hash, not an array, you need to first get it into an array form. That's easy using d3.map() with theData (I'd recommend removing the array [] wrapping around the hash inside theData, since it doesn't do anything, but still): d3.map(theData[0]).entries() /* returns [ { "key": "FB", "value": 4 }, { "key": "Mv", "value": 4 }, { "key": "CB", "value": 5 }, { "key": "SL", "value": 3 }, { "key": "CH", "value": 2 }, ... ]" Once you have this associative array, you can do the usual data(...) binding, append the circles, and then position them with something like .attr("x", function(d) { return x(d.key); })
x-axis zooming with d3 line charts
I'm just getting into using d3, and relatively novice in js still. I'm trying to set up a page of log file visualizations for monitoring some servers. Right now I'm focusing on getting a line chart of CPU utilization, where I can focus on specific time periods (So an x-zoom only). I am able to do a static charts easily, but when it comes to the zooming the examples are going over my head and I can't seem to make them work. This is the static example I followed to get things up and running, and this is the zoom example I've been trying to follow. My input csv is from a rolling set of log files (which will not be labled on the first row), each row looks like this: datetime,server,cpu,memory,disk,network_in,network_out So far what I've been able to get on the zoom looks like this: var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse; // define dimensions of graph var margin = {top: 20, right: 80, bottom: 30, left: 50}, width = 960 - margin.left - margin.right, height = 200 - margin.top - margin.bottom; 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") .tickSize(-height, 0) .tickPadding(6); var yAxis = d3.svg.axis() .scale(y) .orient("left") .tickSize(-width) .tickPadding(6); // Define how we will access the information needed from each row var line = d3.svg.line() .interpolate("step-after") .x(function(d) { return x(d[0]); }) .y(function(d) { return y(d[2]); }); // Insert an svg element into the document for each chart 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 + ")"); // Declare zoom handler var zoom = d3.behavior.zoom().on("zoom", draw); // Open the log and extract the information d3.text("log.csv", function(text) { var data = d3.csv.parseRows(text).map(function(row) { return row.map(function(value, index) { if (index == 0) { return parseDate(value); } else if (index > 1) { return +value; } else { return value; } }); }); // Set the global minimum and maximums x.domain(d3.extent(data, function(d) { return d[0]; })); y.domain(d3.extent(data, function(d) { return d[2]; })); zoom.x(x); // Finally, we have the data parsed, and the parameters of the charts set, so now we // fill in the charts with the lines and the labels 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") .attr("text-anchor", "end") .text("Percent (%)"); svg.append("path") .datum(data) .attr("class", "line") .attr("d", line); svg.append("text") .attr("x", margin.left) .attr("y", 0 - (margin.top / 2)) .attr("text-anchor", "middle") .text('all'); svg.append("rect") .attr("class", "pane") .attr("width", width) .attr("height", height) .call(zoom); svg.select("path.line").data([data]); draw(); }); function draw() { svg.select("g.x.axis").call(xAxis); svg.select("g.y.axis").call(yAxis); svg.select("path.line").attr("d", line); } What this gives me is a very sluggish chart that can be zoomed and panned, but it does not clip off the line at the ends of the chart. I've tried adding in the clipping elements described in the example, but that ends up fully erasing my line every time. Thanks for any help or direction