如何将Python d3blocks弦图迁移至React/D3.js前端
解决方案:从d3blocks导出弦图数据并在React前端重构
方案一:导出核心JSON数据,用D3.js在React中重构(推荐)
d3blocks生成的弦图本质基于D3.js,核心依赖**节点(nodes)和链接(links)**数据。我们可以直接从Python端提取这些数据并导出为JSON,再在React中用D3.js重新渲染,完全摆脱iframe的限制。
1. Python端提取并导出JSON数据
修改你的Python代码,从d3_c对象中提取弦图的核心数据并保存为JSON文件:
from d3blocks import D3Blocks import json d3 = D3Blocks() df = d3.import_example('energy') # 生成弦图但不保存HTML d3_c = d3.chord(df, showfig=False, filepath=None) # 提取节点和链接数据,转为字典格式 chord_data = { "nodes": d3_c.nodes.to_dict('records'), # 包含节点名称、颜色等信息 "links": d3_c.links.to_dict('records') # 包含源节点、目标节点、数值等信息 } # 保存为JSON文件 with open('chord_data.json', 'w', encoding='utf-8') as f: json.dump(chord_data, f, indent=2, ensure_ascii=False)
2. React前端用D3.js渲染弦图
首先在React项目中安装D3依赖:
npm install d3
然后创建一个可复用的弦图组件ChordDiagram.jsx:
import React, { useEffect, useRef } from 'react'; import * as d3 from 'd3'; const ChordDiagram = ({ data }) => { const svgRef = useRef(); useEffect(() => { if (!data) return; // 清除旧图表内容 d3.select(svgRef.current).selectAll('*').remove(); // 图表尺寸配置 const width = 600; const height = 600; const outerRadius = Math.min(width, height) * 0.5 - 40; const innerRadius = outerRadius - 30; // 创建SVG容器 const svg = d3.select(svgRef.current) .attr('width', width) .attr('height', height) .append('g') .attr('transform', `translate(${width/2}, ${height/2})`); // 初始化D3弦图布局 const chord = d3.chord() .padAngle(0.05) .sortSubgroups(d3.descending); const arc = d3.arc() .innerRadius(innerRadius) .outerRadius(outerRadius); const ribbon = d3.ribbon() .radius(innerRadius); // 构建D3弦图需要的矩阵数据 const nodeNames = data.nodes.map(n => n.name); const nodeColorMap = new Map(data.nodes.map(n => [n.name, n.color])); const matrix = Array.from({ length: nodeNames.length }, () => Array(nodeNames.length).fill(0)); data.links.forEach(link => { const sourceIdx = nodeNames.indexOf(link.source); const targetIdx = nodeNames.indexOf(link.target); matrix[sourceIdx][targetIdx] = link.value; matrix[targetIdx][sourceIdx] = link.value; // 弦图默认双向,按需调整 }); const chords = chord(matrix); // 绘制分组弧(外圈) const group = svg.append('g') .selectAll('g') .data(chords.groups) .join('g'); group.append('path') .style('fill', d => nodeColorMap.get(nodeNames[d.index])) .style('stroke', d => nodeColorMap.get(nodeNames[d.index])) .attr('d', arc); // 绘制节点标签 group.append('text') .each(d => { d.angle = (d.startAngle + d.endAngle) / 2; }) .attr('dy', '.35em') .attr('transform', d => ` rotate(${(d.angle * 180 / Math.PI - 90)}) translate(${outerRadius + 10}) ${d.angle > Math.PI ? 'rotate(180)' : ''} `) .style('text-anchor', d => d.angle > Math.PI ? 'end' : 'start') .text(d => nodeNames[d.index]); // 绘制弦带(内圈连接) svg.append('g') .attr('fill-opacity', 0.67) .selectAll('path') .data(chords) .join('path') .style('fill', d => nodeColorMap.get(nodeNames[d.source.index])) .style('stroke', d => d3.color(nodeColorMap.get(nodeNames[d.source.index])).darker()) .attr('d', ribbon); }, [data]); return <svg ref={svgRef}></svg>; }; export default ChordDiagram;
最后在父组件中导入JSON数据并使用该组件:
import ChordDiagram from './ChordDiagram'; import chordData from './chord_data.json'; function App() { return ( <div className="App"> <ChordDiagram data={chordData} /> </div> ); } export default App;
方案二:复用d3blocks生成的JS代码片段
如果想直接复用d3blocks的渲染逻辑,可以先导出HTML文件:
d3_c = d3.chord(df, showfig=False, filepath='chord.html')
打开生成的chord.html,提取其中<script>标签内的渲染代码,将其改造为React的useEffect钩子逻辑(类似方案一的结构),这样可以保留d3blocks默认的样式和交互配置。
内容的提问来源于stack exchange,提问作者ntg
相关产品推荐
相关产品推荐

