I am having a hard time resizing my line graph based on window size. See my code here:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
svg {
font: 10px "Times New Roman";
}
path {
stroke-width: 2;
fill: none;
}
.axis path, .axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.overlay {
fill: none;
pointer-events: all;
}
</style>
</head>
<div class="chart-container"></div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
<body>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d").parse;
// Parse the time for the Day
var parseMinute = d3.time.format("%H:%M").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) { return "$" + formatValue(d);};
// 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);
// Define the line
var valueline = d3.svg.line()
//.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
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 + ")");
// Get the minumum Value from the array to add space at the bottom of the graph
Array.min = function (array) {
return Math.min.apply(Math, array);
};
var url = "https://api.iextrading.com/1.0/stock/aapl/chart/5y";
// Get the data
$.ajax({
url: url,
success: function(data) {
// Setting global variable
var arrayClose = [];
var firstPrice = null;
var lastPrice = null;
var minimum = null;
var result = null;
var lineColor = null;
// Get the data
d3.json(url, function (error, data) {
data.forEach(function (d) {
d.date = parseDate(d.date);
d.close = +d.close;
// Adding each result to the end of the array
arrayClose.push(d.close);
// Finding the minimum value in the close price in the JSON File
minimum = Array.min(arrayClose);
// Taking .05% off of graph to dynamically show white space at the bottom of the minimum value
result = (10 / 100) * minimum;
result = minimum - result;
// Finding first elm in array
firstPrice = arrayClose[0];
// Finding last elm in array
lastPrice = arrayClose[arrayClose.length - 1];
});
if (firstPrice > lastPrice){
lineColor = "red";
} else {
lineColor = "green";
}
// Scale the range of the data
x.domain(d3.extent(data, function (d) {
return d.date;
}));
y.domain([result, d3.max(data, function (d) {
return d.close;
})]);
// Add the valueline path.
svg.append("path")
.transition()
.attr("class", "line")
.attr("stroke", lineColor)
.attr("d", valueline(data))
;
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Add the text label for the X axis
svg.append("text")
.attr("x", width / 2) //Dynamically moves with the graph
.attr("y", height + margin.bottom)
.style("text-anchor", "middle")
.text("Date");
// Add the text label for the Y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("x", 0 - (height / 2))
.attr("y", 0 - margin.left)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Price");
// Adding the Title
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Price to Date");
//Mouseover
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height);
focus.append("line")
.attr("class", "y-hover-line hover-line")
.attr("x1", width)
.attr("x2", width);
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.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;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select(".x-hover-line").attr("y2", height - y(d.close));
focus.select(".y-hover-line").attr("x2", width + width);
}
});
}
});
</script>
</body>
</html>
When I change add a viewbox, the svg disappears completely. I have tried creating a class around the svg but it isn't recognizing it for some reason. My inspiration for this is at Stack Example
Drop the width and height attributes, setting the viewBox:
.attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " "
+ (height + margin.top + margin.bottom))
Here is the code with that change:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
svg {
font: 10px "Times New Roman";
}
path {
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
.overlay {
fill: none;
pointer-events: all;
}
</style>
</head>
<div class="chart-container"></div>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
<body>
<script>
// Set the dimensions of the canvas / graph
var margin = {
top: 30,
right: 20,
bottom: 30,
left: 50
},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d").parse;
// Parse the time for the Day
var parseMinute = d3.time.format("%H:%M").parse,
bisectDate = d3.bisector(function(d) {
return d.date;
}).left,
formatValue = d3.format(",.2f"),
formatCurrency = function(d) {
return "$" + formatValue(d);
};
// 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);
// Define the line
var valueline = d3.svg.line()
//.interpolate("basis")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("viewBox", "0 0 " + (width + margin.left + margin.right) + " " + (height + margin.top + margin.bottom))
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Get the minumum Value from the array to add space at the bottom of the graph
Array.min = function(array) {
return Math.min.apply(Math, array);
};
var url = "https://api.iextrading.com/1.0/stock/aapl/chart/5y";
// Get the data
$.ajax({
url: url,
success: function(data) {
// Setting global variable
var arrayClose = [];
var firstPrice = null;
var lastPrice = null;
var minimum = null;
var result = null;
var lineColor = null;
// Get the data
d3.json(url, function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
// Adding each result to the end of the array
arrayClose.push(d.close);
// Finding the minimum value in the close price in the JSON File
minimum = Array.min(arrayClose);
// Taking .05% off of graph to dynamically show white space at the bottom of the minimum value
result = (10 / 100) * minimum;
result = minimum - result;
// Finding first elm in array
firstPrice = arrayClose[0];
// Finding last elm in array
lastPrice = arrayClose[arrayClose.length - 1];
});
if (firstPrice > lastPrice) {
lineColor = "red";
} else {
lineColor = "green";
}
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([result, d3.max(data, function(d) {
return d.close;
})]);
// Add the valueline path.
svg.append("path")
.transition()
.attr("class", "line")
.attr("stroke", lineColor)
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// Add the text label for the X axis
svg.append("text")
.attr("x", width / 2) //Dynamically moves with the graph
.attr("y", height + margin.bottom)
.style("text-anchor", "middle")
.text("Date");
// Add the text label for the Y axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("x", 0 - (height / 2))
.attr("y", 0 - margin.left)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Price");
// Adding the Title
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Price to Date");
//Mouseover
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("line")
.attr("class", "x-hover-line hover-line")
.attr("y1", 0)
.attr("y2", height);
focus.append("line")
.attr("class", "y-hover-line hover-line")
.attr("x1", width)
.attr("x2", width);
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() {
focus.style("display", null);
})
.on("mouseout", function() {
focus.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;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
focus.select(".x-hover-line").attr("y2", height - y(d.close));
focus.select(".y-hover-line").attr("x2", width + width);
}
});
}
});
</script>
</body>
</html>
PS: you have another issues in your code.
Related
i have plotted dynamic waves based on randomly generated data in d3.js. I am using "dot" (svg.selectAll("dot")) element to represent the data point(x and y axis) on the waves. Based on setinterval method my data is getting updated every 200ms and i am transforming the data from right to left. But the data points(dots) that i added to the waves are not moving along with the waves, they are fixed(not moving) and only waves are moving.
here's the code:
https://jsfiddle.net/rajatmehta/tm5166e1/4/
function updateData() {
var newData = GenData(N,lastUpdateTime);
lastUpdateTime = newData[newData.length-1].timestamp;
var newData2 = GenData2(N,lastUpdateTimeNew);
lastUpdateTimeNew = newData2[newData2.length-1].timestamp;
for (var i=0; i<newData.length; i++){
console.log(globalData.length);
if(globalData.length>99){
globalData.shift();
}
globalData.push(newData[i]);
}
for (var i=0; i<newData2.length; i++){
console.log(globalDataNew.length);
if(globalDataNew.length>99){
globalDataNew.shift();
}
globalDataNew.push(newData2[i]);
}
//code for transition start
x1 = newData[0].timestamp;
x2 = newData[newData.length - 1].timestamp;
dx = dx + (x(x1) - x(x2)); // dx needs to be cummulative
x1New = newData2[0].timestamp;
x2New = newData2[newData2.length - 1].timestamp;
dxNew = dxNew + (x(x1New) - x(x2New)); // dx needs to be cummulative
d3.select("path#path1")
.datum(globalData)
.attr("class", "line")
.attr("d", valueline(globalData))
.transition()
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
d3.select("path#path2")
.datum(globalDataNew)
.attr("class", "line")
.attr("d", valueline2(globalDataNew))
.transition()
.ease("linear")
.attr("transform", "translate(" + String(dxNew) + ")");
svg.select(".x.axis").call(xAxis);
}
I am new to d3.js, so dont have much idea about this.
Two problems:
You are not appending the circles correctly: you cannot append a <circle> element to a <path>element. You have to use an "enter" selection, appending them to the SVG (or a group element):
chartBody.selectAll(null)
.data(globalData)
.enter()
.append("circle")
.attr("class", "dot1")
.attr("r", 3)
.attr("cx", function(d) {
console.log(d)
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
In the update function, select those circles by class:
d3.selectAll(".dot1")
.data(globalData)
.transition()
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
Here is your code with those changes:
var lastUpdateTime = +new Date();
var lastUpdateTimeNew = +new Date();
var GenData = function(N, lastTime) {
var output = [];
for (var i = 0; i < N; i++) {
output.push({
value: Math.random() * 10,
timestamp: lastTime
});
lastTime = lastTime + 1000;
}
return output;
}
var GenData2 = function(N, lastTime) {
var output = [];
for (var i = 0; i < N; i++) {
output.push({
value: Math.random() * 20,
timestamp: lastTime
});
lastTime = lastTime + 1000;
}
return output;
}
var globalData;
var globalDataNew;
// plot the original data by retrieving everything from time 0
data = GenData(50, lastUpdateTime);
dataNew = GenData2(50, lastUpdateTimeNew);
lastUpdateTime = data[data.length - 1].timestamp;
lastUpdateTimeNew = dataNew[dataNew.length - 1].timestamp;
globalData = data;
globalDataNew = dataNew;
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var margin = {
top: 30,
right: 20,
bottom: 30,
left: 50
},
width = 800 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
x.domain(d3.extent(globalDataNew, function(d) {
return d.timestamp;
}));
y.domain(d3.extent(globalDataNew, function(d) {
return d.value;
}));
var xAxis = d3.svg.axis().scale(x)
.orient("bottom")
.ticks(d3.time.seconds, 20)
.tickFormat(d3.time.format('%X'))
.tickSize(5)
.tickPadding(8);
var xAxisTop = d3.svg.axis().scale(x)
.orient("bottom").tickFormat("").tickSize(0);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var yAxisRight = d3.svg.axis().scale(y)
.orient("right").tickFormat("").tickSize(0);
var valueline = d3.svg.line()
.x(function(d) {
return x(d.timestamp);
})
.y(function(d) {
return y(d.value);
});
var valueline2 = d3.svg.line()
.x(function(d) {
return x(d.timestamp);
})
.y(function(d) {
return y(d.value);
});
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("rect")
.attr("width", width)
.attr("height", height)
.attr("class", "plot");
var clip = svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var chartBody = svg.append("g")
.attr("clip-path", "url(#clip)");
/* .on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div .html(formatTime(d.timestamp) + "<br/>" + d.close)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
})*/
chartBody.append("path") // Add the valueline path
.datum(globalData)
.attr("id", "path1")
.attr("class", "line")
.attr("d", valueline);
chartBody.selectAll(null)
.data(globalData)
.enter()
.append("circle")
.attr("class", "dot1")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
chartBody.selectAll(null)
.data(globalDataNew)
.enter()
.append("circle")
.attr("class", "dot2")
.attr("r", 3)
.attr("cx", function(d) {
return x(d.timestamp);
})
.attr("cy", function(d) {
return y(d.value);
});
chartBody.append("path") // Add the valueline path
.datum(globalDataNew)
.attr("id", "path2")
.attr("class", "line")
.attr("d", valueline2);
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ",0)")
.call(yAxisRight);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + String(0) + ")")
.call(xAxisTop);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x", (0 - (height / 2)))
.attr("dy", "1em")
.style("text-anchor", "middle")
.style("font-weight", "bold")
.text("Return (%)");
var inter = setInterval(function() {
updateData();
}, 1000);
//////////////////////////////////////////////////////////////
var N = 3;
var dx = 0;
var dxNew = 0;
function updateData() {
var newData = GenData(N, lastUpdateTime);
lastUpdateTime = newData[newData.length - 1].timestamp;
var newData2 = GenData2(N, lastUpdateTimeNew);
lastUpdateTimeNew = newData2[newData2.length - 1].timestamp;
for (var i = 0; i < newData.length; i++) {
if (globalData.length > 99) {
globalData.shift();
}
globalData.push(newData[i]);
}
for (var i = 0; i < newData2.length; i++) {
if (globalDataNew.length > 99) {
globalDataNew.shift();
}
globalDataNew.push(newData2[i]);
}
//code for transition start
x1 = newData[0].timestamp;
x2 = newData[newData.length - 1].timestamp;
dx = dx + (x(x1) - x(x2)); // dx needs to be cummulative
x1New = newData2[0].timestamp;
x2New = newData2[newData2.length - 1].timestamp;
dxNew = dxNew + (x(x1New) - x(x2New)); // dx needs to be cummulative
d3.select("path#path1")
.datum(globalData)
.attr("class", "line")
.attr("d", valueline(globalData))
.transition()
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
d3.select("path#path2")
.datum(globalDataNew)
.attr("class", "line")
.attr("d", valueline2(globalDataNew))
.transition()
.ease("linear")
.attr("transform", "translate(" + String(dxNew) + ")");
d3.selectAll(".dot1")
.data(globalData)
.transition()
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
d3.selectAll(".dot2")
.data(globalDataNew)
.transition()
.ease("linear")
.attr("transform", "translate(" + String(dx) + ")");
svg.select(".x.axis").call(xAxis);
}
body {
font: 12px Arial;
}
path {
stroke: black;
stroke-width: 1;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: black;
stroke-width: 2;
shape-rendering: crispEdges;
}
text {
fill: black;
}
rect {
fill: #add8e6;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
PS: You have to append new circles as the lines move to the left. However, this is another issue.
I am trying to create a slider which reveals data as you slide the bar across from left to right. When I slide from right to left, my data does not show up. And secondly, the highest number the x-axis scales to is 9. I have played around with my data, if I put 8 as the highest value for the x-axis, 8 will be the highest value. But I cannot go beyond 9 for some reason. And not all my data displays even if I have all the numbers under 9.
In my data, I have two columns. One called "ep" (this is for the x-axis), and the other called "char" (this is for the y-axis).
Any ideas on how I can get the x-axis to scale properly and have my data show up?
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>LD V6</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body {
font-family:"avenir next", Arial, sans-serif;
font-size: 12px;
color: #696969;
}
.ticks {
font-size: 10px;
}
.track,
.track-inset,
.track-overlay {
stroke-linecap: round;
}
.track {
stroke: #000;
stroke-opacity: 0.3;
stroke-width: 10px;
}
.track-inset {
stroke: #dcdcdc;
stroke-width: 8px;
}
.track-overlay {
pointer-events: stroke;
stroke-width: 50px;
stroke: transparent;
cursor: crosshair;
}
.handle {
fill: #fff;
stroke: #000;
stroke-opacity: 0.5;
stroke-width: 1.25px;
}
</style>
</head>
<body>
<div id="vis">
</div>
<script>
var margin = {top:50, right:30, bottom:30, left:30},
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var svg = d3.select("#vis")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
////////// slider //////////
var moving = false;
var currentValue = 0;
var targetValue = 200;
var playButton = d3.select("#play-button");
var x = d3.scaleLinear().range([0, width])
.clamp(true);
var y = d3.scaleLinear().range([height, 0]);
var slider = svg.append("g")
.attr("class", "slider")
.attr("transform", "translate(" + 50 + "," + (height) + ")");
slider.append("line")
.attr("class", "track")
.attr("x1", x.range()[0])
.attr("x2", x.range()[1])
.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
.attr("class", "track-inset")
.select(function() { return this.parentNode.appendChild(this.cloneNode(true)); })
.attr("class", "track-overlay")
.call(d3.drag()
.on("start.interrupt", function() { slider.interrupt(); })
.on("start drag", function() {
currentValue = d3.event.x;
update(x.invert(currentValue));
})
);
//Attributes of the slider
slider.insert("g", ".track-overlay")
.attr("class", "ticks")
.attr("transform", "translate(0," + 18 + ")")
/* .selectAll("text")
.data(x.ticks(8))
.enter()
.append("text")
.attr("x", x)
.attr("y", 10)
.attr("text-anchor", "middle")
.text(function(d) { return d.ep); }); */
//Attributes of the slider handle
var handle = slider.insert("circle", ".track-overlay")
.attr("class", "handle")
.attr("r", 8);
/*
var label = slider.append("text")
.attr("class", "label")
.attr("text-anchor", "middle")
.text(formatDate(startDate))
.attr("transform", "translate(0," + (-25) + ")")
*/
////////// plot //////////
var dataset;
var plot = svg.append("g")
.attr("class", "plot")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("trial_v3.csv", prepare, function(data) {
dataset = data;
drawPlot(dataset);
// scale the range of the data
y.domain([0, d3.max(data, function(d) { return d.char; })]);
x.domain([0, d3.max(data, function(d) { return d.ep; })]);
// add the Y Axis
svg.append("g")
.call(d3.axisLeft(y))
.attr("transform", "translate(" + 50 + ",0)");
// add the X Axis
svg.append("g")
.call(d3.axisBottom(x))
.attr("transform", "translate(" + 50 +"," + height + ")")
})
function prepare(d) {
d.ep = d.ep;
d.char = d.char;
return d;
}
function drawPlot(data) {
var locations = plot.selectAll(".location")
.data(data);
// if filtered dataset has more circles than already existing, transition new ones in
locations.enter()
.append("circle")
.attr("class", "location")
.attr("cx", function(d) { return x(d.ep); })
.attr("cy", function(d){ return y(d.char)})
.style("opacity", 0.5)
.attr("r", 5)
.transition()
.duration(1200)
.attr("r", 11
);
// if filtered dataset has less circles than already existing, remove excess
locations.exit()
.remove();
}
function update(h) {
// update position and text of label according to slider scale circle
handle.attr("cx", x(h));
/*label
.attr("x", x(h))
.text(formatDate(h)); */
// filter data set and redraw plot
var newData = dataset.filter(function(d) {
return d.ep < h;
})
drawPlot(newData);
};
/////////////////////////////////////////////////// SVG 2 /////////////////////////////////////////////
/*
var svg2 = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);
svg2.append("rect")
.attr("width", 50)
.attr("height",50)
*/
</script>
</body>
I create a bubble map with D3, and I want the user to be able to click on a button and the circles on the map will transition into bars of a bar chart. I am using the enter, update, exit pattern, but right now what I have isn't working as the bar chart is drawn on top and all the bars and circles are translated, instead of the circles transitioning into bars and the bars being translated into place. Below is the relevant part of my code, and here is the link to the demo: https://jhjanicki.github.io/circles-to-bars/
var projection = d3.geo.mercator()
.scale(150)
.center([20, 40])
.translate([width / 2, height / 2]);
var path= d3.geo.path()
.projection(projection);
var features = countries2.features;
d3.csv("data/sum_by_country.csv", function(error, data) {
data.sort(function(a,b){
return a.value - b.value;
});
var myfeatures= joinData(features, data, ['value']);
var worldMap = svg.append('g');
var world = worldMap.selectAll(".worldcountries")
.data(myfeatures)
.enter()
.append("path")
.attr("class", function(d){
return "World " + d.properties.name+" worldcountries";
})
.attr("d", path)
.style("fill", "#ddd")
.style("stroke", "white")
.style("stroke-width", "1");
var radius = d3.scale.sqrt()
.domain([0,1097805])
.range([3, 20]);
var newFeatures = [];
myfeatures.forEach(function(d){
if(d.properties.hasOwnProperty("value")){
console.log(d.properties.name);
newFeatures.push(d);
}
});
newFeatures.sort(function(a,b){
return b.properties.value - a.properties.value;
});
var bubbles = svg.append("g").classed("bubbleG","true");
bubbles.selectAll("circle")
.data(newFeatures)
.enter().append("circle")
.attr("class", "bubble")
.attr("transform", function(d) {
return "translate(" + path.centroid(d) + ")";
})
.attr("r", function(d){
return radius(d.properties.value);
})
.attr("fill","#2166ac")
.attr("stroke","white")
.attr("id", function(d){
return "circle "+d.properties.name;
});
$('#bubblebar').click(function(){
mapBarTransition(newFeatures,bubbles)
});
});
// button onclick
function mapBarTransition(data,bubbles){
var margin = {top:20, right:20, bottom:120, left:80},
chartW = width - margin.left - margin.right,
chartH = height - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(data.map(function(d) { return d.properties.name; }))
.rangeRoundBands([0, chartW], .4);
var y = d3.scale.linear()
.domain([0,1097805])
.nice()
.range([chartH,0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.ticks(8)
.orient("left");
var barW = width / data.length;
bubbles.append("g").classed("bubblebar-chart-group", true);
bubbles.append("g").classed("bubblebar-x-axis-group axis", true);
bubbles.append("g").classed("bubblebar-y-axis-group axis", true);
bubbles.transition().duration(1000).attr({transform: "translate(" + margin.left + "," + margin.top + ")"});
bubbles.select(".bubblebar-x-axis-group.axis")
.attr({transform: "translate(0," + (chartH) + ")"})
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-65)"
});
bubbles.select(".bubblebar-y-axis-group.axis")
.transition()
.call(yAxis);
barW = x.rangeBand();
var bars = bubbles.select(".bubblebar-chart-group")
.selectAll(".bubble")
.data(data);
bars.enter().append("rect")
.classed("bubble", true)
.attr("x", function(d) { return x(d.properties.name); })
.attr("y", function(d) { return y(d.properties.value); })
.attr("width", barW)
.attr("height", function(d) { return chartH - y(d.properties.value); })
.attr("fill","#2166ac");
bars.transition()
.attr("x", function(d) { return x(d.properties.name); })
.attr("y", function(d) { return y(d.properties.value); })
.attr("width", barW)
.attr("height", function(d) { return chartH - y(d.properties.value); });
bars.exit().transition().style({opacity: 0}).remove();
}
And here is the repo for your reference: https://github.com/jhjanicki/circles-to-bars
First, you have two very different selections with your circles and bars. They are in separate g containers and when you draw the bar chart, you aren't even selecting the circles.
Second, I'm not sure that d3 has any built-in way to know how to transition from a circle element to a rect element. There's some discussion here and here
That said, here's a quick hack with your code to demonstrate one way you could do this:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel='stylesheet'>
<link href="//rawgit.com/jhjanicki/circles-to-bars/master/css/style.css" rel='stylesheet'>
<!-- Roboto & Asar CSS -->
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/css?family=Asar" rel="stylesheet">
</head>
<body>
<button type="button" class="btn btn-primary" id="bubblebar">Bar Chart</button>
<div id="chart"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<!-- D3.geo -->
<script src="https://d3js.org/d3.geo.projection.v0.min.js"></script>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="//rawgit.com/jhjanicki/circles-to-bars/master/data/countries2.js"></script>
<script>
window.onload = function() {
// set up svg and scrolling
var width = window.innerWidth / 2;
var height = window.innerHeight;
var svg = d3.select("#chart").append("svg")
.attr('width', width)
.attr('height', height);
var bubbleMapState = 'map'; // map or bar
var projection = d3.geo.mercator()
.scale(150)
.center([20, 40])
.translate([width / 2, height / 2]);
var path = d3.geo.path()
.projection(projection);
var features = countries2.features;
d3.csv("//rawgit.com/jhjanicki/circles-to-bars/master/data/sum_by_country.csv", function(error, data) {
data.sort(function(a, b) {
return a.value - b.value;
});
var myfeatures = joinData(features, data, ['value']);
var worldMap = svg.append('g');
var world = worldMap.selectAll(".worldcountries")
.data(myfeatures)
.enter()
.append("path")
.attr("class", function(d) {
return "World " + d.properties.name + " worldcountries";
})
.attr("d", path)
.style("fill", "#ddd")
.style("stroke", "white")
.style("stroke-width", "1");
var radius = d3.scale.sqrt()
.domain([0, 1097805])
.range([3, 20]);
var newFeatures = [];
myfeatures.forEach(function(d) {
if (d.properties.hasOwnProperty("value")) {
console.log(d.properties.name);
newFeatures.push(d);
}
});
newFeatures.sort(function(a, b) {
return b.properties.value - a.properties.value;
});
var bubbles = svg.append("g").classed("bubbleG", "true");
bubbles.selectAll("rect")
.data(newFeatures)
.enter().append("rect")
.attr("class", "bubble")
.attr("transform", function(d) {
return "translate(" + path.centroid(d) + ")";
})
.attr("width", function(d) {
return radius(d.properties.value) * 2;
})
.attr("height", function(d){
return radius(d.properties.value) * 2;
})
.attr("rx", 20)
.attr("fill", "#2166ac")
.attr("stroke", "white")
.attr("id", function(d) {
return "circle " + d.properties.name;
});
$('#bubblebar').click(function() {
mapBarTransition(newFeatures, bubbles)
});
});
// button onclick
function mapBarTransition(data, bubbles) {
if (bubbleMapState == 'map') {
bubbleMapState == 'bar';
} else {
bubbleMapState == 'map';
}
var margin = {
top: 20,
right: 20,
bottom: 120,
left: 80
},
chartW = width - margin.left - margin.right,
chartH = height - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.domain(data.map(function(d) {
return d.properties.name;
}))
.rangeRoundBands([0, chartW], .4);
var y = d3.scale.linear()
.domain([0, 1097805])
.nice()
.range([chartH, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.ticks(8)
.orient("left");
var barW = width / data.length;
bubbles.append("g").classed("bubblebar-chart-group", true);
bubbles.append("g").classed("bubblebar-x-axis-group axis", true);
bubbles.append("g").classed("bubblebar-y-axis-group axis", true);
bubbles.transition().duration(1000).attr({
transform: "translate(" + margin.left + "," + margin.top + ")"
});
bubbles.select(".bubblebar-x-axis-group.axis")
.attr({
transform: "translate(0," + (chartH) + ")"
})
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", function(d) {
return "rotate(-65)"
});
bubbles.select(".bubblebar-y-axis-group.axis")
.transition()
.call(yAxis);
barW = x.rangeBand();
var bars = d3.select(".bubbleG")
.selectAll(".bubble")
.data(data);
bars.enter().append("rect")
.classed("bubble", true)
.attr("x", function(d) {
return x(d.properties.name);
})
.attr("y", function(d) {
return y(d.properties.value);
})
.attr("width", barW)
.attr("height", function(d) {
return chartH - y(d.properties.value);
})
.attr("fill", "#2166ac");
bars.transition()
.duration(1000)
.attr("transform", function(d){
return "translate(" + x(d.properties.name) + "," + y(d.properties.value) + ")";
})
.attr("rx", 0)
.attr("width", barW)
.attr("height", function(d) {
return chartH - y(d.properties.value);
});
bars.exit().transition().style({
opacity: 0
}).remove();
}
function joinData(thisFeatures, thisData, DataArray) {
//loop through csv to assign each set of csv attribute values to geojson counties
for (var i = 0; i < thisData.length; i++) {
var csvCountry = thisData[i]; //the current county
var csvKey = csvCountry.Country; //the CSV primary key
//loop through geojson regions to find correct counties
for (var a = 0; a < thisFeatures.length; a++) {
var geojsonProps = thisFeatures[a].properties; //the current region geojson properties
var geojsonKey = geojsonProps.name; //the geojson primary key
//where primary keys match, transfer csv data to geojson properties object
if (geojsonKey == csvKey) {
//assign all attributes and values
DataArray.forEach(function(attr) {
var val = parseFloat(csvCountry[attr]); //get csv attribute value
geojsonProps[attr] = val; //assign attribute and value to geojson properties
});
};
};
};
return thisFeatures;
};
}
</script>
</body>
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.
Hello all I'm trying to repurpose the Focus+Context graph found here: Focus + Context Example to work with a bar graph instead. I've been able to get the bars in but I have some overlap problems. When you make a selection in the context area the focus area will sometimes display bars that interfere with the display of the scale. Here's my code, there are some parts I know I need to clean up so lets not focus on that. Can someone point me in the right direction here?
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
path {
fill: steelblue;
}
.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 focusGraph;
var dataTest = d3.csv("sp500.csv");
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([0,height]),
y2 = d3.scale.linear().range([0,height2]);
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("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 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("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.csv("sp500.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.price = +d.price;
});
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("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
focusGraph = focus.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("x", function(d, i) { return x(d.date); })
.attr("y", function(d) { return height - y(d.price); })
.attr("width", 5)
.attr("height", function(d) { return y(d.price); });
context.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("x", function(d, i) { return x2(d.date); })
.attr("y", function(d) { return height2 - y2(d.price); })
.attr("width", 5)
.attr("height", function(d) { return y2(d.price); });
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() {
var data = d3.csv("sp500.csv");
x.domain(brush.empty() ? x2.domain() : brush.extent());
focusGraph.attr("x", function(d, i) { return x(d.date); });
focusGraph.attr("width", 20);
focus.select(".x.axis").call(xAxis);
}
</script>
That's because you simply forgot to set clip-path to the chart. So consider the following idea:
var focus = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// here we insert the new group that will be the container for the bars
var barsGroup = focus.append("g")
.attr('clip-path', 'url(#clip)');
And then you define the actual chart as within this new group:
focusGraph = barsGroup.selectAll("rect")
.data(data)
.enter().append("rect")
See the demo: http://jsfiddle.net/JGytk/