I started the D3.js challenge on FreeCodeCamp, the problem is that I solved it with the chart but it only gives me a display on the rectum, only one with the width and height that it I put, I'll show the code below.
The entire code on
<script>
//set d3
var w = 1000, h = 500;
var padding = 50;
var svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h)
//title
svg.append('text')
.attr('x', w / 2)
.attr('y', 50)
.text('United States GDP')
fetch('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json')
.then((result)=>result.json())
.then((data)=>{
var the_data = data['data']
//get vals
var get_max = d3.max(data['data'])
var get_mix = d3.min(data['data'])
//for x
var max_x = Number(get_max[0].split('-')[0])
var min_x = Number(get_mix[0].split('-')[0])
//for y
var max_y = get_max[1]
var min_y = get_mix[1]
var xScale = d3.scaleLinear()
.domain([min_x, max_x])
.range([padding, w-padding])
var yScale = d3.scaleLinear()
.domain([min_y, max_y])
.range([h-padding, padding])
//the_chars
for(var i in the_data){
var get_year = Number(the_data[i][0].split('-')[0])
the_data[i][0] = get_year
}
svg.selectAll('rect')
.data(the_data)
.enter()
.append('rect')
.attr("x", (d) => { xScale(d[0]) })
.attr('y', (d)=>{ yScale(d[1]) })
.attr("width", 200)
.attr("height", 20)
//axis
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
//display axis
svg.append("g")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append('g')
.attr('transform', 'translate(' + padding + ', 0)')
.call(yAxis)
})
Now, what I need to do to display the charts!
I mention that the script tags are embedded in the body
Problem: Arrow functions without a return value. Solution: Instead use an explicit or an implicit return.
.attr("x", (d) => { xScale(d[0]) }) // returns undefined
.attr("x", (d) => xScale(d[0])) // implicit return
.attr("x", (d) => { return xScale(d[0]) }) // explicit return
Problem: Fixed height value. Solution Evaluate the height of each based on the GDP value (d[1]) instead.
.attr('height', 20) // fixed height
.attr('height', d => yScale(min_y) - yScale(d[1]))
// subtract from min range to account for padding and inverted y coordinates in SVG
Full solution in this codepen
Related
Trying to build a bar chart and, I don't know why, it's only showing the last value for each year and not all the values in both arrays, and that's what I thought that it was supposed to happen. How can I fix that?
let url = "https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json";
const padding = 50;
const height = 460;
const width = 940;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height);
var arr = [];
var years = [];
d3.json(url, function(data) {
for (let i = 0; i < data.data.length; i++) {
arr[i] = data.data[i];
years[i] = parseInt(data.data[i][0].slice(0,4));
}
const yScale = d3.scaleLinear()
.domain([0, d3.max(arr, (d) => d[1])])
.range([height - padding, padding]);
const xScale = d3.scaleLinear()
.domain([d3.min(years, d => d), d3.max(years, (d) => d)])
.range([padding, width - padding]);
let bandScale = d3.scaleBand().domain(years, d => d).range([padding, width - padding]);
const xAxis = d3.axisBottom(bandScale)
const yAxis = d3.axisLeft(yScale);
svg.append("g")
.attr("transform", "translate(0," + (height - padding) + ")")
.call(xAxis);
svg.append('g')
.attr('transform', 'translate(' + padding + ', 0)')
.call(yAxis)
svg.selectAll('rect')
.data(arr)
.enter()
.append('rect')
.attr('fill', 'blue')
.attr('height', d => height - padding - yScale(d[1]))
.attr('width', d => bandScale.bandwidth())
.attr('x', (d, i) => (bandScale(years[i])))
.attr('y', d => yScale(d[1]))
.append('title')
.text((d, i) => years[i] + ': ' + d[1])
});
<script src="https://d3js.org/d3.v4.min.js"></script>
I'm trying to make a bar chart but I can't figure out a way to make the bar start from the 0 point of y axis and not from the very bottom of the svg. How can I fix that?
let url = "https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json";
const padding = 50;
const height = 460;
const width = 900;
var svg = d3.select('body')
.append('svg')
.attr('width', width)
.attr('height', height);
var arr = [];
d3.json(url, function(data) {
for (let i = 0; i < data.data.length; i++) arr[i] = data.data[i];
const yScale = d3.scaleLinear()
.domain([0, d3.max(arr, (d) => d[1])])
.range([height - padding, padding]);
const yAxis = d3.axisLeft(yScale);
svg.append('g')
.attr('transform', 'translate(' + padding + ', 0)')
.call(yAxis)
svg.selectAll('rect')
.data(arr)
.enter()
.append('rect')
.attr('fill', 'blue')
.attr('height', d => d[1] + padding)
.attr('width', 2.909090909090909)
.attr('x', (d, i) => padding + (3.2 * i))
.attr('y', d => yScale(d[1]))
.append('title')
.text(d => d[1])
});
<script src="https://d3js.org/d3.v4.min.js"></script>
You are incorrectly calculating the height of the rectangle, and not using your scale. It's also trickier since your use of padding is not the typical D3 convention.
svg.selectAll('rect')
.data(arr)
.enter()
.append('rect')
.attr('fill', 'blue')
.attr('height', d => height - padding - yScale(d[1]))
I'm really having trouble with D3 and need some help changing my existing barchart to be a grouped barchart The barchart is being used within a tooltip and currently looks like:
Each colour represents a sector of industry (pink = retail, teal = groceries...etc).
I need to change the bar chart so that it compares the percentage change in each industry with the world average percentage change in this industry.
At the moment the bar chart is being created from an array of data. I also have an array with the world percentage values.
So imagine:
countryData = [10,-20,-30,-63,-23,20],
worldData = [23,-40,-23,-42,-23,40]
Where index 0 = retail sector, index 1 = grocery sector, etc.
I need to plot a grouped barchart comparing each sector to the world average (show the world average in red). This is a bit tricky to explain so I drew it for you (...excuse the shoddy drawing).
Please can someone help me change my existing tooltip?
Here's the current code. If you want to simulate the data values changing.
If you want to scrap my existing code that's fine.
.on('mouseover', ({ properties }) => {
// get county data
const mobilityData = covid.data[properties[key]] || {};
const {
retailAverage,
groceryAverage,
parksAverage,
transitAverage,
workplaceAverage,
residentialAverage,
} = getAverage(covid1);
let avgArray = [retailAverage, groceryAverage, parksAverage, transitAverage, workplaceAverage, retailAverage];
let categoriesNames = ["Retail", "Grocery", "Parks", "Transit", "Workplaces", "Residential"];
// create tooltip
div = d3.select('body')
.append('div')
.attr('class', 'tooltip')
.style('opacity', 0);
div.html(properties[key]);
div.transition()
.duration(200)
.style('opacity', 0.9);
// calculate bar graph data for tooltip
const barData = [];
Object.keys(mobilityData).forEach((industry) => {
const stringMinusPercentage = mobilityData[industry].slice(0, -1);
barData.push(+stringMinusPercentage); // changing it to an integer value, from string
});
//combine the two lists for the combined bar graph
var combinedList = [];
for(var i = 0; i < barData.length; i++) {
const stringMinusPercentage2 = +(avgArray[i].slice(0, -1));
const object = {category: categoriesNames[i], country: barData[i], world: stringMinusPercentage2}
combinedList.push(object); //Push object into list
}
console.log(combinedList);
// barData = barData.sort(function (a, b) { return a - b; });
// sort into ascending ^ keeping this in case we need it later
const height2 = 220;
const width2 = 250;
const margin = {
left: 50, right: 10, top: 20, bottom: 15,
};
// create bar chart svg
const svgA = div.append('svg')
.attr('height', height2)
.attr('width', width2)
.style('border', '1px solid')
.append('g')
// apply the margins:
.attr('transform', `translate(${[`${margin.left},${margin.top}`]})`);
const barWidth = 30; // Width of the bars
// plot area is height - vertical margins.
const chartHeight = height2 - margin.top - margin.left;
// set the scale:
const yScale = d3.scaleLinear()
.domain([-100, 100])
.range([chartHeight, 0]);
// draw some rectangles:
svgA
.selectAll('rect')
.data(barData)
.enter()
.append('rect')
.attr('x', (d, i) => i * barWidth)
.attr('y', (d) => {
if (d < 0) {
return yScale(0); // if the value is under zero, the top of the bar is at yScale(0);
}
return yScale(d); // otherwise the rectangle top is above yScale(0) at yScale(d);
})
.attr('height', (d) => Math.abs(yScale(0) - yScale(d))) // the height of the rectangle is the difference between the scale value and yScale(0);
.attr('width', barWidth)
.style('fill', (d, i) => colours[i % 6]) // colour the bars depending on index
.style('stroke', 'black')
.style('stroke-width', '1px');
// Labelling the Y axis
const yAxis = d3.axisLeft(yScale);
svgA.append('text')
.attr('class', 'y label')
.attr('text-anchor', 'end')
.attr('x', -15)
.attr('y', -25)
.attr('dy', '-.75em')
.attr('transform', 'rotate(-90)')
.text('Percentage Change (%)');
svgA.append('g')
.call(yAxis);
})
.on('mouseout', () => {
div.style('opacity', 0);
div.remove();
})
.on('mousemove', () => div
.style('top', `${d3.event.pageY - 140}px`)
.style('left', `${d3.event.pageX + 15}px`));
svg.append('g')
.attr('transform', 'translate(25,25)')
.call(colorLegend, {
colorScale,
circleRadius: 10,
spacing: 30,
textOffset: 20,
});
};
drawMap(svg1, geoJson1, geoPath1, covid1, key1, 'impact1');
drawMap(svg2, geoJson2, geoPath2, covid2, key2, 'impact2');
};
In short I would suggest you to use two Band Scales for x axis. I've attached a code snippet showing the solution.
Enjoy ;)
//Assuming the following data final format
var finalData = [
{
"groupKey": "Retail",
"sectorValue": 70,
"worldValue": 60
},
{
"groupKey": "Grocery",
"sectorValue": 90,
"worldValue": 90
},
{
"groupKey": "other",
"sectorValue": -20,
"worldValue": 30
}
];
var colorRange = d3.scaleOrdinal().range(["#00BCD4", "#FFC400", "#ECEFF1"]);
var subGroupKeys = ["sectorValue", "worldValue"];
var svg = d3.select("svg");
var margin = {top: 20, right: 20, bottom: 30, left: 40};
var width = +svg.attr("width") - margin.left - margin.right;
var height = +svg.attr("height") - margin.top - margin.bottom;
var container = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// The scale spacing the groups, your "sectors":
var x0 = d3.scaleBand()
.domain(finalData.map(d => d.groupKey))
.rangeRound([0, width])
.paddingInner(0.1);
// The scale for spacing each group's bar, your "sector bar":
var x1 = d3.scaleBand()
.domain(subGroupKeys)
.rangeRound([0, x0.bandwidth()])
.padding(0.05);
var yScale = d3.scaleLinear()
.domain([-100, 100])
.rangeRound([height, 0]);
//and then you will need to append both, groups and bars
var groups = container.append('g')
.selectAll('g')
.data(finalData, d => d.groupKey)
.join("g")
.attr("transform", (d) => "translate(" + x0(d.groupKey) + ",0)");
//define groups bars, one per sub group
var bars = groups
.selectAll("rect")
.data(d => subGroupKeys.map(key => ({ key, value: d[key], groupKey: d.groupKey })), (d) => "" + d.groupKey + "_" + d.key)
.join("rect")
.attr("fill", d => colorRange(d.key))
.attr("x", d => x1(d.key))
.attr("width", (d) => x1.bandwidth())
.attr('y', (d) => Math.min(yScale(0), yScale(d.value)))
.attr('height', (d) => Math.abs(yScale(0) - yScale(d.value)));
//append x axis
container.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x0));
//append y axis
container.append("g")
.attr("class", "y axis")
.call(d3.axisLeft(yScale))
.append("text")
.attr("x", 2)
.attr("y", yScale(yScale.ticks().pop()) + 0.5)
.attr("dy", "0.32em")
.attr("fill", "#000")
.attr("font-weight", "bold")
.attr("text-anchor", "start")
.text("Values");
<script src="https://d3js.org/d3.v7.min.js"></script>
<svg width="600" height="400"></svg>
I want to modify the basic side bar chart to be a stack bar chart, which will reflect partial-amount:total relationship. I already created a matrix with the following:
[{y:0, x0:221, x1:1670},
{y:1, x0:581, x1:1473},
{y:2, x0:2485, x1:2643},
{y:3, x0:135, x1:8714},
{y:4, x0:31, x1:211}]
For reference, in each case the true total would be x0 + x1.
I have a normal bar chart for the totals, but I cannot understand how to convert it to a stacked chart. Also, if there is a way to accomplish this without mutating the data (subtracting x0 from the true total to get x1), that would also be ideal.
Existing BarChart
// Constants
var width = 450,
barHeight = 20,
height = 300,
padding = 10,
leftMargin = 10;
var typeBarChart = d3.select('.typeBarChart')
.attr('width', width)
.attr('height', barHeight*dataGroupByType.length); // dataGroupByType is a D3 nest data series with length is 5
// X-axis;
var x = d3.scale.linear()
.domain([0, maxCrime]) // maxCrime determine elsewhere, approx. 8850
.range([0, width]);
var chart = d3.select(".typeBarChart")
.attr("width", width)
.attr("height", barHeight * dataGroupByType.length);
var bar = chart.selectAll("g")
.data(dataGroupByType)
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
bar.append("rect")
.attr("width", function(d) { return x(d.values); })
.attr("height", barHeight - 1);
bar.append("text")
.attr("x", function(d) {
if (d.values < 1000) {
return x(d.values) + 20;
} else {
return x(d.values) - 3;
}
})
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d.values; });
There are a some issues with the code template....
I refined few to create a simplest stacked bar graph.. this would help you get started...
Working fiddle: https://jsfiddle.net/egmf47ne/
CODE:
HTML
<div class ="typeBarChart"></div>
JS
var _data = [{y:0, x0:221, x1:1670},
{y:1, x0:581, x1:1473},
{y:2, x0:2485, x1:2643},
{y:3, x0:135, x1:8714},
{y:4, x0:31, x1:211}]
// Constants
var width = 450,
barHeight = 20,
height = 300,
padding = 10,
leftMargin = 10;
var typeBarChart = d3.select('.typeBarChart')
.append('svg')
.attr('width', width)
.attr('height', barHeight*_data.length);
var x = d3.scale.linear()
.domain([0, 8850]) // maxCrime
.range([0, width]);
var bar = typeBarChart.selectAll("g")
.data(_data)
.enter()
.append("g")
.attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });
bar.append("rect")
.attr("fill","blue") // blue bars of x0 + x1
.attr("width", function(d) { return x(d.x0 + d.x1); })
.attr("height", barHeight - 1);
bar.append("rect")
.attr("fill","red") // red bars of x0 only
.attr("width", function(d) { return x(d.x0); })
.attr("height", barHeight - 1);
I'm trying to implement an SVG mask in D3, similar to this very simple jsfiddle example, but I must have lost something in translation. My implementation all takes place in a class that renders a graph. I'm trying to apply the mask to define bounds for the graph, so that when the data exceeds those bounds, the graph is neatly clipped. When I apply the mask, the bars of the graph completely disappear. As far as I can tell the mask in the right place. HELP!
Here is where I define the mask in my init() function:
// Add an SVG element with the desired dimensions and margin.
this.graph = d3.select(this.config.id).append("svg:svg")
.attr("width", this.width + this.m[1] + this.m[3])
.attr("height", this.height + this.m[0] + this.m[2])
.append("svg:g")
.attr("transform", "translate(" + this.m[3] + "," + this.m[0] + ")");
var maskWidth = 640;
var maskHeight = 321;
this.graph.append('svg:defs') <------ I START DEFINING IT HERE !
.call(function (defs) {
// Appending the mask
defs.append('svg:mask')
.attr('id', 'mask')
.attr('width', maskWidth)
.attr('height', maskHeight)
.attr('x', 0)
.attr('y', 0)
.call(function(mask) {
mask.append('svg:rect')
.attr('width', maskWidth)
.attr('height', maskHeight)
.attr('fill', '#ffffff')
});
});
Here is the Method that draws bars on the graph where I attempt to apply the mask (see the last line):
addBars: function (data){
var numberOfBars = Math.floor(this.xMaximum);
var barWidth = this.width/numberOfBars;
// Generate a histogram using twenty uniformly-spaced bins.
var histogramData = d3.layout.histogram()
.bins(this.xScale.ticks(numberOfBars))
(data);
//console.trace('typeof: '+typeof this.xScale);
var xScale = this.xScale;
var yScale = this.yScale;
var height = this.height;
this.bars = this.graph.selectAll("bar")
.data(histogramData, function(d){ return d;})
.enter()
.append("rect")
.attr("class","bar")
.attr("fill","steelblue")
.attr("transform", function(d, i) {
var yOffset = height;
return "translate(" + (i * barWidth - barWidth/2) + ","+yOffset+")";
})
.attr("y", function(d,i) {
var yPosition = yScale(d.length)- height;
return (yScale(d.length)-height);
})
.attr("height", function(d) {
return height - yScale(d.length);
})
.attr("width", barWidth - 1)
.attr('mask', 'url(#mask)'); <---- OVER HERE !!!!
},
Here is a link to the resulting HTML in Chrome Developer Tools (I've highlighted the <defs> and one of the graph bars that should be masked):Chrome Developer Tools Dynamic HTML
As far as I can tell everything looks good. This leads me to believe that the mask is mis-aligned with the bar, causing the bar to be invisible. However, in the developer tools, when I hover over the <rect> element, it shows it as overlaying the graph bars, so it doesn't seem like an alignment issue. Any help would be appreciated.
Lastly, I've made a jsfiddle of the class being used in my application (see the comments for the link.). Below is also the entire class for drawing the graph, just in case it would be helpful to see the code in context:
// HistogramGrapher class - constructor
var HistogramGrapher = function() {
// assign default properties
this.config = {
id: "",
xAxisLabel: "xAxis",
yAxisLabel: "yAxis",
width: 1000,
height: 400,
title: "Title",
mean: 20
};
// define variables
this.m = [40, 80, 40, 80]; // margins
this.width; // width
this.height; // height
this.xAxisLabel;
this.yAxisLabel;
this.graph;
this.bars;
this.lines;
this.xScale;
this.xScaleInvert;
this.xAxis;
this.yScale;
this.yScaleInvert;
this.yAxis;
this.yMaximum = 25;
this.xMaximum = 2 * this.config.mean;
}
// methods for this class
HistogramGrapher.prototype = {
init: function (options) {
// copy properties of `options` to `config`. Will overwrite existing ones.
for(var prop in options) {
if(options.hasOwnProperty(prop)){
this.config[prop] = options[prop];
}
}
// update variables
this.updateWidth(this.config.width);
this.updateHeight(this.config.height);
this.updateXMaximum(this.config.mean);
// X scale will fit all values from datay[] within pixels 0-w
this.xScale = d3.scale.linear()
.domain([0, this.xMaximum])
.range([0, this.width]);
this.xScaleInvert = d3.scale.linear()
.range([0, this.xMaximum])
.domain([0, this.width]);
// Y scale
this.yScale = d3.scale.linear()
.domain([0, this.yMaximum])
.range([this.height,0]);
this.yScaleInvert = d3.scale.linear()
.range([0, this.yMaximum])
.domain([this.height,0]);
// Add an SVG element with the desired dimensions and margin.
this.graph = d3.select(this.config.id).append("svg:svg")
.attr("width", this.width + this.m[1] + this.m[3])
.attr("height", this.height + this.m[0] + this.m[2])
.append("svg:g")
.attr("transform", "translate(" + this.m[3] + "," + this.m[0] + ")");
var maskWidth = 640;
var maskHeight = 321;
this.graph.append('svg:defs')
.call(function (defs) {
// Appending the mask
defs.append('svg:mask')
.attr('id', 'mask')
.attr('width', maskWidth)
.attr('height', maskHeight)
.attr('x', 0)
.attr('y', 0)
.call(function(mask) {
mask.append('svg:rect')
.attr('width', maskWidth)
.attr('height', maskHeight)
.attr('fill', '#ffffff')
});
});
// create xAxis
this.xAxis = d3.svg.axis().scale(this.xScale)
.tickSize(-this.height)
.tickSubdivide(true);
// create yAxis
this.yAxis = d3.svg.axis().scale(this.yScale)
.tickSize(-this.width)
.tickSubdivide(true)
.orient("left");
// Add the x-axis label.
this.graph.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", this.width)
.attr("y", this.height + 25)
.text(this.config.xAxisLabel);
// Add the y-axis label.
this.graph.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", -30)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text(this.config.yAxisLabel);
// add Title
this.graph.append("text")
.attr("x", this.width/2 )
.attr("y", -20 )
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text(this.config.title);
// Add the x-axis.
this.graph.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + this.height + ")")
.call(this.xAxis);
// Add the y-axis.
this.graph.append("svg:g")
.attr("class", "y axis")
.call(this.yAxis);
},
updateWidth: function(width){
this.width = width - this.m[1] - this.m[3];
},
updateHeight: function(height){
this.height = height - this.m[0] - this.m[2]; // height
},
updateXMaximum: function(mean){
this.xMaximum = 2.5 * mean;
},
addBars: function (data){
var numberOfBars = Math.floor(this.xMaximum);
var barWidth = this.width/numberOfBars;
// Generate a histogram using twenty uniformly-spaced bins.
var histogramData = d3.layout.histogram()
.bins(this.xScale.ticks(numberOfBars))
(data);
//console.trace('typeof: '+typeof this.xScale);
var xScale = this.xScale;
var yScale = this.yScale;
var height = this.height;
this.bars = this.graph.selectAll("bar")
.data(histogramData, function(d){ return d;})
.enter()
.append("rect")
.attr("class","bar")
.attr("fill","steelblue")
.attr("transform", function(d, i) {
var yOffset = height;
return "translate(" + (i * barWidth - barWidth/2) + ","+yOffset+")";
})
.attr("y", function(d,i) {
var yPosition = yScale(d.length)- height;
return (yScale(d.length)-height);
})
.attr("height", function(d) {
return height - yScale(d.length);
})
.attr("width", barWidth - 1)
.attr('mask', 'url(#mask)');
},
addLine: function (data){ // the data must be in the form " [ {'x':x1, 'y':y1} , {'x':x2, 'y':y2} , {'x':x3, 'y':y3} ... ]
var xScale = this.xScale;
var yScale = this.yScale;
var height = this.height;
// create a line function that can convert data[] into x and y points
var lineFunction = d3.svg.line()
// assign the X function to plot our line as we wish
.x(function(d) { return xScale(d.x); })
.y(function(d) { return yScale(d.y); })
.interpolate("linear");
this.lines = this.graph.append("path")
.attr("d", lineFunction(data))
.attr("class", "line")
.attr("stroke", "green")
.attr("stroke-width", 2)
.attr("fill","none");
},
clear: function () {
var bars = d3.selectAll(".bar").remove();
var lines = d3.selectAll(".line").remove();
},
getxScale: function () {
return this.xScale;
},
getxScaleInvert: function () {
return this.xScaleInvert;
}
}
Ok, I saw what's going on. You should apply the clipping mask to the bars and the line by appending a clipping mask to the graph area:
//clipping mask
yourSvg.append("clipPath")
.attr("id", "chart-area")
.append("rect")
.attr("x", yourXcoordinates)
.attr("y", yourYcoordinates)
.attr("width", 333) //this was the width provided by the webinspector
.attr("height", 649) //this was the height provided by the webinspector;
then when you plot the line and the bars, add this to both of the generators
.attr("clip-path", "url(#chart-area)")
and this should give you the clipping you're looking for. Basically what it does is clip everything outside the area of that rectangle, so if you plot it correctly, it should clip out unwanted things