d3js

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

D3.js Data Visualization Skill

D3.js 数据可视化技能

Create powerful, custom data visualizations using D3.js for complete control over SVG elements, transitions, and data binding.
使用D3.js创建功能强大的自定义数据可视化,完全掌控SVG元素、过渡效果和数据绑定。

When to Use This Skill

何时使用该技能

Use D3.js when you need:
  • Complete customization - Every aspect of the visualization controlled
  • Complex interactions - Advanced user interactions and transitions
  • Unique visualizations - Bespoke charts not available in other libraries
  • Data-driven DOM manipulation - Direct binding of data to DOM elements
  • Custom animations - Sophisticated transitions and effects
Avoid when:
  • Simple charts with default styling are sufficient (use Chart.js)
  • Quick implementation is priority (use Plotly or Chart.js)
  • Team lacks JavaScript expertise
在以下场景中使用D3.js:
  • 完全自定义 - 控制可视化的每一个细节
  • 复杂交互 - 高级用户交互与过渡效果
  • 独特可视化 - 其他库无法实现的定制化图表
  • 数据驱动DOM操作 - 将数据直接绑定到DOM元素
  • 自定义动画 - 复杂的过渡与特效
避免使用的场景:
  • 仅需默认样式的简单图表(使用Chart.js)
  • 优先考虑快速实现的场景(使用Plotly或Chart.js)
  • 团队缺乏JavaScript专业能力

Core Capabilities

核心功能

1. Data Binding

1. 数据绑定

javascript
// Select and bind data to elements
d3.select('#chart')
  .selectAll('circle')
  .data(dataset)
  .enter()
  .append('circle')
  .attr('cx', d => xScale(d.x))
  .attr('cy', d => yScale(d.y))
  .attr('r', d => d.radius)
  .style('fill', d => colorScale(d.category));
javascript
// Select and bind data to elements
d3.select('#chart')
  .selectAll('circle')
  .data(dataset)
  .enter()
  .append('circle')
  .attr('cx', d => xScale(d.x))
  .attr('cy', d => yScale(d.y))
  .attr('r', d => d.radius)
  .style('fill', d => colorScale(d.category));

2. Scales and Axes

2. 比例尺与坐标轴

javascript
// Create scales for positioning
const xScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.x)])
  .range([0, width]);

const yScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.y)])
  .range([height, 0]);

// Create axes
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);

svg.append('g')
  .attr('transform', `translate(0, ${height})`)
  .call(xAxis);

svg.append('g')
  .call(yAxis);
javascript
// Create scales for positioning
const xScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.x)])
  .range([0, width]);

const yScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.y)])
  .range([height, 0]);

// Create axes
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);

svg.append('g')
  .attr('transform', `translate(0, ${height})`)
  .call(xAxis);

svg.append('g')
  .call(yAxis);

3. Transitions and Animations

3. 过渡与动画

javascript
// Smooth transitions
d3.selectAll('circle')
  .transition()
  .duration(1000)
  .attr('r', d => d.newRadius)
  .style('fill', 'steelblue');
javascript
// Smooth transitions
d3.selectAll('circle')
  .transition()
  .duration(1000)
  .attr('r', d => d.newRadius)
  .style('fill', 'steelblue');

4. Interactive Elements

4. 交互元素

javascript
// Add interactivity
const tooltip = d3.select('body')
  .append('div')
  .attr('class', 'tooltip')
  .style('opacity', 0);

circles
  .on('mouseover', function(event, d) {
    tooltip.transition()
      .duration(200)
      .style('opacity', .9);
    tooltip.html(`Value: ${d.value}`)
      .style('left', (event.pageX + 10) + 'px')
      .style('top', (event.pageY - 28) + 'px');
  })
  .on('mouseout', function(d) {
    tooltip.transition()
      .duration(500)
      .style('opacity', 0);
  });
javascript
// Add interactivity
const tooltip = d3.select('body')
  .append('div')
  .attr('class', 'tooltip')
  .style('opacity', 0);

