Urara-Blog/urara/2022-07-23-d3.md
2022-08-14 14:10:39 +08:00

13 KiB
Raw Blame History

title created summary tags
D3.js 基础笔记 2022-07-23 即使是FreeCodeCamp也要做笔记
D3.js
数据可视化

内容出自:FreeCodeCamp

D3 或 D3.js 表示数据驱动文档。它是一个用于在浏览器中创建动态和交互式数据视觉化的 JavaScript 库。1

学习资源

基础操作

修改元素

  • select()
    • 功能:从文档中选择一个元素。
    • 参数:它接受你想要选择的元素的名字作为参数,并返回文档中第一个与名字匹配的 HTML 节点。
  • selectAll()
    • 选择一组元素。 并以 HTML 节点数组的形式返回该文本中所有匹配所输入字符串的对象
  • append()
    • 功能:将 HTML 节点附加到选定项目,并返回该节点的句柄。
    • 参数:接收你希望添加到文档中的元素
  • text()
    • 功能:设置所选节点的文本,也可以获取当前文本。 也可以用来添加标签
    • 参数:字符串或者回调函数
const anchor = d3.select('a')

在 D3 中可以串联多个方法,连续执行一系列操作。->function chaining

使用数据

d3-selection

  • data()
    • 将元素与数据绑定
    • 不需要写 for 循环或者用 forEach() 迭代数据集中的对象。 data() 方法会解析数据集,任何链接在 data() 后面的方法都会为数据集中的每个对象运行一次。
    • 可以使用方括号的方式,如 d[0],来访问数组中的值。
  • enter():获取需要插入的选择集(数据个数大于元素个数)的占位符.

当 enter() 和 data() 方法一起使用时,它把从页面中选择的元素和数据集中的元素作比较。 如果页面中选择的元素较少则创建缺少的元素。

可以理解为管理仓库的,选择的元素是货架,数据是货,如果货架不够了,就再补几个货架,如果多了就不管

<body>
  <ul></ul>
  <script>
    const dataset = ['a', 'b', 'c']
    d3.select('ul').selectAll('li').data(dataset).enter().append('li').text('New item')
  </script>
</body>

使用动态数据

text 中设置回调处理数据如:

  • d3.json(): 从指定的 input URL 获取 JSON 文件。如果指定了 init 则会将其传递给底层的 fetch 方法
<body>
  <script>
    const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9]

    d3.select('body')
      .selectAll('h2')
      .data(dataset)
      .enter()
      .append('h2')
      .text(d => d + ' USD')
  </script>
</body>

给元素添加内联样式

  • style()
    • 功能:在动态元素上添加内联 CSS 样式
    • 参数:以用逗号分隔的键值对作为参数
selection.style('color', 'blue')

//用回调过滤
selection.style('color', d => {
  return d < 20 ? 'red' : 'green'
})
// 动态设置样式
selection.style('height', d => d + 'px') // 动态设置高度

添加 Class

  • attr()
    • 功能:可以给元素添加任何 HTML 属性,包括 class 名称。
    • 参数:
      • attr() 方法和 style() 的使用方法一样。 它使用逗号分隔值,并且可以使用回调函数
      • 可接收一个回调函数来动态设置属性。 这个回调函数有两个参数,一个是数据点本身(通常是 d),另一个是该数据点在数组中的下标 i 这个参数是可选的
    • 当需要添加 class 时class 参数保持不变,只有 container 参数会发生变化。
selection.attr('class', 'container')
// 回调
selection.attr('property', (d, i) => {})

// 比如改变间距
svg
  .selectAll('rect')
  .data(dataset)
  .enter()
  .append('rect')
  .attr('x', (d, i) => {
    return i * 30 //改变间距
  })
  .attr('y', (d, i) => {
    return d * 3 //改变高度
  })
  //悬停效果
  .attr('class', 'bar')

标签

  • 和 rect 元素类似text 元素也需要 x 和 y 属性来指定其放置在 SVG 画布上的位置, 它也需要能够获取数据来显示数据值。
  • 标签样式
    • fill 属性为 text 节点设置文本颜色
    • style() 方法设置其它样式的 CSS 规则,例如 font-family 或 font-size。
