可缩放d3折线图有消失的数据

zoomable d3 line chart has disappearing data

本文关键字:消失 数据 折线图 缩放 d3      更新时间:2023-09-26

我正在尝试为使用自定义数据对象构建的历史折线图添加缩放功能。我一直使用http://codepen.io/brantwills/pen/igsoc/作为模板。图表呈现,但当我尝试缩放有两个错误:

错误:路径属性d="
无效值未捕获的TypeError: undefined不是一个函数(在缩放函数的最后一部分的最后一个转换中)

JSFiddle: http://jsfiddle.net/dshamis317/sFp6Q/

下面是我的代码:
function renderHistoricalData(data) {
  var parseDate = d3.time.format("%Y%m%d").parse;
  data.forEach(function(d) { d.date = parseDate(d.date); });
  // data.sort(function(a,b) { return a.date - b.date; });
  var margin = {top: 20, right: 80, bottom: 30, left: 50},
  width = 1200 - margin.left - margin.right,
  height = 450 - margin.top - margin.bottom;
  var x = d3.time.scale()
    .range([0, width]);
  var y = d3.scale.linear()
    .range([height, 0]);
  var color = d3.scale.category10();
  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");
  var zoom = d3.behavior.zoom()
    .x(x)
    .y(y)
    .scaleExtent([1, 10])
    .on("zoom", zoomed);
  var line = d3.svg.line()
  .interpolate("basis")
  // .defined(function(d) { return d.y!=0; })
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.sentiment); });
  var svg = d3.select("#historical_chart").append("svg")
    .call(zoom)
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
  var sites = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {date: d.date, sentiment: +d[name]};
      })
    };
  });
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain([
    d3.min(sites, function(c) { return d3.min(c.values, function(v) { return v.sentiment; }); }),
    d3.max(sites, function(c) { return d3.max(c.values, function(v) { return v.sentiment; }); })
    ]);
  var site = svg.selectAll(".site")
    .data(sites)
    .enter().append("g")
      .attr("class", "site");
  site.append("path")
    .attr("class", "line")
    .attr("d", function(d) { return line(d.values); })
    .style("stroke", function(d) { return color(d.name); });
  site.append("text")
    .attr("transform", function(d) {
        var val = d.values[d.values.length-1];
        return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
    })
    .attr("x", 3)
    .attr("dy", ".35em")
        .style("text-anchor", "start")
        .text(function(d) { return d.name; });
  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".71em")
    .style("text-anchor", "end")
    .text("Sentiment (%)");
  function zoomed() {
    svg.select(".x.axis").call(xAxis);
    svg.select(".y.axis").call(yAxis);
    svg.selectAll('path.line').attr('d', line);
    sites.selectAll('.site').attr("transform", function(d) {
      return "translate(" + x(d.date) + "," + y(d.sentiment) + ")"; }
    );
  }
}

谢谢!

好吧,让我们来看看。

首先,在zoomed中,最后一个变换不需要在那里。在原版中,它是用来移动圆圈的,而你没有。

同样重要的是,您在path.line上的编辑将d设置为错误的功能。如果你看看你在第一次制作它时设置的d,它应该是相同的,作为一般的经验法则,所以它应该是function(d) { return line(d.values); },而不仅仅是line

现在,它消失的真正原因。

您的缩放范围是基于原始域计算的。但是,直到调用scaleExtent之后才设置域,这意味着您的缩放都基于默认值。它并没有消失,而是被压缩到图的左边。如果你去掉x轴,你会看到所有数据的彩色涂抹在侧面。

把你所有的域计算移到你建立规模的地方,它会很好。

让事情更具体一点:

function renderHistoricalData(data) {
  var parseDate = d3.time.format("%Y%m%d").parse;
  data.forEach(function(d) { d.date = parseDate(d.date); });
  // data.sort(function(a,b) { return a.date - b.date; });
  var margin = {top: 20, right: 80, bottom: 30, left: 50},
  width = 1200 - margin.left - margin.right,
  height = 450 - margin.top - margin.bottom;
  var x = d3.time.scale()
    .range([0, width]);
  var y = d3.scale.linear()
    .range([height, 0]);
  var color = d3.scale.category10();
  var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");
  var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");
  color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
  var sites = color.domain().map(function(name) {
    return {
      name: name,
      values: data.map(function(d) {
        return {date: d.date, sentiment: +d[name]};
      })
    };
  });
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain([
    d3.min(sites, function(c) { return d3.min(c.values, function(v) { return v.sentiment; }); }),
    d3.max(sites, function(c) { return d3.max(c.values, function(v) { return v.sentiment; }); })
    ]);
  var zoom = d3.behavior.zoom()
    .x(x)
    .y(y)
    .scaleExtent([1, 10])
    .on("zoom", zoomed);
  var line = d3.svg.line()
  .interpolate("basis")
  // .defined(function(d) { return d.y!=0; })
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.sentiment); });
  var svg = d3.select("#historical_chart").append("svg")
    .call(zoom)
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  var site = svg.selectAll(".site")
    .data(sites)
    .enter().append("g")
      .attr("class", "site");
  site.append("path")
    .attr("class", "line")
    .attr("d", function(d) { return line(d.values); })
    .style("stroke", function(d) { return color(d.name); });
  site.append("text")
    .attr("transform", function(d) {
        var val = d.values[d.values.length-1];
        return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
    })
    .attr("x", 3)
    .attr("dy", ".35em")
        .style("text-anchor", "start")
        .text(function(d) { return d.name; });
  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".71em")
    .style("text-anchor", "end")
    .text("Sentiment (%)");
  function zoomed() {
    svg.select(".x.axis").call(xAxis);
    svg.select(".y.axis").call(yAxis);
    svg.selectAll('path.line').attr('d', function(d) { return line(d.values); });
  }
}

如果你想让文字移动,你可以给它一个容易识别的类,然后在zoomed中更新它。

给它一个类:

site.append("文本").attr("阶级","lineLabel")

zoomed中更新:

svg.selectAll(".lineLabel")
.attr("transform", function(d) {
    var val = d.values[d.values.length-1];
    return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
});

这只会使它跟随行尾,但你可以修改任何你喜欢的属性来获得想要的效果