使用D3.js创建带年份X轴的逮捕数据柱状图遇问题
嘿,我来帮你搞定这个年份X轴的柱状图问题!看你已经准备好了年份和逮捕数的等长数组,还有barWidth、barOffset这类变量,我给你两种实用的实现方案,你可以根据自己的技术栈来选:
方案一:原生Canvas实现
如果是用原生Canvas手动绘制,我们可以通过计算坐标和缩放比例来适配年份X轴,具体代码如下:
首先在HTML里准备Canvas元素:
<canvas id="arrestChart" width="800" height="500"></canvas>
然后编写JavaScript逻辑:
const canvas = document.getElementById('arrestChart'); const ctx = canvas.getContext('2d'); // 你已定义的变量 const barWidth = 35; const barOffset = 10; const years = [1988, 1989, /* ... 你的年份数据直到2018 */ 2018]; const number_of_arrests = [1000, 200, /* ... 对应的逮捕数数据 */]; // 计算Y轴缩放比例,适配画布高度(避免数值过大超出画布) const maxArrests = Math.max(...number_of_arrests); const scaleY = (canvas.height - 80) / maxArrests; // 预留空间给底部年份标签和顶部边距 const startX = 50; // X轴起始位置,留左侧边距 const startY = canvas.height - 50; // Y轴起始位置,留底部边距给年份 // 遍历数组绘制每个柱子和年份标签 years.forEach((year, index) => { const arrests = number_of_arrests[index]; // 计算柱子X坐标:起始位置 + (柱子宽度 + 间距) * 索引 const x = startX + (barWidth + barOffset) * index; // 柱子高度:逮捕数 * 缩放比例 const barHeight = arrests * scaleY; // 柱子Y坐标:CanvasY轴向下,所以从底部往上算 const y = startY - barHeight; // 绘制柱状条 ctx.fillStyle = '#2ecc71'; ctx.fillRect(x, y, barWidth, barHeight); // 绘制X轴年份标签 ctx.fillStyle = '#333'; ctx.font = '12px Arial'; ctx.textAlign = 'center'; // 把标签放在柱子正下方,留一点间距 ctx.fillText(year, x + barWidth/2, startY + 20); }); // 绘制Y轴标签(逮捕数量) ctx.fillStyle = '#333'; ctx.font = '14px Arial'; ctx.textAlign = 'center'; ctx.save(); ctx.translate(20, canvas.height/2); ctx.rotate(-Math.PI/2); // 旋转标签使其垂直 ctx.fillText('逮捕数量', 0, 0); ctx.restore(); // 绘制X轴和Y轴的基线 ctx.strokeStyle = '#333'; ctx.beginPath(); ctx.moveTo(startX, startY); ctx.lineTo(canvas.width - 30, startY); // 绘制X轴 ctx.moveTo(startX, startY); ctx.lineTo(startX, 30); // 绘制Y轴 ctx.stroke();
方案二:D3.js实现(更便捷的可视化库)
如果使用D3.js这类可视化库,能更高效地处理坐标轴和数据映射,还能自动处理标签重叠问题,代码如下:
首先准备HTML容器:
<div id="arrestChart" style="width: 800px; height: 500px;"></div>
然后编写JavaScript逻辑(确保你已经引入了D3.js库):
const years = [1988, 1989, /* ... 你的年份数据直到2018 */ 2018]; const number_of_arrests = [1000, 200, /* ... 对应的逮捕数数据 */]; // 将年份和逮捕数配对,整理成D3需要的数据格式 const data = years.map((year, index) => ({ year: year.toString(), arrests: number_of_arrests[index] })); // 设置画布尺寸和边距 const width = 800; const height = 500; const margin = { top: 30, right: 30, bottom: 60, left: 60 }; // 创建SVG容器 const svg = d3.select('#arrestChart') .append('svg') .attr('width', width) .attr('height', height); // 创建X轴比例尺(对应你的barWidth和barOffset) const xScale = d3.scaleBand() .domain(data.map(d => d.year)) .range([margin.left, width - margin.right]) .padding(0.2); // padding对应柱子间的间距,类似你的barOffset // 创建Y轴比例尺 const yScale = d3.scaleLinear() .domain([0, d3.max(data, d => d.arrests)]) .range([height - margin.bottom, margin.top]); // 绘制柱状条 svg.selectAll('rect') .data(data) .enter() .append('rect') .attr('x', d => xScale(d.year)) .attr('y', d => yScale(d.arrests)) .attr('width', xScale.bandwidth()) // bandwidth对应柱子宽度,类似你的barWidth .attr('height', d => height - margin.bottom - yScale(d.arrests)) .attr('fill', '#2ecc71'); // 绘制X轴(年份) svg.append('g') .attr('transform', `translate(0, ${height - margin.bottom})`) .call(d3.axisBottom(xScale)) .selectAll('text') .attr('transform', 'rotate(-45)') // 旋转标签避免年份重叠 .style('text-anchor', 'end'); // 绘制Y轴(逮捕数量) svg.append('g') .attr('transform', `translate(${margin.left}, 0)`) .call(d3.axisLeft(yScale)); // 添加Y轴标签 svg.append('text') .attr('transform', 'rotate(-90)') .attr('y', margin.left / 2) .attr('x', -height/2) .style('text-anchor', 'center') .text('逮捕数量'); // 添加图表标题 svg.append('text') .attr('x', width/2) .attr('y', margin.top/2) .style('text-anchor', 'center') .style('font-size', '16px') .text('各年份逮捕数量统计');
内容的提问来源于stack exchange,提问作者mathquestion
相关产品推荐
相关产品推荐

