I was trying to make a d3 example from http://bl.ocks.org/mbostock/3887051 modified with my data. I use concepts similar to example. I didn't have problems with acquiring the data, but there's an unexpected identifier error.
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
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("datatest.csv", function(error, data) {
var inflasiTahun = d3.keys(data[0]).filter(function(key) { return key !== "tahun"; });
data.forEach(function(d) {
d.inflasi = inflasiTahun.map(function(name) { return {name: name, value: parseFloat(d[name])}; });
});
x0.domain(data.map(function(d) { return d.tahun; }));
x1.domain(inflasiTahun).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.inflasi, function(d) { return d.value; }); })
svg.append("g") //this is the error
.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("Inflasi");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.tahun) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.inflasi; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
});
</script>
I dont know In the console, the unexpected identifier points to this:
svg.append("g") //this is the error
You forgot to close the y.domain([ with ]); on the following line:
y.domain([0, d3.max(data, function(d) { return d3.max(d.inflasi, function(d) { return d.value; }); })
Tools like JSLint and JSHint as well as proper indentation can help you in tracking down this kind of errors.
Related
I am trying to create a d3 (version 4) grouped bar chart with my own data, based on Mike Bostock's great example. I had to change all d3 v3 outdated functions to the new v4 ones (e.g. d3.scale.ordinal -> d3.scaleOrdinal) but then I got errors relating to the 'width' and 'x' attributes of the rect bars:
'Unexpected value 0,0,900 parsing width attribute.'
'Unexpected value 0,900 parsing x attribute.'
here is the relevant part of the code:
var x0 = d3.scaleBand()
.range([0, width])
.round(true);
var x1 = d3.scaleOrdinal();
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.scale(x0);
var yAxis = d3.axisLeft()
.scale(y);
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("myData.csv", function(error, data) {
if (error) throw error;
var yearNames = d3.keys(data[0]).filter(function(key) { return key !== "Unit"; });
data.forEach(function(d) {
d.years = yearNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Unit; }));
x1.domain(yearNames).range([0, x0.range()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.years, function(d) { return d.value; }); })]);
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("Population");
var unit = svg.selectAll(".unit")
.data(data)
.enter().append("g")
.attr("class", "unit")
.attr("transform", function(d) { return "translate(" + x0(d.Unit) + ",0)"; });
unit.selectAll("rect")
.data(function(d) { return d.years; })
.enter().append("rect")
.attr("width", x1.range())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
});
and here is the csv data:
Unit,2012,2013
Comp,54.13809524,52.25
Edu,20.39642857,18.75
Bus,16.3,18.5
SoW,16.08,7
Pharm,45,59
Agr,150.3,122.51
Soc,105.2,112.72
Nat,264.86,277.73
Hum,61.73174603,52.91
Law,14.5,22.33
Dent,27.5,11.5
Med,149.1,147.33
Vet,15,19
Jew,1,0.25
Bra,2.5,4
Most of your problems come from an incorrect usage of .range(). For example here:
x1.domain(yearNames).range([0, x0.range()]);
and here:
.attr("width", x1.range())
.range return an array, which is not what you want.
Further, you probably don't want x1 to be a scaleOrdinal but rather a scaleBand. I'd set it up like this:
x0.domain(data.map(function(d) {
return d.Unit;
}));
// set a sane bar width
var barWidth = x0.bandwidth() / yearNames.length,
barPadding = barWidth * 0.3;
// set up x1 as a scaleBand with padding
x1.domain(yearNames).range([barPadding , x0.bandwidth() - barPadding]);
y.domain([0, d3.max(data, function(d) {
return d3.max(d.years, function(d) {
return d.value;
});
})]);
Running code here.
So i have the following js to create my linechart:
var data = scope.dataset;
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - 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");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.x(function (d) {
return x(d.label);
})
.y(function (d) {
return y(d.value);
});
data.forEach(function (d) {
d.label = d.label;
d.value = d.value;
});
var svg = d3.select("#lbLineChart").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(d3.extent(data, function (d) {
return d.label;
}));
y.domain(d3.extent(data, function (d) {
return d.value;
}));
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);
Where the data is an array of objects: {label: 'mylabel', value: 5}
Invalid value for <path> attribute
Im not quite sure what im doing wrong? ive checked the variables again and again but was unable to find where there is an error.
Have the following code to show a bar graph. I am trying to show the value on a text label. The things is that the element is created but is not showing the value.
Here is the code:
var data =[{"Anio":"1998","EJF":"50726","EXP":"0","RDC":"0","Total":"50726"}, {"Anio":"1999","EJF":"6403","EXP":"0","RDC":"0","Total":"6403"},{"Anio":"2000","EJF":"59211","EXP":"417","RDC":"0","Total":"59628"},{"Anio":"2001","EJF":"153053","EXP":"2801","RDC":"0","Total":"155854"},{"Anio":"2002","EJF":"68500","EXP":"2768","RDC":"0","Total":"71268"},{"Anio":"2003","EJF":"85650","EXP":"4658","RDC":"0","Total":"90308"},{"Anio":"2004","EJF":"70980","EXP":"4689","RDC":"0","Total":"75669"},{"Anio":"2005","EJF":"32670","EXP":"5889","RDC":"0","Total":"38559"},{"Anio":"2006","EJF":"78843","EXP":"5822","RDC":"0","Total":"84665"},{"Anio":"2007","EJF":"3771","EXP":"4925","RDC":"322","Total":"8696"},{"Anio":"2008","EJF":"82869","EXP":"5501","RDC":"342","Total":"88370"},{"Anio":"2009","EJF":"55795","EXP":"4148","RDC":"349","Total":"59943"},{"Anio":"2010","EJF":"54755","EXP":"4261","RDC":"341","Total":"59016"},{"Anio":"2011","EJF":"83147","EXP":"4000","RDC":"301","Total":"87147"},{"Anio":"2012","EJF":"27939","EXP":"3251","RDC":"248","Total":"31190"},{"Anio":"2013","EJF":"89643","EXP":"4385","RDC":"240","Total":"94028"},{"Anio":"2014","EJF":"53832","EXP":"3993","RDC":"688","Total":"58513"}];
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 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);
chart.selectAll(".bar")
.data(arr_data)
.enter().append("rect")
.attr("class", "bar")
.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");
}).on('mouseout',function(d){
var a = d3.select(this)
.attr("fill","#632423"); //old color: #790018
});
chart.selectAll(".bar")
.append("text")
.text(function(d) { return d.value; })
.attr("y", function(d) { return y(d.value)+16; })
.style("stroke", 'white');
I dont know why is that, if someone could show me some light...thanks!!
Thanks in advance!
I add a G (group) element, the code looks like this:
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 ; });
I'm trying to add a zoom ability to a historical line chart I've built using a custom data object. I've been using http://codepen.io/brantwills/pen/igsoc/ as a template. The chart is rendered but when I try zooming there are two errors:
Error: Invalid value for path attribute d=""
Uncaught TypeError: undefined is not a function (in the last transform, translate of the last part of the zoomed function)
JSFiddle: http://jsfiddle.net/dshamis317/sFp6Q/
This is what my code looks like:
function renderHistoricalData(data) {
var parseDate = d3.time.format("%Y%m%d").parse;
data.forEach(function(d) { d.date = parseDate(d.date); });
// data.sort(function(a,b) { return a.date - b.date; });
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 1200 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
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 zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var line = d3.svg.line()
.interpolate("basis")
// .defined(function(d) { return d.y!=0; })
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sentiment); });
var svg = d3.select("#historical_chart").append("svg")
.call(zoom)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
var sites = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, sentiment: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(sites, function(c) { return d3.min(c.values, function(v) { return v.sentiment; }); }),
d3.max(sites, function(c) { return d3.max(c.values, function(v) { return v.sentiment; }); })
]);
var site = svg.selectAll(".site")
.data(sites)
.enter().append("g")
.attr("class", "site");
site.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
site.append("text")
.attr("transform", function(d) {
var val = d.values[d.values.length-1];
return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d.name; });
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("Sentiment (%)");
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll('path.line').attr('d', line);
sites.selectAll('.site').attr("transform", function(d) {
return "translate(" + x(d.date) + "," + y(d.sentiment) + ")"; }
);
}
}
Thank you!
Alright, let's walk through each thing.
To start with, in zoomed, the last transform doesn't need to be there. In the original, it's there to move the circles, which you don't have.
Also important, your edit on path.line sets d to the wrong function. If you look at what you're setting d to when you first make it, it should be the same, as a general rule of thumb, so it should be function(d) { return line(d.values); }, not just line.
Now, for the actual reason it's disappearing.
Your scale extent is calculated based off the original domain. However, you don't set the domain until AFTER you call scaleExtent, which means your scaling is all based on the default. It's not actually disappearing, it's being compressed to the left hand side of the graph. If you remove your x axis, you'll see the colored smear of all your data flattened against the side.
Move all your domain calculations to above where you build your scale, and it'll be fine.
To make things a bit more concrete:
function renderHistoricalData(data) {
var parseDate = d3.time.format("%Y%m%d").parse;
data.forEach(function(d) { d.date = parseDate(d.date); });
// data.sort(function(a,b) { return a.date - b.date; });
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 1200 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
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");
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
var sites = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, sentiment: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(sites, function(c) { return d3.min(c.values, function(v) { return v.sentiment; }); }),
d3.max(sites, function(c) { return d3.max(c.values, function(v) { return v.sentiment; }); })
]);
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var line = d3.svg.line()
.interpolate("basis")
// .defined(function(d) { return d.y!=0; })
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sentiment); });
var svg = d3.select("#historical_chart").append("svg")
.call(zoom)
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var site = svg.selectAll(".site")
.data(sites)
.enter().append("g")
.attr("class", "site");
site.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
site.append("text")
.attr("transform", function(d) {
var val = d.values[d.values.length-1];
return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d.name; });
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("Sentiment (%)");
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll('path.line').attr('d', function(d) { return line(d.values); });
}
}
If you want to text to move, you can give it an easily identifiable class, and then update it in zoomed.
Giving it a class:
site.append("text")
.attr("class", "lineLabel")
Updating it in zoomed:
svg.selectAll(".lineLabel")
.attr("transform", function(d) {
var val = d.values[d.values.length-1];
return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
});
This will just make it follow the ends of the lines, but you can modify whatever attributes you like to get the wanted effects.
I'm trying to create a multiline graph using D3, and I keep running across the same error
Error: Problem parsing d="MNaN,450LNaN,0LNaN,450LNaN,450LNaN,0LNaN,0"
Which seems to occur when I try to graph my line:
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
I'm trying to graph a single line at the moment with the following data set:
{"name":"application_active_users","values":[{"value":0,"end_time":"2013-06-14T11:00:00.000Z"},{"value":1,"end_time":"2013-06-15T11:00:00.000Z"},{"value":0,"end_time":"2013-06-16T11:00:00.000Z"},{"value":0,"end_time":"2013-06-17T11:00:00.000Z"},{"value":1,"end_time":"2013-06-18T11:00:00.000Z"},{"value":1,"end_time":"2013-06-19T11:00:00.000Z"}]}
I'm assuming something is wrong with my datasource. Does anyone see an immediate issue with how my datasource is set up?
Here is a portion of the D3 code. The entire code is here http://jsfiddle.net/hy4Hz/.
var payload;
var storedMetrics = [];
var metricCount = 1;
var graphData = [];
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//var parseDate = d3.time.format("%Y-%m-%d").parse;
//var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%SZ").parse;
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
var color = d3.scale.category10();
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.end_time);
})
.y(function (d) {
return y(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 + ")");
x.domain(d3.extent(
data, function (d) {
return d.end_time;
}));
y.domain([
d3.min(metrics, function (c) {
return d3.min(c.values, function (v) {
return v.value;
});
}),
d3.max(metrics, function (c) {
return d3.max(c.values, function (v) {
return v.value;
});
})]);
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("Temperature (ºF)");
var city = svg.selectAll(".city")
.data(metrics)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
})
.style("stroke", function (d) {
return color(d.name);
});
city.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.end_time) + "," + y(d.value.value) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.text(function (d) {
return d.name;
});
It looks like your x.domain() might not be set up correctly. The first argument to d3.extent should be data.values.