You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:03:36