D3.js - Drawing Charts
D3.js - Drawing Basic Charts
Section titled “D3.js - Drawing Basic Charts”D3.js is exceptionally versatile for creating a wide array of static and interactive charts by manipulating SVG elements. Common charts you can build include:
- Bar Charts
- Scatter Plots (often using circles)
- Pie Charts and Donut Charts
- Line Charts
- Bubble Charts, and many more.
This chapter will guide you through drawing some fundamental chart types using D3.js and SVG.
Bar Chart
Section titled “Bar Chart”Bar charts are used to display and compare categorical data, where the length or height of each bar is proportional to its value. The x-axis typically represents categories, and the y-axis (or x-axis for horizontal bars) represents the measured value.
Drawing a Horizontal Bar Chart
Section titled “Drawing a Horizontal Bar Chart”Let’s create a simple horizontal bar chart. We’ll use SVG <rect> elements for bars and <text> elements for labels.
Step 1: Define HTML Structure and Styles. Create an HTML file (e.g., barchart.html).
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>D3 Bar Chart</title> <script src="https://d3js.org/d3.v7.min.js"></script> <style> .bar-chart-container svg { border: 1px solid #ccc; /* Optional: to see SVG boundary */ } .bar-chart-container .bar rect { fill: steelblue; } .bar-chart-container .bar rect:hover { fill: orange; } .bar-chart-container .bar text { fill: black; font: 10px sans-serif; text-anchor: start; /* For labels next to bars */ dominant-baseline: middle; } </style></head><body> <div class="bar-chart-container"> <h3>Simple Horizontal Bar Chart</h3> <div id="chart-area"></div> </div> <script> // D3 code will go here </script></body></html>Step 2: JavaScript - Define data and chart parameters.
// Inside the <script> tag at the bottom of barchart.htmlconst data = [10, 5, 12, 15, 8, 10];
const chartWidth = 400;const barHeight = 20;const barPadding = 5; // Space between barsconst labelOffset = 5; // Space for text label from bar endconst chartHeight = data.length * (barHeight + barPadding);
// Create a scale for bar widths (data values to pixels)// Note: For a more robust chart, use d3.scaleLinear().domain([0, d3.max(data)]).range([0, chartWidth - labelOffsetArea])// For simplicity, we'll use a manual scaleFactor here for very basic example.const scaleFactor = (chartWidth - 50) / d3.max(data); // 50 is arbitrary space for labelsA more robust approach for scaling would use d3.scaleLinear(): const xScale = d3.scaleLinear().domain([0, d3.max(data)]).range([0, chartWidth - 50]); Then bar widths would be d => xScale(d).
Step 3: Create SVG and bar groups.
const svg = d3.select("#chart-area") .append("svg") .attr("width", chartWidth) .attr("height", chartHeight);
const bars = svg.selectAll(".bar") .data(data) .enter() .append("g") .attr("class", "bar") .attr("transform", (d, i) => `translate(0, ${i * (barHeight + barPadding)})`);Step 4: Append <rect> for bars.
bars.append("rect") .attr("width", d => d * scaleFactor) // Or xScale(d) if using d3.scaleLinear .attr("height", barHeight);Step 5: Append <text> for labels.
bars.append("text") .attr("x", d => (d * scaleFactor) + labelOffset) // Or xScale(d) + labelOffset .attr("y", barHeight / 2) // .attr("dy", ".35em") // dominant-baseline: middle is often better .text(d => d);The complete barchart.html (with the script part filled):
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>D3 Bar Chart</title> <script src="https://d3js.org/d3.v7.min.js"></script> <style> .bar-chart-container svg { border: 1px solid #ccc; } .bar-chart-container .bar rect { fill: steelblue; } .bar-chart-container .bar rect:hover { fill: orange; } .bar-chart-container .bar text { fill: black; font: 10px sans-serif; text-anchor: start; dominant-baseline: middle; } </style></head><body> <div class="bar-chart-container"> <h3>Simple Horizontal Bar Chart</h3> <div id="chart-area"></div> </div> <script> const data = [10, 5, 12, 15, 8, 10]; const chartWidth = 400; const barHeight = 20; const barPadding = 5; const labelOffset = 5; const chartHeight = data.length * (barHeight + barPadding); const scaleFactor = (chartWidth - 50) / d3.max(data);
const svg = d3.select("#chart-area") .append("svg") .attr("width", chartWidth) .attr("height", chartHeight);
const bars = svg.selectAll(".bar") .data(data) .enter() .append("g") .attr("class", "bar") .attr("transform", (d, i) => `translate(0, ${i * (barHeight + barPadding)})`);
bars.append("rect") .attr("width", d => d * scaleFactor) .attr("height", barHeight);
bars.append("text") .attr("x", d => (d * scaleFactor) + labelOffset) .attr("y", barHeight / 2) .text(d => d); </script></body></html>When opened in a browser, this will display a simple horizontal bar chart. Each bar’s length corresponds to its data value, with the value printed next to it.
Circle Chart (Simple Scatter Plot Points)
Section titled “Circle Chart (Simple Scatter Plot Points)”This example demonstrates drawing circles whose radii are based on data values, arranged horizontally.
Drawing a Circle Chart
Section titled “Drawing a Circle Chart”Step 1: HTML Structure (e.g., circlechart.html).
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>D3 Circle Chart</title> <script src="https://d3js.org/d3.v7.min.js"></script> <style> #circle-chart-area svg { border: 1px solid #ccc; } #circle-chart-area .data-circle { stroke: black; stroke-width: 1px; } #circle-chart-area .data-label { font: 10px sans-serif; text-anchor: middle; } </style></head><body> <h3>Simple Circle Chart</h3> <div id="circle-chart-area"></div> <script> // D3 code here </script></body></html>Step 2: JavaScript - Data and parameters.
// Inside the <script> tagconst circleData = [10, 20, 30, 15, 25];const circleColors = ['green', 'purple', 'yellow', 'blue', 'red'];
const svgWidth = 500;const svgHeight = 150; // Height to accommodate largest circle and labelsconst circleYPosition = svgHeight / 2; // Center circles verticallyconst circleSpacing = 100; // Horizontal space between circle centersStep 3: Create SVG and groups for each circle-label pair.
const svgCircles = d3.select("#circle-chart-area") .append("svg") .attr("width", svgWidth) .attr("height", svgHeight);
const circleGroups = svgCircles.selectAll(".circle-group") .data(circleData) .enter() .append("g") .attr("class", "circle-group") .attr("transform", (d, i) => `translate(${i * circleSpacing + 50}, 0)`); // +50 for initial paddingStep 4: Append <circle> elements.
circleGroups.append("circle") .attr("class", "data-circle") .attr("cy", circleYPosition) .attr("r", d => d * 1.5) // Radius based on data, scaled .attr("fill", (d, i) => circleColors[i % circleColors.length]);Step 5: Append <text> labels.
circleGroups.append("text") .attr("class", "data-label") .attr("y", circleYPosition) // .attr("dy", d => (d * 1.5) + 15) // Position label below circle, adjust as needed .attr("dy", ".35em") // Center text on cy if not offsetting for below circle .text(d => d);The complete script section for circlechart.html:
const circleData = [10, 20, 30, 15, 25]; const circleColors = ['green', 'purple', 'yellow', 'blue', 'red']; const svgWidth = 500; const svgHeight = 150; const circleYPosition = svgHeight / 2; const circleSpacing = (svgWidth - 50) / circleData.length; // Dynamic spacing
const svgCircles = d3.select("#circle-chart-area") .append("svg") .attr("width", svgWidth) .attr("height", svgHeight);
const circleGroups = svgCircles.selectAll(".circle-group") .data(circleData) .enter() .append("g") .attr("class", "circle-group") .attr("transform", (d, i) => `translate(${i * circleSpacing + circleSpacing/2 + 25}, 0)`); // Center in allocated space, +25 for initial margin
circleGroups.append("circle") .attr("class", "data-circle") .attr("cy", circleYPosition) .attr("r", d => d * 1.5) .attr("fill", (d, i) => circleColors[i % circleColors.length]);
circleGroups.append("text") .attr("class", "data-label") .attr("y", circleYPosition) .attr("dy", ".35em") .text(d => d);This will render a series of colored circles, each with a radius proportional to its data value, and the value itself printed in the center of the circle.
Pie Chart
Section titled “Pie Chart”Pie charts represent data as slices of a circle, where each slice’s angle is proportional to its value relative to the total. D3 provides d3.pie() to calculate angles and d3.arc() to generate SVG path data for the slices.
Drawing a Pie Chart
Section titled “Drawing a Pie Chart”Step 1: HTML Structure and Styles (e.g., piechart.html).
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>D3 Pie Chart</title> <script src="https://d3js.org/d3.v7.min.js"></script> <style> #pie-chart-area svg { border: 1px solid #ccc; } .pie-slice path { stroke: #fff; /* White border between slices */ stroke-width: 1px; } .pie-label text { font: 12px sans-serif; text-anchor: middle; fill: white; } .chart-title { font: bold 16px sans-serif; text-anchor: middle; } </style></head><body> <h3>Population Distribution (Pie Chart)</h3> <div id="pie-chart-area"></div> <script> // D3 code for pie chart </script></body></html>Step 2: Data and Chart Parameters. We’ll use a sample dataset (e.g., populations). In a real scenario, you might load this from a CSV or JSON file using d3.csv() or d3.json() which return Promises.
// Inside the <script> tagconst populationData = [ { state: "UP", percent: 20.00 }, { state: "MH", percent: 15.00 }, { state: "BR", percent: 12.50 }, { state: "WB", percent: 10.00 }, { state: "MP", percent: 8.00 }, { state: "Other", percent: 34.50 }];
const pieWidth = 400;const pieHeight = 400;const radius = Math.min(pieWidth, pieHeight) / 2 - 10; // -10 for marginStep 3: Create SVG and a group element for the pie, centered.
const svgPie = d3.select("#pie-chart-area") .append("svg") .attr("width", pieWidth) .attr("height", pieHeight) .append("g") // Group to center the pie chart .attr("transform", `translate(${pieWidth / 2}, ${pieHeight / 2})`);Step 4: Color Scale and Pie Generator.
const colorScale = d3.scaleOrdinal(d3.schemeCategory10); // Built-in color scheme
const pieGenerator = d3.pie() .value(d => d.percent) // Accessor for the values to determine slice sizes .sort(null); // Optional: preserve original data order or sort by valueStep 5: Arc Generator for drawing slices.
const arcGenerator = d3.arc() .innerRadius(0) // For a pie chart; > 0 for donut chart .outerRadius(radius);Step 6: Arc Generator for label positioning (optional, for placing labels inside/outside slices).
const labelArcGenerator = d3.arc() .innerRadius(radius * 0.6) // Position labels within the slice .outerRadius(radius * 0.6);Step 7: Bind data and draw slices.
const arcs = svgPie.selectAll(".pie-slice") .data(pieGenerator(populationData)) .enter() .append("g") .attr("class", "pie-slice");
arcs.append("path") .attr("d", arcGenerator) .attr("fill", d => colorScale(d.data.state));Step 8: Add labels to slices.
arcs.append("text") .attr("class", "pie-label") .attr("transform", d => `translate(${labelArcGenerator.centroid(d)})`) // Position using centroid of labelArc .text(d => `${d.data.state} (${d.data.percent}%)`) .each(function(d) { // Hide label if slice is too small const angle = d.endAngle - d.startAngle; if (angle < 0.25) { // Threshold angle in radians, adjust as needed d3.select(this).remove(); } });Step 9: Add a title (optional).
d3.select("#pie-chart-area svg") // Select the main SVG again .append("text") .attr("class", "chart-title") .attr("x", pieWidth / 2) .attr("y", 20) // Position at the top .text("State Population Distribution");The full script section for piechart.html would combine these JavaScript snippets. When viewed, it shows a pie chart representing the population distribution, with labels on the slices.
These examples provide a foundation. Real-world charts often involve more complex scales, axes, legends, and interactions, all of which D3.js can handle.