You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

D3.v4.js折线图添加画笔过滤器报错:<path>属性d期望数值

Hey there! Let's break down why those NaN errors are showing up in your D3 v4 line chart with brush filtering, and fix them step by step.

What's Causing the Errors?

The Error: <path> attribute d: Expected number messages mean your line generator is trying to create a path using non-numeric values (NaN) for x/y coordinates. This almost always ties back to one of these issues:

  • Time parsing failing (resulting in invalid date objects)
  • Missing or incorrectly typed data values (e.g., string values instead of numbers)
  • Brush filtering logic producing empty/invalid data
  • Mismatched scales between the main chart and brush chart

Step 1: Fix Time Parsing

You mentioned parseTime = d3.time...—if your time string format doesn't match the parser, you'll get null (which becomes NaN when passed to a scale).

For example:

  • If your data uses dates like "2023-10-05", use d3.timeParse("%Y-%m-%d")
  • If it uses timestamps like "2023-10-05T14:30:00", use d3.timeParse("%Y-%m-%dT%H:%M:%S")

Verify parsing works by logging a sample data point after loading:

// Inside your data loading callback
console.log(data[0].date); // Should show a valid Date object, not null

Step 2: Ensure Data Values Are Numbers

If your y-axis values are stored as strings in the raw data, converting them to numbers is critical. Add a type cast when processing data:

// Example data processing for CSV
d3.csv("your-data.csv", function(d) {
  return {
    date: parseTime(d.date),
    value: +d.value // The "+" converts the string to a number
  };
}, function(error, data) {
  // Rest of your chart code here
});

Step 3: Fix Brush Filtering Logic

When filtering data with the brush, make sure you're converting the brush's pixel range back to a time range correctly, and only keep valid data points:

function brushed() {
  var extent = d3.event.selection;
  if (!extent) return; // Exit if no brush selection

  // Convert brush pixel positions to time values using the small chart's scale
  var startDate = x2.invert(extent[0]),
      endDate = x2.invert(extent[1]);

  // Filter data: only keep points with valid dates in the range
  var filteredData = data.filter(function(d) {
    return d.date && d.date >= startDate && d.date <= endDate;
  });

  // Update the main chart line
  mainLine.datum(filteredData)
    .attr("d", line);
}

Step 4: Verify Scale Consistency

Make sure the small brush chart's x-scale (x2) shares the same domain as the main chart's x-scale (x):

// Set domains after processing data
x.domain(d3.extent(data, d => d.date));
y.domain([0, d3.max(data, d => d.value)]);
// Mirror main scale domain for the brush chart
x2.domain(x.domain());
y2.domain(y.domain());

Full Working Snippet (Simplified)

Here's a condensed example tying all these fixes together:

var margin = {top: 20, right: 20, bottom: 110, left: 50},
    width = 900 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    margin2 = { top: 430, right: 20, bottom: 30, left: 50 },
    height2 = 500 - margin2.top - margin2.bottom;

var parseTime = d3.timeParse("%Y-%m-%d"); // Adjust to your date format

// Load and process data
d3.csv("data.csv", function(d) {
  return {
    date: parseTime(d.date),
    value: +d.value
  };
}, function(error, data) {
  if (error) throw error;

  // Define scales
  var x = d3.scaleTime().range([0, width]);
  var y = d3.scaleLinear().range([height, 0]);
  var x2 = d3.scaleTime().range([0, width]);
  var y2 = d3.scaleLinear().range([height2, 0]);

  // Set scale domains
  x.domain(d3.extent(data, d => d.date));
  y.domain([0, d3.max(data, d => d.value)]);
  x2.domain(x.domain());
  y2.domain(y.domain());

  // Define line generators
  var line = d3.line()
    .x(d => x(d.date))
    .y(d => y(d.value));

  var line2 = d3.line()
    .x(d => x2(d.date))
    .y(d => y2(d.value));

  // Create SVG and groups
  var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

  var mainGroup = svg.append("g")
    .attr("transform", `translate(${margin.left},${margin.top})`);

  var brushGroup = svg.append("g")
    .attr("transform", `translate(${margin2.left},${margin2.top})`);

  // Draw lines
  var mainLine = mainGroup.append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line);

  brushGroup.append("path")
    .datum(data)
    .attr("class", "line")
    .attr("d", line2);

  // Add brush
  var brush = d3.brushX()
    .extent([[0, 0], [width, height2]])
    .on("brush end", brushed);

  brushGroup.append("g")
    .attr("class", "brush")
    .call(brush);

  // Brush handler
  function brushed() {
    var extent = d3.event.selection;
    if (!extent) return;

    var startDate = x2.invert(extent[0]),
        endDate = x2.invert(extent[1]);

    var filteredData = data.filter(d => d.date && d.date >= startDate && d.date <= endDate);
    mainLine.datum(filteredData).attr("d", line);
  }
});

Quick Debugging Tip

If you still see errors, log key values to the console:

  • console.log(data[0]) to check if date/value are valid
  • console.log(x(data[0].date)) to confirm scale outputs are numbers
  • console.log(filteredData) to ensure the brush returns valid data points

内容的提问来源于stack exchange,提问作者user9026955

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:42:22