D3高级图形绘制

数据的海洋汹涌澎湃,其中有着不可计数的线索和彩虹。若要在波涛中捕捉这些光影,高级的图形绘制技术便是必备的舟桨。D3提供了强大的工具,以灵巧的指尖操纵数据,用精细的图形展现出来。这里,将介绍D3高级图形的绘制方法,为阅读者揭开绘画数据图谱的另一幅画卷。

力导向图(Force-Directed Graph)

力导向图是表现复杂关系网的理想选择,每个节点彼此吸引或排斥,形成一个动态的交互系统。

javascript 复制代码
var nodes_data = [
  {id: 'node1'}, {id: 'node2'}, {id: 'node3'}
];

var links_data = [
  {source: 'node1', target: 'node2'},
  {source: 'node2', target: 'node3'}
];

var simulation = d3.forceSimulation(nodes_data)
  .force('charge', d3.forceManyBody())
  .force('center', d3.forceCenter(150, 150))
  .force('link', d3.forceLink(links_data).id(d => d.id));

simulation.on('tick', function() {
  d3.select('svg')
    .selectAll('line')
    .data(links_data)
    .enter()
    .append('line')
    .attr('x1', d => d.source.x)
    .attr('y1', d => d.source.y)
    .attr('x2', d => d.target.x)
    .attr('y2', d => d.target.y);
});

此代码段使用D3力导向模拟器创建了节点间的吸引与排斥,绘制出了节点与连接线。

树图(Tree Graph)

树图能够体现层级数据的结构,让每一支数据枝节尽收眼底。

javascript 复制代码
var treeData = {
  name: "Root",
  children: [
    {name: "Branch1"},
    {name: "Branch2"}
  ]
};

var treeLayout = d3.tree().size([400, 200]);

var root = d3.hierarchy(treeData);
treeLayout(root);

var nodes = root.descendants();
var links = root.links();

d3.select('svg')
  .selectAll('.node')
  .data(nodes)
  .enter().append('circle')
  .classed('node', true)
  .attr('r', 5)
  .attr('cx', d => d.x)
  .attr('cy', d => d.y);

d3.select('svg')
  .selectAll('.link')
  .data(links)
  .enter().append('line')
  .classed('link', true)
  .attr('x1', d => d.source.x)
  .attr('y1', d => d.source.y)
  .attr('x2', d => d.target.x)
  .attr('y2', d => d.target.y);

上述代码构建了树图的布局,并绘制了节点及其连线。

地图绘制(Maps)

D3能够通过地理数据生成极其精确的地图,为乏味的数字赋予所在之地的生气。

javascript 复制代码
var projection = d3.geoMercator().center([107, 31]).scale(400);
var pathGenerator = d3.geoPath().projection(projection);

d3.json("china.geojson", function(error, data) {
  d3.select('svg')
    .selectAll('path')
    .data(data.features)
    .enter()
    .append('path')
    .attr('d', pathGenerator)
    .attr('fill', 'lightgrey')
    .attr('stroke', 'white');
});

在该段代码中,引用的地图数据文件 china.geojson 提供了地理信息,D3利用这些信息为每个行政区绘制了边界。

饼图(Pie Chart)

将饼图的各个切片着色,能够迅速传递部分与整体的关系。

javascript 复制代码
var pieData = [1, 2, 3, 4];

var pieGenerator = d3.pie();
var arc = d3.arc().innerRadius(0).outerRadius(100);

d3.select('svg')
  .selectAll('path')
  .data(pieGenerator(pieData))
  .enter()
  .append('path')
  .attr('d', arc)
  .attr('transform', 'translate(150,150)')
  .attr('fill', (d, i) => d3.schemeCategory10[i]);

此代码绘制了一个四色饼图,每个切片的大小与数据成比例。

堆叠图(Stacked Chart)

堆叠图将不同组的数据堆积起来,直观展现各部分之间的量度关系。

javascript 复制代码
var stackData = [
  {month: 'Jan', apples: 10, oranges: 5},
  {month: 'Feb', apples: 15, oranges: 10},
  {month: 'Mar', apples: 12, oranges: 8}
];

var stack = d3.stack().keys(['apples', 'oranges']);
var series = stack(stackData);

var color = d3.scaleOrdinal(d3.schemeCategory10);

d3.select('svg')
  .selectAll('g.series')
  .data(series)
  .enter().append('g')
  .classed('series', true)
  .style('fill', (d, i) => color(i))
  .selectAll('rect')
  .data(d => d)
  .enter().append('rect')
  .attr('x', d => xScale(d.data.month))
  .attr('y', d => yScale(d[1]))
  .attr('height', d => yScale(d[0]) - yScale(d[1]))
  .attr('width', xScale.bandwidth());

