D3 transitions with multiple graphs - javascript

I'm trying to add a drop down menu that selects which measure to graph. I have 8 graphs, all graphing the same measure but by different ethnicities. Below is the code, any thoughts on what I'm doing wrong? Right now i get the error exit() is not a function.
Ok i've made some progress with the following, however it's still a little wonky. The graphs are changing but are going off the charts - the yAxis is rescaling to the max of all of the graphs, not the local one.:
function updateGraphs(newData) {
d3.selectAll("svg").each(function(d, i){
eachRace = d.values;
svg = d3.select(this);
yMax = d3.max(eachRace, function(d) { return d[newData]; });
yScale = d3.scale.linear().domain([0, yMax*1.25]).range([height/8, 0]).nice();
yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(5);
line = d3.svg.line()
.x(function (d) { return x(d.date); })
.y(function (d) { return yScale(d[newData]); })
d3.transition().duration(1000).selectAll(".line")
.attr("id", function(d) { return d.key ;})
.attr('class', 'line')
.attr('opacity', .8)
.attr('d', function(d) { return line(d.values); })
d3.selectAll(".y.axis")
.call(yAxis);
});
}
var svgContainer = d3.select("body").selectAll("svg")
.data(data2)
svgContainer.enter()
.append("svg")
.attr("width", 150)
.attr("height", 400)
.attr("transform", "translate(" + margin.left + "," + margin.top+ ")");
d3.selectAll("svg").each(function(d, i){
var eachRace = d.values;
var svg = d3.select(this);
var yMax = d3.max(eachRace, function(d) { return d.app; });
var yScale = d3.scale.linear().domain([0, yMax*1.25]).range([height/8, 0]).nice();
var yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(5);
var line = d3.svg.line()
.x(function (d) { return x(d.date); })
.y(function (d) { return yScale(d.app); })
svg.append("path")
.attr("id", function(d) { return d.key ;})
.attr('class', 'line')
.attr('opacity', .8)
.attr('d', function(d) { return line(d.values); })
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});

Thanks JSBob for working with me. I've got it working with:
function updateGraphs(newData) {
d3.selectAll("svg").each(function(d, i){
eachRace = d.values;
svg = d3.select(this);
yMax = d3.max(eachRace, function(d) { return d[newData]; });
yScale = d3.scale.linear().domain([0, yMax*1.25]).range([height/8, 0]).nice();
yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(5);
console.log(yMax);
line = d3.svg.line()
.x(function (d) { return x(d.date); })
.y(function (d) { return yScale(d[newData]); })
svg.transition().duration(1000).select(".line")
.attr("id", function(d) { return d.key ;})
.attr('class', 'line')
.attr('opacity', .8)
.attr('d', function(d) { return line(d.values); });
svg.transition().duration(1000).select(".y.axis")
.call(yAxis);
});
}

Related

Add labels to D3 line

I want to add labels that show the values on a line chart and can't figure out how to do this.
var svg = d3.select('svg')
.attr("width", width)
.attr("height", height);
var g = svg.append("g")
.attr("transform", "translate(" + 0 + "," + 0 + ")");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.date)})
.y(function(d) { return y(d.value)})
x.domain(d3.extent(data, function(d) { return d.date }));
y.domain(d3.extent(data, function(d) { return d.value }));
I don't know how to add labels, like here for example (though my case is simpler, because I have only one chart)
I've generated some random data here. Relevant code to add the text labels:
g.selectAll('.textLabels')
.data(data).enter()
.append('text')
.classed('textLabels', true)
.attr('x', function(d) { return x(d.date); })
.attr('y', function(d) { return y(d.value); })
.text(function(d) { return d.value; });
which are positioned based on x(date) and y(value) values in the data array. You can adjust the offsets using dx, dy attributes and use some styles to fill/stroke the text.
var data = [];
function randomDate(start, end) {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
}
for(var i=0; i<20; i++) {
var obj = {};
obj.date = randomDate(new Date(2018, 01,01), new Date());
obj.value = Math.floor(Math.random() * 50);
data.push(obj);
}
data.sort(function(a, b) {
return a.date > b.date ? -1 : 1;
})
var width = 800, height = 400;
var svg = d3.select('svg')
.attr("width", width)
.attr("height", height);
var g = svg.append("g")
.attr("transform", "translate(" + 0 + "," + 0 + ")");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) {
return x(d.date)
})
.y(function(d) {
return y(d.value)
})
x.domain(d3.extent(data, function(d) {
return d.date
}));
y.domain(d3.extent(data, function(d) {
return d.value
}));
g.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);
g.selectAll('.textLabels')
.data(data).enter()
.append('text')
.classed('textLabels', true)
.attr('x', function(d) { return x(d.date); })
.attr('y', function(d) { return y(d.value); })
.text(function(d) { return d.value; });
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Let me know if you have any questions. Hope this helps.:)

