闪闪发亮的小猪
需要读完
17 号
分钟
仅需6分钟速读
/ 使用 Apache ECharts 可视化 Neo4j 图形数据/
除了使用Neo4j Browser和Neo4j Bloom来展示Neo4j查询结果之外,还有很多第三方可视化工具可以用来展示图数据。
今天给大家简单演示一下在Apache ECharts中展示Neo4j数据库中的数据。
什么是电子图表
ECharts是Apache的开源项目,由百度开发并捐赠给Apache开源软件基金会。 ECharts 是一个基于 JavaScript 的开源可视化图表库。
除了提供常规的折线图、柱状图、饼图等之外,ECharts 将重点关注今天提供的关系图。 您可以在示例网站上看到以下示例:
如何使用ECharts(以及后端可视化工具)
用 JavaScript 实现的可视化工具被广泛使用,因为它们几乎总是在 Web 和移动设备上可用,甚至可以通过嵌入集成到本机客户端应用程序中。
2.1
全栈系统架构
在开始之前,我们先来了解一下这类可视化工具在我们整个软件系统中的地位。 如果你是新手或者没有全栈经验,也可以从右图了解系统架构。
当用户需要查看我们的可视化图表时,用户需要通过浏览器访问我们的后端网页。 ECharts是一个运行在后端网页上的可视化框架。
我们知道“数据可视化”是一个完整的词,可视化就是数据。 ECharts需要指定格式的数据才能显示直观的图表。 该数据由前端API层提供。
后端API可以看作是通过业务逻辑层进行处理,而我们将业务数据存储在数据库层,例如Neo4j数据库实例。
所以当我们要做一个可视化应用的时候,就需要了解整个流程。 即使这条线可能由不同的团队实现,你也将能够与不同的团队更好地沟通。
2.2
ECharts 入门
ECharts是以JS库的形式分发的,我们只需要把js文件导入到后端页面就可以了:
然后在页面上创建占位符节点,用于显示ECharts图表:
接下来可以配置ECharts如何显示和使用数据,就可以看到图表了:
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
可以看到,具体的数据是串联存储的,然后将整个选项赋值给ECharts实例,根据配置就可以显示对应的图表。 这部分可以在ECharts官方文档中找到详细的介绍。
接下来我们详细看一下明天关系图的反例。
ECharts图表配置
我们通过官网的例子来学习一下如何规划关系图的数据。
打开示例后,我们可以看到如图所示的编辑器。 通过编辑左边的JS代码,我们可以实时看到疗效。 此时建议使用少量数据来熟悉ECharts所需的格式。 上图中使用的代码如下:
option = {
series: [
{
type: 'graph',
layout: 'force',
roam: true,
data: [
{
"name": "The Matrix"
},
{
"name": "Carrie-Anne Moss"
},
{
"name": "Emil Eifrem"
}
],
links: [
{
"source": 1,
"target": 0
},
{
"source": 2,
"target": 0
}
],
categories: []
}
]
};
myChart.setOption(option);
如果您想了解各项的含义,可以访问ECharts官网的文档>配置项指南进行详细了解。
要显示关系图,需要将type设置为graph,然后有两个重要的配置项:数据(或节点)和链接(或边),类别用于表示节点的不同类别。
另外,我们可以看到节点的数据项包含name属性,链接的数据项使用source和target来指示关系的方向。
那么,如何将Neo4j查询的数据转换成这些格式呢?
数据一览
让我们以电影数据集为例,并在 Neo4j 中使用此查询:
MATCH path=(m:Movie)<-[r]-(p:Person)
WHERE m.title = 'The Matrix'
RETURN path
这是Neo4j浏览器显示的图片。 从ECharts里面的配置我们知道我们需要将数据封装成不同的格式。
现在让我们通过后端访问数据库。
全栈应用概述
我使用 ASP.NET Core 来开发这个应用程序。 NET目前是一个跨平台的框架,我已经使用它十多年了。 这里使用MVC模式来实现后端和业务层,使用Repository模式来实现数据库访问。
具体开发项目配置可以参考GitHub上的代码库。
ECharts介绍和配置的代码位于wwwroot/echarts.html。
为ECharts提供数据的API代码位于Controllers/MoviesController.cs。
从Neo4j数据库获取数据是通过Neo4j官方的.NET Client Driver实现的,这部分代码在Repositories/MovieRepository.cs中。
Neo4j数据库实例我使用AuraDB的免费版。 注册后即可无缝使用,免去运维和配置的后顾之忧。
准备数据
我们知道ECharts关系图需要将节点和关系分成两组,因此我们需要对Cypher查询进行一些更新:
MATCH path=(m:Movie)<-[r]-(p:Person)
WHERE m.title ='The Matrix'
RETURN m.title as title, collect(p.name) as cast
我们按电影分组并将角色的名字作为一个集合返回,这样我们就可以在 2 个数组中看到该数据。
这一步需要在我们的应用程序中实现,这里是使用.NET Driver来做到这一点,部分代码如下:
public async Task FetchEChartsGraph(int limit)
{
var session = _driver.AsyncSession(WithDatabase);
try
{
return await session.ReadTransactionAsync(async transaction =>
{
var cursor = await transaction.RunAsync(@"
MATCH path=(m:Movie)<-[r]-(p:Person)
WHERE m.title = 'The Matrix'
RETURN m.title AS title, collect(p.name) AS cast
LIMIT $limit",
new {limit});
var nodes = new List();
var links = new List();
var records = await cursor.ToListAsync();
foreach (var record in records){
var movie = new EChartsNode{Name=record["title"].As()};
var movieIndex = nodes.IndexOf(movie);
movieIndex = movieIndex == -1 ? nodes.Count : movieIndex;
if(!nodes.Exists(m => m.Name == movie.Name))
nodes.Add(movie);
foreach (var actorName in record["cast"].As<IList>()){
var actor = new EChartsNode{Name=actorName, Value=1, Category=1};
var actorIndex = nodes.IndexOf(actor);
actorIndex = actorIndex == -1 ? nodes.Count : actorIndex;
if(!nodes.Exists(a => a.Name == actor.Name))
nodes.Add(actor);
links.Add(new EChartsLink{Source=actorIndex, Target=movieIndex});
}
}
return new EChartsGraph(nodes, links, categories);
});
}
finally
{
await session.CloseAsync();
}
}
这部分代码精简了。 具体逻辑是通过Driver连接Neo4j数据库,然后在事务中运行Cypher语句,然后解析Cypher结果。 这里我构建了一个EChartsGraph类来表示需要封装的数据,其中包含EChartsNode。 EChartsLink用于表示节点和关系。
下一个逻辑是将数据封装到节点和链接集合中。 请注意echarts 构建,集合中不能有重复的名称echarts 构建,因此需要进行一些检测。
提供API
完成数据处理层的代码后,我们可以在API层通过Web API向ECharts提供REST接口。 API层的代码如下:
[Route("/echarts")]
[HttpGet]
public async Task FetchEChartsGraph([FromQuery(Name = "limit")] int limit = 100)
{
return await _movieRepository.FetchEChartsGraph(limit);
}
代码中的_movieRepository是数据层Repository的实例,直接调用获取数据的方法即可。
前端调用API
根据之前的配置,前端ECharts只读取固定数据。 我们需要调用后端的REST API,才能显示真实的数据。
此时的ECharts配置如下:
var myChart = echarts.init(document.getElementById("echarts"));
myChart.showLoading();
$.get("/echarts").done(function(graph){
myChart.hideLoading();
option = {
legend: {
data: ['Movie', 'Person']
},
series: [
{
type: 'graph',
layout: 'force',
animation: true,
draggable: true,
roam: true,
selectedMode: true,
lineStyle: {
curveness: 0
},
emphasis: {
focus: 'adjacency',
lineStyle: {
width: 5
}
},
force: {
repulsion: 50
},
nodes: graph.nodes,
links: graph.links,
categories: graph.categories
}
]
};
myChart.setOption(option);
})
这里我使用了另一个JS框架jQuery,它提供了一个非常简单的方法来调用Web API。
然后将数据从服务器传递到节点和链路,从而完成真实数据的连接。
你有这样的感觉吗?