I am trying to create a line chart but I get the error...
Error: attribute d: Expected number, "M67,0L67,0LNaN,0LNaN,0L728"
... every time I have three or more elements. I want to set the date with that format in the x-axis. I have tried scaling with times, but I just want to show the dates that the JSON file contains, not a range of dates.
This is the JSON file I am using:
[{"date": "20-Jun-19", "close": "5", "text": "Test"},
{"date": "21-Jun-19", "close": "5", "text": "Test"},
{"date": "25-Jun-19", "close": "5", "text": "Test"}]
This is the Javascript I am using.
var label = d3.select(".label");
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 1460 - margin.left - margin.right,
height = 870 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(20);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(15);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
var svg = d3.select(".anxiety-graphic")
.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.json("data.json", function(error, data) {
var categoriesNames = data.map(function (d) {
return +d.date;
});
x.domain(categoriesNames);
// Scale the range of the data
x.domain(d3.extent(data, function(d) { console.log(d); return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data));
// Add the valueline path.
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 10)
.attr("cx", function(d) {
return x(d.date)
})
.attr("cy", function(d) {
return y(d.close)
})
.on("mouseover", function(d,i) {
label.style("transform", "translate("+ x(d.date) +"px," + (y(d.close)) +"px)")
label.text(d.close)
});
// Add the X Axis
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
});
For whatever reason, you are replacing the correct domain...
x.domain(categoriesNames);
... for a wrong one in the very next line:
x.domain(d3.extent(data, function(d){ return d.date; }));
d3.extent returns an array with 2 values only, and that's why you're getting this issue when your data have three or more elements.
Also, the map for creating categoriesNames has an issue:
var categoriesNames = data.map(function (d) {
return +d.date;
});
Since the date is a string containing letters, it's not clear why you're using the unary plus (which will return NaN). Drop that:
var categoriesNames = data.map(function (d) {
return d.date;
});
Here is your code with those changes:
var label = d3.select(".label");
var margin = {
top: 30,
right: 20,
bottom: 30,
left: 50
},
width = 1460 - margin.left - margin.right,
height = 870 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(20);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(15);
// Define the line
var valueline = d3.svg.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
// Adds the svg canvas
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 = [{
"date": "20-Jun-19",
"close": "5",
"text": "Test"
},
{
"date": "21-Jun-19",
"close": "5",
"text": "Test"
},
{
"date": "25-Jun-19",
"close": "5",
"text": "Test"
}
];
var categoriesNames = data.map(function(d) {
return d.date;
});
x.domain(categoriesNames);
y.domain([0, d3.max(data, function(d) {
return d.close;
})]);
// Add the valueline path.
svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data));
// Add the valueline path.
svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("r", 10)
.attr("cx", function(d) {
return x(d.date)
})
.attr("cy", function(d) {
return y(d.close)
})
.on("mouseover", function(d, i) {
label.style("transform", "translate(" + x(d.date) + "px," + (y(d.close)) + "px)")
label.text(d.close)
});
// Add the X Axis
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
Related
i am using D3 to draw line graph in JavaScript. Line of Line graph is drawn right but date on x axis is not correct and it is also showing one extra tick on x axis. I had also tried changing tick format but i failed. I don't know where i am doing wrong. please help. here is my code
var margin = {top: 50, right: 50, bottom: 50, left: 50}
, width = window.innerWidth - margin.left - margin.right // Use the window's width
, height = window.innerHeight - margin.top - margin.bottom; // Use the window's height
// The number of datapoints
var n = 4;
var xScale = d3.scaleLinear()
.domain([0, n-1]) // input
.range([0, width]); // output
var parseTime = d3.timeParse("%d-%b-%y");
// 6. Y scale will use the randomly generate number
var yScale = d3.scaleLinear()
.domain([0, 100]) // input
.range([height, 0]); // output
d3.csv("Data_vis.csv", function(data){
//console.log(data);
var nov_11_percent= 22;
var oct_16_percent= 25;
var nov_13_percent= 24;
var oct_22_percent= 21;
var dataset2=[{"date":'2018-09-11', "value": nov_11_percent},
{"date":'2018-10-16', "value": oct_16_percent},
{"date":'2018-10-22', "value": oct_22_percent},
{"date":'2018-11-13', "value": nov_13_percent}];
dataset2.forEach(function(d) {
d.date = new Date(d.date);
});
var line = d3.line()
.x(function(d, i) {
//alert(parseTime(d.date));
return xScale(d.date);
})
.y(function(d,i ) {
return yScale(d.value);
})
.curve(d3.curveMonotoneX)
xScale.domain(d3.extent(dataset2, function(d) {
return d.date; }));
yScale.domain([0, d3.max(dataset2, function(d) {
return d.value;
})]);
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 + ")");
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale)
.ticks(4)
.tickFormat(d3.timeFormat("%Y-%m-%d")));
svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale));
svg.append("path")
.datum(dataset2)
.attr("class", "line")
.attr("d", line);
svg.selectAll(".dot")
.data(dataset2)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d) { return xScale(d.date) })
.attr("cy", function(d) { return yScale(d.value) })
.attr("r", 10);
});
any help would be much appreciated. thank you
Use a point scale instead of a linear scale for x.
var xScale = d3
.scalePoint()
.range([0, width])
.domain(dataset2.map(i => i.date))
const margin = { top: 50, right: 50, bottom: 50, left: 50 }
const width = window.innerWidth - margin.left - margin.right // Use the window's width
const height = window.innerHeight - margin.top - margin.bottom // Use the window's height
const dataset2 = [{ date: "2018-09-11", value: 22 },{ date: "2018-10-16", value: 25 },{ date: "2018-10-22", value: 24 },{ date: "2018-11-13", value: 21 }]
dataset2.forEach(function(d) {
d.date = new Date(d.date)
})
// 6. Y scale will use the randomly generate number
const yScale = d3
.scaleLinear()
.domain([
0,
d3.max(dataset2, function(d) {
return d.value
})
]) // input
.range([height, 0]) // output
const xScale = d3
.scalePoint()
.range([0, width])
.domain(dataset2.map(d => d.date))
const line = d3
.line()
.x(function(d, i) {
return xScale(d.date)
})
.y(function(d, i) {
return yScale(d.value)
})
.curve(d3.curveMonotoneX)
const 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 + ")")
svg
.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(
d3
.axisBottom(xScale)
.tickFormat(d3.timeFormat("%m/%d"))
)
svg
.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale))
svg
.append("path")
.datum(dataset2)
.attr("class", "line")
.attr("d", line)
.attr("fill", "none")
.attr("stroke", "black")
svg
.selectAll(".dot")
.data(dataset2)
.enter()
.append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function(d) {
return xScale(d.date)
})
.attr("cy", function(d) {
return yScale(d.value)
})
.attr("r", 10)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Codepen
I am trying to render 2 graphs on the same page: chart graph and a linear graph
in html i have two divs which bind to the 2 different graphs respectively like so:
<div id="svg-container">
<div id="svg-container-avg">
The first graph that i import in html is this linear 'average' graph that just doesn't display the path or the x axis.
It works fine if i delete the chart graph which is imported straight after. I would automatically assume that there are some sort of dependencies between the two graphs, but i cannot find anything...
my first import, linear graph: scns-avg.js file contains this
// Set the dimensions of the canvas / graph
var margin = {
top: 30,
right: 20,
bottom: 70,
left: 50
},
width = 800 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var x = d3.scale.linear().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var valueline = d3.svg.line()
.x(function(d) {
return x(d.scnsID);
})
.y(function(d) {
return y(d.average);
});
var svg2 = d3.select("#svg-container-avg")
.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 + ")");
// Get the data
d3.json("scns-avg-data-retrieval.php", function(error, data) {
data.forEach(function(d) {
d.scnsID = d.scnsID;
d.average = +d.average;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.scnsID;
}));
y.domain([0, d3.max(data, function(d) {
return d.average;
})]);
svg2.append("path") // Add the valueline path.
.style("stroke", "rgba(13, 183, 196, 0.9)")
.attr("d", valueline(data));
svg2.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) {
return x(d.scnsID);
})
.attr("cy", function(d) {
return y(d.average);
})
svg2.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg2.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
});
My Data structor in JSON:
[{"date":"11-Mar-16","average":"3.18","scnsID":"2"},{"date":"12-Mar-16","average":"3.09","scnsID":"3"},{"date":"15-Mar-16","average":"3.16","scnsID":"4"},{"date":"17-Mar-16","average":"3.20","scnsID":"5"}]
When trying to run the html page with both graphs being imported the scns-avg.js throws up in the console Error: Invalid value for attribute d="M43,2.8124999999999902LNaN,15.46875000000002LNaN,5.6249999999999805L471,0"
which points to valueline(data) in this part of the code
svg2.append("path")
.style("stroke", "rgba(13, 183, 196, 0.9)")
.attr("d", valueline(data));
That is dependent on this piece of code, so the problem must be lying here, but for 6 hours now i can't find the solution to this..
var valueline = d3.svg.line()
.x(function(d) { return x(d.scnsID); })
.y(function(d) { return y(d.average); });
My chart graph that gets imported next and if disabled the linear graph renders properly is as follows below:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - 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(5);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Frequency:</strong> <span style='color:rgba(13, 183, 196, 0.9)'>" + d.average + "</span>";
});
var svg = d3.select("#svg-container").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.call(tip);
// Get the data
d3.json("scns-data-retrieval.php", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.question = d.question;
d.average = +d.average;
});
x.domain(data.map(function(d) { return d.question; }));
y.domain([0, 5]);
legendSpace = width/5;
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", 0 - margin.left)
.attr("x", 0 - (height / 3))
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Level of need for help:");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.question); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.average); })
.attr("height", function(d) { return height - y(d.average); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
});
function type(d) {
d.average = +d.average;
return d;
};
data structure in JSON:
[{"question":1,"average":3.3333333333333},{"question":2,"average":2.5},{"question":3,"average":4},{"question":4,"average":2.75},{"question":5,"average":2.75},{"question":6,"average":2.75},{"question":7,"average":3},{"question":8,"average":3},{"question":9,"average":2.75},{"question":10,"average":3.25},{"question":11,"average":3.25},{"question":12,"average":3.5},{"question":13,"average":3},{"question":14,"average":3.25},{"question":15,"average":3.5},{"question":16,"average":3.5},{"question":17,"average":3.25},{"question":18,"average":3.75},{"question":19,"average":3.5},{"question":20,"average":3},{"question":21,"average":3},{"question":22,"average":3.5},{"question":23,"average":3.25},{"question":24,"average":3.75},{"question":25,"average":3.75},{"question":26,"average":3.75},{"question":27,"average":3.5},{"question":28,"average":2.75},{"question":29,"average":2.25},{"question":30,"average":3.5},{"question":31,"average":3},{"question":32,"average":3}]
I can't do this anymore and it's driving me crazy so i am now turning to the power of stackoverflow!
After some mad research and trial and error i have fixed this problem.
When you are trying to render more than 1 graph, if they are of different type and not lets say - multiple linear graphs, but something like a linear graph with a bar chart the variable scope is getting mixed up and it's not restricted to the javascript file once it's imported into html.
To fix this problem every graph js file has to wrapped in (function(){ All your graph code goes here })();
This restricts the variable scope to just the function.
I am just learning how to use d3-tip in a multiline chart. I took this example for practising: http://bl.ocks.org/d3noob/d8be922a10cb0b148cd5
I've added d3-tip to the code but the tooltip doesn't appear. The chart is displayed correctly, but when I check the console: "Uncaught TypeError: Cannot read property 'value' of undefined" pointing to this code line:
.html(function(d) {
return "<b>" + d.value + "</b>";
})
Here I show you the script:
<script src="d3/d3.min.js" charset="utf-8"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%b %Y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 5])
.direction('n')
.html(function(d) {
return "<b>" + d.value + "</b>";
})
// Define the line
var priceline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
// Adds the svg canvas
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 + ")");
svg.call(tip);
// Get the data
d3.csv("stocks.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
// Nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {return d.name;})
.entries(data);
// Loop through each symbol / key
dataNest.forEach(function(d) {
svg.append("path")
.attr("class", "line")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.attr("d", priceline(d.values))
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
function type(d) {
d.value = +d.value;
return d;
}
</script>
I have changed many things, but I don't find the way. Any idea?
Thanks in advance.
You don't have any data bound to the elements you're calling the tooltip on. You don't need a loop, just use D3's data binding:
svg.selectAll("path")
.data(dataNest)
.enter()
.append("path")
.attr("class", "line")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.attr("d", function(d) { return priceline(d.values); });
You probably also want to redefine your tooltip function:
.html(function(d) {
return "<b>" + d.key + "</b>";
});
really stucked on this issue for days. I am trying to update my d3 graph to show how long it takes to run a function on a calculator. With the info I get, I will show the time taken and display it on the graph that I previously drew. My issue here now is that I just can't get the graph to update.
Codes for the graph:
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 400 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var x = d3.scale.linear()
.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 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 = dataone.map(function(d) {
return {
date:d[0],
close: d[1]
};
});
console.log(data);
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.close; }));
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);
Code for update function and update of array:
function updateArray(){
dataone.push(clickss-0.5,clickss);
updateData();
}
function updateData() {
var data = dataone.map(function(d) {
return {
date:d[0],
close: d[1]
};
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Select the section we want to apply our changes to
var svg = d3.select("body").transition();
// Make the changes
svg.select(".line") // change the line
.duration(750)
.attr("d", valueline(data));
svg.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
}
Please advise on how I can get this to work. I read quite a few guides now but
Couple things:
1.) In your update function, your line generator function is line not valueline.
2.) By looking at your accessor functions, I don't think you meant dataone.push(clickss-0.5,clickss); but rather dataone.push([clickss-0.5,clickss]);. You need an array of arrays.
In addition, you don't need to map your dataone array to another structure. Just change your accessors:
x.domain(d3.extent(data, function(d) {
return d[0];
}));
y.domain(d3.extent(data, function(d) {
return d[1];
}));
...
var line = d3.svg.line()
.x(function(d) {
return x(d[0]);
})
.y(function(d) {
return y(d[1]);
});
Here's your code working and cleaned up a bit:
<!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 dataone = [];
for (var i = 0; i < 10; i++){
dataone.push([i,Math.random()]);
}
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = 400 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var x = d3.scale.linear()
.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[0]);
})
.y(function(d) {
return y(d[1]);
});
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 + ")");
// Scale the range of the data again
x.domain(d3.extent(dataone, function(d) {
return d[0];
}));
y.domain([0, d3.max(dataone, function(d) {
return d[1];
})]);
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(dataone)
.attr("class", "line")
.attr("d", line)
.style("fill","none")
.style("stroke","steelblue");
function updateData() {
// Scale the range of the data again
x.domain(d3.extent(dataone, function(d) {
return d[0];
}));
y.domain([0, d3.max(dataone, function(d) {
return d[1];
})]);
// Select the section we want to apply our changes to
var svg = d3.select("body").transition();
// Make the changes
svg.select(".line") // change the line
.duration(750)
.attr("d", line(dataone));
svg.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
}
setInterval(function(){
for (var i = 0; i < 5; i++){
dataone.push([dataone.length + i, Math.random()]);
}
updateData();
},1000);
</script>
</body>
</html>
I have this bar chart on D3.js... It works fine..
But I'm having problems with the scale... When a data series has a value much grater than the others, the <rect> does not fit into the scale.
Any idea how to solve this matter?
Here is the code:
var data = [
{"Anio":"1999","CONTRAVENCIONAL":"78484","PENAL":"0","FALTAS":"0","MULTAS":"0","OTROS":"0","TOTAL":"78484"},
{"Anio":"2000","CONTRAVENCIONAL":"92879","PENAL":"0","FALTAS":"0","MULTAS":"0","OTROS":"0","TOTAL":"92879"},
{"Anio":"2001","CONTRAVENCIONAL":"100018","PENAL":"0","FALTAS":"1818","MULTAS":"0","OTROS":"0","TOTAL":"101836"},
{"Anio":"2002","CONTRAVENCIONAL":"101380","PENAL":"0","FALTAS":"3692","MULTAS":"0","OTROS":"0","TOTAL":"105072 "},
{"Anio":"2003","CONTRAVENCIONAL":"86791","PENAL":"0","FALTAS":"7417","MULTAS":"0","OTROS":"0","TOTAL":"94208"},
{"Anio":"2004","CONTRAVENCIONAL":"47870","PENAL":"255","FALTAS":"1105","MULTAS":"1811","OTROS":"0","TOTAL":"51041"},
{"Anio":"2005","CONTRAVENCIONAL":"33013","PENAL":"348","FALTAS":"1473","MULTAS":"634","OTROS":"0","TOTAL":"35468"},
];
var margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 860 - margin.left - margin.right,
height = 400 - 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");
var arr_data = [];
for (var i = 0; i < data.length; i++) {
var o = {'name':data[i].Anio,'value':data[i].TOTAL};
arr_data.push(o);
};
var chart = d3.select(".chart")
.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(arr_data.map(function(d) { return d.name; }));
y.domain([0, d3.max(arr_data, function(d) { return d.value; })]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
chart.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar = chart.selectAll(".bar")
.data(arr_data)
.enter().append("g");
bar.append("rect")
.attr("class", "rect")
.attr("x", function(d) { return x(d.name); })
.attr("y", function(d) { return y(d.value) ; })
.attr("height", function(d) { return height - y(d.value); })
.attr("width", x.rangeBand())
.attr("fill","#632423")
.on('mouseover',function(d){
var a = d3.select(this)
.attr("fill","#733A39");
var a = d3.select("#tooltip")
.style("left","100px")
.style("top","20px")
.select("#value")
.text(d.value);
}).on('mouseout',function(d){
var a = d3.select(this)
.attr("fill","#632423"); //old color: #790018
});
bar.append("text")
.attr("class", "label")
.text(function(d) { return d.value; })
.attr("x", function(d) { return x(d.name)+4; })
.attr("y", function(d) { return y(d.value)+20 ; });
Your scale will actually handle series with larger values for you because you're dynamically setting it to go from 0 to the max value in your data:
y.domain([0, d3.max(arr_data, function(d) { return d.value; })]);
However, you're not converting your data to numbers from strings, so right now the scale is from [0, 94208] instead of [0, 105072]. This is because the character "9" is greater than "1". You can fix this by converting the values to numbers when you construct your arr_data, like this:
var o = {'name':data[i].Anio,'value':+data[i].TOTAL}; // <---- notice the '+'
This produces a better looking graph: