I made a two-line chart with a legend. I want to highlight the stroke-width of each of the lines to 4px based on the color of the legend circle when the user hovers over it. So, user hovers over the blue legend circle, the blue line stroke-width changes to 4px. Same for the red one if he hovers over the red circle on the legend. Is this possible to do based on my code? Here is the whole code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>D3 Test</title>
<script type="text/javascript" src="../d3/d3.js"></script>
<script type="text/javascript" src="../d3/d3-tip.js"></script>
<style type="text/css">
body{
font: 16px Calibri;
}
.line1{
fill: none;
stroke: steelblue;
stroke-width: 2px;
}
.line1:hover{
stroke-width: 3.5px;
}
.line2{
fill: none;
stroke: red;
stroke-width: 2px;
}
.line2:hover{
stroke-width: 3.5px;
}
.axis path,
.axis line{
fill:none;
stroke: black;
stroke-width: 1px;
shape-rendering: crispEdges;
}
.axis text{
font-family: sans-serif;
font-size: 14px;
stroke: black;
stroke-width: 0.5px;
}
.legend .series {
cursor: pointer;
}
.legend circle {
stroke-width: 2px;
}
.legend .disabled circle {
fill-opacity: 0;
}
</style>
<!--...this code will be used on an external html file and instered-->
<html>
<body>
<div id="dropdown">
<select id = "opts">
<option value = "ds1">Atlas</option>
<option value = "ds2">BioSQL</option>
<option value = "ds3">Coppermine</option>
<option value = "ds4">Ensembl</option>
<option value = "ds5">Mediawiki</option>
<option value = "ds6">Opencart</option>
<option value = "ds7">PhpBB</option>
<option value = "ds8">Typo3</option>
</select>
</div>
<script type="text/javascript">
console.log("worked");
var ds1="../CSV/atlas/results/metrics.csv";
var ds2="../CSV/biosql/results/metrics.csv";
var ds3="../CSV/coppermine/results/metrics.csv";
var ds4="../CSV/ensembl/results/metrics.csv";
var ds5="../CSV/mediawiki/results/metrics.csv";
var ds6="../CSV/opencart/results/metrics.csv";
var ds7="../CSV/phpbb/results/metrics.csv";
var ds8="../CSV/typo3/results/metrics.csv";
</script>
</body>
</html> <!--...............................................................-->
<div id="area1"></div>
<div id="area2"></div>
</head>
<body>
<script type="text/javascript">
var margin = {top: 60, right: 20, bottom: 40, left: 40},
margin2 = {top: 430, right: 20, bottom: 0, left: 50},
width = 800 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
height2 = 870 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y").parse;
var color = d3.scale.category20()
.range(["#1f77b4", "#d62728", "#98df8a"]);
var x = d3.scale.linear()
.range([0, width]);
var x1 = d3.time.scale()
.nice(d3.time.year)
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
var x1Axis = d3.svg.axis()
.scale(x1)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg1 = d3.select("#area1").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height2 + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var line1 = d3.svg.line()
.x(function(d) { return x(d.trID);})
.y(function (d) {return y(d.newT);})
.interpolate("basis");
var line2 = d3.svg.line()
.x(function(d) { return x1(d.time);})
.y(function (d) {return y(d.newT);})
.interpolate("basis");
var dsv = d3.dsv(";", "text/plain"); //setting the delimiter
var dataset = [] //defining the data array
var datapath="../CSV/atlas/results/metrics.csv";
dsv(datapath, function(data){ //------------select the file to load the csv------------
var label = document.getElementById('opts')[document.getElementById('opts').selectedIndex].innerHTML;//takes the name of the f
console.log(label);
dataset= data.map(function(d){ //parse
return { //insert parsed data in the array
trID: +d["trID"],
newT: +d["#newT"],
time: +d["time"]
};
});
dataset.forEach(function(d){
d.time = new Date(d.time*1000);
});
console.log(dataset);
x.domain(d3.extent(dataset, function(d) { return d.trID; }));
x1.domain(d3.extent(dataset, function(d) { return d.time; }));
// y.domain([0, d3.max(dataset.map( function(d) {return d.newT}))]);
y.domain(d3.extent(dataset, function(d) { return d.newT; }));
//------------------creating the lines---------------------
svg1.append("path")
.datum(dataset)
.attr("class", "line1")
.attr("d", line1);
svg1.append("path")
.datum(dataset)
.attr("class", "line2")
// .style("stroke-dasharray",("5,5"))
.attr("d", line2);
//----------------appending Legend--------------------------
var legend = svg1.selectAll(".legend")
.data((["Duration/Time","Duration/ID"]).slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("circle")
.attr("r", 7)
.attr("cx", 45)
.attr("cy", 10)
.style("fill", color);
legend.append("text")
.attr("x", 54)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "begin")
.style("font-family", "Calibri")
.text(function(d) { return d; });
//-----------------------------------------------------------
svg1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("trID");
svg1.append("g")
.attr("class", "x1 axis")
.attr("transform", "translate(0," + height2 + ")")
.call(x1Axis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("time");
svg1.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("num of tables");
svg1.append("text")
.attr("class","simpletext")
.attr("x", (width/2))
.attr("y", 0 - (margin.top/2))
.attr("text-anchor", "middle")
.style("font-size", "20px")
.style("text-decoration", "underline")
.text(label);
});
d3.select('#opts')
.on('change', function(){
var dataset=[]
var datapath = eval(d3.select(this).property('value'));
label = document.getElementById('opts')[document.getElementById('opts').selectedIndex].innerHTML;
dsv(datapath, function(data){ //------------select the file to load the csv------------
dataset= data.map(function(d){ //parse
return { //insert parsed data in the array
trID: +d["trID"],
newT: +d["#newT"],
time: +d["time"]
};
});
dataset.forEach(function(d){
d.time = new Date(d.time*1000);
});
x.domain(d3.extent(dataset, function(d) { return d.trID; }));
x1.domain(d3.extent(dataset, function(d) { return d.time; }));
// y.domain([0, d3.max(dataset.map( function(d) {return d.newT}))]);
y.domain(d3.extent(dataset, function(d) { return d.newT; }));
d3.selectAll(".line1")
.transition()
.duration(1000)
.attr("d", line1(dataset));
d3.selectAll(".line2")
.transition()
.duration(1000)
.attr("d", line2(dataset));
//Update Axis
//Update X axis
svg1.select(".x.axis")
.transition()
.duration(1000)
.call(xAxis);
svg1.select(".x1.axis")
.transition()
.duration(1000)
.call(x1Axis);
//Update Y axis
svg1.select(".y.axis")
.transition()
.duration(1000)
.call(yAxis);
svg1.selectAll("path")
.data(dataset)
.exit()
.remove();
console.log(label);
svg1.selectAll(".simpletext")
.transition()
.text(label);
/* .attr("x", (width/2))
.attr("y", 0 - (margin.top/2))
.attr("text-anchor", "middle")
.style("font-size", "20px")
.style("text-decoration", "underline")
.text(label);*/
});
});
</script>
</body>
</html>
I define my color as this:
var color = d3.scale.category20()
.range(["#1f77b4", "#d62728", "#98df8a"]);
And each of my lines as this:
var line1 = d3.svg.line()
.x(function(d) { return x(d.trID);})
.y(function (d) {return y(d.newT);})
.interpolate("basis");
var line2 = d3.svg.line()
.x(function(d) { return x1(d.time);})
.y(function (d) {return y(d.newT);})
.interpolate("basis");
Of course it's possible.
So first it has nothing to do with line1 and line2 - they are about data of the line, not actual visual element. You need to change style of the path elements .line1 and .line2.
You can add event listeners when creating the legend.
//----------------appending Legend--------------------------
var legend = svg1.selectAll(".legend")
.data((["Duration/Time","Duration/ID"]).slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; })
.on("mouseover", function(d) {
if (d === "Duration/ID") {
// line1's legend is hovered
svg1.selectAll(".line1").style("stroke-width", "4px");
}
else if (d === "Duration/Time") {
// line2's legend is hovered
svg1.selectAll(".line2").style("stroke-width", "4px");
}
})
.on("mouseout", function() {
// revert the styles
svg1.selectAll(".line1").style("stroke-width", "2px");
svg1.selectAll(".line2").style("stroke-width", "2px");
});
This is just a demonstration. Of course it would be more consistent to define the styles in css and change class on events, and you may not want to hardcode legend names when you have more/dynamic series.
Related
I've tried to build d3 graph where line and columns are combined, but all of my attempts were unsuccessful.
Styles:
svg {
margin-left: auto;
margin-right: auto;
display: block;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.axis text{
font: Times;
font-size: 12px;
font-weight: bold;
}
JavaScript:
var margin = {top: 20, right: 10, bottom: 100, left:50},
width = 700 - margin.right - margin.left,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("body")
.append("svg")
.attr ({
"width": width + margin.right + margin.left,
"height": height + margin.top + margin.bottom
})
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.right + ")");
// define x and y scales
var xScale = d3.scale.ordinal()
.rangeRoundBands([0,width], 0.93, 0.93);
var yScale = d3.scale.linear()
.range([height, 0]);
var formater = d3.format("");
// define x axis and y axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.tickFormat(formater);
d3.csv("result.csv", function(error,data) {
if(error) console.log("Error: data not loaded!");
data.forEach(function(d) {
d.day = d.day;
d.dayStr = d.dayStr;
d.Ratio = +d.Ratio;
console.log(d.dayStr);
});
// Specify the domains of the x and y scales
xScale.domain(data.map(function(d) { return d.dayStr; }) );
yScale.domain([0, 6]);
// Draw xAxis and position the label
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("dx", "-.8em")
.attr("dy", ".25em")
.attr("transform", "rotate(-60)" )
.style("text-anchor", "end")
.attr("font-size", "10px");
// Draw yAxis and postion the label
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height/8)
.attr("dy", "-3em")
.style("text-anchor", "middle")
.text("Risk Value (in %)");
});
Data:
Day,DayStr,Ratio,Note
2016-06-29T00:00:00+03:00,06-29-2016,1.3,
2016-06-30T00:00:00+03:00,06-30-2016,1.4,
2016-07-01T00:00:00+03:00,07-01-2016,1.2,
2016-07-02T00:00:00+03:00,07-02-2016,1.7,
2016-07-03T00:00:00+03:00,07-03-2016,1.9,
2016-07-04T00:00:00+03:00,07-04-2016,2.2,
2016-07-05T00:00:00+03:00,07-05-2016,2.5,
2016-07-06T00:00:00+03:00,07-06-2016,2.5,
2016-07-07T00:00:00+03:00,07-07-2016,2.4,
2016-07-08T00:00:00+03:00,07-08-2016,2.7,
2016-07-09T00:00:00+03:00,07-09-2016,3.1,
2016-07-10T00:00:00+03:00,07-10-2016,3.5,
2016-07-11T00:00:00+03:00,07-11-2016,3.7,
2016-07-12T00:00:00+03:00,07-12-2016,4.5,
2016-07-13T00:00:00+03:00,07-13-2016,4.4,
2016-07-14T00:00:00+03:00,07-14-2016,5,Alert!
Link to full code.
The final result should be something like this:
Your code is a good starting point, but you haven't drawn any of the columns, points or text. Here's one way to do it:
var colAndPointAndText =
svg.selectAll(".cPT")
.data(data)
.enter().append("g")
.attr("class", "cPT");
colAndPointAndText.append("rect")
.attr("x", function(d) {
return xScale(d.dayStr);
})
.attr("width", xScale.rangeBand())
.attr("y", function(d) {
return yScale(d.Ratio);
})
.attr("height", function(d) {
return height - yScale(d.Ratio);
})
.style("fill", "black");
colAndPointAndText.append("circle")
.attr("cx", function(d) {
return xScale(d.dayStr);
})
.attr("cy", function(d) {
return yScale(d.Ratio);
})
.attr("r", 5)
.style("fill", "none")
.style("stroke", "orange")
.style("stroke-width", "2px")
colAndPointAndText.append("text")
.attr("x", function(d) {
return xScale(d.dayStr);
})
.attr("y", function(d) {
return yScale(d.Ratio);
})
.text(function(d) {
return d.Note;
})
.style("fill", "#d62728")
var line = d3.svg.line()
.x(function(d) {
return xScale(d.dayStr);
})
.y(function(d) {
return yScale(d.Ratio);
});
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.style("fill", "none")
.style("stroke", "steelblue")
.style("stroke-width", "2px");
Full code running here.
I am new to d3 and am trying to draw mean line through all the bars in the bar chart but not quite able to achieve that. Below is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: #444;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script>
var data=[
{"letter": "BU", "higher": .08,"lower": .05},
{"letter": "AU", "higher": .05,"lower": .03},
{"letter": "LA", "higher": .04,"lower": .02}
]
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 x2 = d3.scale.ordinal()
.rangeBands([0, width], 0);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(formatPercent);
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 + ")");
data.forEach(function(d) {
d.higher = +d.higher;
d.lower = +d.lower;
});
x.domain(data.map(function(d) { return d.letter; }));
x2.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d.higher; })]);
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.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.higher); })
.attr("height", function(d) { return height - y(d.higher-d.lower); });
var dataSum = d3.mean(data, function(d) { return (d.higher + d.lower); });
var line = d3.svg.line()
.x(function(d, i) {
return x(d.letter) + i; })
.y(function(d, i) { return y(dataSum/data.length); });
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
</script>
</body>
</html>
The proper code is here'http://jsbin.com/beyakumohi/1/edit?html' . The line should pass through center of each bars but it only happens for the 3rd bar and that too it do not cross it. Is there any mistake in my code.
d3.mean will give you the mean value of the full array. Meaning, that in this case you will get the mean of:
data[0].higher + data[0].lower + data[1].higher + data[1].lower + data[2].higher + data[2].lower
In this case I would say it is more appropiate to edit your line function as following
var line = d3.svg.line()
.x(function(d, i) {
return x(d.letter); })
.y(function(d, i) { return y((d.higher + d.lower) / 2); });
I am making a scatterplot, and pulling in an image fill for each circle on the plot. The problem is that the images are PNG's with transparent backgrounds. This means my overlapping circles show through each other:
Seen here - http://i.stack.imgur.com/bphon.png
I have tried setting a background colour with the CSS, but it seems to be completely overwritten by the .style("fill") in the JS. And I am looking to pull in 30ish images, so I don't want to have to save them all to be able to load the images with my CSS.
So, my question is, is there a way to put a white background behind my PNGs, while pulling those PNGs from URL's contained in my dataset?
Thanks for the help
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<style type="text/css">
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis-text {
font-family: sans-serif;
font-size: 11px;
background-color: white;
font-weight: bold;
}
.teamcircle {
background-color: white;
}
</style>
</head>
<body>
<div>
<input type="button" id="playerbtn" value="See Player View">
<input type="button" id="teambtn" value="See Team View">
</div>
<div id="data">
<div id="player-circles">
</div>
</div>
<script type="text/javascript">
//Width and height
var margin = {top: 50, right: 20, bottom: 30, left: 40};
var w = 960 - margin.left - margin.right;
var h = 500 - margin.top - margin.bottom;
//Create scale functions
var xScale = d3.scale.linear()
.range([0, w]);
var yScale = d3.scale.linear()
.range([h, 0]);
// var color = d3.scale.color();
// Define the Axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//Load the TEAM data set
var teamdata = d3.tsv("team.tsv", function(error, teamdata) {
if (error) throw error;
teamdata.forEach(function(d) {
d.entriesper60 = +d.entriesper60;
d.carryinpercent = +d.carryinpercent;
});
xScale.domain(d3.extent(teamdata, function(d) { return d.carryinpercent; })).nice();
yScale.domain(d3.extent(teamdata, function(d) { return d.entriesper60; })).nice();
//Create X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis)
.append("text")
.attr("class", "axis-text")
.attr("x", w)
.attr("y", -6)
.style("text-anchor", "end")
.text("Carry-in %");
//Create Y axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "axis-text")
.attr("y", -20)
.attr("z", 0)
.style("text-anchor", "middle")
.text("Entries/60")
// DEFS & Pattern for images
svg.append("defs")
.selectAll("pattern")
.data(teamdata)
.enter()
.append("pattern")
.attr('id', function(d, i) {
return d.name;
})
// .attr('patternUnits', 'userSpaceOnUse')
.attr('width', 20)
.attr('height', 20)
.append("image")
.attr("xlink:href", function(d) {
return d.image + d.name;
})
.attr('width', 20)
.attr('height', 20)
.attr("transform", "translate(2, 2)");
// Create TEAM Circles
svg.selectAll("circle")
.data(teamdata)
.enter()
.append("circle")
.attr("class", "teamcircle")
.style("stroke", function(d) { return d.hex; })
.style("stroke-width", 2)
.style("stroke-opacity", .8)
.attr("r", 12)
.attr("cx", function(d) { return xScale(d.carryinpercent); })
.attr("cy", function(d) { return yScale(d.entriesper60); })
.attr("fill", function(d) { return "url(#" + d.name + ")";
});
});
</script>
</body>
</html>
The best way I can think of is to create a group for every circle, and create a circle with a white background first. Something like this:
var teamCircle = svg.selectAll("g.teamcircle")
.data(teamdata)
.enter()
.append("g")
.attr("class", "teamcircle")
.transform(function(d){return "translate(" + xScale(d.carryinpercent) + "," + yScale(d.entriesper60) + ")"});
teamCircle.append("circle")
.attr("fill", "white")
.attr("r", 12)
teamCircle.append("circle")
.style("stroke", function(d) { return d.hex; })
.style("stroke-width", 2)
.style("stroke-opacity", .8)
.attr("r", 12)
.attr("fill", function(d) { return "url(#" + d.name + ")";
I'm trying to create a grouped bar chart that can include transitions. I referenced Mike Bostock's grouped bar chart example and have the bar chart transition working but can't get the axis to transition as well. What I'm referring to in this example is the state labels.
I tried following another example posted but I'm baffled as to why I can get it to work. For my example code the transition occurs on click of the SVG
Grouped Bar Chart Reference Example
Axis Reference Example
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x_axis path {
display: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
//Update the flips bars but not the axis
function update() {
var data_update = data.reverse()
x0.domain[data_update]
svg.selectAll(".state")
.data(data_update)
.transition()
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
svg.select(".x_axis")
.transition()
.call(xAxis);
}
d3.select("svg")
.on("click", update)
//The rest of the code
var data
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", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
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("data.csv", function(error, csv) {
data = csv
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]}; });
});
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(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x_axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.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'm a dummy and figured it out.
Calling the .domain method on an array of objects is useless. I forgot to map the object array to get the value of the states
x0.domain(data_update.map(function(d) { return d.State; }))
Full Code below for those curious
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x_axis path {
display: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var data
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", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
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("data.csv", function(error, csv) {
data = csv
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]}; });
});
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(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 state = svg.selectAll(".state")
.data(data, function(d) {return d.State})
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.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); });
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
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; });
});
//Update the flips bars
function update() {
data.reverse()
x0.domain(data.map(function(d) { return d.State; }))
svg.selectAll(".state")
.data(data, function(d) {return d.State})
.transition()
.attr("transform", function(d) { return "translate(" + x0(d.State) + ",0)"; });
svg.select(".x_axis")
.transition()
.call(xAxis);
}
d3.select("svg")
.on("click", update)
</script>
I am trying to create multiple series in d3 with different fill colors for the area in between the lines for each series. I have successfully gotten the first series in, and I am confident I can create multiple series, but I can't figure out how to append the fill color of just that series. I've tried to do something along the lines of: .attr("fill","red"); to append the area but this doesn't work. Here is my full code:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.area {
fill: steelblue;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
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("%H:%M:%S").parse;
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.date); })
.y(function(d) { return y(d.close); });
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(function(d) { return y(d.low); })
.y1(function(d) { return y(d.high); });
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 context = svg.append("g")
.attr('class','container')
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.high = +d.positive;
d.low = +d.positivelow;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
<!--y.domain(d3.extent(data, function(d) { return d.close; }));-->
<!--y.domain([d3.min(data, function(d) { return d.low; }), d3.max(data, function(d) { return d.high; })]);-->
y.domain([1720,1780])
svg.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
<!--(This line below doesn't work)-->
<!--.attr("fill","red");-->
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("Some Y Title");
});
</script>