在React中使用D3.js实现数据可视化

数据可视化是指使用图表、图形等可视化对象以更清晰、更有效的方式进行数据通信的技术。

在web上,有许多库可用来可视化数据,但最突出的是D3js库。它已经成为数据可视化的事实,并赢得了许多开发人员的信任。

React是一个被许多开发人员使用的库。在本文中,我们将了解如何使用React和D3创建既可重用又美观的组件。

首先,让我们简要分析一下这些库。

React

React是一个用于构建用户界面的JavaScript库。它使创建可重用组件变得容易,这些组件可以组合在一起形成更复杂的组件。

这些组件能够自己维护它们的状态。

D3

D3.js是一个基于数据操作文档的JavaScript库。它使用HTML、CSS和SVG使数据栩栩如生。

D3试图提供一种基于数据的高效操作数据的方法,而不是提供框架来完成所有可能的功能。

D3是快速的,支持大数据集和动态行为的动画和交互。

下面就来看看如何一起使用这两个库来创建动态数据可视化组件。

安装React

安装react最简单的方法是使用react团队的create-react-app模板。
在本地机器上全局安装,以便可以重用,在终端上运行以下命令:

npm install -g create-react-app

接下来我们使用create-react-app模板创建一个新的app

create-react-app react-d3

下面进入新工程的目录

cd react-d3

安装D3

您可以使用CDN或通过NPM安装将D3库添加到应用程序

在本例中,我们使用NPM来安装:

npm install d3

现在准备工作做完了,我们可以在React中使用D3进行数据可视化开发了。

要在默认浏览器上预览创建的应用程序,请运行以下代码:

npm start

使用D3创建一个条形图(chart)

使用你喜欢的编辑器(我用vscode)打开工程,并打开文件 src/App.js.

这是当前在浏览器中呈现的组件。我们需要删除render()方法的内容,替换成我们自己的内容。

src目录中创建一个BarChart.js的文件,用来创建我们的条形图。

在文件中加入以下代码:

import React, {Component} from 'react';
import * as d3 from "d3";

class BarChart extends Component {

}

export default BarChart;

我们将使用ComponentDidMount生命周期方法在BarChart组件已被装载到DOM中时显示条形图。

在BarChart组件中添加以下内容:

class BarChart extends Component {
    
  componentDidMount() {
    this.drawChart();
  }
}

我们将在drawChart方法中完成D3的绘制工作。

通常,在不使用React的情况下使用D3时,您不必将D3代码放入方法中,但这在React中非常重要,可以确保只在组件被挂载到DOM上时才显示图表

接下来,我们创建drawChart方法:

drawChart() {
  
  const data = [12, 5, 6, 6, 9, 10];
    
  const svg = d3.select("body").append("svg").attr("width", 700).attr("height", 300);
  
}

这个方法做了些什么呢?

首先,我们定义了一个变量data,它包含了我们想要可视化的数据。

其次,我们使用D3的方法定义了一个svg。我们使用SVG是因为它是可伸缩的,也就是说,无论屏幕有多大,或者您放大多少来查看数据,它都不会显示为像素化。

d3.select()用来选择文档中的HTML元素。它选择与传递参数相匹配的第一个元素,并为其创建一个节点。

在本例中,我们传递了body元素,稍后将对其进行更改,以使组件更加可重用。

append()方法的作用是:将一个HTML节点附加到所选项上,并返回该节点的句柄。

attr方法用于向元素添加属性。这可以是您通常添加到HTML元素中的任何属性,如classheightwidthfill

接着我们向body元素添加了一个svg元素,高:700,宽:300。

在我们创建的SVG变量下面,添加以下代码:

svg.selectAll("rect").data(data).enter().append("rect")

select方法一样,selectAll()选择与传递给它的参数匹配的元素。而selectAll()选择的所有与参数匹配的元素,而不仅仅是第一个。

data()方法用于将数据附加到所选HTML元素。

大多数情况下,这些元素不会被找到,因为大多数可视化处理的是动态数据,而且几乎不可能估计要表示的数据量。

enter()方法将我们从瓶颈中解救出来,因为它与append方法一起使用来创建丢失的节点,并且仍然可视化数据。

到目前为止,我们已经为每个数据点创建了节点。剩下的就是让它可见了。

为了使其可见,我们需要为每个数据集创建一个栏,设置一个宽度并动态更新每个栏的高度。

