如何将流量统计JSON数据展示为分组柱状图(Grouped Bar Chart)
Got it, let's build a flexible grouped bar chart solution for your hourly traffic data. Below are two solid implementations—one using Chart.js (great for quick, clean charts with minimal code) and another with vanilla JS + D3.js (for full control over every detail). Both work with any grouped data structure, not just your traffic stats.
Option 1: Using Chart.js (Quick & User-Friendly)
Chart.js is perfect if you want a low-effort setup with built-in responsiveness and interactivity. Here's how to map your JSON data to a grouped bar chart:
Step 1: Set Up HTML Structure
First, add a canvas element where the chart will render:
<canvas id="trafficChart" width="800" height="400"></canvas>
Step 2: Include Chart.js
Download the latest version of Chart.js from its official repository, save it locally, and include it with a script tag:
<script src="./path/to/chart.min.js"></script>
Step 3: Parse & Render the Chart
Write the JavaScript to process your JSON data and generate the chart:
// Your traffic data const trafficData = [ {"call_time":"0","total_inc_traffic":"1363.10","total_out_traffic":"88.70"}, {"call_time":"1","total_inc_traffic":"479.57","total_out_traffic":"36.98"}, {"call_time":"2","total_inc_traffic":"239.57","total_out_traffic":"13.43"}, {"call_time":"3","total_inc_traffic":"190.28","total_out_traffic":"8.20"}, {"call_time":"4","total_inc_traffic":"223.80","total_out_traffic":"0.00"}, {"call_time":"5","total_inc_traffic":"158.87","total_out_traffic":"19.58"}, {"call_time":"6","total_inc_traffic":"27.52","total_out_traffic":"36.18"}, {"call_time":"7","total_inc_traffic":"47.70","total_out_traffic":"69.57"}, {"call_time":"8","total_inc_traffic":"2234.35","total_out_traffic":"137.60"}, {"call_time":"9","total_inc_traffic":"150.67","total_out_traffic":"162.07"}, {"call_time":"10","total_inc_traffic":"4497.05","total_out_traffic":"267.32"}, {"call_time":"11","total_inc_traffic":"5049.87","total_out_traffic":"242.42"}, {"call_time":"12","total_inc_traffic":"5227.67","total_out_traffic":"286.88"}, {"call_time":"13","total_inc_traffic":"3384.30","total_out_traffic":"360.88"}, {"call_time":"14","total_inc_traffic":"3650.73","total_out_traffic":"328.28"} ]; // Extract labels and datasets from the JSON const labels = trafficData.map(item => `Hour ${item.call_time}`); const incomingTraffic = trafficData.map(item => parseFloat(item.total_inc_traffic)); const outgoingTraffic = trafficData.map(item => parseFloat(item.total_out_traffic)); // Initialize the grouped bar chart const ctx = document.getElementById('trafficChart').getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [ { label: 'Incoming Traffic (MB)', data: incomingTraffic, backgroundColor: 'rgba(54, 162, 235, 0.6)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }, { label: 'Outgoing Traffic (MB)', data: outgoingTraffic, backgroundColor: 'rgba(255, 99, 132, 0.6)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 } ] }, options: { responsive: true, scales: { y: { beginAtZero: true, title: { display: true, text: 'Traffic Volume (MB)' } }, x: { title: { display: true, text: 'Hour of Day' } } }, plugins: { legend: { position: 'top', }, tooltip: { mode: 'index', intersect: false } } } });
Adapting to Any Grouped Data
- Swap the
labelsarray with your category values (e.g., product names, regions). - Add more objects to the
datasetsarray for additional data groups (e.g., a third traffic type). - Adjust the
parseFloatstep if your data uses different numeric formats (e.g., commas as decimal separators).
Option 2: Vanilla JavaScript + D3.js (Full Customization)
If you need complete control over animations, styling, or complex interactions, D3.js is the way to go. Here's a flexible implementation:
Step 1: HTML Structure
Add a container for the SVG chart:
<div id="chartContainer" style="width: 800px; height: 400px;"></div>
Step 2: Include D3.js
Download D3.js v7 from its official repository, save it locally, and include it:
<script src="./path/to/d3.v7.min.js"></script>
Step 3: D3.js Code for Grouped Bars
const trafficData = [/* Paste your JSON data here */]; // Set up chart dimensions and margins const margin = {top: 30, right: 30, bottom: 70, left: 60}; const width = 800 - margin.left - margin.right; const height = 400 - margin.top - margin.bottom; // Create SVG container const svg = d3.select("#chartContainer") .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})`); // Prepare data: Convert string values to numbers trafficData.forEach(d => { d.total_inc_traffic = +d.total_inc_traffic; d.total_out_traffic = +d.total_out_traffic; }); // Define groups and their display names const groups = ["total_inc_traffic", "total_out_traffic"]; const groupLabels = { "total_inc_traffic": "Incoming Traffic (MB)", "total_out_traffic": "Outgoing Traffic (MB)" }; const hourLabels = trafficData.map(d => `Hour ${d.call_time}`); // Set up scales for axes and bar positioning const x0 = d3.scaleBand() .domain(hourLabels) .range([0, width]) .padding(0.2); const x1 = d3.scaleBand() .domain(groups) .range([0, x0.bandwidth()]) .padding(0.1); const y = d3.scaleLinear() .domain([0, d3.max(trafficData, d => Math.max(d.total_inc_traffic, d.total_out_traffic))]) .range([height, 0]); // Add X and Y axes svg.append("g") .attr("transform", `translate(0, ${height})`) .call(d3.axisBottom(x0)) .selectAll("text") .attr("transform", "rotate(-45)") .style("text-anchor", "end"); svg.append("g") .call(d3.axisLeft(y)); // Render grouped bars svg.append("g") .selectAll("g") .data(trafficData) .enter() .append("g") .attr("transform", d => `translate(${x0(`Hour ${d.call_time}`)}, 0)`) .selectAll("rect") .data(d => groups.map(key => ({key: key, value: d[key]}))) .enter() .append("rect") .attr("x", d => x1(d.key)) .attr("y", d => y(d.value)) .attr("width", x1.bandwidth()) .attr("height", d => height - y(d.value)) .attr("fill", d => d.key === "total_inc_traffic" ? "#36a2eb" : "#ff6384"); // Add axis titles svg.append("text") .attr("transform", `translate(${width/2}, ${height + margin.bottom - 10})`) .style("text-anchor", "middle") .text("Hour of Day"); svg.append("text") .attr("transform", "rotate(-90)") .attr("y", 0 - margin.left) .attr("x", 0 - (height / 2)) .attr("dy", "1em") .style("text-anchor", "middle") .text("Traffic Volume (MB)"); // Add legend const legend = svg.append("g") .attr("transform", `translate(${width - 150}, 0)`); groups.forEach((group, index) => { const legendRow = legend.append("g") .attr("transform", `translate(0, ${index * 25})`); legendRow.append("rect") .attr("width", 15) .attr("height", 15) .attr("fill", group === "total_inc_traffic" ? "#36a2eb" : "#ff6384"); legendRow.append("text") .attr("x", 20) .attr("y", 12) .style("font-size", "12px") .text(groupLabels[group]); });
Flexibility for Any Grouped Data
- To add more data groups, extend the
groupsarray and updategroupLabelswith new display names. - Adjust colors, padding, or axis behavior by modifying scale attributes and styling properties.
- The code uses a generic approach to map data keys to bars, so it works with any JSON structure where each object has category labels and numeric group values.
Quick Tips for Adaptation
- Data Parsing: Always convert string-based numeric values to actual numbers (using
parseFloator the+operator) to ensure proper chart rendering. - Responsiveness: Both solutions can be made responsive by using relative container widths/heights and adjusting scale ranges dynamically.
- Customization: Tweak colors, labels, tooltips, and animations to match your design requirements.
内容的提问来源于stack exchange,提问作者Tanvir Nabil

