「數據可視化 D3系列」入門第十一章:力導向圖深度解析與實現

D3.js 力導向圖深度解析與實現

力導向圖核心概念

力導向圖是一種通過物理模擬來展示復雜關系網絡的圖表類型,特別適合表現社交網絡、知識圖譜、系統拓撲等關系型數據。其核心原理是通過模擬粒子間的物理作用力(電荷斥力、彈簧引力等)自動計算節點的最優布局。

核心API詳解

1. 力模擬系統

const simulation = d3.forceSimulation(nodes).force("charge", d3.forceManyBody().strength(-100)) // 節點間作用力.force("link", d3.forceLink(links).id(d => d.id))   // 連接線作用力.force("center", d3.forceCenter(width/2, height/2)) // 向心力.force("collision", d3.forceCollide().radius(20));  // 碰撞檢測

2. 關鍵作用力類型

力類型作用描述常用配置方法
forceManyBody節點間電荷力(正為引力,負為斥力).strength()
forceLink連接線彈簧力.distance().id().strength()
forceCenter向中心點的引力.x().y()
forceCollide防止節點重疊的碰撞力.radius().strength()
forceX/Y沿X/Y軸方向的定位力.strength().x()/.y()

3. 動態控制方法

simulation.alpha(0.3)        // 設置當前alpha值(0-1).alphaTarget(0.1)  // 設置目標alpha值.alphaDecay(0.02)  // 設置衰減率(默認0.0228).velocityDecay(0.4)// 設置速度衰減(0-1).restart()         // 重啟模擬.stop()            // 停止模擬.tick()            // 手動推進模擬一步