在此例中,每个月的苹果和橙子销量数据被顺序堆叠在一起,构成堆叠图的每一层。

散点图(Scatter Plot)

散点图通过标点在坐标轴上的位置,展示变量之间的关系。

javascript 复制代码
var scatterData = [{x: 30, y: 30}, {x: 70, y: 70}, {x: 110, y: 100}];

var xScale = d3.scaleLinear().domain([0, 130]).range([0, 400]);
var yScale = d3.scaleLinear().domain([0, 130]).range([400, 0]);

d3.select('svg')
  .selectAll('circle')
  .data(scatterData)
  .enter().append('circle')
  .attr('cx', d => xScale(d.x))
  .attr('cy', d => yScale(d.y))
  .attr('r', 5)
  .attr('fill', 'tomato');

这些标点的位置揭示了x和y两变量之间的相互作用。

热力图(Heatmap)

热力图以颜色的深浅来显示数值大小,使得数据热点一目了然。

javascript 复制代码
var heatmapData = [
  { day: 1, hour: 1, value: 10},
  { day: 2, hour: 1, value: 58},
  { day: 1, hour: 2, value: 30}
];

var colorScale = d3.scaleSequential(d3.interpolateInferno)
  .domain(d3.extent(heatmapData, d => d.value));

d3.select('svg')
  .selectAll('rect')
  .data(heatmapData)
  .enter().append('rect')
  .attr('x', d => xScale(d.hour))
  .attr('y', d => yScale(d.day))
  .attr('width', xScale.bandwidth())
  .attr('height', yScale.bandwidth())
  .attr('fill', d => colorScale(d.value));

热力图使热度如同火焰一般跃然纸上,暗藏的规律随之浮出水面。

箱线图(Boxplot)

箱线图展示了数据的分布情况,将中位数、四分位数及极值一览无余。

javascript 复制代码
var boxplotData = [10, 20, 30, 40, 50];

var chartWidth = 400, chartHeight = 400;

var y = d3.scaleLinear()
  .domain([0, 60])
  .range([chartHeight, 0]);

var boxplot = d3.box()
  .whiskers(iqr(1.5))
  .height(chartHeight)
  .domain(y.domain());

d3.select('svg')
  .data([boxplotData])
  .append('g')
  .call(boxplot);

此例中的箱线图利用四分位距规则界定了数据的主要离散范围。

矩阵布局(Treemap)

矩阵布局利用了空间,让数据的大小关系在几何形状的差异中表现出来。

javascript 复制代码
var treemapData = {
  "name": "Root",
  "children": [
    {"name": "Leaf A", "value": 30},
    {"name": "Leaf B", "value": 20},
    {"name": "Leaf C", "value": 50}
  ]
};

var treemapLayout = d3.treemap().size([400, 200]);

var root = d3.hierarchy(treemapData)
  .sum(d => d.value);

treemapLayout(root);

d3.select('svg')
  .selectAll('rect')
  .data(root.leaves())
  .enter().append('rect')
  .attr('x', d => d.x0)
  .attr('y', d => d.y0)
  .attr('width', d => d.x1 - d.x0)
  .attr('height', d => d.y1 - d.y0)
  .attr('fill', 'steelblue');

通过矩阵布局,每个叶子节点的面积与其数值成正比。

当数据遇见技术,便有了色彩斑斓的缤纷世界;而编织这幅图画的绘师,在数据的海洋中翱翔,用技术的羽翼折射出数据的鲜活与与众不同。高级图形绘制在D3的笔触之下,不再是简单的线条与色彩探索,而是深入数据的内在意义,从而描绘出让人心悦的数据风景画。

相关推荐
laocooon52385788619 分钟前
HTML CSS 超链
前端·css·html
LUwantAC22 分钟前
CSS(二):美化网页元素
前端·css
素**颜32 分钟前
uniapp 基于xgplayer(西瓜视频) + renderjs开发,实现APP视频播放
javascript·uni-app·音视频
m0_7482510833 分钟前
docker安装nginx,docker部署vue前端,以及docker部署java的jar部署
java·前端·docker
我是ed1 小时前
# thingjs 基础案例整理
前端
Ashore_1 小时前
从简单封装到数据响应:Vue如何引领开发新模式❓❗️
前端·vue.js
落魄实习生1 小时前
小米路由器开启SSH,配置阿里云ddns,开启外网访问SSH和WEB管理界面
前端·阿里云·ssh
bug丸1 小时前
v8引擎垃圾回收
前端·javascript·垃圾回收
安全小王子1 小时前
攻防世界web第三题file_include
前端
&活在当下&1 小时前
ref 和 reactive 的用法和区别
前端·javascript·vue.js