「数据可视化 D3系列」入门第五章:绘制第一个D3图表

发布于:2025-04-17 ⋅ 阅读:(77) ⋅ 点赞:(0)


从数据到可视化:第一个完整图表

本章将通过创建基础柱状图,一起来体验D3数据可视化的完整流程。以下是我们将构建的图表效果:

在这里插入图片描述


一、核心概念:SVG与数据绑定的可视化实现

SVG基础认知

<svg width="500" height="300"> <!-- SVG画布 -->
  <rect x="0" y="0" width="100" height="50" fill="steelblue"/> <!-- 矩形 -->
  <text x="10" y="20" font-size="12">数据标签</text> <!-- 文本 -->
</svg>
  • SVG坐标系:以左上角为原点(0,0),X轴向右,Y轴向下
  • 图形元素<rect>矩形、<text>文本、<path>路径等
  • 分组容器<g>元素用于组合图形,可统一设置变换属性

图表容器规范

const margin = { top: 30, right: 20, bottom: 40, left: 50 };
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;

const svg = d3.select("body")
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom);

const chart = svg.append("g")
  .attr("transform", `translate(${margin.left},${margin.top})`);

最佳实践:通过margin对象管理边距,保证绘图区域与容器的清晰分离


二、基础示例:水平柱状图

👇 完整实现代码

<!DOCTYPE html>
<html>
<head>
  <script src="https://d3js.org/d3.v7.min.js"></script>
  <style>
    .bar { transition: all 0.3s; }
    .bar:hover { opacity: 0.8; }
  </style>
</head>
<body>
  <svg width="600" height="300"></svg>

  <script>
    // 模拟数据
    const dataset = [730, 530, 330, 230, 130];
    
    // 1. 选择容器
    const svg = d3.select("svg");
    
    // 2. 创建图表区域
    const chart = svg.append("g")
      .attr("transform", "translate(50, 30)");
    
    // 3. 数据绑定与图形创建
    chart.selectAll(".bar")
      .data(dataset)
      .enter()
      .append("rect")
      .attr("class", "bar")
      .attr("x", 0)
      .attr("y", (d, i) => i * 35)  // 每个柱形间隔35px
      .attr("width", d => d)        // 直接使用数据值作为宽度
      .attr("height", 25)           // 固定高度
      .attr("fill", "#4CAF50");     // 初始颜色
  </script>
</body>
</html>

👇 运行效果:

在这里插入图片描述


三、图表优化三部曲

1. 添加坐标轴(简单实现)

// X轴(后续章节会优化)
chart.append("line")
  .attr("x1", 0)
  .attr("y1", dataset.length * 35)
  .attr("x2", d3.max(dataset))
  .attr("y2", dataset.length * 35)
  .attr("stroke", "#333")
  .attr("stroke-width", 1);

2. 添加数据标签

chart.selectAll(".label")
  .data(dataset)
  .enter()
  .append("text")
  .attr("class", "label")
  .attr("x", d => d + 5)  // 在柱形右侧显示
  .attr("y", (d, i) => i * 35 + 18)
  .text(d => d)
  .attr("font-size", "12px")
  .attr("fill", "#666");

3. 样式美化

.bar {
  rx: 3px;  /* 圆角 */
  filter: drop-shadow(2px 2px 2px rgba(0,0,0,0.1));
}

.label {
  font-family: Arial;
  dominant-baseline: middle;  /* 垂直居中 */
}

👇 优化后效果:
在这里插入图片描述


四、交互增强:鼠标响应

1. 悬停效果

d3.selectAll(".bar")
  .on("mouseover", function() {
    d3.select(this)
      .attr("fill", "#FF5722");
  })
  .on("mouseout", function() {
    d3.select(this)
      .attr("fill", "#4CAF50");
  });

👇 优化后效果:

在这里插入图片描述

2. 简单工具提示

// 添加提示框
const tooltip = d3.select("body")
  .append("div")
  .style("position", "absolute")
  .style("visibility", "hidden")
  .style("background", "#fff")
  .style("padding", "5px 10px")
  .style("border-radius", "4px")
  .style("box-shadow", "0 2px 4px rgba(0,0,0,0.2)");

// 交互逻辑
d3.selectAll(".bar")
  .on("mouseover", function(event, d) {
    tooltip
      .style("visibility", "visible")
      .html(`数值:${d}`);
  })
  .on("mousemove", function(event) {
    tooltip
      .style("left", `${event.pageX + 10}px`)
      .style("top", `${event.pageY - 20}px`);
  })
  .on("mouseout", function() {
    tooltip.style("visibility", "hidden");
  });

👇 优化后效果:

在这里插入图片描述


五、当前实现的问题分析

1. 数据直接映射的问题

.attr("width", d => d) // 当数据超过容器宽度时会出现显示异常

解决方案预告:下一章将使用d3.scaleLinear()比例尺解决此问题

2. 硬编码间距问题

.attr("y", (d, i) => i * 35) // 35是手动计算的间距值

优化方向:根据容器高度动态计算间距


小结

  1. SVG绘图流程

    准备数据
    创建SVG容器
    数据绑定
    图形绘制
    样式优化
  2. 核心方法链

    selection.data(data)
      .enter()
      .append(element)
      .attr(property, value)
    
  3. 可视化要素

    • 图表容器与边距管理
    • 数据到图形的映射关系
    • 基础交互实现

下章预告:比例尺(Scale)的魔法

  • 线性比例尺scaleLinear的应用
  • 序数比例尺scaleBand实现自动间距
  • 颜色比例尺scaleOrdinal的妙用
  • 坐标轴的自动化生成

网站公告

今日签到

点亮在社区的每一天
去签到