//添加标签
svg
  .selectAll('text')
  .data(dataset)
  .enter()
  .append('text')
  .attr('x', (d, i) => i * 30)
  .attr('y', (d, i) => h - 3 * d - 3) // 高三个单位是减
  .text(d => d)
  // 添加样式
  .attr('fill', 'red')
  .style('font-size', '25px')
  //悬停效果
  .attr('class', 'bar')
/** css中
		    .bar:hover {
			    fill: brown;
			  }
		  **/

添加工具提示 tooltip

  • 当用户在一个对象上悬停时,提示框可以显示关于这个对象更多的信息
  1. title
svg
  .selectAll('rect')
  .data(dataset)
  .enter()
  .append('rect')
  .attr('x', (d, i) => i * 30)
  .attr('y', (d, i) => h - 3 * d)
  .attr('width', 25)
  .attr('height', (d, i) => d * 3)
  // 每个 rect 节点下附加 title 元素。 然后用回调函数调用 text() 方法使它的文本显示数据值。
  .append('title')
  .text(d => d)

SVG

  • 坐标系:坐标轴的原点在左上角。 x 坐标为 0 将图形放在 SVG 区域的左边缘, y 坐标为 0 将图形放在 SVG 区域的上边缘。 x 值增大矩形将向右移动, y 值增大矩形将向下移动。

创建 SVG

//创建svg
selection.append('svg')

反转 SVG 元素

  • 为了使条形图向上,需要改变 y 坐标计算的方式

SVG 区域的高度为 100。 如果在集合中一个数据点的值为 0那么条形将从 SVG 区域的最底端开始(而不是顶端)。 为此y 坐标的值应为 100。 如果数据点的值为 1你将从 y 坐标为 100 开始来将这个条形设置在底端, 然后需要考虑该条形的高度为 1所以最终的 y 坐标将是 99。

(高度从下面开始计算,坐标轴从上面开始)

  • y 坐标为 y = heightOfSVG - heightOfBar 会将条形图向上放置。
  • 通常,关系是 y = h - m * d,其中 m 是缩放数据点的常数。

更改 SVG 元素的颜色

  • 在 SVG 中, rect 图形用 fill 属性着色。 它支持十六进制代码、颜色名称、rgb 值以及更复杂的选项,比如渐变和透明。
svg
  .selectAll('rect')
  .data(dataset)
  .enter()
  .append('rect')
  .attr('x', (d, i) => i * 30)
  .attr('y', (d, i) => h - 3 * d)
  .attr('width', 25)
  .attr('height', (d, i) => 3 * d)
  //将所有条形图的 fill 设置为海军蓝。
  .attr('fill', 'navy')

SVG 图形

  • SVG 支持多种图形,比如矩形和圆形, 并用它们来显示数据。

矩形

SVG 的 rect 有四个属性。 x 和 y 坐标指定图形放在 svg 区域的位置, height 和 width 指定图形大小

const svg = d3
  .select('body')
  .append('svg')
  .attr('width', w)
  .attr('height', h)
  .append('rect') //rect矩形
  .attr('width', 25)
  .attr('height', 100)
  .attr('x', 0)
  .attr('y', 0)

圆形

  • SVG 用 circle 标签来创建圆形
  • circle 有三个主要的属性。
    • cx 和 cy 属性是坐标。 它们告诉 D3 将图形的中心放在 SVG 画布的何处。
    • 半径( r 属性)给出 circle 的大小。
  • 和 rect 的 y 坐标一样circle 的 cy 属性是从 SVG 画布的顶端开始测量的,而不是从底端。
svg
  .selectAll('circle')
  .data(dataset)
  .enter()
  .append('circle')
  //散点图
  .attr('cx', d => d[0])
  .attr('cy', d => h - d[1])
  .attr('r', '5')

比例尺

创建线性比例

条形图和散点图都直接在 SVG 画布上绘制数据。 但是,如果一组的高或者其中一个数据点比 SVG 的高或宽更大,它将跑到 SVG 区域外。

D3 中,比例尺可帮助布局数据。 scales 是函数,它告诉程序如何将一组原始数据点映射到 SVG 画布上。

线性缩放

  • 通常使用于定量数据
  • 默认情况下比例尺使用一对一关系identity relationship。 输入的值和输出的值相同。
const scale = d3.scaleLinear()

例子

const scale = d3.scaleLinear() // 在这里创建轴
const output = scale(50) // 调用 scale传入一个参数
d3.select('body').append('h2').text(output)