增強版力導向圖實現

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>高級力導向圖</title><script src="https://d3js.org/d3.v5.min.js"></script><style>.node {stroke: #fff;stroke-width: 1.5px;}.link {stroke: #999;stroke-opacity: 0.6;}.link-text {font-size: 10px;fill: #333;pointer-events: none;}.node-text {font-size: 12px;font-weight: bold;pointer-events: none;}.tooltip {position: absolute;padding: 8px;background: rgba(0,0,0,0.8);color: white;border-radius: 4px;pointer-events: none;font-size: 12px;}</style>
</head>
<body><div class="controls"><button id="reset">重置布局</button><button id="addNode">添加節點</button><span>斥力強度: <input type="range" id="charge" min="-200" max="0" value="-100"></span></div><svg width="800" height="600"></svg><div class="tooltip"></div><script>// 配置參數const config = {margin: {top: 20, right: 20, bottom: 20, left: 20},nodeRadius: 12,linkDistance: 150,chargeStrength: -100,collisionRadius: 20};// 數據準備const nodes = [{id: 0, name: "湖南邵陽", type: "location"},{id: 1, name: "山東萊州", type: "location"},{id: 2, name: "廣東陽江", type: "location"},{id: 3, name: "山東棗莊", type: "location"},{id: 4, name: "趙麗澤", type: "person"},{id: 5, name: "王恒", type: "person"},{id: 6, name: "張欣鑫", type: "person"},{id: 7, name: "趙明山", type: "person"},{id: 8, name: "班長", type: "role"}];const links = [{source: 0, target: 4, relation: "籍貫", value: 1.3},{source: 4, target: 5, relation: "舍友", value: 1},{source: 4, target: 6, relation: "舍友", value: 1},{source: 4, target: 7, relation: "舍友", value: 1},{source: 1, target: 6, relation: "籍貫", value: 2},{source: 2, target: 5, relation: "籍貫", value: 0.9},{source: 3, target: 7, relation: "籍貫", value: 1},{source: 5, target: 6, relation: "同學", value: 1.6},{source: 6, target: 7, relation: "朋友", value: 0.7},{source: 6, target: 8, relation: "職責", value: 2}];// 初始化SVGconst svg = d3.select('svg');const width = +svg.attr('width');const height = +svg.attr('height');const tooltip = d3.select('.tooltip');// 創建畫布const g = svg.append('g').attr('transform', `translate(${config.margin.left}, ${config.margin.top})`);// 顏色比例尺const colorScale = d3.scaleOrdinal().domain(['location', 'person', 'role']).range(['#66c2a5', '#fc8d62', '#8da0cb']);// 創建力導向圖模擬const simulation = d3.forceSimulation(nodes).force("link", d3.forceLink(links).id(d => d.id).force("charge", d3.forceManyBody().strength(config.chargeStrength)).force("center", d3.forceCenter(width/2, height/2)).force("collision", d3.forceCollide(config.collisionRadius)).force("x", d3.forceX(width/2).strength(0.05)).force("y", d3.forceY(height/2).strength(0.05));// 創建連接線const link = g.append('g').selectAll('.link').data(links).enter().append('line').attr('class', 'link').attr('stroke-width', d => Math.sqrt(d.value));// 創建連接線文字const linkText = g.append('g').selectAll('.link-text').data(links).enter().append('text').attr('class', 'link-text').text(d => d.relation);// 創建節點組const node = g.append('g').selectAll('.node').data(nodes).enter().append('g').attr('class', 'node').call(d3.drag().on('start', dragStarted).on('drag', dragged).on('end', dragEnded)).on('mouseover', showTooltip).on('mouseout', hideTooltip);// 添加節點圓形node.append('circle').attr('r', config.nodeRadius).attr('fill', d => colorScale(d.type)).attr('stroke-width', 2);// 添加節點文字node.append('text').attr('class', 'node-text').attr('dy', 4).text(d => d.name);// 模擬tick事件處理simulation.on('tick', () => {link.attr('x1', d => d.source.x).attr('y1', d => d.source.y).attr('x2', d => d.target.x).attr('y2', d => d.target.y);linkText.attr('x', d => (d.source.x + d.target.x)/2).attr('y', d => (d.source.y + d.target.y)/2);node.attr('transform', d => `translate(${d.x},${d.y})`);});// 拖拽事件處理function dragStarted(d) {if (!d3.event.active) simulation.alphaTarget(0.3).restart();d.fx = d.x;d.fy = d.y;}function dragged(d) {d.fx = d3.event.x;d.fy = d3.event.y;}function dragEnded(d) {if (!d3.event.active) simulation.alphaTarget(0);d.fx = null;d.fy = null;}// 工具提示function showTooltip(d) {tooltip.transition().duration(200).style('opacity', 0.9);tooltip.html(`<strong>${d.name}</strong><br/>類型: ${d.type}`).style('left', (d3.event.pageX + 10) + 'px').style('top', (d3.event.pageY - 28) + 'px');// 高亮相關節點和連接線node.select('circle').attr('opacity', 0.2);d3.select(this).select('circle').attr('opacity', 1);link.attr('stroke-opacity', 0.1);link.filter(l => l.source === d || l.target === d).attr('stroke-opacity', 0.8).attr('stroke', '#ff0000');}function hideTooltip() {tooltip.transition().duration(500).style('opacity', 0);// 恢復所有元素樣式node.select('circle').attr('opacity', 1);link.attr('stroke-opacity', 0.6).attr('stroke', '#999');}// 交互控制d3.select('#reset').on('click', () => {simulation.alpha(1).restart();nodes.forEach(d => {d.fx = null;d.fy = null;});});d3.select('#addNode').on('click', () => {const newNode = {id: nodes.length,name: `新節點${nodes.length}`,type: ['location', 'person', 'role'][Math.floor(Math.random()*3)]};nodes.push(newNode);// 隨機連接到現有節點if (nodes.length > 1) {const randomTarget = Math.floor(Math.random() * (nodes.length - 1));links.push({source: newNode.id,target: randomTarget,relation: ['連接', '關系', '關聯'][Math.floor(Math.random()*3)],value: Math.random() * 2 + 0.5});}// 更新模擬simulation.nodes(nodes);simulation.force('link').links(links);// 重新繪制元素updateGraph();});d3.select('#charge').on('input', function() {simulation.force('charge').strength(+this.value);simulation.alpha(0.3).restart();});// 更新圖形函數function updateGraph() {// 更新連接線const newLinks = link.data(links).enter().append('line').attr('class', 'link').attr('stroke-width', d => Math.sqrt(d.value));link.merge(newLinks);// 更新連接線文字const newLinkText = linkText.data(links).enter().append('text').attr('class', 'link-text').text(d => d.relation);linkText.merge(newLinkText);// 更新節點const newNode = node.data(nodes).enter().append('g').attr('class', 'node').call(d3.drag().on('start', dragStarted).on('drag', dragged).on('end', dragEnded)).on('mouseover', showTooltip).on('mouseout', hideTooltip);newNode.append('circle').attr('r', config.nodeRadius).attr('fill', d => colorScale(d.type)).attr('stroke-width', 2);newNode.append('text').attr('class', 'node-text').attr('dy', 4).text(d => d.name);node.merge(newNode);simulation.alpha(1).restart();}
</script>
</body>
</html>

本章小結

核心實現要點

  1. 力模擬系統構建

    • 多力組合實現復雜布局(電荷力+彈簧力+向心力+碰撞力)
    • 參數調優實現不同視覺效果
  2. 動態交互體系

    • 拖拽行為與物理模擬的協調
    • 動態alpha值控制模擬過程
    • 實時tick更新機制
  3. 可視化增強

    • 基于類型的顏色編碼
    • 交互式高亮關聯元素
    • 動態工具提示顯示

高級特性實現

  1. 動態數據更新

    • 節點/連接的實時添加
    • 模擬系統的熱更新
  2. 交互控制面板

    • 力參數實時調節
    • 布局重置功能
  3. 視覺優化

    • 智能碰撞檢測
    • 連接線權重可視化
    • 焦點元素高亮

下章預告:地圖可視化

在下一章中,我們將探索:

  1. 地理數據基礎

    • GeoJSON/TopoJSON格式解析
    • 地理投影原理與應用
  2. 核心API

    • d3.geoPath() 地理路徑生成器
    • d3.geoProjection() 投影系統
    • d3.zoom() 地圖縮放行為
  3. 高級技術

    • 分級統計圖(Choropleth)實現
    • 氣泡地圖疊加
    • 地圖交互與鉆取
  4. 性能優化

    • 大數據量地圖渲染
    • 拓撲簡化技術
    • 動態加載策略

通過地圖可視化的學習,您將掌握D3.js處理地理空間數據的能力,能夠創建交互式的地圖數據可視化應用。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79435.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79435.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79435.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

音頻格式轉換

1. 下載ffmpeg https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-7.1.1-full_build.7z 2. 配置ffmpeg環境變量 3.安裝pydub pip install pydub 4.編寫轉化工具代碼 from pydub import AudioSegment def convertM4aToWav(m4a,wav):sound AudioSegment.from_file(m4a, f…

基于spring boot 集成 deepseek 流式輸出 的vue3使用指南

本文使用deepseek API接口流式輸出的文章。 環境要求 jdk17 spring boot 3.4 代碼如下: package com.example.controller;import jakarta.annotation.PostConstruct; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.mes…

微博輻射源和干擾機

微波輻射源和干擾機是電子戰和通信領域中的兩個重要概念&#xff0c;它們在軍事、民用及科研中具有廣泛應用。以下是兩者的詳細解析及其相互關系&#xff1a; ?1. 微波輻射源? ?定義?&#xff1a; 微波輻射源是指能夠主動發射微波&#xff08;頻率范圍通常為 ?300 MHz&…

2025年4月16日華為留學生筆試第三題300分

?? 點擊直達筆試專欄 ??《大廠筆試突圍》 ?? 春秋招筆試突圍在線OJ ?? 筆試突圍OJ 03. 智慧城市網絡優化 問題描述 K小姐是一家智慧城市服務提供商的網絡架構師。她負責規劃城市邊緣計算節點的布局,以提供更快速、穩定的網絡服務。 城市內有 n n

多線程編程的簡單案例——單例模式[多線程編程篇(3)]

目錄 前言 1.wati() 和 notify() wait() 和 notify() 的產生原因 如何使用wait()和notify()? 案例一:單例模式 餓漢式寫法: 懶漢式寫法 對于它的優化 再次優化 結尾 前言 如何簡單的去使用jconsloe 查看線程 (多線程編程篇1)_eclipse查看線程-CSDN博客 淺談Thread類…

pytorch基本操作2

torch.clamp 主要用于對張量中的元素進行截斷&#xff08;clamping&#xff09;&#xff0c;將其限制在一個指定的區間范圍內。 函數定義 torch.clamp(input, minNone, maxNone) → Tensor 參數說明 input 類型&#xff1a;Tensor 需要進行截斷操作的輸入張…

一次制作參考網雜志的閱讀書源的實操經驗總結(附書源)

文章目錄 一、背景介紹二、書源文件三、詳解制作書源&#xff08;一&#xff09;打開Web服務&#xff08;二&#xff09;參考網結構解釋&#xff08;三&#xff09;閱讀書源 基礎&#xff08;四&#xff09;閱讀書源 發現&#xff08;五&#xff09;閱讀書源 詳細&#xff08;六…

并發設計模式實戰系列(2):領導者/追隨者模式

&#x1f31f; ?大家好&#xff0c;我是摘星&#xff01;? &#x1f31f; 今天為大家帶來的是并發設計模式實戰系列&#xff0c;第二章領導者/追隨者&#xff08;Leader/Followers&#xff09;模式&#xff0c;廢話不多說直接開始~ 目錄 領導者/追隨者&#xff08;Leader/…

自求導實現線性回歸與PyTorch張量詳解

目錄 前言一、自求導的方法實現線性回歸1.1自求導的方法實現線性回歸的理論講解1.1.1 線性回歸是什么&#xff1f;1.1.2線性回歸方程是什么&#xff1f;1.1.3散點輸入1.2參數初始化1.2.1 參數與超參數1.2.1.1 參數定義1.2.1.2 參數內容1.2.1.3 超參數定義1.2.1.4 超參數內容1.…

2025年機電一體化、機器人與人工智能國際學術會議(MRAI 2025)

重要信息 時間&#xff1a;2025年4月25日-27日 地點&#xff1a;中國濟南 官網&#xff1a;http://www.icmrai.org 征稿主題 機電一體化機器人人工智能 傳感器和執行器 3D打印技術 智能控制 運動控制 光電系統 光機電一體化 類人機器人 人機界面 先進的運動控制 集成制造系…

線性代數 | 知識點整理 Ref 3

注&#xff1a;本文為 “線性代數 | 知識點整理” 相關文章合輯。 因 csdn 篇幅合并超限分篇連載&#xff0c;本篇為 Ref 3。 略作重排&#xff0c;未整理去重。 圖片清晰度限于引文原狀。 如有內容異常&#xff0c;請看原文。 《線性代數》總復習要點、公式、重要結論與重點釋…

CFD中的動量方程非守恒形式詳解

在計算流體力學&#xff08;CFD&#xff09;中&#xff0c;動量方程可以寫成守恒形式和非守恒形式&#xff0c;兩者在數學上等價&#xff0c;但推導方式和應用場景不同。以下是對非守恒形式的詳細解釋&#xff1a; 1. 動量方程的守恒形式 首先回顧守恒形式的動量方程&#xff…

Leetcode 1504. 統計全 1 子矩形

1.題目基本信息 1.1.題目描述 給你一個 m x n 的二進制矩陣 mat &#xff0c;請你返回有多少個 子矩形 的元素全部都是 1 。 1.2.題目地址 https://leetcode.cn/problems/count-submatrices-with-all-ones/description/ 2.解題方法 2.1.解題思路 單調棧 時間復雜度&…

【Docker】運行錯誤提示 unknown shorthand flag: ‘d‘ in -d ----詳細解決方法

使用docker拉取Dify的時候遇到錯誤 錯誤提示 unknown shorthand flag: d in -dUsage: docker [OPTIONS] COMMAND [ARG...]錯誤原因解析 出現 unknown shorthand flag: d in -d 的根本原因是 Docker 命令格式與當前版本不兼容&#xff0c;具體分為以下兩種情況&#xff1a; 新…

華為OD機試真題——攀登者2(2025A卷:200分)Java/python/JavaScript/C++/C語言/GO六種最佳實現

2025 A卷 200分 題型 本文涵蓋詳細的問題分析、解題思路、代碼實現、代碼詳解、測試用例以及綜合分析&#xff1b; 并提供Java、python、JavaScript、C、C語言、GO六種語言的最佳實現方式&#xff01; 2025華為OD真題目錄全流程解析/備考攻略/經驗分享 華為OD機試真題《攀登者2…

qt硬件與軟件通信中 16進制與十進制轉化

1. 首先上代碼, 這是在qt語言上的操作 截取 01 03 0C 00 00 00 00 00 00 00 0C 00 0C 00 0C 93 70 這串16進制數值進行處理&#xff0c;截取這樣一段內容 00 0C 00 0C 00 0C 字節數組轉字符串。從bytearray數組轉換為string. QString CustomTcpSocket::recieveInfo() {QByteArr…

圖形變換算法

一、學習目的 &#xff08;1&#xff09;掌握多面體的存儲方法。 &#xff08;2&#xff09;掌握圖形的幾何變換及投影變換。 &#xff08;3&#xff09;掌握三維形體不同投影方法的投影圖的生成原理。 &#xff08;4&#xff09;掌握多面體投影圖繪制的編程方法。 二、學…

【JAVAFX】自定義FXML 文件存放的位置以及使用

情況 1&#xff1a;FXML 文件與調用類在同一個包中&#xff08;推薦&#xff09; 假設類 MainApp 的包是 com.example&#xff0c;且 FXML 文件放在 resources/com/example 下&#xff1a; 項目根目錄 ├── src │ └── sample │ └── Main.java ├── src/s…

Ubuntu20.04安裝企業微信

建議先去企業微信官網看一下有沒有linux版本&#xff0c;沒有的話在按如下方式安裝&#xff0c;不過現在是沒有的。 方案 1、使用docker容器 2、使用deepin-wine 3、使用星火應用商店 4. 使用星火包deepin-wine 5、使用ukylin-wine 本人對docker不太熟悉&#xff0c;現…

CSS appearance 屬性:掌握UI元素的原生外觀

在現代網頁設計中&#xff0c;為了達到一致的用戶體驗&#xff0c;我們有時需要讓HTML元素模仿操作系統的默認控件樣式。CSS中的appearance屬性提供了一種簡便的方式來控制這些元素是否以及如何顯示其默認外觀。本文將詳細介紹appearance屬性&#xff0c;并通過實際代碼示例來展…