Adding circles to multi line graph with dropdown on d3.js

I am trying to add circles to the data points on the following line graph example: https://bl.ocks.org/ProQuestionAsker/8382f70af7f4a7355827c6dc4ee8817d
To generate the circles I have used the following:
svg.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3)
.attr("color", "pink")
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
However, as seen here, all the circles for each every fruit. I would like only the circles for selected fruits to appear, as per the lines.
Many thanks
James
You see the circles for each and every fruit because you're not filtering the data based on the dropdown selection.
Here's a snippet doing that data filtering and appending the dots:
var dataAsCsv = `Month,Sales,Fruit,Year
Jan,87,strawberry,2016
Feb,3,strawberry,2016
Mar,89,strawberry,2016
Apr,56,strawberry,2016
May,1,strawberry,2016
Jun,17,strawberry,2016
Jul,59,strawberry,2016
Aug,43,strawberry,2016
Sep,16,strawberry,2016
Oct,94,strawberry,2016
Nov,99,strawberry,2016
Dec,53,strawberry,2016
Jan,93,grape,2016
Feb,8,grape,2016
Mar,95,grape,2016
Apr,62,grape,2016
May,5,grape,2016
Jun,24,grape,2016
Jul,62,grape,2016
Aug,49,grape,2016
Sep,18,grape,2016
Oct,101,grape,2016
Nov,103,grape,2016
Dec,53,grape,2016
Jan,94,blueberry,2016
Feb,15,blueberry,2016
Mar,95,blueberry,2016
Apr,64,blueberry,2016
May,11,blueberry,2016
Jun,33,blueberry,2016
Jul,64,blueberry,2016
Aug,53,blueberry,2016
Sep,27,blueberry,2016
Oct,103,blueberry,2016
Nov,108,blueberry,2016
Dec,62,blueberry,2016
Jan,80,strawberry,2015
Feb,0,strawberry,2015
Mar,71,strawberry,2015
Apr,51,strawberry,2015
May,3,strawberry,2015
Jun,11,strawberry,2015
Jul,56,strawberry,2015
Aug,34,strawberry,2015
Sep,12,strawberry,2015
Oct,75,strawberry,2015
Nov,94,strawberry,2015
Dec,46,strawberry,2015
Jan,76,grape,2015
Feb,0,grape,2015
Mar,78,grape,2015
Apr,58,grape,2015
May,10,grape,2015
Jun,22,grape,2015
Jul,47,grape,2015
Aug,36,grape,2015
Sep,18,grape,2015
Oct,86,grape,2015
Nov,98,grape,2015
Dec,40,grape,2015
Jan,79,blueberry,2015
Feb,0,blueberry,2015
Mar,78,blueberry,2015
Apr,49,blueberry,2015
May,5,blueberry,2015
Jun,31,blueberry,2015
Jul,62,blueberry,2015
Aug,49,blueberry,2015
Sep,7,blueberry,2015
Oct,86,blueberry,2015
Nov,100,blueberry,2015
Dec,46,blueberry,2015`;
// Set the margins
var margin = {top: 60, right: 100, bottom: 20, left: 80},
width = 850 - margin.left - margin.right,
height = 370 - margin.top - margin.bottom;
// Parse the month variable
var parseMonth = d3.timeParse("%b");
var formatMonth = d3.timeFormat("%b");
var formatYear = d3.timeFormat("%Y");
var parseYear = d3.timeParse("%Y");
// Set the ranges
var x = d3.scaleTime().domain([parseMonth("Jan"), parseMonth("Dec")]).range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// Define the line
var valueLine = d3.line()
.x(function(d) { return x(d.Month); })
.y(function(d) { return y(+d.Sales); })
// Create the svg canvas in the "graph" div
var svg = d3.select("#graph")
.append("svg")
.style("width", width + margin.left + margin.right + "px")
.style("height", height + margin.top + margin.bottom + "px")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform","translate(" + margin.left + "," + margin.top + ")")
.attr("class", "svg");
var data = d3.csvParse(dataAsCsv);
// Format the data
data.forEach(function(d) {
d.Month = parseMonth(d.Month);
d.Sales = +d.Sales;
d.Fruit = d.Fruit;
d.Year = formatYear(parseYear(+d.Year));
});
var nest = d3.nest()
.key(function(d){
return d.Fruit;
})
.key(function(d){
return d.Year;
})
.entries(data)
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Month; }));
y.domain([0, d3.max(data, function(d) { return d.Sales; })]);
// Set up the x axis
var xaxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.attr("class", "x axis")
.call(d3.axisBottom(x)
.ticks(d3.timeMonth)
.tickSize(0, 0)
.tickFormat(d3.timeFormat("%B"))
.tickSizeInner(0)
.tickPadding(10));
// Add the Y Axis
var yaxis = svg.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(y)
.ticks(5)
.tickSizeInner(0)
.tickPadding(6)
.tickSize(0, 0));
// Add a label to the y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - 60)
.attr("x", 0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Monthly Sales")
.attr("class", "y axis label");
svg.append('g').classed('data-points', true);
// Create a dropdown
var fruitMenu = d3.select("#fruitDropdown")
fruitMenu
.append("select")
.selectAll("option")
.data(nest)
.enter()
.append("option")
.attr("value", function(d){
return d.key;
})
.text(function(d){
return d.key;
})
// Function to create the initial graph
var initialGraph = function(fruit){
// Filter the data to include only fruit of interest
var selectFruit = nest.filter(function(d){
return d.key == fruit;
})
var selectFruitGroups = svg.selectAll(".fruitGroups")
.data(selectFruit, function(d){
return d ? d.key : this.key;
})
.enter()
.append("g")
.attr("class", "fruitGroups")
var initialPath = selectFruitGroups.selectAll(".line")
.data(function(d) { return d.values; })
.enter()
.append("path")
initialPath
.attr("d", function(d){
return valueLine(d.values)
})
.attr("class", "line")
svg.select('g.data-points').selectAll("dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}))
.enter().append("circle").classed('dot', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
}
// Create initial graph
initialGraph("strawberry")
// Update the data
var updateGraph = function(fruit){
// Filter the data to include only fruit of interest
var selectFruit = nest.filter(function(d){
return d.key == fruit;
})
// Select all of the grouped elements and update the data
var selectFruitGroups = svg.selectAll(".fruitGroups")
.data(selectFruit)
// Select all the lines and transition to new positions
selectFruitGroups.selectAll("path.line")
.data(function(d){
return (d.values);
})
.transition()
.duration(1000)
.attr("d", function(d){
return valueLine(d.values)
});
var circles = svg.select('g.data-points').selectAll(".dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}));
circles
.enter().append("circle")
.merge(circles).classed('data-point', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.transition().duration(1000)
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
}
// Run update function when dropdown selection changes
fruitMenu.on('change', function(){
// Find which fruit was selected from the dropdown
var selectedFruit = d3.select(this)
.select("select")
.property("value")
// Run update function with the selected fruit
updateGraph(selectedFruit)
});
.line {
fill: none;
stroke: #EF5285;
stroke-width: 2px;
}
<script src="https://d3js.org/d3.v4.js"></script>
<div id = "fruitDropdown"></div>
<div id="graph"></div>
Important code changes:
Instead of appending circles directly to the SVG, I've created a group <g class="data-points"></g> that holds all the dots.
svg.append('g').classed('data-points', true);
Enter/update/exit all dots within the above group in both functions i.e. initialGraph and updateGraph
InitialGraph:
svg.select('g.data-points').selectAll("dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}))
.enter().append("circle").classed('dot', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
UpdateGraph:
var circles = svg.select('g.data-points').selectAll(".dot")
.data(data.filter(function(d) {
return d.Fruit === fruit;
}));
circles
.enter().append("circle")
.merge(circles).classed('data-point', true)
.attr("r", 3)
.style("fill", "pink").style('stroke', '#000')
.transition().duration(1000)
.attr("cx", function(d) { return x(d.Month); })
.attr("cy", function(d) { return y(+d.Sales); });
Observe the data filtering based on the fruit selected bound to the circles and the transition applied in order to match the transition for the lines.
Always use style for applying fill and not attr. It's a good practice. Adding color:pink wouldn't change the color of the circles but fill would. In addition, I've added a stroke in order to make them visible even with a pink color. You can always change that though.
I would suggest you to add a code snippet every time you ask a question and not provide links. That would be easier for anyone to debug and help fix errors.
Hope this helps. :)

How to Resize D3 Line Charts

I have a question about resizing D3 multi line charts. I followed Building Responsive Visualizations with D3.js. But I am having trouble updating the elements inside of my chart. I am successfully updating the axis, but not the lines themselves. I also am unsure of how to update the dots and text in the graph.
Thanks for your help!
Here is the code I have so far:
<svg id="graph"></svg>
<script>
// Set the dimensions of the canvas / graph
var margin = 40,
width = 960 - margin*2,
height = 500 - margin*2;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d").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(8);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.average_ticnum); });
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.average_fatiguenum); });
var valueline3 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.average_stressnum); });
var valueline4 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sum_nf_sugars); });
var valueline5 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sum_nf_total_carbohydrate); });
// Adds the svg canvas
var graph = d3.select("#graph")
.attr("width", width + margin*2)
.attr("height", height + margin*2)
.append("g")
.attr("transform", "translate(" + margin + "," + margin + ")");
// Get the data
d3.json("progress_output.php?useremail=<?php echo $useremail; ?>", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.average_ticnum = +d.average_ticnum;
d.fatiguenum = +d.average_fatiguenum;
d.stressnum = +d.average_stressnum;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0,12]);
// Add the valueline path.
graph.append("path")
.attr("class", "line")
.style("stroke", "#891f83")
.attr("id","ticLine")
.attr("d", valueline(data));
graph.append("path")
.attr("class", "line")
.style("stroke", "#7db6e3")
.attr("id","fatigueLine")
.attr("d", valueline2(data));
graph.append("path")
.attr("class", "line")
.style("stroke", "#36376a")
.attr("id","stressLine")
.attr("d", valueline3(data));
graph.append("path")
.attr("class", "line")
.style("stroke", "#9bcf81")
.attr("id","sugarLine")
.attr("d", valueline4(data));
graph.append("path")
.attr("class", "line")
.style("stroke", "#efa465")
.attr("id","carbLine")
.attr("d", valueline5(data));
// Add the Dots
graph.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("id","ticDots")
.attr("r", 3.5)
.style("fill", "#891f83")
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.average_ticnum); });
graph.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.style("fill", "#7db6e3")
.attr("id","fatigueDots")
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.average_fatiguenum); });
graph.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.style("fill", "#36376a")
.attr("id", "stressDots")
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.average_stressnum); });
graph.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("id","sugarDots")
.attr("r", 3.5)
.style("fill", "#9bcf81")
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.sum_nf_sugars); });
graph.selectAll("dot")
.data(data)
.enter().append("circle")
.attr("r", 3.5)
.style("fill", "#efa465")
.attr("id","carbDots")
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.sum_nf_total_carbohydrate); });
// Add the X Axis
graph.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
graph.append("g")
.attr("class", "y axis")
.call(yAxis);
//Add the Tic title
graph.append("text")
.attr("x", 15)
.attr("y", 0)
.attr("class", "legend")
.attr("id", "ticText")
.style("color", "#891f83")
.style("fill", "#891f83")
.style("cursor", "pointer")
.style("font-family", "cooperbook")
.on("click", function(){
// Determine if current line is visible
var active = ticLine.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements
width = 200;
height = 200;
d3.select("#ticLine").style("opacity", newOpacity);
d3.selectAll("#ticDots").style("opacity", newOpacity);
// Update whether or not the elements are active
ticLine.active = active;
})
.text("Tic Severity");
//Add the fatigue title
graph.append("text")
.attr("x", 115)
.attr("y", 0)
.attr("class", "legend")
.style("color", "#7bd6e3")
.style("fill", "#7bd6e3")
.style("cursor", "pointer")
.style("font-family", "cooperbook")
.on("click", function(){
// Determine if current line is visible
var active = fatigueLine.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements
d3.select("#fatigueLine").style("opacity", newOpacity);
d3.selectAll("#fatigueDots").style("opacity", newOpacity);
// Update whether or not the elements are active
fatigueLine.active = active;
})
.text("Fatigue");
//Add the Stress title
graph.append("text")
.attr("x", 190)
.attr("y", 0)
.attr("class", "legend")
.style("color", "#36376a")
.style("fill", "#36376a")
.style("cursor", "pointer")
.style("font-family", "cooperbook")
.on("click", function(){
// Determine if current line is visible
var active = stressLine.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements
d3.select("#stressLine").style("opacity", newOpacity);
d3.selectAll("#stressDots").style("opacity", newOpacity);
// Update whether or not the elements are active
stressLine.active = active;
})
.text("Stress");
//Add the sugar title
graph.append("text")
.attr("x", 250)
.attr("y", 0)
.attr("class", "legend")
.style("color", "#9bcf81")
.style("fill", "#9bcf81")
.style("cursor", "pointer")
.style("font-family", "cooperbook")
.on("click", function(){
// Determine if current line is visible
var active = sugarLine.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements
d3.select("#sugarLine").style("opacity", newOpacity);
d3.selectAll("#sugarDots").style("opacity", newOpacity);
// Update whether or not the elements are active
sugarLine.active = active;
})
.text("Sugars");
//Add the carb title
graph.append("text")
.attr("x", 320)
.attr("y", 0)
.attr("class", "legend")
.style("color", "#efa465")
.style("fill", "#efa465")
.style("cursor", "pointer")
.style("font-family", "cooperbook")
.on("click", function(){
// Determine if current line is visible
var active = carbLine.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements
d3.select("#carbLine").style("opacity", newOpacity);
d3.selectAll("#carbDots").style("opacity", newOpacity);
// Update whether or not the elements are active
carbLine.active = active;
})
.text("Carbohydrates");
});
function resize() {
/* Find the new window dimensions */
var width = parseInt(d3.select("#graph").style("width")) - margin*2,
height = parseInt(d3.select("#graph").style("height")) - margin*2;
/* Update the range of the scale with new width/height */
x.range([0, width]).nice(d3.time.year);
y.range([height, 0]).nice();
/* Update the axis with the new scale */
graph.select('.x.axis')
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
graph.select('.y.axis')
.call(yAxis);
/* Force D3 to recalculate and update the line */
graph.selectAll('.line')
.attr("d", valueline(data));
}
d3.select(window).on('resize', resize);