按比例设置域和范围

  • 域 domain假设有一个数据集范围为 50 到 480 这是缩放的输入信息,也被称为域。
  • 范围 range沿着 x 轴将这些点映射到 SVG 画布上,位置介于 10 个单位到 500 个单位之间。 这是输出信息,也被称为范围。
  • domain()range() 方法设置比例尺的值, 它们都接受一个至少有两个元素的数组作为参数。
    • domain() 方法给比例尺传递关于散点图原数据值的信息
    • range() 方法给出在页面上进行可视化的实际空间信息

例子:

scale.domain([50, 480]); //域
scale.range([10, 500]); //范围
scale(50) //10
scale(480) //500
scale(325) //323.37
scale(750)// 807.。67
d3.scaleLinear()

按顺序将在控制台中显示以下值10、500、323.37 和 807.67。

注意,比例尺使用了域和范围之间的线性关系来找出给定数字的输出值。 域中的最小值50映射为范围中的最小值10

(也就是给定范围,用线性关系缩小,比如图片放大缩小,给了原图大小和缩小后的图片大小,根据线性关系比例来计算每个像素的位置,元素的大小)

最小值最大值

  • d3.min:最小值
  • d3.max: 最大值
  • min()max() 都可以使用回调函数,下面例子中回调函数的参数 d 是当前的内部数组。
  • min()max() 方法在设置比例尺时十分有用

例子:找到二维数组的最大值和最小值

const locationData = [
  [1, 7],
  [6, 3],
  [8, 3]
]
const minX = d3.min(locationData, d => d[0]) //查找在d[0]位置上最小的值

使用动态比例

  • min()max() 来确定比例尺范围和域
  • padding 将在散点图和 SVG 画布边缘之间添加空隙。
  • 保持绘图在右上角。 当为 y 坐标设置 range 时大的值height 减去 padding是第一个参数小的值是第二个参数。
const dataset = [
  [34, 78],
  [109, 280],
  [310, 120],
  [79, 411],
  [420, 220],
  [233, 145],
  [333, 96],
  [222, 333],
  [78, 320],
  [21, 123]
]
const w = 500
const h = 500

const padding = 30
const xScale = d3
  .scaleLinear()
  .domain([0, d3.max(dataset, d => d[0])])
  .range([padding, w - padding])

使用预定义的比例放置元素

  • 用比例尺函数为 SVG 图形设置坐标属性值。
  • 当显示实际数据值时,不用使用比例尺,例如,在提示框或标签中的 text() 方法。
svg
  .selectAll('circle')
  .data(dataset)
  .enter()
  .append('circle')
  .attr('cx', d => xScale(d[0]))
  .attr('cy', d => yScale(d[1]))
  .attr('r', '5')

添加坐标轴

  • 位置:axisLeft()axisBottom()
  • g 元素, g 是英文中组group的缩写在渲染时轴只是一条直线。 因为它是一个简单的图形,所以可以用 g
  • SVG 支持多种 transforms但是定位轴需要使用 translate 属性

例子:

// X轴
const xAxis = d3.axisBottom(xScale)

svg
  .append('g')
  .attr('transform', 'translate(0, ' + (h - padding) + ')') // translate(0,x)
  .call(xAxis) // x轴作为参数被传递给 call() 方法

// Y轴
const yAxis = d3.axisLeft(yScale)

svg
  .append('g')
  .attr('transform', 'translate(0,' + (h - padding) + ')')
  .call(xAxis)
svg
  .append('g')
  .attr('transform', 'translate(' + padding + ',0)')
  .call(yAxis)

常见图表

散点图

圆圈来映射数据点,每个数据点有两个值。 这两个值和 x 和 y 轴相关联,在可视化中用来给圆圈定位。

svg
  .selectAll('circle')
  .data(dataset)
  .enter()
  .append('circle')
  .attr('cx', d => d[0])
  //反转图像
  .attr('cy', d => h - d[1])
  .attr('r', '5')

// 散点图加标签
svg
  .selectAll('text')
  .data(dataset)
  .enter()
  .append('text')
  // Add your code below this line

  .attr('x', d => d[0] + 5)
  .attr('y', d => h - d[1])
  .text(d => d[0] + ', ' + d[1])