circles
  .on('mouseover', function(event, d) {
    tooltip.transition()
      .duration(200)
      .style('opacity', .9);
    tooltip.html(`Value: ${d.value}`)
      .style('left', (event.pageX + 10) + 'px')
      .style('top', (event.pageY - 28) + 'px');
  })
  .on('mouseout', function(d) {
    tooltip.transition()
      .duration(500)
      .style('opacity', 0);
  });

Complete Examples

完整示例

Example 1: Interactive Bar Chart

示例1:交互式柱状图

html
<!DOCTYPE html>
<html>
<head>
  <script src="https://d3js.org/d3.v7.min.js"></script>
  <style>
    .bar { fill: steelblue; cursor: pointer; }
    .bar:hover { fill: orange; }
    .tooltip {
      position: absolute;
      padding: 10px;
      background: rgba(0,0,0,0.8);
      color: white;
      border-radius: 5px;
      pointer-events: none;
    }
  </style>
</head>
<body>
  <div id="chart"></div>
  <script>
    // Data
    const data = [
      { category: 'A', value: 30 },
      { category: 'B', value: 80 },
      { category: 'C', value: 45 },
      { category: 'D', value: 60 },
      { category: 'E', value: 20 }
    ];

    // Dimensions
    const margin = { top: 20, right: 20, bottom: 30, left: 40 };
    const width = 600 - margin.left - margin.right;
    const height = 400 - margin.top - margin.bottom;

    // Create SVG
    const svg = d3.select('#chart')
      .append('svg')
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.top + margin.bottom)
      .append('g')
      .attr('transform', `translate(${margin.left},${margin.top})`);

    // Scales
    const xScale = d3.scaleBand()
      .domain(data.map(d => d.category))
      .range([0, width])
      .padding(0.1);

    const yScale = d3.scaleLinear()
      .domain([0, d3.max(data, d => d.value)])
      .range([height, 0]);

    // Axes
    svg.append('g')
      .attr('transform', `translate(0,${height})`)
      .call(d3.axisBottom(xScale));

    svg.append('g')
      .call(d3.axisLeft(yScale));

    // Tooltip
    const tooltip = d3.select('body')
      .append('div')
      .attr('class', 'tooltip')
      .style('opacity', 0);

    // Bars
    svg.selectAll('.bar')
      .data(data)
      .enter()
      .append('rect')
      .attr('class', 'bar')
      .attr('x', d => xScale(d.category))
      .attr('y', d => yScale(d.value))
      .attr('width', xScale.bandwidth())
      .attr('height', d => height - yScale(d.value))
      .on('mouseover', function(event, d) {
        d3.select(this).style('fill', 'orange');
        tooltip.transition().duration(200).style('opacity', .9);
        tooltip.html(`${d.category}: ${d.value}`)
          .style('left', (event.pageX + 10) + 'px')
          .style('top', (event.pageY - 28) + 'px');
      })
      .on('mouseout', function(d) {
        d3.select(this).style('fill', 'steelblue');
        tooltip.transition().duration(500).style('opacity', 0);
      });
  </script>
</body>
</html>
html
<!DOCTYPE html>
<html>
<head>
  <script src="https://d3js.org/d3.v7.min.js"></script>
  <style>
    .bar { fill: steelblue; cursor: pointer; }
    .bar:hover { fill: orange; }
    .tooltip {
      position: absolute;
      padding: 10px;
      background: rgba(0,0,0,0.8);
      color: white;
      border-radius: 5px;
      pointer-events: none;
    }
  </style>
</head>
<body>
  <div id="chart"></div>
  <script>
    // Data
    const data = [
      { category: 'A', value: 30 },
      { category: 'B', value: 80 },
      { category: 'C', value: 45 },
      { category: 'D', value: 60 },
      { category: 'E', value: 20 }
    ];

    // Dimensions
    const margin = { top: 20, right: 20, bottom: 30, left: 40 };
    const width = 600 - margin.left - margin.right;
    const height = 400 - margin.top - margin.bottom;

    // Create SVG
    const svg = d3.select('#chart')
      .append('svg')
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.top + margin.bottom)
      .append('g')
      .attr('transform', `translate(${margin.left},${margin.top})`);

    // Scales
    const xScale = d3.scaleBand()
      .domain(data.map(d => d.category))
      .range([0, width])
      .padding(0.1);

    const yScale = d3.scaleLinear()
      .domain([0, d3.max(data, d => d.value)])
      .range([height, 0]);

    // Axes
    svg.append('g')
      .attr('transform', `translate(0,${height})`)
      .call(d3.axisBottom(xScale));

    svg.append('g')
      .call(d3.axisLeft(yScale));

    // Tooltip
    const tooltip = d3.select('body')
      .append('div')
      .attr('class', 'tooltip')
      .style('opacity', 0);

    // Bars
    svg.selectAll('.bar')
      .data(data)
      .enter()
      .append('rect')
      .attr('class', 'bar')
      .attr('x', d => xScale(d.category))
      .attr('y', d => yScale(d.value))
      .attr('width', xScale.bandwidth())
      .attr('height', d => height - yScale(d.value))
      .on('mouseover', function(event, d) {
        d3.select(this).style('fill', 'orange');
        tooltip.transition().duration(200).style('opacity', .9);
        tooltip.html(`${d.category}: ${d.value}`)
          .style('left', (event.pageX + 10) + 'px')
          .style('top', (event.pageY - 28) + 'px');
      })
      .on('mouseout', function(d) {
        d3.select(this).style('fill', 'steelblue');
        tooltip.transition().duration(500).style('opacity', 0);
      });
  </script>
</body>
</html>

Example 2: Animated Line Chart with CSV Data

示例2:加载CSV数据的动画折线图

javascript
// Load and visualize CSV data
d3.csv('../data/timeseries.csv').then(data => {
  // Parse dates and values
  const parseDate = d3.timeParse('%Y-%m-%d');
  data.forEach(d => {
    d.date = parseDate(d.date);
    d.value = +d.value;
  });

  // Scales
  const xScale = d3.scaleTime()
    .domain(d3.extent(data, d => d.date))
    .range([0, width]);

  const yScale = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.value)])
    .range([height, 0]);

  // Line generator
  const line = d3.line()
    .x(d => xScale(d.date))
    .y(d => yScale(d.value))
    .curve(d3.curveMonotoneX);

  // Draw line with animation
  const path = svg.append('path')
    .datum(data)
    .attr('class', 'line')
    .attr('d', line)
    .style('fill', 'none')
    .style('stroke', 'steelblue')
    .style('stroke-width', 2);

  // Animate path
  const totalLength = path.node().getTotalLength();
  path
    .attr('stroke-dasharray', totalLength + ' ' + totalLength)
    .attr('stroke-dashoffset', totalLength)
    .transition()
    .duration(2000)
    .ease(d3.easeLinear)
    .attr('stroke-dashoffset', 0);

  // Add dots
  svg.selectAll('.dot')
    .data(data)
    .enter()
    .append('circle')
    .attr('class', 'dot')
    .attr('cx', d => xScale(d.date))
    .attr('cy', d => yScale(d.value))
    .attr('r', 0)
    .style('fill', 'steelblue')
    .transition()
    .delay((d, i) => i * 50)
    .duration(500)
    .attr('r', 4);
});
javascript
// Load and visualize CSV data
d3.csv('../data/timeseries.csv').then(data => {
  // Parse dates and values
  const parseDate = d3.timeParse('%Y-%m-%d');
  data.forEach(d => {
    d.date = parseDate(d.date);
    d.value = +d.value;
  });

  // Scales
  const xScale = d3.scaleTime()
    .domain(d3.extent(data, d => d.date))
    .range([0, width]);

  const yScale = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.value)])
    .range([height, 0]);

  // Line generator
  const line = d3.line()
    .x(d => xScale(d.date))
    .y(d => yScale(d.value))
    .curve(d3.curveMonotoneX);

  // Draw line with animation
  const path = svg.append('path')
    .datum(data)
    .attr('class', 'line')
    .attr('d', line)
    .style('fill', 'none')
    .style('stroke', 'steelblue')
    .style('stroke-width', 2);

  // Animate path
  const totalLength = path.node().getTotalLength();
  path
    .attr('stroke-dasharray', totalLength + ' ' + totalLength)
    .attr('stroke-dashoffset', totalLength)
    .transition()
    .duration(2000)
    .ease(d3.easeLinear)
    .attr('stroke-dashoffset', 0);

  // Add dots
  svg.selectAll('.dot')
    .data(data)
    .enter()
    .append('circle')
    .attr('class', 'dot')
    .attr('cx', d => xScale(d.date))
    .attr('cy', d => yScale(d.value))
    .attr('r', 0)
    .style('fill', 'steelblue')
    .transition()
    .delay((d, i) => i * 50)
    .duration(500)
    .attr('r', 4);
});

Example 3: Force-Directed Network Graph

示例3:力导向网络图

javascript
// Network data
const nodes = [
  { id: 'A', group: 1 },
  { id: 'B', group: 1 },
  { id: 'C', group: 2 },
  { id: 'D', group: 2 },
  { id: 'E', group: 3 }
];

const links = [
  { source: 'A', target: 'B', value: 1 },
  { source: 'B', target: 'C', value: 2 },
  { source: 'C', target: 'D', value: 1 },
  { source: 'D', target: 'E', value: 3 },
  { source: 'E', target: 'A', value: 2 }
];

// Create force simulation
const simulation = d3.forceSimulation(nodes)
  .force('link', d3.forceLink(links).id(d => d.id))
  .force('charge', d3.forceManyBody().strength(-200))
  .force('center', d3.forceCenter(width / 2, height / 2));

// Draw links
const link = svg.append('g')
  .selectAll('line')
  .data(links)
  .enter()
  .append('line')
  .style('stroke', '#999')
  .style('stroke-width', d => Math.sqrt(d.value));

// Draw nodes
const node = svg.append('g')
  .selectAll('circle')
  .data(nodes)
  .enter()
  .append('circle')
  .attr('r', 10)
  .style('fill', d => d3.schemeCategory10[d.group])
  .call(d3.drag()
    .on('start', dragstarted)
    .on('drag', dragged)
    .on('end', dragended));

// Add labels
const label = svg.append('g')
  .selectAll('text')
  .data(nodes)
  .enter()
  .append('text')
  .text(d => d.id)
  .style('font-size', '12px')
  .attr('dx', 12)
  .attr('dy', 4);

// Update positions on 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);

  node
    .attr('cx', d => d.x)
    .attr('cy', d => d.y);

  label
    .attr('x', d => d.x)
    .attr('y', d => d.y);
});

