簡體   English   中英

D3刷組合條形圖

[英]D3 brushing on grouped bar chart

我試圖刷牙工作類似於這個例子,但有一個分組的條形圖: http//bl.ocks.org/mbostock/1667367

我真的不太了解刷牙是如何工作的(我還沒有找到任何好的教程),所以我對於出了什么問題感到有些不知所措。 我將嘗試在下面包含相關的代碼。 該圖表跟蹤按天修復損壞的構建的時間,然后按投資組合分組。 到目前為止,刷子已創建,用戶可以移動並拖動它,但主圖表中的條形圖被奇怪地重新繪制,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);
}

問題來自於嘗試使用畫筆來設置x比例域,當x尺度是序數尺度時。 換句話說,x軸的預期域是一個類別列表,而不是max-min數值范圍。 所以問題就在刷牙功能的頂部:

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

brush.extent()設置的域是一個包含兩個數字的數組,然后完全brush.extent()您的序數。

根據wiki ,如果附加到畫筆函數的其中一個音階是序數音階,則brush.extent()返回的值是輸出范圍中的值,而不是輸入域中的值。 序數標度沒有用於將范圍值轉換為域值invert()方法

那么,您有幾個選項可以繼續:

您可以使用主x軸的線性時間刻度而不是序數刻度來重新繪制整個圖形。 但是你必須編寫自己的函數來計算該軸上每天的寬度,而不是能夠使用.rangeBand()

您可以創建自己的“反轉”函數,以確定哪些分類值( mini_x0.domain上的mini_x0.domain )包含在brush.extent()返回的范圍內。 然后,你就必須重置main_x0.domain只包含在軸線上的日期你的矩形過濾掉,只畫那些矩形。

或者你可以離開main_x0.域名 main_x0. 是,並改為改變范圍 通過使圖形的范圍更大,可以使條形更大。 結合剪切路徑來切斷繪圖區域外的條形圖,這具有僅顯示條形的某個子集的效果,這無論如何都是您想要的。

但新范圍應該是什么? brush.extent()返回的范圍是刷子矩形的起始位置和結束位置。 如果您將這些值用作主圖上的范圍,則整個圖形將被壓縮到該寬度。 這與你想要的相反。 你想要的是最初填充該寬度的圖形區域被拉伸以填充整個繪圖區域。

因此,如果您的原始x范圍是[0,100],並且畫筆覆蓋了區域[20,60],那么您需要一個滿足以下條件的新范圍:

  • 新范圍寬度的20%標記為0;
  • 新范圍寬度的60%標記為100。

因此,

  • 新范圍的總寬度為((100-0)/(60-20))*(100-0)= 250;
  • 新范圍的起點是(0 - (20/100)* 250)= - 50;
  • 新范圍的結尾是(-50)+ 250 = 200。

現在你可以做所有的代數來自己搞清楚這個轉換。 但這實際上只是另一種縮放方程式,所以為什么不創建一個新的縮放函數來在舊范圍和放大范圍之間進行轉換。

具體來說,我們需要一個線性比例 ,其輸出范圍設置為繪圖區域的實際范圍。 然后根據我們想要拉伸的拉絲區域的范圍設置域以覆蓋繪圖區域。 最后,我們通過使用線性比例來計算出序數比例的范圍,以計算出距離屏幕的原始最大值和最小值的距離。 從那里,我們可以調整其他序數尺度並重新定位所有矩形。

在代碼中:

//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/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM