You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flask应用中如何在Plotly里使用D3层次边缘捆绑图

Hey there! I've implemented something similar before, so let me walk you through how to add a D3 hierarchical edge bundling visualization to your Flask + Plotly app. Since Plotly doesn't have a native hierarchical edge bundling trace, we'll integrate D3 directly into your Flask templates while keeping your existing Plotly charts intact.

Step 1: Prepare Hierarchical Data

First, you'll need nested hierarchical data (usually in JSON format) that represents your nodes and their parent-child relationships. Here's a simple example:

{
  "name": "Root",
  "children": [
    {
      "name": "Category A",
      "children": [{"name": "Item 1"}, {"name": "Item 2"}]
    },
    {
      "name": "Category B",
      "children": [{"name": "Item 3"}, {"name": "Item 4"}]
    }
  ]
}

Step 2: Pass Data from Flask to Template

Update your Flask route to serialize this data and pass it to your HTML template:

from flask import Flask, render_template
import json

app = Flask(__name__)

@app.route('/')
def dashboard():
    # Replace this with your actual hierarchical data
    hierarchy_data = {
        "name": "Root",
        "children": [
            {"name": "Category A", "children": [{"name": "Item 1"}, {"name": "Item 2"}]},
            {"name": "Category B", "children": [{"name": "Item 3"}, {"name": "Item 4"}]}
        ]
    }
    # Serialize data to JSON for the template
    return render_template('dashboard.html', hierarchy_data=json.dumps(hierarchy_data))

if __name__ == '__main__':
    app.run(debug=True)

Step 3: Build the HTML Template with D3 and Plotly

Create a template (e.g., templates/dashboard.html) that includes both your existing Plotly charts and the D3 hierarchical edge bundling visualization. We'll use D3 v7 for this example:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask + Plotly + D3 Hierarchical Edge Bundling</title>
    <!-- Load D3.js -->
    <script src="https://d3js.org/d3.v7.min.js"></script>
    <!-- Load Plotly.js -->
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
    <style>
        /* Style for D3 bundling links */
        .bundle-link {
            fill: none;
            stroke: #888;
            stroke-opacity: 0.6;
            stroke-width: 1.2px;
        }
        /* Style for node labels */
        .bundle-node text {
            font-family: sans-serif;
            font-size: 10px;
            pointer-events: none;
        }
        /* Container styling to separate charts */
        .chart-container {
            margin: 20px;
        }
    </style>
</head>
<body>
    <!-- Your existing Plotly chart container -->
    <div class="chart-container" id="plotly-chart" style="width: 800px; height: 500px;"></div>

    <!-- D3 Hierarchical Edge Bundling container -->
    <div class="chart-container" id="bundle-chart" style="width: 900px; height: 700px;"></div>

    <script>
        // Render your existing Plotly chart (keep your existing code here)
        const plotlyTrace = {
            x: [1, 2, 3, 4, 5],
            y: [12, 19, 15, 25, 22],
            type: 'line',
            name: 'Sample Data'
        };
        Plotly.newPlot('plotly-chart', [plotlyTrace]);

        // Render D3 Hierarchical Edge Bundling
        const hierarchyData = JSON.parse('{{ hierarchy_data|safe }}');
        const width = 900;
        const height = 700;

        // Create SVG container centered in the div
        const svg = d3.select('#bundle-chart')
            .append('svg')
            .attr('width', width)
            .attr('height', height)
            .append('g')
            .attr('transform', `translate(${width/2}, ${height/2})`);

        // Convert data to D3 hierarchy structure
        const root = d3.hierarchy(hierarchyData)
            .sort((a, b) => d3.ascending(a.data.name, b.data.name));

        // Use cluster layout to position nodes radially
        const clusterLayout = d3.cluster()
            .size([360, height/2 - 100]); // [angle range, radius]

        clusterLayout(root);

        // Create a radial line generator with bundle curve
        const lineGenerator = d3.lineRadial()
            .curve(d3.curveBundle.beta(0.85)) // Adjust beta for curve tightness
            .radius(d => d.y)
            .angle(d => d.x / 180 * Math.PI);

        // Draw the connecting links
        svg.append('g')
            .selectAll('.bundle-link')
            .data(root.links())
            .join('path')
            .attr('class', 'bundle-link')
            .attr('d', d => lineGenerator(d.source.path(d.target)));

        // Draw node labels
        svg.append('g')
            .selectAll('.bundle-node')
            .data(root.leaves())
            .join('g')
            .attr('class', 'bundle-node')
            .attr('transform', d => `rotate(${d.x - 90}) translate(${d.y}, 0)`)
            .append('text')
            .attr('dy', '0.3em')
            .attr('x', d => d.x < 180 ? 6 : -6)
            .attr('text-anchor', d => d.x < 180 ? 'start' : 'end')
            .attr('transform', d => d.x >= 180 ? 'rotate(180)' : null)
            .text(d => d.data.name);
    </script>
</body>
</html>

Key Notes to Customize:

  • Curve Tightness: Adjust the beta value in d3.curveBundle.beta(0.85) to make the links tighter (higher value) or looser (lower value).
  • Styling: Modify the CSS for .bundle-link and .bundle-node to match your app's design (colors, stroke width, font size, etc.).
  • Data Integration: If you want to link your Plotly data to the D3 visualization, add event listeners to Plotly charts (e.g., plotly_click) to filter or highlight nodes in the bundling graph.
  • Data Source: Replace the sample hierarchy_data in the Flask route with your actual dataset—make sure it follows the nested parent-child structure D3 expects.

内容的提问来源于stack exchange,提问作者Muhammad Bin Ali

火山引擎 最新活动