d3 nested data - individual graphs - setting y.domain?

I am trying to turn some nested data into 8 individual line charts (one chart for each key). So far I am creating one graph per svg, however I am having issues with the y-domain - specifically setting the y-domain for each graph.
currently:
var line = d3.svg.line()
.x(function (d) { return x(d.date); })
.y(function (d) { return y(d.app); })
x.domain(d3.extent([parseDate("2003.0"), parseDate("2014.0")]));
y.domain(d3.extent([0,20000]));
var data2 = d3.nest()
.key(function(d) { return d.race; })
.entries(data);
var svgContainer = d3.selectAll("body")
.data(data2)
.enter()
.append("svg")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.append("path")
.data(data2)
.attr('id', function(d) { return d.key ;})
.attr('class', 'line')
.attr('opacity', .8)
.attr('d', function(d) { return line(d.values); });
I see parts of some lines in the svg's, but most are cut off. Any suggestions? I'm not sure if the paths are correct either.
Data:
{ key: "1", values: 0: ['app' : 50000, year: '2003'], 1: ['app': 20000, year: '2004'],
key: "2" values: 0: ['app' : 40000, year: '2003'], 1: ['app' 50000, year: '2004']
etc...}
Modified d3 using a different X scale and Y scale domain for each selection
var svgContainer = d3.select("body").selectAll(".line")
.data(data2)
.enter()
.append("svg")
.attr("transform", "translate(" + margin.left + "," + margin.top+ ")")
.append("g")
.each(function(d, i){
var eachRace = d.values;
console.log(eachRace);
var svg = d3.select(this);
var yMax = d3.max(eachRace, function(d) { return d.app; });
var yScale = d3.scale.linear().domain([0, yMax]).range([height/8, 0]);
var yAxis = d3.svg.axis().scale(yScale).orient("left").ticks(5);
var line = d3.svg.line()
.x(function (d) { return x(d.date); })
.y(function (d) { return yScale(d.app); })
svg.append("path")
.attr("id", function(d) { return d.key ;})
.attr('class', 'line')
.attr('opacity', .8)
.attr('d', function(d) { return line(d.values); })
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
})
You can apply extent directly to your data like so:
yScale.domain(d3.extent(data, function(d) { return d.app; }));
This will give you the extent of all the data. If you need to get the extent of portions of the data, such as in your case of one category vs. another, you need to get the extent of the result of some filtering function. You should look into either d3.filter or write your own within extent(). So you'd probably want to make the return value contingent on d.key matching your current key, however you are storing that.

Displaying tooltips permanently in d3.js line chart

I'm making a line chart using d3.js. A tooltip at a point is displayed on mouseover,and disappears on mouseout. I want to display all the tooltips together permanently when the chart is created. Is there a way to do it?
My javascript-
var x = d3.time.scale().range([0, w]);
var y = d3.scale.linear().range([h, 0]);
x.domain(d3.extent(data, function(d) { return d.x; }));
y.domain(d3.extent(data, function(d) { return d.y; }));
var line = d3.svg.line()
.x(function(d) {
return x(d.x);
})
.y(function(d) {
return y(d.y);
})
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var graph = d3.select("#graph").append("svg:svg")
.attr("width", 900)
.attr("height", 600)
.append("svg:g")
.attr("transform", "translate(" + 80 + "," + 80 + ")");
var xAxis = d3.svg.axis().scale(x).ticks(10).orient("bottom");
var yAxisLeft = d3.svg.axis().scale(y).ticks(10).orient("left");
var area = d3.svg.area()
.x(function(d) { return x(d.x); })
.y0(h)
.y1(function(d) { return y(d.y); });
graph.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("class", "circle")
.attr("cx", function (d) { return x(d.x); })
.attr("cy", function (d) { return y(d.y); })
.attr("r", 4.5)
.style("fill", "black")
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div
.html(d.y) + "<br/>" + d.x)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 30) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
To label each data point, you can add text elements at the appropriate positions. The code would look something like this.
graph.selectAll("text").data(data).enter()
.append("text")
.attr("x", function (d) { return x(d.x); })
.attr("y", function (d) { return y(d.y) - 10; })
.text(function(d) { return d.value; });

Categories