// Drag functions
function dragstarted(event, d) {
  if (!event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

function dragged(event, d) {
  d.fx = event.x;
  d.fy = event.y;
}

function dragended(event, d) {
  if (!event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}
javascript
// Network data
const nodes = [
  { id: 'A', group: 1 },
  { id: 'B', group: 1 },
  { id: 'C', group: 2 },
  { id: 'D', group: 2 },
  { id: 'E', group: 3 }
];

const links = [
  { source: 'A', target: 'B', value: 1 },
  { source: 'B', target: 'C', value: 2 },
  { source: 'C', target: 'D', value: 1 },
  { source: 'D', target: 'E', value: 3 },
  { source: 'E', target: 'A', value: 2 }
];

// Create force simulation
const simulation = d3.forceSimulation(nodes)
  .force('link', d3.forceLink(links).id(d => d.id))
  .force('charge', d3.forceManyBody().strength(-200))
  .force('center', d3.forceCenter(width / 2, height / 2));

// Draw links
const link = svg.append('g')
  .selectAll('line')
  .data(links)
  .enter()
  .append('line')
  .style('stroke', '#999')
  .style('stroke-width', d => Math.sqrt(d.value));

// Draw nodes
const node = svg.append('g')
  .selectAll('circle')
  .data(nodes)
  .enter()
  .append('circle')
  .attr('r', 10)
  .style('fill', d => d3.schemeCategory10[d.group])
  .call(d3.drag()
    .on('start', dragstarted)
    .on('drag', dragged)
    .on('end', dragended));

// Add labels
const label = svg.append('g')
  .selectAll('text')
  .data(nodes)
  .enter()
  .append('text')
  .text(d => d.id)
  .style('font-size', '12px')
  .attr('dx', 12)
  .attr('dy', 4);

// Update positions on 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);

  node
    .attr('cx', d => d.x)
    .attr('cy', d => d.y);

  label
    .attr('x', d => d.x)
    .attr('y', d => d.y);
});

// Drag functions
function dragstarted(event, d) {
  if (!event.active) simulation.alphaTarget(0.3).restart();
  d.fx = d.x;
  d.fy = d.y;
}

function dragged(event, d) {
  d.fx = event.x;
  d.fy = event.y;
}

function dragended(event, d) {
  if (!event.active) simulation.alphaTarget(0);
  d.fx = null;
  d.fy = null;
}

Best Practices

最佳实践

1. Use Proper Margins Convention

1. 使用标准边距约定

javascript
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;

const svg = d3.select('body').append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append('g')
  .attr('transform', `translate(${margin.left},${margin.top})`);
javascript
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;

const svg = d3.select('body').append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append('g')
  .attr('transform', `translate(${margin.left},${margin.top})`);

2. Use Method Chaining

2. 使用方法链式调用

javascript
// Good - readable chaining
svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('cx', d => xScale(d.x))
  .attr('cy', d => yScale(d.y))
  .attr('r', 5);
javascript
// Good - readable chaining
svg.selectAll('circle')
  .data(data)
  .enter()
  .append('circle')
  .attr('cx', d => xScale(d.x))
  .attr('cy', d => yScale(d.y))
  .attr('r', 5);

3. Separate Data from Presentation

3. 分离数据与展示

javascript
// Load data separately
d3.json('../data/data.json').then(data => {
  visualize(data);
});

function visualize(data) {
  // Visualization logic here
}
javascript
// Load data separately
d3.json('../data/data.json').then(data => {
  visualize(data);
});

function visualize(data) {
  // Visualization logic here
}

4. Use Responsive Design

4. 使用响应式设计

javascript
// Make chart responsive
function resize() {
  const container = d3.select('#chart').node();
  const width = container.getBoundingClientRect().width;

  xScale.range([0, width]);
  svg.attr('width', width);
  // Update chart elements
}

window.addEventListener('resize', resize);
javascript
// Make chart responsive
function resize() {
  const container = d3.select('#chart').node();
  const width = container.getBoundingClientRect().width;

  xScale.range([0, width]);
  svg.attr('width', width);
  // Update chart elements
}

window.addEventListener('resize', resize);

Common Patterns

常见模式

Update Pattern (Enter, Update, Exit)

更新模式(Enter、Update、Exit)

javascript
function update(data) {
  // Bind data
  const circles = svg.selectAll('circle')
    .data(data, d => d.id);

  // EXIT: Remove old elements
  circles.exit()
    .transition()
    .duration(500)
    .attr('r', 0)
    .remove();

  // UPDATE: Update existing elements
  circles
    .transition()
    .duration(500)
    .attr('cx', d => xScale(d.x))
    .attr('cy', d => yScale(d.y));

  // ENTER: Add new elements
  circles.enter()
    .append('circle')
    .attr('r', 0)
    .attr('cx', d => xScale(d.x))
    .attr('cy', d => yScale(d.y))
    .transition()
    .duration(500)
    .attr('r', 5);
}
javascript
function update(data) {
  // Bind data
  const circles = svg.selectAll('circle')
    .data(data, d => d.id);

  // EXIT: Remove old elements
  circles.exit()
    .transition()
    .duration(500)
    .attr('r', 0)
    .remove();

  // UPDATE: Update existing elements
  circles
    .transition()
    .duration(500)
    .attr('cx', d => xScale(d.x))
    .attr('cy', d => yScale(d.y));

  // ENTER: Add new elements
  circles.enter()
    .append('circle')
    .attr('r', 0)
    .attr('cx', d => xScale(d.x))
    .attr('cy', d => yScale(d.y))
    .transition()
    .duration(500)
    .attr('r', 5);
}

Brush and Zoom

画笔与缩放

javascript
// Add zoom behavior
const zoom = d3.zoom()
  .scaleExtent([1, 10])
  .on('zoom', zoomed);

svg.call(zoom);

function zoomed(event) {
  const transform = event.transform;
  svg.attr('transform', transform);
}

// Add brush selection
const brush = d3.brush()
  .extent([[0, 0], [width, height]])
  .on('end', brushed);

svg.append('g')
  .attr('class', 'brush')
  .call(brush);

function brushed(event) {
  if (!event.selection) return;
  const [[x0, y0], [x1, y1]] = event.selection;
  // Handle selected region
}
javascript
// Add zoom behavior
const zoom = d3.zoom()
  .scaleExtent([1, 10])
  .on('zoom', zoomed);

svg.call(zoom);

function zoomed(event) {
  const transform = event.transform;
  svg.attr('transform', transform);
}

// Add brush selection
const brush = d3.brush()
  .extent([[0, 0], [width, height]])
  .on('end', brushed);

svg.append('g')
  .attr('class', 'brush')
  .call(brush);

function brushed(event) {
  if (!event.selection) return;
  const [[x0, y0], [x1, y1]] = event.selection;
  // Handle selected region
}

Installation & Setup

安装与设置

CDN (Quick Start)

CDN(快速开始)

html
<script src="https://d3js.org/d3.v7.min.js"></script>
html
<script src="https://d3js.org/d3.v7.min.js"></script>

NPM (Production)

NPM(生产环境)

bash
npm install d3
javascript
import * as d3 from 'd3';
// Or import specific modules
import { select, scaleLinear, axisBottom } from 'd3';
bash
npm install d3
javascript
import * as d3 from 'd3';
// Or import specific modules
import { select, scaleLinear, axisBottom } from 'd3';

Performance Tips

性能优化技巧

  1. Minimize DOM operations - Batch updates when possible
  2. Use canvas for large datasets - Switch to canvas for >1000 points
  3. Throttle events - Debounce mousemove/scroll events
  4. Optimize transitions - Limit concurrent animations
  5. Use web workers - Offload heavy computations
  1. 减少DOM操作 - 尽可能批量更新
  2. 大数据集使用Canvas - 数据量超过1000个点时切换到Canvas
  3. 节流事件 - 防抖鼠标移动/滚动事件
  4. 优化过渡效果 - 限制并发动画数量
  5. 使用Web Worker - 卸载繁重的计算任务

Resources

参考资源

Integration with Other Tools

与其他工具的集成

With React

与React集成

javascript
import { useEffect, useRef } from 'react';
import * as d3 from 'd3';

function D3Chart({ data }) {
  const svgRef = useRef();

  useEffect(() => {
    const svg = d3.select(svgRef.current);
    // D3 code here
  }, [data]);

  return <svg ref={svgRef}></svg>;
}
javascript
import { useEffect, useRef } from 'react';
import * as d3 from 'd3';

function D3Chart({ data }) {
  const svgRef = useRef();

  useEffect(() => {
    const svg = d3.select(svgRef.current);
    // D3 code here
  }, [data]);

  return <svg ref={svgRef}></svg>;
}

With CSV/JSON Data

与CSV/JSON数据集成

javascript
// Load from relative path
d3.csv('../data/data.csv').then(data => {
  // Process and visualize
});

d3.json('../data/data.json').then(data => {
  // Visualize JSON
});

Use this skill when you need maximum control and customization in your data visualizations!
javascript
// Load from relative path
d3.csv('../data/data.csv').then(data => {
  // Process and visualize
});

d3.json('../data/data.json').then(data => {
  // Visualize JSON
});

当你需要对数据可视化进行最大程度的控制和自定义时,就使用这项技能!