attr方法允许我们使用回调函数来处理动态数据:

selection.attr("property", (d, i) => {}) 

其中d为数点值,i为数据在数组中的索引。

首先,我们需要将每个数据点设置在条形图的x轴和y轴上的特定点上

首先,我们需要将每个数据点设置在条形图的x轴和y轴上的特定点上。我们使用“x”和“y”属性来实现这一点,其中“x”表示棒沿x轴(水平方向)的位置,“y”表示棒沿y轴的位置。

另外,我们需要设置每个数据点的宽度和高度。每个数据点的宽度是恒定的,因为条形图的宽度是相同的。

另一方面,高度取决于每个数据点的值。我们必须使用回调函数使条形图显示每个数据点的值。

我们将SVG变量修改为:

svg.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("x", (d, i) => i * 70)
  .attr("y", 0)
  .attr("width", 25)
  .attr("height", (d, i) => d)
  .attr("fill", "green");
  

对于“x”,数组中数据点的每个索引都乘以一个常数整数70,使每个条的位置移动70。

y有一个常数y,我们很快就会改变。

宽度也有一个常数值65,小于图表中每个元素的位置,从而在每个元素之间创建一个空间。

条的高度取决于数据集中每个条目的值。

使用它,我们创建了一个条形图。然而,我们有两个问题:

  1. 图表中的条形图很小
  2. 图表也是倒过来的

为了解决上述问题,我们将每个数据乘以一个常量,比如10,以在不影响数据的情况下增加每个bar的大小:

.attr("height", (d, i) => d * 10)

条形图放大了,但仍然是倒置的

接下来,我们将解决柱状图被倒置的问题,但在此之前,我们先来理解为什么图表会被倒置。

SVG的位置从上到下开始,因此使用y属性0将每个条放到SVG元素的顶部边缘。

为了解决这个问题,我们用SVG元素的高度减去每个条的高度:

.attr("y", (d, i) => h - 10 * d)

其中(10 * d)是我们之前计算得到的高度。

综合起来,BarChart组件将是:

class BarChart extends Component {
  componentDidMount() {
    this.drawChart();
  }
    
  drawChart() {
    const data = [12, 5, 6, 6, 9, 10];
    
    const svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h)
    .style("margin-left", 100);
                  
    svg.selectAll("rect")
      .data(data)
      .enter()
      .append("rect")
      .attr("x", (d, i) => i * 70)
      .attr("y", (d, i) => h - 10 * d)
      .attr("width", 65)
      .attr("height", (d, i) => d * 10)
      .attr("fill", "green")
  }
        
  render(){
    return <div id={"#" + this.props.id}></div>
  }
}
    
export default BarChart;

Bar Chart in it’s glory

现在我们有了一个基本的条形图。我们再多做一点,添加标签。

向条形图添加标签

为了添加标签,我们在drawChart函数中添加了以下代码:

svg.selectAll("text")
  .data(data)
  .enter()
  .append("text")
  .text((d) => d)
  .attr("x", (d, i) => i * 70)
  .attr("y", (d, i) => h - (10 * d) - 3)
  

这与我们对这些条所做的类似,但是这次,text被追加。

条形图应该是这样的:

Bar Chart with Labels

构建可重用的柱状图

React的一个重要部分是使组件可重用。

为此,我们需要删除提供的数据,然后通过props将其传递给组件。

SVG的宽度和高度也将通过props传递:

const data = [12, 5, 6, 6, 9, 10];

变成:

const data = this.props.data;

宽度和高度属性由:

const svg = d3.select("body").append("svg").attr("width", 700).attr("height", 300);

变成:

const svg = d3.select("body").append("svg")
  .attr("width", this.props.width)
  .attr("height", this.props.height);
  

在App.js文件中,我们现在可以使用组件并从父组件传递我们想要的数据:

class App extends Component {
  
  state = {
    data: [12, 5, 6, 6, 9, 10],
    width: 700,
    height: 500,
    id: root
  }

  render() {
    return (
      <div className="App">
        <BarChart data={this.state.data} width={this.state.width} height={this.state.height} />
      </div>
    );
  }
}

这样,我们可以在我们的React应用程序中任意地方重用条形图。

感谢!!!!!!!

翻译自:https://blog.logrocket.com/data-visualization-in-react-using-react-d3-c35835af16d0

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342