I would like to draw a line by d3 with below codes.(http://jsfiddle.net/totaljj/L9n7qnv1)
It draws x,y-axis, but does not enter into the line function when appending d attribute.
You can debug on line number 104 to see that the code does not enter into the line function.
Any help would be appreciated.
<!DOCTYPE html>
<html>
<style>
.axis--x path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<body>
<!-- Page Content -->
<div>
<svg width="430" height="250"></svg>
</div>
<section>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data=
'{"recordsFiltered":5,"raCounts":[{"name":"comp_name","values":[{"date_":"2016","actual":170.0,"DT_RowId":"row_null"},{"date_":"2015","actual":198.0,"DT_RowId":"row_null"},{"date_":"2015","actual":149.0,"DT_RowId":"row_null"},{"date_":"2014","actual":197.0,"DT_RowId":"row_null"},{"date_":"2014","actual":146.0,"DT_RowId":"row_null"}],"DT_RowId":"row_null"}],"draw":null,"recordsTotal":5}';
var d = JSON.parse(data);
draw(d.raCounts);
function draw(data){
//svg
var svg = d3.select("svg"),
margin = {top: 100, right: 80, bottom: 30, left: 50},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//time
var parseTime = d3.timeParse("%Y%m%d");
//domain
// var x = d3.scaleTime().range([0, width]),
var x = d3.scaleLinear().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
//line
var line = d3.line()
.curve(d3.curveBasis)
.x(function(d) {
return x(d.date_); })
.y(function(d) {
return y(d.actual); });
//domain
x.domain(d3.extent(data[0].values, function(d) {
return d.date_; }));
y.domain([
d3.min(data, function(c) {
return d3.min(c.values, function(d) {
return d.actual; }); }),
d3.max(data, function(c) {
return d3.max(c.values, function(d) {
return d.actual; }); })
]);
z.domain(data.map(function(c) {
return c.DT_RowId; }));
//axis
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("count");
var ra = g.selectAll(".ra")
.data(data)
.enter().append("g")
.attr("class", "ra");
//ra line
ra.append("path")
.attr("class", "line")
.attr("d",
function(d) { return
line(d.values); })
.style("stroke-dasharray", ("1","1"));
}
</script>
</section>
</body>
</html>
JavaScript doesn't always require semicolons at the end of a line. It will automatically insert them in certain situations, and the place where you call your line function is one of them:
.attr("d",
function(d) { return
line(d.values); })
The fix is therefore to remove the newline after return:
.attr("d",
function(d) { return line(d.values); })
I think both Gerardo Furtado's answer as well as Luke Woodward's answer have good points, but both circumvent the fact, that OP's solution is somewhat off the beaten track. To make full use of the data binding the typical approach would be something like the following:
//ra line
ra.selectAll("path.line")
.data(function(d) { return [d.values]; })
.enter().append("path")
.attr("class", "line")
.attr("d", line)
Passing just the line generator function get rids of the automatical semicolon insertion after the return statement. On the other hand, doing the data binding for the path.line element still allows for multiple lines drawn by the same statement.
Have a look at the following snippet for a working example:
var data =
'{"recordsFiltered":5,"raCounts":[{"name":"comp_name","values":[{"date_":"2016","actual":170.0,"DT_RowId":"row_null"},{"date_":"2015","actual":198.0,"DT_RowId":"row_null"},{"date_":"2015","actual":149.0,"DT_RowId":"row_null"},{"date_":"2014","actual":197.0,"DT_RowId":"row_null"},{"date_":"2014","actual":146.0,"DT_RowId":"row_null"}],"DT_RowId":"row_null"}],"draw":null,"recordsTotal":5}';
data = JSON.parse(data).raCounts;
//svg
var svg = d3.select("svg"),
margin = {
top: 100,
right: 80,
bottom: 30,
left: 50
},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//time
var parseTime = d3.timeParse("%Y%m%d");
//domain
// var x = d3.scaleTime().range([0, width]),
var x = d3.scaleLinear().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
//line
var line = d3.line()
.curve(d3.curveBasis)
.x(function(d) {
return x(d.date_);
})
.y(function(d) {
return y(d.actual);
});
//domain
x.domain(d3.extent(data[0].values, function(d) {
return d.date_;
}));
y.domain([
d3.min(data, function(c) {
return d3.min(c.values, function(d) {
return d.actual;
});
}),
d3.max(data, function(c) {
return d3.max(c.values, function(d) {
return d.actual;
});
})
]);
z.domain(data.map(function(c) {
return c.DT_RowId;
}));
//axis
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("count");
var ra = g.selectAll(".ra")
.data(data)
.enter().append("g")
.attr("class", "ra");
//ra line
ra.selectAll("path.line")
.data(function(d) { return [d.values]; })
.enter().append("path")
.attr("class", "line")
.attr("d", line)
.style("stroke-dasharray", ("1", "1"));
<style> .axis--x path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<script src="https://d3js.org/d3.v4.js"></script>
<svg width="430" height="250">
</svg>
You're not passing the correct data to your line generator. It should be:
ra.append("path")
.attr("class", "line")
.attr("d", line(data[0].values))
.style("stroke-dasharray", ("1", "1"));
Here is your updated fiddle: http://jsfiddle.net/67zs8ph7/
PS: this will plot just one line (see comment below)
Related
I'm trying to build a chart that goes from 1 line to many lines. I have built the two charts separately, but am having trouble combining them. The idea is that I want to show the total of all fruit sold per year, and then show how much of each fruit is sold per year.
This is the template I'm working from: http://bl.ocks.org/d3noob/a048edddbf83bff03a34
In my code, the single line shows up fine. When I click update, the axes update as they should, but the data doesn't. Any help would be greatly appreciated.
My code is in a plunker, here: https://plnkr.co/edit/dgwsGLIRbZ2qm7faEvSw?p=preview
The code is also below.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body { font: 12px Arial;}
path {
stroke: #333;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<div id="option">
<input name="updateButton" id="updateData" type="button" value="Update" />
<input name="revertButton" type="button" value="Revert" onclick="revertData()" />
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script>
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 800 - margin.left - margin.right,
height = 470 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom().scale(x)
.ticks(7)
.tickFormat(d3.format("d"))
var yAxis = d3.axisLeft().scale(y)
.ticks(5);
var valueline = d3.line()
.x(function(d) { return x(d.Year); })
.y(function(d) { return y(d.Count); });
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("datab.csv", function(error, data2) {
d3.csv("dataa.csv", function(error, data) {
data.forEach(function(d) {
d.Year = +d.Year;
d.Count = +d.Count;
});
x.domain(d3.extent(data, function(d) { return d.Year; }));
y.domain([0, d3.max(data, function(d) { return d.Count; })]);
dataNest1 = d3.nest()
.key(function(d) {return d.Type;})
.entries(data);
var result1 = dataNest1.filter(function(val,idx, arr){
return $("." + val.key)
})
var calls = d3.select("svg").selectAll(".line")
.data(result1, function(d){return d.key})
var color1 = d3.scaleOrdinal().range(["#333", "none", "none", "none", "none", "none"]);
calls.enter().append("path")
.attr("class", "line")
.attr("stroke","#333")
.attr("d", function(d){
return valueline(d.values)
})
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
d3.select('#updateData').on('click',function(){
updateData(data2)
})
});
});
function updateData(data2) {
data2.forEach(function(d) {
d.Year = +d.Year;
d.Count = +d.Count;
});
dataNest = d3.nest()
.key(function(d) {return d.Descriptor;})
.entries(data2);
var result = dataNest.filter(function(val,idx, arr){
return $("." + val.key)
})
x.domain(d3.extent(data2, function(d) { return d.Year; }));
y.domain([0, d3.max(data2, function(d) { return d.Count; })]);
var svg = d3.select("body").transition();
svg.selectAll('.circle').duration(0).remove()
d3.select("svg").selectAll(".line")
.data(result, function(d){return d.key})
d3.select("svg").selectAll("path.line")
.transition()
.duration(700)
.style("stroke", "#333")
.attr("d", function(d){
return valueline(d.values)
});
// svg.select(".line") // change the line
// .duration(750)
// .attr("d", valueline(rats));
svg.select(".x.axis")
.transition()
.duration(750)
.call(xAxis);
svg.select(".y.axis")
.duration(750)
.call(yAxis);
}
function revertData() {
// Get the data again
d3.csv("totalsbyyear.csv", function(error, data) {
data.forEach(function(d) {
d.Year = +d.Year;
d.Count = +d.Count;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.Year; }));
y.domain([0, d3.max(data, function(d) { return d.Count; })]);
// 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);
});
}
</script>
</body>
There are a few problems here. The first one being that your datasets are very different and I don't see anywhere in the code to compensate for there being multiple different fruit in the same year. This is something you will need to address either by modifying your csv file or in your updateData function to extract just a single fruit.
I have made some changes to your plunker that will allow the updateFunction to work but without fixing the input data it won't really matter.
https://plnkr.co/edit/DSg09NWPrBADLLbcL5cx?p=preview
The main thing that needed to be fixed was
d3.select("svg").selectAll("path.line")
.data(result, function(d){return d.key})
.transition()
.duration(700)
.style("stroke", "#337")
.attr("d", function(d){
return valueline(result)
});
And putting the d3.csv on datab.csv call in the updateData function instead of wrapping it around the main table creation function.
I was probably being unclear in my question asking. I figured out what I needed to do to make it work as intended. Code here:
https://plnkr.co/edit/YrABkbc8l9oeT1ywMspy?p=preview
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body { font: 12px Arial;}
path {
stroke: #333;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<div id="option">
<input name="updateButton" id="updateData" type="button" value="Update" />
<input name="revertButton" type="button" value="Revert" onclick="revertData()" />
</div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script>
var margin = {top: 30, right: 200, bottom: 30, left: 50},
width = 850 - margin.left - margin.right,
height = 470 - margin.top - margin.bottom;
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var xAxis = d3.axisBottom().scale(x)
.ticks(7)
.tickFormat(d3.format("d"))
var yAxis = d3.axisLeft().scale(y)
.ticks(5);
var valueline = d3.line()
.x(function(d) { return x(d.Year); })
.y(function(d) { return y(d.Count); });
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("datab.csv", function(error, data2) {
d3.csv("dataa.csv", function(error, data) {
data.forEach(function(d) {
d.Year = +d.Year;
d.Count = +d.Count;
});
x.domain(d3.extent(data, function(d) { return d.Year; }));
y.domain([0, d3.max(data, function(d) { return d.Count; })]);
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
svg.append("text")
.attr("transform", function(d) { return "translate(" + x(2017) + "," + y(35074) + ")"; })
.attr("x", 3)
.attr("dy", "0.35em")
.attr('class','toplinetext')
.style("font", "10px sans-serif")
.text(function(d) { return "All"; });
circles = svg.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr('class','circle')
.attr('cx',function(d){ return x(d.Year)})
.attr('cy',function(d){ return y(d.Count)})
.attr('r',3)
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.exit().remove();
d3.select('#updateData').on('click',function(){
updateData(data2)
})
});
});
function updateData(data2) {
data2.forEach(function(d) {
d.Year = +d.Year;
d.Count = +d.Count;
});
var notapples = data2.filter(function(d){return d.Descriptor == "Peach" || d.Descriptor == "Pear" || d.Descriptor == "Plum" || d.Descriptor == "Banana"})
dataNest = d3.nest()
.key(function(d) {return d.Descriptor;})
.entries(notapples);
var result = dataNest.filter(function(val,idx, arr){
return $("." + val.key)
})
$('.toplinetext').text('Apples');
x.domain(d3.extent(data2, function(d) { return d.Year; }));
y.domain([0, d3.max(data2, function(d) { return d.Count; })]);
var svg = d3.select("body").transition();
svg.selectAll('.circle').duration(0).remove()
var typeOfCall = d3.select("svg").selectAll(".dline")
.data(result, function(d){return d.key})
.enter().append("g")
.attr("class", function(d){return "type " + d.key})
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var color2 = d3.scaleOrdinal().range(["#ff0000", "#333", "#333", "#333", "#333", "#333"]);
typeOfCall.append("path")
.attr("height", 0)
.transition()
.duration(700)
.attr("class", "line")
.style("stroke", function(d,i) { return color2(d.key); })
.attr("d", function(d){
return valueline(d.values)
});
typeOfCall.append("text")
.datum(function(d) { return {id: d.Descriptor, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.Year) + "," + y(d.value.Count) + ")"; })
.attr("x", 3)
.attr("dy", "0.35em")
.style("font", "10px sans-serif")
.text(function(d) { return d.value.Descriptor; });
typeOfCall.exit().remove();
apples = data2.filter(function(d){return d.Descriptor == "Apple"})
svg.select(".line")
.duration(750)
.attr("d", valueline(apples));
svg.select(".x.axis")
.transition()
.duration(750)
.call(xAxis);
svg.select(".y.axis")
.duration(750)
.call(yAxis);
}
function revertData() {
// Get the data again
d3.csv("totalsbyyear.csv", function(error, data) {
data.forEach(function(d) {
d.Year = +d.Year;
d.Count = +d.Count;
});
$('.toplinetext').text('All');
$('.Peach,.Pear,.Banana,.Plum').remove();
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.Year; }));
y.domain([0, d3.max(data, function(d) { return d.Count; })]);
// 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);
});
}
</script>
</body>
I am using D3.js to showcase my data. However, I am unable to get two different objects to not overlap. For example, the code below shows a line graph and a bar graph. I am using code from https://github.com/d3/d3/wiki/Gallery for this example to show my issue. The line graph code is from https://bl.ocks.org/mbostock/3883245. The bar graph code is from https://bl.ocks.org/mbostock/3885304. I tried using as shown in this example http://www.d3noob.org/2013/07/arranging-more-than-one-d3js-graph-on.html, but it did not work. I also made sure they both used the same version of d3.js. The data is from two tsv files that are on the links above for the line and bar graph. Any help would be appreciated!
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
.axis--x path {
display: none;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="lineg"></div>
<div id="barg"></div>
<lineg width="960" height="500"></lineg>
<barg width="960" height="500"></barg>
<script>
var svga = d3.select("#lineg"),
margina = {top: 20, right: 20, bottom: 30, left: 40},
widtha = +svga.attr("width") - margina.left - margina.right,
heighta = +svga.attr("height") - margina.top - margina.bottom;
var xa = d3.scaleBand().rangeRound([0, widtha]).padding(0.1),
ya = d3.scaleLinear().rangeRound([heighta, 0]);
var ga = svga.append("g")
.attr("transform", "translate(" + margina.left + "," + margina.top + ")");
d3.tsv("bardata.tsv", function(d) {
d.frequency = +d.frequency;
return d;
}, function(error, data) {
if (error) throw error;
xa.domain(data.map(function(d) { return d.letter; }));
ya.domain([0, d3.max(data, function(d) { return d.frequency; })]);
ga.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + heighta + ")")
.call(d3.axisBottom(xa));
ga.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(ya).ticks(10, "%"))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Frequency");
ga.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xa(d.letter); })
.attr("y", function(d) { return ya(d.frequency); })
.attr("width", xa.bandwidth())
.attr("height", function(d) { return heighta - ya(d.frequency); });
});
</script>
<script>
var svgb = d3.select("barg"),
marginb = {top: 20, right: 20, bottom: 30, left: 50},
widthb = +svgb.attr("width") - marginb.left - marginb.right,
heightb = +svgb.attr("height") - marginb.top - marginb.bottom,
gb = svgb.append("g").attr("transform", "translate(" + marginb.left + "," + marginb.top + ")");
var parseTime = d3.timeParse("%d-%b-%y");
var xb = d3.scaleTime()
.rangeRound([0, widthb]);
var yb = d3.scaleLinear()
.rangeRound([heightb, 0]);
var line = d3.line()
.x(function(d) { return xb(d.date); })
.y(function(d) { return yb(d.close); });
d3.tsv("linedata.tsv", function(d) {
d.date = parseTime(d.date);
d.close = +d.close;
return d;
}, function(error, data) {
if (error) throw error;
xb.domain(d3.extent(data, function(d) { return d.date; }));
yb.domain(d3.extent(data, function(d) { return d.close; }));
gb.append("g")
.attr("transform", "translate(0," + heightb + ")")
.call(d3.axisBottom(xb))
.select(".domain")
.remove();
gb.append("g")
.call(d3.axisLeft(yb))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Price ($)");
gb.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
});
</script>
In your code barg and lineg are just divs:
<div id="lineg"></div>
<div id="barg"></div>
Instead of that, they should be SVG elements, like this:
<svg id="barg" width="960" height="500"></svg>
<svg id="lineg" width="960" height="500"></svg>
Or, alternatively, append an SVG in your selection:
var svga = d3.select("#lineg").append("svg");
var svgb = d3.select("#barg").append("svg");
However, in that case, you cannot use the getters to get the width and height of the SVGs.
Finally, there is no HTML tag named <lineg> or <barg>.
I have created a D3 visualization which contains both a scatterplot and a line chart. They share an x-axis, but each have their own y-axis. My problem involves how to properly implement a brush and update both y-axes.
As you can see here the y-axes are correct initially and also correct again once the brush is turned off. However during 'brushing' both y-axes are set to the 'left' one. I see why this is happening when I setup my brush here:
brush = d3.svg.brush()
.x(brushFilterXScale)
.y(brushFilterTransactionsYScale)
.on('brush', brushed);
I also have a brushFilterBalanceYScale which is the scale for the axis on the right. My question is how do I pass BOTH of these scales to brush so that I can update each y-axis properly?
I don't know of a straight-forward way to do this. You can, however, reverse map it in your brush event:
function brushed() {
var extent = brush.extent(), //<-- the extent
yDomain = [extent[0][1], extent[1][1]]; //<-- the y domain of the extent
y2.domain(
[
y2Brush.invert(yBrush(yDomain[0])), //<-- take the yDomain start, get it's pixel position, then invert that back into the domain of the y2Brush
y2Brush.invert(yBrush(yDomain[1]))
]
);
Here's a working example:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.line {
fill: none;
stroke: steelblue;
clip-path: url(#clip);
}
circle {
clip-path: url(#clip);
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.brush .extent {
stroke: #fff;
fill-opacity: .125;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {
top: 10,
right: 40,
bottom: 100,
left: 40
},
margin2 = {
top: 430,
right: 40,
bottom: 20,
left: 40
},
width = 500 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var x = d3.scale.linear().range([0, width])
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height, 0]),
xBrush = d3.scale.linear().range([0,width]),
yBrush = d3.scale.linear().range([height2, 0]),
y2Brush = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left"),
yAxis2 = d3.svg.axis().scale(y2).orient("right"),
yAxisBrush = d3.svg.axis().scale(yBrush).orient("bottom");
xAxisBrush = d3.svg.axis().scale(xBrush).orient("bottom");
var brush = d3.svg.brush()
.x(xBrush)
.y(yBrush)
.on("brush", brushed);
var line = d3.svg.line()
.interpolate("monotone")
.x(function(d) {
return x(d.x);
})
.y(function(d) {
return y(d.y);
});
var lineBrush = d3.svg.line()
.interpolate("monotone")
.x(function(d) {
return x(d.x);
})
.y(function(d) {
return yBrush(d.y);
});
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
var data1 = [],
data2 = [];
for (var i = 0; i < 100; i++) {
data1.push({
x: i,
y: Math.random() * 10
});
if (i % 3 === 0){
data2.push({
x: i,
y: Math.random() * 100
});
}
}
x.domain([0,100]);
y.domain([0, d3.max(data1.map(function(d) {
return d.y;
}))]);
y2.domain([0, d3.max(data2.map(function(d) {
return d.y;
}))]);
xBrush.domain(x.domain());
yBrush.domain(y.domain());
y2Brush.domain(y2.domain());
focus.append("path")
.datum(data1)
.attr("class", "line")
.attr("d", line);
var scatter = focus.append("g")
.selectAll("circle")
.data(data2);
scatter
.enter()
.append("circle")
.attr("cx", function(d){
return x(d.x);
})
.attr("cy", function(d){
return y2(d.y);
})
.attr("r", function(d){
d.r = Math.random() * 20;
return d.r;
})
.style("fill", "orange")
.style("opacity", "0.5");
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
focus.append("g")
.attr("transform", "translate(" + width + " ,0)")
.attr("class", "y2 axis")
.call(yAxis2);
context.append("path")
.datum(data1)
.attr("class", "line")
.attr("d", lineBrush);
context.append("g")
.selectAll("circle")
.data(data2)
.enter()
.append("circle")
.attr("cx", function(d){
return x(d.x);
})
.attr("cy", function(d){
return y2Brush(d.y);
})
.attr("r", function(d){
return d.r * 0.25;
})
.style("fill", "orange")
.style("opacity", "0.5");
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxisBrush);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
function brushed() {
var extent = brush.extent(),
yDomain = [extent[0][1], extent[1][1]];
y2.domain([y2Brush.invert(yBrush(yDomain[0])), y2Brush.invert(yBrush(yDomain[1]))]);
x.domain(brush.empty() ? xBrush.domain() : [extent[0][0], extent[1][0]]);
y.domain(brush.empty() ? yBrush.domain() : yDomain);
scatter
.attr("cx", function(d){
return x(d.x);
})
.attr("cy", function(d){
return y2(d.y);
})
focus.select(".line").attr("d", line);
focus.select(".x.axis").call(xAxis);
focus.select(".y.axis").call(yAxis);
focus.select(".y2.axis").call(yAxis2);
}
</script>
I'm using on d3.js, and it's working fine.But i'm not figuring out why the scatter serie is not displayed.
this is my code:
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 70},
width = 1000 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%H-%M-%d-%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);
// Adds the plot
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 + ")");
lineSerie();
scatterSerie();
function lineSerie(){
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
d3.csv("timeSeries.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
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", ".60em")
.style("text-anchor", "end")
.text("CPU RunQueue");
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
});
}
function scatterSerie(){
d3.csv("scatterSerie.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); });
});
}
</script>
</body>
line serie:
date,close
05-17-14-Oct-14,223233.06250
05-18-14-Oct-14,223233.06250
05-19-14-Oct-14,223233.06250
05-20-14-Oct-14,223233.06250
05-21-14-Oct-14,223233.06250
05-22-14-Oct-14,223233.06250
05-23-14-Oct-14,223233.06250
05-24-14-Oct-14,223233.06250
05-25-14-Oct-14,223233.06250
line serie
date,close
10-27-02-Oct-14,223233.06250
10-28-02-Oct-14,223233.06250
10-29-02-Oct-14,223233.06250
10-30-02-Oct-14,223233.06250
10-31-02-Oct-14,223233.06250
10-32-02-Oct-14,223233.06250
10-33-02-Oct-14,223233.06250
10-34-02-Oct-14,223233.06250
10-35-02-Oct-14,223233.06250
10-36-02-Oct-14,223233.06250
10-37-02-Oct-14,223233.06250
10-38-02-Oct-14,223233.06250
the line serie is displayed, but the scatter serie is not being displayed.
Can someone tell me what's wrong?
thanks in advance.
In your scatterSerie() function, your select statement doesn't add up.
There's no such thing as a 'dot' element. You'll want to select all elements with class 'dot' like so (think jQuery):
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr('class','dot')
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); });
Don't forget to set that 'dot' class to your newly added elements, otherwise your future updates might go south.
One other thing you might wanna look into is the style of your circles. Right now they have no defined stroke color, stroke-width or fill. You can add those as CSS rules or add them within your d3 code.
UPDATED
Problem
a) Only one of my bar charts is showing after I switched a variable var csvData in my scripts.js to the real data from the dummy data. The previous data referenced states and demographics, which has now been switched to food and their prices.
scripts.js (UPDATED, chart still not showing up)
$(function() {
$("#placeholder").remove();
var margin = {top: 60, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// X is the horizontal axis
var x0 = d3.scale.ordinal() // ordinal for non quantitative scales, like names, categories
.rangeRoundBands([0, width], .1); // Width of each individual bar?
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
// Bar chart colors
var color = d3.scale.ordinal()
.range(["#001F4C", "#003D99", "#005CE6", "#0066FF", "#3385FF", "#80B2FF", "#CCE0FF", "#E6F0FF", "#E6EBFA"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left") // Where the Y axis goes, you'll want it on the left
.ticks(8)
.tickValues([0, 1, 2, 3, 4, 5, 6]);
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 + ")");
// Bar chart data
var csvData = [
{"Store":"Co-op","Broccoli":2.69,"Cauliflower":3.69,"Celery":1.89,"Strawberries":4.49,"Oranges":1.69,"Tomatoes":3.49,"Lemons":0.99, "Lettuce":0.01, "Cucumber":2},
{"Store":"Safeway","Broccoli":2.97,"Cauliflower":3.98,"Celery":1.77,"Strawberries":5.96,"Oranges":0.97,"Tomatoes":2.97,"Lemons":0.77, "Lettuce":4.97, "Cucumber":1.97},
{"Store":"Sobeys","Broccoli":3.49,"Cauliflower":3.99,"Celery":1.29,"Strawberries":3.99,"Oranges":1.99,"Tomatoes":4.99,"Lemons":1.29, "Lettuce":3.49, "Cucumber":1.99},
{"Store":"Superstore","Broccoli":2.69,"Cauliflower":2.49,"Celery":1.09,"Strawberries":2.99,"Oranges":0.99,"Tomatoes":3.99,"Lemons":0.99, "Lettuce":4.99, "Cucumber":2.49},
];
var data = csvData;
var foodNames = d3.keys(data[0]).filter(function(key) { return key !== "Store"; });
data.forEach(function(d) {
d.food = foodNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Store; }));
x1.domain(foodNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.food, 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)") // Rotates the label on the Y axis
.attr("y", 8) // Label spacing from Y axis
.attr("dy", ".71em") // Label spacing from Y axis
.style("text-anchor", "end") // Anchor the label to the end of the Y axis
.text("Price (in dollars)"); // Changes the text on the Y or vertical axis
var store = svg.selectAll(".store") // Selects all of the data in column labelled store
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.store) + ",0)"; });
store.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("class", "stick")
.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); });
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 22.5 + ")"; }); // Determines spacing between items in legend
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="assets/js/scripts.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
</body>
</html>
style.css
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
/*.stick {
fill: steelblue;
}
.stick:hover {
fill: brown;
}*/
.x.axis path {
display: none;
}
$(function() {
$("#placeholder").remove();
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// X is the horizontal axis
var x0 = d3.scale.ordinal() // ordinal for non quantitative scales, like names, categories
.rangeRoundBands([0, width], .1); // Width of each individual bar?
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0])
// These are the colors
var color = d3.scale.ordinal()
// .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
.range(["#001F4C", "#003D99", "#005CE6", "#0066FF", "#3385FF", "#80B2FF", "#CCE0FF", "#E6F0FF"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left") // Where the Y axis goes, you'll want it on the left
// .tickFormat(d3.format(".1s"));
.ticks(6);
//.tickValues([0, 1, 2, 3, 4, 5]);
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 + ")");
// Bar chart data
var csvData = [
{"State":"Co-op","Broccoli":2027307,"Cauliflower":3277946,"Celery":1420518,"Strawberries":2454721,"Oranges":7017731,"Tomatoes":5656528,"Lemons":2472223, "Lettuce":2472223, "Cucumber":2472223},
{"State":"Safeway","Broccoli":2704659,"Cauliflower":4499890,"Celery":2159981,"Strawberries":3853788,"Oranges":10604510,"Tomatoes":8819342,"Lemons":4114496, "Lettuce":2472223, "Cucumber":2472223},
{"State":"Sobeys","Broccoli":1140516,"Cauliflower":1938695,"Celery":925060,"Strawberries":1607297,"Oranges":4782119,"Tomatoes":4746856,"Lemons":3187797, "Lettuce":2472223, "Cucumber":2472223},
{"State":"Superstore","Broccoli":1208495,"Cauliflower":2141490,"Celery":1058031,"Strawberries":1999120,"Oranges":5355235,"Tomatoes":5120254,"Lemons":2607672, "Lettuce":2472223, "Cucumber":2472223},
];
// Food Prices
// var csvData = [
// {"Store":"Sobey","Broccoli":2.69,"Cauliflower":3.69,"Celery":$1.89,"Strawberries":$4.49,"Oranges":"1.69,"Tomatoes":$3.49,"Lemons":$0.99,"Lettuce":$0.00,"Cucumber":2.00},
// {"Store":"Superstore","Broccoli":2.97,"Cauliflower":3.98,"Celery":1.77,"Strawberries":5.96,"Oranges":0.97,"Tomatoes":2.97,"Lemons":0.77,"Lettuce":4.97,"Cucumber":1.97},
// {"Store":"Safeway","Broccoli":3.49,"Cauliflower":3.99,"Celery":1.29,"Strawberries":3.99,"Oranges":1.99,"Tomatoes":4.99,"Lemons":1.29,"Lettuce":3.49,"Cucumber":1.99},
// {"Store":"Coop","Broccoli":2.69,"Cauliflower":"2.49","Celery":"1.09","Strawberries":"2.99","Oranges":"0.99","Tomatoes":"3.99","Lemons":"0.99","Lettuce":"4.99","Cucumber":"2.49"}
// ];
// AgeNames = FoodNames
// States = Stores
var data = csvData;
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "State"; });
data.forEach(function(d) {
d.ages = ageNames.map(function(name) { return {name: name, value: (+d[name])/2000000}; });
});
x0.domain(data.map(function(d) { return d.State; }));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) {
return d3.max(d.ages, function(c) {
return c.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)") // Rotates the label on the Y axis
.attr("y", 8) // Label spacing from Y axis
.attr("dy", ".71em") // Label spacing from Y axis
.style("text-anchor", "end") // Anchor the label to the end of the Y axis
.text("Price (in dollars)"); // Changes the text on the Y or vertical axis
var state = svg.selectAll(".state") // Selects all of the data in column labelled State
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("class", "stick")
.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); });
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 22.5 + ")"; });
// Number (20) determines spacing between items in legend
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
/*.stick {
fill: steelblue;
}
.stick:hover {
fill: brown;
}*/
.x.axis path {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
To achieve our requirement I've added one thing,i.e.
(+d[name])/2000000 while assigning the value I'm just dividing it to fit to our scale. y domain is set to very big number like near to one Crore.