2014-01-31 5 views
2

Я пытаюсь получить чищу работать аналогичны этот пример, но с сгруппированной гистограммой: http://bl.ocks.org/mbostock/1667367D3 чистки на сгруппированную гистограмме

Я действительно не имеет хорошее представление о том, как чистить работы (I убежища я не смог найти хорошие учебники), поэтому я немного не понимаю, что происходит. Я попытаюсь включить соответствующие биты кода ниже. Диаграмма отслеживает время для исправления сломанных сборок днем, а затем группируется по портфелю. Пока создаётся кисть, и пользователь может перемещать и перетаскивать ее, но штрихи в основной диаграмме перерисовываются странно, и ось x вообще не обновляется. Любая помощь, которую вы можете дать, будет очень признательна. Спасибо.

// x0 is the time scale on the X axis 
var main_x0 = d3.scale.ordinal().rangeRoundBands([0, main_width-275], 0.2); 
var mini_x0 = d3.scale.ordinal().rangeRoundBands([0, main_width-275], 0.2); 

// x1 is the portfolio scale on the X axis 
var main_x1 = d3.scale.ordinal(); 
var mini_x1 = d3.scale.ordinal(); 

// Define the X axis 
var main_xAxis = d3.svg.axis() 
    .scale(main_x0) 
    .tickFormat(dateFormat) 
    .orient("bottom"); 

var mini_xAxis = d3.svg.axis() 
    .scale(mini_x0) 
    .tickFormat(dateFormat) 
    .orient("bottom"); 

После связывания данных ...

// define the axis domains 
main_x0.domain(data.result.map(function(d) { return d.date; }) 
    .sort(d3.ascending)); 
mini_x0.domain(data.result.map(function(d) { return d.date; }) 
    .sort(d3.ascending)); 

main_x1.domain(data.result.map(function(d) { return d.portfolio; }) 
    .sort(d3.ascending)) 
    .rangeRoundBands([0, main_x0.rangeBand() ], 0); 
mini_x1.domain(data.result.map(function(d) { return d.portfolio; }) 
    .sort(d3.ascending)) 
    .rangeRoundBands([0, main_x0.rangeBand() ], 0); 

// Create brush for mini graph 
var brush = d3.svg.brush() 
    .x(mini_x0) 
    .on("brush", brushed); 

После добавления оси-х и т.д.

// Create the bars 
var bar = main.selectAll(".bars") 
    .data(nested) 
.enter().append("g") 
    .attr("class", function(d) { return d.key + "-group bar"; }) 
    .attr("fill", function(d) { return color(d.key); }); 

bar.selectAll("rect").append("rect") 
    .data(function(d) { return d.values; }) 
.enter().append("rect") 
    .attr("class", function(d) { return d.portfolio; }) 
    .attr("transform", function(d) { return "translate(" + main_x0(d.date) + ",0)"; }) 
    .attr("width", function(d) { return main_x1.rangeBand(); }) 
    .attr("x", function(d) { return main_x1(d.portfolio); }) 
    .attr("y", function(d) { return main_y(d.buildFixTime); }) 
    .attr("height", function(d) { return main_height - main_y(d.buildFixTime); }); 

Здесь функция кисти (пытается несколько различных вариантов) ...

function brushed() { 
    main_x1.domain(brush.empty() ? mini_x1.domain() : brush.extent()); 

    //main.select("rect") 
     //.attr("x", function(d) { return d.values; }) 
     //.attr("width", function(d) { return d.values; }); 
    bar.select("rect") 
     .attr("width", function(d) { return main_x1.rangeBand(); }) 
     .attr("x", function(d) { return main_x1(d.portfolio); }); 
     //.attr("y", function(d) { console.log(d); return main_y(d.buildFixTime); }) 
     //.attr("height", function(d) { return main_height - main_y(d.buildFixTime); }); 

    main.select(".x.axis").call(main_xAxis); 
} 
+1

Похоже, вы добавление элементов 'rect' внутри элементов' rect' - вам не нужно это делать. Кроме того, вы, вероятно, хотите «bar.selectAll (« rect »)' в вашей «матовой» функции. Похоже, вы обновляете домен для 'main_x1', а затем перерисовываете' main_xAxis', который использует другой масштаб. –

+0

ОК, имеет смысл, но когда я меняю домен на main_x0, я получаю следующее сообщение об ошибке: Uncaught TypeError: Объект 113 не имеет метода 'getDay' – JamesE

+0

Можете ли вы представить полный пример, демонстрирующий проблему, пожалуйста? –

ответ

14

Проблема возникает из пытаясь использовать кисть для установки домена x-scale, когда ваш x-масштаб является порядковым номером. Другими словами, ожидаемый домен вашей оси х представляет собой список категорий, а не максимальную численную степень. Так что проблема на самом верху функции чистки зубов:

function brushed() { 
    main_x0.domain(brush.empty() ? mini_x0.domain() : brush.extent()); 

домен устанавливается brush.extent() представляет собой массив из двух чисел, которые затем полностью скидывают свою порядковую шкалу.

According to the wiki, если один из шкал, прикрепленных к функции кисти, является порядковой шкалой, значения, возвращаемые brush.extent(), являются значениями в выходном диапазоне, а не во входном домене. Ordinal scales don't have an invert() method для преобразования значений диапазона в значения домена.

Итак, у вас есть несколько вариантов, как поступить:

Вы могли бы вновь сделать весь граф, используя линейную шкалу времени для основных х осей вместо порядковой шкалы. Но тогда вы должны написать свою собственную функцию, чтобы определить ширину каждого дня на этой оси, вместо того, чтобы использовать .rangeBand().

Вы можете создать свою собственную функцию «инвертировать», чтобы выяснить, какие категориальные значения (даты на mini_x0.domain) включены в диапазон, возвращаемый brush.extent(). Тогда вам нужно будет и сбрасывать main_x0.domain только с указанием этих дат на оси, и отфильтровывайте свои прямоугольники, чтобы рисовать только эти прямоугольники.

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

Но какой должен быть новый диапазон?Диапазон, возвращаемый brush.extent(), является начальным и конечным положениями прямоугольника для чистки. Если вы использовали эти значения в качестве диапазона на главном графике, весь ваш граф будет сжиматься до такой ширины. Это противоположность тому, что вы хотите. Что вы хотите, так это для области графика, что изначально заполнил эту ширину, чтобы растянуть ее, чтобы заполнить всю область графика.

Итак, если ваш оригинальный й диапазон от [0,100], и кисть охватывает область [20,60], то вам нужен новый диапазон, который удовлетворяет эти условия:

  • на 20% знак новой ширины диапазона - 0;
  • 60% марка новой ширины диапазона находится на 100.

Поэтому

  • общая ширина нового диапазона ((100-0)/(60-20)) * (100-0) = 250;
  • начало нового диапазона - (0 - (20/100) * 250) = -50;
  • конец нового диапазона в (-50) + 250 = 200.

Теперь вы могли бы сделать все алгебры для выясняя это преобразование самостоятельно. Но это действительно просто еще один тип уравнения масштабирования, поэтому почему бы не создать 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 »

В частности, нам нужна линейная шкала , с ее диапазоном выходных значений, который является фактическим диапазоном области построения графика. Затем установите домен в соответствии с диапазоном области щетки, которую мы хотим растянуть, чтобы покрыть область графика. Наконец, мы вычисляем диапазон порядковой шкалы , используя линейную шкалу, чтобы выяснить, насколько далеки от экрана исходные значения max и min. И оттуда мы можем изменить размер другой ординальной шкалы и переместить все прямоугольники.

В коде:

//Initialization: 
var main_xZoom = d3.scale.linear() 
    .range([0, main_width - 275]) 
    .domain([0, main_width - 275]); 

//Brushing function: 
function brushed() { 
    var originalRange = main_xZoom.range(); 
    main_xZoom.domain(brush.empty() ? 
        originalRange: 
        brush.extent()); 

    main_x0.rangeRoundBands([ 
     main_xZoom(originalRange[0]), 
     main_xZoom(originalRange[1]) 
     ], 0.2); 

    main_x1.rangeRoundBands([0, main_x0.rangeBand()], 0); 

    bar.selectAll("rect") 
     .attr("transform", function (d) { 
      return "translate(" + main_x0(d.date) + ",0)"; 
     }) 
     .attr("width", function (d) { 
      return main_x1.rangeBand(); 
     }) 
     .attr("x", function (d) { 
      return main_x1(d.portfolio); 
     }); 

    main.select("g.x.axis").call(main_xAxis); 
} 

Работая скрипку на основе вашего упрощенного кода (Примечание: вы по-прежнему необходимо установить прямоугольник отсечения на основной сюжет):
http://fiddle.jshell.net/CjaD3/1/

+0

Это фантастика - спасибо за помощь! – JamesE

+2

Это была интересная головоломка. Оглядываясь назад, я сожалею о том, что предлагаю ([по вашему предыдущему вопросу] (http://stackoverflow.com/a/21370479/3128209)), что вместо шкалы времени вы используете порядковый масштаб.На самом деле не было бы * * * трудно заставить его работать с временным масштабом, вам просто нужно получить ширину каждого кластера, обнаружив разницу между масштабированными значениями двух последовательных дней. – AmeliaBR

+1

@AmeliaBR Я не могу поблагодарить вас за этот пример. Это отлично и именно то, что мне нужно, чтобы начать меня. Большое спасибо! – MartynJones87

Смежные вопросы