I would appreciate any help on this! I am currently attempting to add two paths from two different csv files to code adapted from this Focus+Context via Brushing d3 visualization: http://bl.ocks.org/mbostock/1667367
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.area {
fill: none;
stroke: #000;
clip-path: url(#clip);
}
.area_ {
fill: none;
stroke: #a0f2;
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;
}
.brush_ .extent {
stroke: #fff;
fill-opacity: .125;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%b %Y").parse;
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]),
x_ = d3.time.scale().range([0, width]),
x2_ = d3.time.scale().range([0, width]),
y_ = d3.scale.linear().range([height, 0]),
y2_ = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
xAxis2_ = d3.svg.axis().scale(x2_).orient("bottom"),
xAxis_ = d3.svg.axis().scale(x_).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left"),
yAxis_ = d3.svg.axis().scale(y_).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var brush_ = d3.svg.brush()
.x(x2_)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var area_ = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x_(d.date); })
.y0(height)
.y1(function(d) { return y_(d.price); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.price); });
var area2_ = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2_(d.date); })
.y0(height2)
.y1(function(d) { return y2_(d.price); });
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 + ")");
d3.csv("sp500.csv", type, function(error, data) {
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
d3.csv("academia_score.csv", type, function(error, data) {
x_.domain(d3.extent(data.map(function(d) { return d.date; })));
y_.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
x2_.domain(x_.domain());
y2_.domain(y_.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area_);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2_);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".area_").attr("d", area_);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.price = +d.price;
return d;
}
</script>
However, the brush zoom is not working on my second path. The output can be viewed on this page: http://researchiq.net/comp.html Why isn't the zoom working on the second path??? Thanks!
Because d3.select() only selects a single element, not multiple, so focus.select(".area") is incorrect. Switch it to focus.selectAll(".area") and, assuming everything else was done properly, you'll be good to go.
Related
I'm newbie in D3.js. I would like to make many graphs on one page as here http://bl.ocks.org/d3noob/5987480 based on this example https://bl.ocks.org/mbostock/1166403
But I ran into a problem. The scale in the first chart is incorrect. And I just don't understand, why... How to fix this?
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 12px Arial;
}
path.line {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
path.area {
fill: #e7e7e7;
}
.axis {
shape-rendering: crispEdges;
}
.x.axis line {
stroke: #fff;
}
.x.axis .minor {
stroke-opacity: .5;
}
.x.axis path {
display: none;
}
.y.axis line,
.y.axis path {
fill: none;
stroke: #000;
}
</style>
<body>
<div id="area1"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 10, right: 20, bottom: 20, left: 40},
width = 300 - margin.left - margin.right,
height = 150 - margin.top - margin.bottom;
var parse = d3.time.format("%Y").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.ticks(8)
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.ticks(4)
.orient("left");
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var line = d3.svg.line()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
var svg1 = d3.select("#area1").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 + ")");
svg1.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
d3.csv("1-1.9.csv", function(error, data) {
data.forEach(function(d) {
d.date = parse(d.date);
d.close = +d.price;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.price; })]);
area.y0(y(0));
svg1
.datum(data);
svg1.append("path")
.attr("class", "area")
.attr("clip-path", "url(#clip)")
.attr("d", area);
svg1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg1.append("g")
.attr("class", "y axis")
.call(yAxis);
svg1.append("path")
.attr("class", "line")
.attr("clip-path", "url(#clip)")
.attr("d", line);
svg1.append("text")
.attr("x", width - 6)
.attr("y", height - 6)
.style("text-anchor", "end")
.text(data[0].symbol);
});
var svg2 = d3.select("#area1").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 + ")");
svg2.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
d3.csv("2-2.9.csv", function(error, data) {
data.forEach(function(d) {
d.date = parse(d.date);
d.close = +d.price;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.price; })]);
area.y0(y(0));
svg2
.datum(data);
svg2.append("path")
.attr("class", "area")
.attr("clip-path", "url(#clip)")
.attr("d", area);
svg2.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg2.append("g")
.attr("class", "y axis")
.call(yAxis);
svg2.append("path")
.attr("class", "line")
.attr("clip-path", "url(#clip)")
.attr("d", line);
svg2.append("text")
.attr("x", width - 6)
.attr("y", height - 6)
.style("text-anchor", "end")
.text(data[0].symbol);
});
</script>
1-1.9.csv:
symbol,date,price
1-1.9,2003,339
1-1.9,2004,560
1-1.9,2005,792
1-1.9,2006,2579
1-1.9,2007,960
1-1.9,2008,3295
1-1.9,2009,3807
1-1.9,2010,2634
1-1.9,2011,2576
1-1.9,2012,2748
1-1.9,2013,4292
1-1.9,2014,4295
1-1.9,2015,4045
2-2.9.csv:
symbol,date,price
2-2.9,2003,1768
2-2.9,2004,1732
2-2.9,2005,1714
2-2.9,2006,2622
2-2.9,2007,2281
2-2.9,2008,3801
2-2.9,2009,3712
2-2.9,2010,3407
2-2.9,2011,3349
2-2.9,2012,3237
2-2.9,2013,5180
2-2.9,2014,3496
2-2.9,2015,3076
Your scale's domain is set to find the maximum value in the property price, not the property close. price is a string, close is an integer.
Your data array has objects such as:
{ symbol: "1-1.9", date: Date 2006-01-01T08:00:00.000Z, price: "2579", close: 2579 }
{ symbol: "1-1.9", date: Date 2007-01-01T08:00:00.000Z, price: "960", close: 960 }
Comparing price will compare strings. In javascript, strings are compared in a manner similar to alphabetical order, so the string with the highest first digit will be last (the maximum, see this answer or this one for more info on comparing strings). In your case, that is 960, as you can see if you include this line after you set the domain:
console.log(y.domain()); // [0,960]
Instead, simply change your scale's domain to:
y.domain([0, d3.max(data, function(d) { return d.close; })]);
clipPath in a d3-project don't clips: the graph overflows the chart window on the left.
I followed several examples available online, but I don't see, why my clipPath don't works.
Working example can be found here: https://phinetwork.ch/wolf/dynamicgraph.html
Code:
<style>
.area {
fill: darkorange;
}
.bgrect {
background-color:#999;
}
.zoom {
cursor: move;
fill: none;
pointer-events: all;
background-color:grey;
}
.grid line{
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid text {
display:none;
}
.grid path, .xgrid path{
stroke-width: 0;
}
</style>
<svg width="900" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 0, bottom: 110, left: 40},
margin2 = {top: 430, right: 0, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
height2 = +svg.attr("height") - margin2.top - margin2.bottom;
var parseDate = d3.timeParse("%Y-%m-%d");
var x = d3.scaleTime().range([0, width]),
x2 = d3.scaleTime().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
y2 = d3.scaleLinear().range([height2, 0]);
var xAxis = d3.axisBottom(x)
.ticks(10),
yAxis = d3.axisLeft(y)
.ticks(7),
xgAxis = d3.axisBottom(x)
.ticks(10)
.tickSize(-height),
ygAxis = d3.axisLeft(x)
.ticks(10)
.tickSize(-width - margin.left),
xAxis2 = d3.axisBottom(x2);
var brush = d3.brushX()
.extent([[0, 0], [width, height2]])
.on("brush end", brushed);
var zoom = d3.zoom()
.scaleExtent([1, Infinity])
.translateExtent([[0, 0], [width, height]])
.extent([[0, 0], [width, height]])
.on("zoom", zoomed);
var area = d3.area()
.curve(d3.curveMonotoneX)
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.rz); });
var area2 = d3.area()
.curve(d3.curveMonotoneX)
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.rz); });
//svg.append("defs").append("clipPath")
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("x", 40)
.attr("y", 0)
.attr("width", width-margin.left)
.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 + ")");
d3.csv("files/institute/testdat.csv", type, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.rz; })]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("rect")
.attr("class", "bgrect")
.attr("width", width)
.attr("height", height)
//.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("clip-path", "url(#clip)")
.attr("d", area);
focus.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "axis grid")
.attr("transform", "translate(0," + height + ")")
.call(xgAxis);
focus.append("g")
.attr("class", "axis grid")
.attr("transform", "translate(0," + -margin.top + ")")
.call(ygAxis);
focus.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
context.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, x.range());
svg.append("rect")
.attr("class", "zoom")
.attr("width", width - margin.left)
.attr("height", height)
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
});
function brushed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
var s = d3.event.selection || x2.range();
x.domain(s.map(x2.invert, x2));
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
focus.select(".grid").call(xgAxis);
svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
.scale(width / (s[1] - s[0]))
.translate(-s[0], 0));
}
function zoomed() {
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
var t = d3.event.transform;
x.domain(t.rescaleX(x2).domain());
focus.select(".area").attr("d", area);
focus.select(".axis--x").call(xAxis);
focus.select(".grid").call(xgAxis);
context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
}
function type(d) {
d.date = parseDate(d.date);
d.rz = +d.rz;
return d;
}
</script>
Any suggestions for this problem?
I am new to D3.js
I've gone through some tutorials and have straight up jumped into my first project. I was hoping to combine the following with slight tweaks according to my needs. Currently I am having two issues
Focus+Context via Brushing
and
X-Value Mouseover
The Mouseover is wrongly displayed. It renders to the left of the chart. Could be a very small issue but I cant seem to find it.
I cant seem to figure out a way to display the "Safe Value" text outside the chart right next to the line. EDIT 2 - I've figured this out
Any help would be much appreciated.
Here is the CSS
body {
font: 10px sans-serif;
}
svg {
font: 10px sans-serif;
}
.line {
fill: none;
stroke: steelBlue;
stroke-width: 1.5px;
/*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;
}
.overlay {
fill: none;
pointer-events: all;
}
.xy circle {
fill: steelblue;
stroke: black;
}
JS
var margin = {top: 10, right: 15, bottom: 100, left: 60},
margin2 = {top: 430, right: 15, bottom: 20, left: 60},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%SZ").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatData = function(d) { return formatValue(d) + " %"; };
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(d3.time.months, 1).tickFormat(d3.time.format("%m/%y")),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom").ticks(d3.time.months, 1).tickFormat(d3.time.format("%m/%y")),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var line = d3.svg.line()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
var line2 = d3.svg.line()
.interpolate("monotone")
.x(function(d) { return x2(d.date); })
.y(function(d) { return y2(d.value); });
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 + ")");
d3.csv("data.csv", function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
data.sort(function(a, b) {
return a.date - b.date;
});
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.value; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
focus.append("line")
.attr("x1",x(data[0].date))
.attr("y1",y(83))
.attr("x2",x(data[data.length - 1].date))
.attr("y2",y(83))
.attr("stroke","orangered");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(83) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "orangered")
.text(function(d) { return "Safe Value = 83" });
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("x", 0)
.attr("y", 0)
.style("text-anchor", "middle")
.attr("transform", "translate(-50,"+ height/2 + ") rotate(-90)")
.text("Dissolved Oxygen (%)");
context.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line2);
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
var xy = svg.append("g")
.attr("class", "xy")
.style("display", "none");
xy.append("circle")
.attr("r", 4.5);
xy.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.on("mouseover", function() { xy.style("display", null); })
.on("mouseout", function() { xy.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
console.log(x0);
xy.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
xy.select("text").text(formatData(d.value));
}
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".line").attr("d", line);
focus.select(".x.axis").call(xAxis);
}
Plunker Code
(Please refer to the code at Plunker, since I have updated a few things over there.) Thanks
Image1
Image2
For your problem #2, the code for the text is placing it out of the visible area. Just adjust your arguments to translate to something like the following:
.attr("transform", "translate(" + (width - 35) + ",30" + ")")
or something else that you prefer - note the minus on the x.
I've created a graph with multiple area plots using d3.nest() that are colored by another function. When I attempted to add this zoom functionality, I'm only getting it to work with the first area plot.
Here's a Plunk
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.area {
fill: steelblue;
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="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var x = d3.scale.linear().range([0, width]),
x2 = d3.scale.linear().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x(d.distance); })
.y0(height)
.y1(function(d) { return y(d.elevation); });
var area2 = d3.svg.area()
.interpolate("basis")
.x(function(d) { return x2(d.distance); })
.y0(height2)
.y1(function(d) { return y2(d.elevation); });
// Map colors to limits
var color = d3.scale.ordinal()
.domain([-10,-5,0,5,10])
.range(['#a1d99b','#c7e9c0','#fdd0a2','#fdae6b','#fd8d3c','#e6550d']);
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 + ")");
// Caculate the average gradient of a dataGroup.
function dataGroupGradient(dataGroup) {
return d3.mean(dataGroup, function(value) {
return parseFloat(value.gradient);
});
}
var line_points = [];
d3.csv("first5km_Strade_Bianche.csv", function(error, data) {
data.forEach(function(d) {
d.distance = +d.distance;
d.elevation = +d.elevation;
d.latitude = +d.latitude;
d.longitude = +d.longitude;
line_points.push([d.latitude, d.longitude]);
});
// Split the data based on "group"
var dataGroup = d3.nest()
.key(function(d) {
return d.group;
})
.entries(data);
// To remove white space between dataGroups, append the first element of one
// dataGroup to the last element of the previous dataGroup.
dataGroup.forEach(function(group, i) {
if(i < dataGroup.length - 1) {
group.values.push(dataGroup[i+1].values[0])
}
})
x.domain(d3.extent(data.map(function(d) { return d.distance; })));
y.domain([0, d3.max(data.map(function(d) { return d.elevation; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
// Add a line and an area for each dataGroup
dataGroup.forEach(function(d, i){
focus.append("path")
.datum(d.values)
.attr("class", "area")
.attr("d", area);
});
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area2);
dataGroup.forEach(function(d, i){
context.append("path")
.datum(d.values)
.attr("class", "area")
.attr("d", area2);
});
// Fill the dataGroups with color
svg.selectAll(".area")
.style("fill", function(d) { return color(dataGroupGradient(d)); });
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.distance = parseDate(d.distance);
d.elevation = +d.elevation;
return d;
}
</script>
Just a small mistake inside the brush handler:
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".area").attr("d", area);// <-- HERE!
focus.select(".x.axis").call(xAxis);
}
The call to focus.select(".area") only selects a single path. You want all paths. So, instead, use selectAll():
focus.selectAll(".area").attr("d", area);
Updated Plunk
d3 noob here.
I'd like to draw something like this:
(http://bl.ocks.org/mbostock/3883195)
But with a heat aspect, sort of like this:
Code (from above link):
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.area {
fill: steelblue;
}
</style>
<body>
<center>
<div>
<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("%d-%b-%y").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 area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.close); });
var svg = d3.select("div").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.tsv("data.tsv", 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([0, d3.max(data, function(d) { return d.close; })]);
svg.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
// .attr("style", "stroke: #001")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Price ($)");
});
</script>
</div>
</center>
</body>
Perhaps changing the area variable in someway? I could add another column to the data, say, color. But how would I apply the color to the "vertical line" of each day?
Thoughts? Thanks in advance!