масштабируемая линейная диаграмма d3 имеет исчезающие данные

Я пытаюсь добавить возможность масштабирования к исторической линейной диаграмме, которую я построил с использованием пользовательского объекта данных. Я использовал http://codepen.io/brantwills/pen/igsoc/ в качестве шаблон. Диаграмма отображается, но когда я пытаюсь изменить масштаб, возникают две ошибки:

Ошибка: недопустимое значение для атрибута пути d=""
Uncaught 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) + ")"; }
    );
  }
}

Благодарю вас!


person dshamis317    schedule 30.07.2014    source источник


Ответы (1)


Хорошо, давайте пройдемся по каждой вещи.

Начнем с того, что в 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) + ")";
});

Это просто заставит его следовать за концами строк, но вы можете изменить любые атрибуты, которые вам нравятся, чтобы получить желаемые эффекты.

person Mike Precup    schedule 30.07.2014
comment
это имеет смысл. спасибо! есть идеи, как сделать масштаб текста с данными? в настоящее время он просто сидит сложа руки на стороне - person dshamis317; 30.07.2014