📜  带有形状的 d3 折线图 (1)

📅  最后修改于: 2023-12-03 15:25:27.430000             🧑  作者: Mango

带有形状的 d3 折线图

在数据可视化中,折线图是最常用的一种图表类型。而d3(Data-Driven Documents)是一个流行的JavaScript库,它能帮助程序员构建可交互的、动态的、高度自定义的数据可视化。

在这里,我们将介绍如何在d3中创建一个带有形状的折线图。它可以为你的数据添加视觉上的趣味和吸引力。

需求

在我们开始之前,我们需要确定我们的数据和需求。我们将使用以下示例数据:

const data = [
  { month: "January", value: 25 },
  { month: "February", value: 50 },
  { month: "March", value: 75 },
  { month: "April", value: 100 },
  { month: "May", value: 125 },
  { month: "June", value: 150 },
  { month: "July", value: 175 },
  { month: "August", value: 200 },
  { month: "September", value: 225 },
  { month: "October", value: 250 },
  { month: "November", value: 275 },
  { month: "December", value: 300 }
];

我们想要创建一个折线图,以月份作为X轴上的标签,以值为Y轴上的标签。此外,我们还想在每个数据点上使用一个形状表示该数据点。

准备工作

在开始构建图表之前,我们需要准备一些HTML和CSS。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>D3 Line Chart with Shapes Example</title>
    <style>
      .line {
        fill: none;
        stroke: steelblue;
        stroke-width: 2px;
      }
      .dot {
        fill: steelblue;
        stroke: white;
        stroke-width: 2px;
      }
    </style>
  </head>
  <body>
    <svg width="500" height="300"></svg>

    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script src="app.js"></script>
  </body>
</html>

我们在HTML文件中引入了d3库和app.js文件,并在SVG元素中准备好了一个画布。

在CSS样式中,我们定义了折线和点的样式。注意该示例中的SVG元素的高度、宽度、线的颜色、以及线与点的宽度的定义要与该示例数据相符。

接下来,我们将会通过JavaScript代码来构建我们的折线图。

创建折线图

在我们的JavaScript代码中,我们首先需要设置一些环境和变量。

const margin = {
  top: 20,
  right: 20,
  bottom: 30,
  left: 50
};

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

我们定义了一个名为margin的常量,它表示图表的四个边缘的值。我们还在SVG元素中创建了一个G元素,并将其移至图表的左上角。

接下来,我们需要为我们的数据集设置比例尺。我们可以使用d3.scaleBand函数为X轴定义一个序列,并使用d3.scaleLinear函数为Y轴定义线性比例。我们还需要定义一些颜色和形状。

const x = d3.scaleBand()
  .rangeRound([0, width])
  .padding(0.1)
  .domain(data.map(d => d.month));

const y = d3.scaleLinear()
  .rangeRound([height, 0])
  .domain([0, d3.max(data, d => d.value)]);

const line = d3.line()
  .x(d => x(d.month))
  .y(d => y(d.value));

const color = d3.scaleOrdinal(d3.schemeCategory10);
const shape = d3.symbol().size(50).type(d3.symbolCircle);

x和y变量分别表示X和Y的比例尺。d3.scaleBand函数的rangeRound函数接收一个数组,它定义了序列的范围。padding函数定义了序列中每个元素的间隔。domain函数定义了该变量中的值的数组。

d3.line函数用于创建折线,并且可以定义X轴和Y轴的值。颜色常量使用d3.scaleOrdinal根据每个数据点的索引将其映射到一个颜色。形状变量使用d3.symbo()函数创建一个图片形状变量。此示例中创建了一个圆形,并通过其大小和类型定义其大小和形状。

接下来,我们将要绘制X轴和Y轴以及数据对应的折线和点。

g.append("g")
  .attr("class", "axis axis--x")
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(x));

g.append("g")
  .attr("class", "axis axis--y")
  .call(d3.axisLeft(y).ticks(10))
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", "0.71em")
  .attr("text-anchor", "end")
  .text("Value ($)");


const path = g.append("path")
  .datum(data)
  .attr("class", "line")
  .attr("d", line);

g.selectAll(".dot")
  .data(data)
  .enter().append("path")
  .attr("class", "dot")
  .attr("transform", d => "translate(" + x(d.month) + "," + y(d.value) + ")")
  .attr("d", shape);

我们首先为X轴和Y轴绘制了序列。g.append(“g”)函数将一个新元素附加到元素g。我们调用d3.axisBottom和d3.axisLeft函数来定义我们的轴。我们还在元素的标记(.append(“text”))中为Y轴定义了一个说明。

我们对数据使用了折线函数来绘制一个路径。g.append(“path”)函数附加一个具有路径数据的新路径元素。

接下来,我们为数据点创建了路径形状的元素。g.selectAll(“dot”)函数创建一个组选择器,它根据数据集中的每个数据点创建一个虚拟元素。然后,attr(“transform”)函数使用translate函数移动所有圆点的位置,并将其放置在X和Y轴上。

最后,我们将我们的数据集附加到这些元素中,并为每个元素赋予相应的颜色和形状。

以上这些JavaScript代码全部合并到一个文件app.js中。

const margin = {
  top: 20,
  right: 20,
  bottom: 30,
  left: 50
};

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

const data = [
  { month: "January", value: 25 },
  { month: "February", value: 50 },
  { month: "March", value: 75 },
  { month: "April", value: 100 },
  { month: "May", value: 125 },
  { month: "June", value: 150 },
  { month: "July", value: 175 },
  { month: "August", value: 200 },
  { month: "September", value: 225 },
  { month: "October", value: 250 },
  { month: "November", value: 275 },
  { month: "December", value: 300 }
];

const x = d3.scaleBand()
  .rangeRound([0, width])
  .padding(0.1)
  .domain(data.map(d => d.month));

const y = d3.scaleLinear()
  .rangeRound([height, 0])
  .domain([0, d3.max(data, d => d.value)]);

const line = d3.line()
  .x(d => x(d.month))
  .y(d => y(d.value));

const color = d3.scaleOrdinal(d3.schemeCategory10);
const shape = d3.symbol().size(50).type(d3.symbolCircle);

g.append("g")
  .attr("class", "axis axis--x")
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(x));

g.append("g")
  .attr("class", "axis axis--y")
  .call(d3.axisLeft(y).ticks(10))
  .append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", "0.71em")
  .attr("text-anchor", "end")
  .text("Value ($)");


const path = g.append("path")
  .datum(data)
  .attr("class", "line")
  .attr("d", line);

g.selectAll(".dot")
  .data(data)
  .enter().append("path")
  .attr("class", "dot")
  .attr("transform", d => "translate(" + x(d.month) + "," + y(d.value) + ")")
  .attr("d", shape);
总结

在这篇文章中,我们学习了如何使用d3库创建一个带有形状的折线图。我们学习如何绘制X轴和Y轴、如何用比例尺使用数据集、如何绘制一个折线、如何使用形状在数据点上绘制一个图形,以及如何将所有这些元素组合在一起来创建一个图表。

我们强烈建议您深入研究d3库以及不同类型的可视化图表。它可以帮助您了解数据可视化在前端开发中的广泛应用,以及如何使自己的数据在视觉上更具吸引力。