Can anyone tell me how to provide gaps between the bars that are getting stacked at one particular place?
Here is the code:
P.s: Sorry i tried but coukd not post it as a code snippet due to some error "Please add some explanation"
Part 1
Part 2
Output
#Samrat- When appending rect to your svg, change this line in your code .attr("x"), function(d,i){return x(i)}) to .attr("x", (d, i) => i * (svgWidth / info.length)). This code divides the entire svg width by the length of your dataset and multiplies each value by its index, which distances bars from each other.
Hope this helps.
Fiddle for your reference: https://jsfiddle.net/zfjcLopw/1/
Note: Going forward while posting questions on SO, follow the guidelines listed in this article https://stackoverflow.com/help/how-to-ask. This helps in getting answers promptly.
Here is the updated code:
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<body>
<script>
const width = 600;
const height = 500;
const margin = { top: 100, right: 100, bottom: 100, left: 120 };
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const barPadding = 2;
const svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const tag = ["mango", "banana", "apple", "lemon", "coconut"];
const info = [23, 54, 34, 51, 22];
const xScale = d3
.scaleBand()
.domain(tag.map(d => d))
.rangeRound([0, innerWidth]);
const yScale = d3
.scaleLinear()
.domain([0, d3.max(info, d => d)])
.range([innerHeight, 0]);
const mainG = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
const g = mainG
.selectAll("g")
.data(info)
.enter()
.append("g")
.attr("transform", `translate(0,0)`);
g.append("rect")
.attr("x", (d, i) => i * (innerWidth / info.length))
// .attr("x", (d, i) => xScale(i)) - This line will stack bars on top of each other
.attr("y", d => yScale(d))
.attr("width", innerWidth / info.length - barPadding)
.attr("height", d => innerHeight - yScale(d))
.attr("fill", "blue");
mainG.append("g").call(d3.axisLeft(yScale));
mainG
.append("g")
.call(d3.axisBottom(xScale))
.attr("transform", `translate(0, ${innerHeight})`);
</script>
</body>
</html>
X scaleBand domain is set to tag values, but you call it with i index. Try x(tag[i])
Related
I have made two separate graph on separate page of Bar and pie chart respectively and now i wanted to combine this two graph in the single page so that I can have a dashboard. but when i start to combine to two graph in the main page its not happening and they overlap of each other.
Code:
https://github.com/Mustafa2911/d3-design/blob/main/combine.html
Combine file contain: Code of both pie and bar chart.
Bar file contain: Code of bar chart.
Pie chart contain: Code of pie chart.
Tried this with your code.
Scroll to see the bar graph axis.
NOTE: The bar graph data will not be available ∵ it is from the demo1.csv file in your repository.
Hope this helps.
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
</head>
<body>
<div id="my_dataviz"></div>
<script>
// set the dimensions and margins of the graph
var width = 800
height = 450
margin = 40
// The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
var radius = Math.min(width, height) / 2 - margin
// append the svg object to the div called 'my_dataviz'
var svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
// Create dummy data
var data = {
Corporation_Tax: 15,
Income_Tax: 15,
Customs: 5,
Union_Excise_Duties: 7,
Good_and_Service_tax: 16,
Non_tax_Revenue: 5,
Non_Dept_Capital_Receipt: 2,
Borrowings_Liabilities: 35
}
// set the color scale
var color = d3.scaleOrdinal()
.domain(["a", "b", "c", "d", "e", "f", "g", "h"])
.range(d3.schemeSet1);
// Compute the position of each group on the pie:
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {
return d.value;
})
var data_ready = pie(d3.entries(data))
// The arc generator
var arc = d3.arc()
.innerRadius(radius * 0.5) // This is the size of the donut hole
.outerRadius(radius * 0.8)
// Another arc that won't be drawn. Just for labels positioning
var outerArc = d3.arc()
.innerRadius(radius * 0.9)
.outerRadius(radius * 0.9)
// Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d) {
return (color(d.data.key))
})
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 1)
// Add the polylines between chart and labels:
svg
.selectAll('allPolylines')
.data(data_ready)
.enter()
.append('polyline')
.attr("stroke", "black")
.style("fill", "none")
.attr("stroke-width", 1)
.attr('points', function(d) {
var posA = arc.centroid(d) // line insertion in the slice
var posB = outerArc.centroid(d) // line break: we use the other arc generator that has been built only for that
var posC = outerArc.centroid(d); // Label position = almost the same as posB
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2 // we need the angle to see if the X position will be at the extreme right or extreme left
posC[0] = radius * 0.95 * (midangle < Math.PI ? 1 : -1); // multiply by 1 or -1 to put it on the right or on the left
return [posA, posB, posC]
})
// Add the polylines between chart and labels:
svg
.selectAll('allLabels')
.data(data_ready)
.enter()
.append('text')
.text(function(d) {
console.log(d.data.key);
return d.data.key
})
.attr('transform', function(d) {
var pos = outerArc.centroid(d);
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
pos[0] = radius * 0.99 * (midangle < Math.PI ? 1 : -1);
return 'translate(' + pos + ')';
})
.style('text-anchor', function(d) {
var midangle = d.startAngle + (d.endAngle - d.startAngle) / 2
return (midangle < Math.PI ? 'start' : 'end')
})
</script>
<style>
#my_dataviz {
display: inline-block;
width: 50%;
}
</style>
<div id="my_dataviz_es"></div>
<script>
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 30,
bottom: 40,
left: 160
},
width = 460,
height = 400;
// append the svg object to the body of the page
var svg = d3.select("#my_dataviz_es")
.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 + ")");
// Parse the Data
d3.csv("demo1.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([0, 550000])
.range([0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var y = d3.scaleBand()
.range([0, height])
.domain(data.map(function(d) {
return d.Country;
}))
.padding(.1);
svg.append("g")
.call(d3.axisLeft(y))
//Bars
svg.selectAll("myRect")
.data(data)
.enter()
.append("rect")
.attr("x", x(0))
.attr("y", function(d) {
return y(d.Country);
})
.attr("width", function(d) {
return x(d.Value);
})
.attr("height", y.bandwidth())
.attr("fill", "#69b3a2")
// .attr("x", function(d) { return x(d.Country); })
// .attr("y", function(d) { return y(d.Value); })
// .attr("width", x.bandwidth())
// .attr("height", function(d) { return height - y(d.Value); })
// .attr
})
</script>
</body>
</html>
EDIT: See here - https://codepen.io/KZJ/pen/rNpqvdq?editors=1011 - for changes made reg. the below comment
what if I want to have my bar chart at the top and on right side i want to have my pie chart
Changed -
a) Both charts were using the same name 'svg' to d3.select() the divs. This caused the charts to overlap.
b) Modified width, height, transform, and added some border CSS - only for demonstration purposes - It can be removed/edited as required.
FYR this is how it looks now -
I have a bar chart with zoom function. The issue is, the zooming isn't actually centered. If, I place the cursor, on a bar and zoom, the bar underneath the cursor moves away as opposed to staying there, However, if I set the MARGIN.LEFT = 0, then the issue is rectified and No matter what bar I have my cursor on, when I zoom the bar stays there, right underneath. Could anyone help me with this?
Working Code Here: https://codesandbox.io/s/d3-zoom-not-centered-sfziyk
D3 Code:
const MARGIN = {
LEFT: 60,
RIGHT: 40,
TOP: 10,
BOTTOM: 130
};
// total width incl margin
const VIEWPORT_WIDTH = 1140;
// total height incl margin
const VIEWPORT_HEIGHT = 400;
const WIDTH = VIEWPORT_WIDTH - MARGIN.LEFT - MARGIN.RIGHT;
const HEIGHT = VIEWPORT_HEIGHT - MARGIN.TOP - MARGIN.BOTTOM;
const svg = d3
.select(".chart-container")
.append("svg")
.attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
.attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM);
const g = svg
.append("g")
.attr("transform", `translate(${MARGIN.LEFT}, ${MARGIN.TOP})`);
g.append("text")
.attr("class", "x axis-label")
.attr("x", WIDTH / 2)
.attr("y", HEIGHT + 110)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.text("Month");
g.append("text")
.attr("class", "y axis-label")
.attr("x", -(HEIGHT / 2))
.attr("y", -60)
.attr("font-size", "20px")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.text("");
const zoom = d3.zoom().scaleExtent([0.5, 10]).on("zoom", zoomed);
svg.call(zoom);
function zoomed(event) {
x.range([0, WIDTH].map((d) => event.transform.applyX(d)));
barsGroup
.selectAll("rect.profit")
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth());
barsGroup
.selectAll("rect.revenue")
.attr("x", (d) => x(d.month) + 0.5 * x.bandwidth())
.attr("width", 0.5 * x.bandwidth());
xAxisGroup.call(xAxisCall);
}
const x = d3.scaleBand().range([0, WIDTH]).paddingInner(0.3).paddingOuter(0.2);
const y = d3.scaleLinear().range([HEIGHT, 0]);
const xAxisGroup = g
.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${HEIGHT})`);
const yAxisGroup = g.append("g").attr("class", "y axis");
const xAxisCall = d3.axisBottom(x);
const yAxisCall = d3
.axisLeft(y)
.ticks(3)
.tickFormat((d) => "$" + d);
const defs = svg.append("defs");
const barsClipPath = defs
.append("clipPath")
.attr("id", "bars-clip-path")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", WIDTH)
.attr("height", 400);
const barsGroup = g.append("g");
const zoomGroup = barsGroup.append("g");
barsGroup.attr("class", "bars");
zoomGroup.attr("class", "zoom");
barsGroup.attr("clip-path", "url(#bars-clip-path)");
xAxisGroup.attr("clip-path", "url(#bars-clip-path)");
d3.csv("data.csv").then((data) => {
data.forEach((d) => {
d.profit = Number(d.profit);
d.revenue = Number(d.revenue);
d.month = d.month;
});
var y0 = d3.max(data, (d) => d.profit);
var y1 = d3.max(data, (d) => d.revenue);
var maxdomain = y1;
if (y0 > y1) var maxdomain = y0;
x.domain(data.map((d) => d.month));
y.domain([0, maxdomain]);
xAxisGroup
.call(xAxisCall)
.selectAll("text")
.attr("y", "10")
.attr("x", "-5")
.attr("text-anchor", "end")
.attr("transform", "rotate(-40)");
yAxisGroup.call(yAxisCall);
const rects = zoomGroup.selectAll("rect").data(data);
rects.exit().remove();
rects
.attr("y", (d) => y(d.profit))
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.profit));
rects
.enter()
.append("rect")
.attr("class", "profit")
.attr("y", (d) => y(d.profit))
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.profit))
.attr("fill", "grey");
const rects_revenue = zoomGroup.selectAll("rect.revenue").data(data);
rects_revenue.exit().remove();
rects_revenue
.attr("y", (d) => y(d.revenue))
.attr("x", (d) => x(d.month))
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.revenue));
rects_revenue
.enter()
.append("rect")
.attr("class", "revenue")
.style("fill", "red")
.attr("y", (d) => y(d.revenue))
.attr("x", (d) => x(d.month) + 0.5 * x.bandwidth())
.attr("width", 0.5 * x.bandwidth())
.attr("height", (d) => HEIGHT - y(d.revenue))
.attr("fill", "grey");
});
When you call the zoom on the svg, all zoom behaviour is relative to the svg.
Imagine that your x-axis is at initial zoom level of length 100 representing the domain [0, 100]. So the x-scale has range([0, 100]) and domain([0, 100]). Add a left margin of 10.
If you zoom by scale 2 at the midpoint of your axis at x=50 you would expect to get the following behaviour after the zoom:
The midpoint does not move.
The interval [25, 75] is visible.
However, since the zoom is called on the svg you have to account for the left margin of 10. The zoom does not occur at the midpoint but at x = 10 + 50 = 60. The transform is thus x -> x * k + t with k = 2 and t = -60. This results in
x = 50 -> 2 * 50 - 60 = 40,
x = 80 -> 2 * 80 - 60 = 100,
x = 30 -> 2 * 30 - 60 = 0.
Visible after the zoom is the interval [30, 80] and the point x = 50 is shifted to the left.
This is what you observe in your chart.
In order to get the expected behaviour, you can do two things:
a. Follow the bar chart example where the range of the x-scale does not start at 0 but at the left margin. The g which is translated by margin.left and margin.top is also omitted here. Instead, the ranges of the axes incorporate the margins directly.
b. Add a rect with fill: none; pointer-events: all; to the svg that is of the size of the chart without the margins. Then call the zoom on that rectangle, as done in this example.
Note that all the new examples on ObservableHQ follow the pattern "a" that needs fewer markup.
I'm trying to learn how to use d3.js in react, but something is wrong in my code.
I'm doing a bar chart, but the value of bar are "inverted", for example, a bar has a value of 30% but in the chart, the bar appears with 70% (like, 100% - 30% = 70%).
How can I fix that?
Here is my code: codeSandBox.
Other question that I have is: how can I change the height of bars? I want to add some margin-top to show everything of the y Axis, but if I do that, the bars still with the same height and don't match with yAxis value
The issue here is that you're swapping the y and height logic, it should be:
.attr("y", d => yScale(d.percent))
.attr("height", d => height - margin.bottom - margin.top - yScale(d.percent))
Or, if you set the working height as...
height = totalHeight - margin.bottom - margin.top
... it can be just:
.attr("y", d => yScale(d.percent))
.attr("height", d => height - yScale(d.percent))
On top of that (and this addresses your second question), you are using Bostock's margin convention wrong. You should translate the g group according to the margins, and then appending all the bars to that translated group, without translating them again. Also, append the axes' groups to that g group.
All that being said, this is the code with those changes:
const data = [{
year: 2012,
percent: 50
},
{
year: 2013,
percent: 30
},
{
year: 2014,
percent: 90
},
{
year: 2015,
percent: 60
},
{
year: 2016,
percent: 75
},
{
year: 2017,
percent: 20
}
];
const height = 300;
const width = 370;
const margin = {
top: 20,
right: 10,
bottom: 20,
left: 25
};
const xScale = d3.scaleBand()
.domain(data.map(d => d.year))
.padding(0.2)
.range([0, width - margin.right - margin.left]);
const yScale = d3
.scaleLinear()
.domain([0, 100])
.range([height - margin.bottom - margin.top, 0]);
const svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height)
.style("margin-left", 10);
const g = svg
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
g
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => xScale(d.year))
.attr("y", d => yScale(d.percent))
.attr("width", xScale.bandwidth())
.attr("height", d => height - margin.bottom - margin.top - yScale(d.percent))
.attr("fill", "steelblue")
g.append("g")
.call(d3.axisLeft(yScale));
g.append("g")
.call(d3.axisBottom(xScale))
.attr(
"transform",
`translate(0, ${height - margin.bottom - margin.top})`
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
svg
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", d => xScale(d.year))
.attr("y", d => height - yScale(100-d.percent))
.attr("width", xScale.bandwidth())
.attr("height", d => yScale(100-d.percent))
.attr("fill", "steelblue")
.attr("transform", `translate(${margin.left}, -${margin.bottom})`);
You need to minus the percentage from 100
Working: https://codesandbox.io/s/crimson-microservice-8kjqd
I wan to four graphs side-by-side linearly but they keep overlapping. I am using d3.js and I would like to draw these four graphs side by side.
I tried drawing each graph in its own svg tag and then combine them but it doesn't work.
<script>
const svg = d3.select("svg");
const width = +svg.attr("width");
const height = +svg.attr("height");
var TelescopeData = [
{ Average: 2000, TelescopeName: "1 meter" },
{ Average: 3000, TelescopeName: "1.9 meter" },
{ Average: 4000, TelescopeName: "Lesedi" }
];
var padding = { top: 40, right: 20, bottom: 30, left: 75 };
const innerWidth = width - padding.left - padding.right;
const innerHeight = height - padding.top - padding.bottom;
var colors = ["red", "black", "green"];
var yScale = d3
.scaleLinear()
.domain([0, d3.max(TelescopeData, d => d.Average)])
.range([innerHeight, 0])
.nice();
var xScale = d3
.scaleBand()
.domain(
TelescopeData.map(d => {
return d.TelescopeName;
})
)
.range([0, innerWidth])
.padding(0.4);
//xAxis
const xAxis = svg
.append("g")
.classed("xAxis", true)
.attr(
"transform",
`translate(${padding.left},${innerHeight + padding.top})`
)
.call(d3.axisBottom(xScale));
//yAxis
const yAxis = svg
.append("g")
.classed("yAxis", true)
.attr("transform", `translate(${padding.left},${padding.top})`)
.call(d3.axisLeft(yScale));
// now adding the data
const rectGrp = svg
.append("g")
.attr("transform", `translate(${padding.left},${padding.top})`);
rectGrp
.selectAll("rect")
.data(TelescopeData)
.enter()
.append("rect")
.attr("width", xScale.bandwidth())
.attr("height", (d, i) => {
return innerHeight - yScale(d.Average);
})
.attr("x", d => {
return xScale(d.TelescopeName);
})
.attr("y", function(d) {
return yScale(d.Average);
})
.attr("fill", (d, i) => {
return colors[i];
});
rectGrp
.append("text")
.attr("y", -20)
.attr("x", 50)
.text("Quarterly Average");
</script>
I expect to see the code attached here to be used for drawing 3 other graphs side-side with the first one
Are you wanting to have four graphs shown side by side on the screen next to each other?
That is what your question seems to imply, without having an example of what you want the output to look like. The other option would be, how to merge four graphs into one graph, which is an entirely different question.
Here is a very simple HTML document that will put the four graphs side by side on the screen. I think your problem was probably that you were selecting the element to draw to using the SVG selector instead of assigning an id to each different element and then selecting each element id.
<html>
<head>
<title>Example</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
function drawGraph(elementId) {
const svg = d3.select(elementId);
const width = +svg.attr("width");
const height = +svg.attr("height");
let TelescopeData = [
{ Average: 2000, TelescopeName: "1 meter" },
{ Average: 3000, TelescopeName: "1.9 meter" },
{ Average: 4000, TelescopeName: "Lesedi" }
];
let padding = { top: 40, right: 20, bottom: 30, left: 75 };
const innerWidth = width - padding.left - padding.right;
const innerHeight = height - padding.top - padding.bottom;
let colors = ["red", "black", "green"];
let yScale = d3
.scaleLinear()
.domain([0, d3.max(TelescopeData, d => d.Average)])
.range([innerHeight, 0])
.nice();
let xScale = d3
.scaleBand()
.domain(
TelescopeData.map(d => {
return d.TelescopeName;
})
)
.range([0, innerWidth])
.padding(0.4);
//xAxis
const xAxis = svg
.append("g")
.classed("xAxis", true)
.attr("transform",`translate(${padding.left},${innerHeight + padding.top})`)
.call(d3.axisBottom(xScale));
//yAxis
const yAxis = svg
.append("g")
.classed("yAxis", true)
.attr("transform", `translate(${padding.left},${padding.top})`)
.call(d3.axisLeft(yScale));
// now adding the data
const rectGrp = svg
.append("g")
.attr("transform", `translate(${padding.left},${padding.top})`);
rectGrp
.selectAll("rect")
.data(TelescopeData)
.enter()
.append("rect")
.attr("width", xScale.bandwidth())
.attr("height", (d, i) => {
return innerHeight - yScale(d.Average);
})
.attr("x", d => {
return xScale(d.TelescopeName);
})
.attr("y", function(d) {
return yScale(d.Average);
})
.attr("fill", (d, i) => {
return colors[i];
});
rectGrp
.append("text")
.attr("y", -20)
.attr("x", 50)
.text("Quarterly Average");
}
drawGraph("#testsvg1");
drawGraph("#testsvg2");
drawGraph("#testsvg3");
drawGraph("#testsvg4");
</script>
</head>
<body>
<svg id="#testsvg1" width="200" height="200"></svg>
<svg id="#testsvg2" width="200" height="200"></svg>
<svg id="#testsvg3" width="200" height="200"></svg>
<svg id="#testsvg4" width="200" height="200"></svg>
</body>
</html>
I'm trying to create a function that creates a histogram for a given array. Clearly, there's no data for the X-Axis and I have to choose the bins arbitrarily. What would be the best way to do so?
My code:
var width = 700, height = 500, pad = 30, barPadding = 1;
function plotHistogram(element, dataset) {
var svg = d3.select(element)
.append("svg")
.attr("width", width)
.attr("height", height)
var bars = svg.append("g")
// Container box
var rectangle = svg.append("rect")
.attr("height", height)
.attr("width", width)
.attr("stroke-width", 2).attr("stroke", "#ccc")
.attr("fill", "transparent")
var xScale = d3.scaleLinear()
// Using default domain (0 - 1)
.range([pad, width - pad * 2])
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, function(d) { return d; })])
.range([height - pad, pad])
var xAxis = d3.axisBottom(xScale)
var yAxis = d3.axisLeft(yScale)
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (height - pad) + ")")
.call(xAxis)
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + pad +", 0)")
.call(yAxis)
svg.selectAll("bars")
.data(dataset)
.enter()
.append("rect")
// Evenly spacing out bars
.attr("x", function(d, i) { return i * width/dataset.length; })
// Top of each bar as the top of svg. To remove inverted bar graph.
.attr("y", function(d) { return height - (d * 4); })
// To give padding between bars
.attr("width", width / dataset.length - barPadding)
// To make the bars taller
.attr("height", function(d) { return d * 4; })
.attr("fill", "teal");
}
// #normal is the id of the div element.
plotHistogram("#normal", [10, 20, 30, 40, 50, 60, 70, 80]);
Edit 1: I have decided to use the default bin size (0 - 1) for the xScale above. I'm facing problems creating the bars.
Generate the bins as in https://bl.ocks.org/mbostock/3048450
The array in your plotHistogram is like the array data in #mbostock's bl.ock...
HTH