0

私はD3とJavascriptに非常に慣れていないので、コードが少し醜い、または整理されていないように見える場合はご容赦ください。

私は、x軸とy軸、およびプロットのデータメトリックとしての円の半径の3つのメトリックを利用するプロットに取り組んでいます。私が読んでいるデータは2次元配列であり、各行は異なるメトリックであり、各列は新しいデータポイントです。ドロップボックスから別のメトリックを選択することで円の半径を動的に変更する方法を正常に実装しましたが、これは非常に特定の問題に際限なく苦労した後のことでした。データが間違った円に割り当てられていました。

最初に円を作成するときは、最初にsort()を使用して、デフォルトの半径メトリック(コードでは「impactcpu」)から降順で円を並べ替えます。これは、小さな円の後に描かれた大きな円が小さな円を遮っていた問題を修正するために行われたので、最初に最大の円を「ペイント」したいと思いました。

計算されたデータ配列を円に割り当てる前に最初に並べ替えることで、この問題を回避することができました。これにより、デフォルトの順序が維持されます。しかし、私は今、X軸とY軸で同じようなことをしようとしています。ドロップダウンメニューは、メトリック値を円に正しく割り当てていますが、間違った円に割り当てています。割り当ての前に配列を再ソートすることは、半径に対して行っていたように機能しないため、この問題の解決策をまだ理解していません(私は期待していました)。正しいデータポイントが正しい円に割り当てられていることを確認する方法について何か提案はありますか?できれば、私のコードの残りの部分のオーバーホールを必要としないもの:)

上記の状況の例については、私のjsfiddleをご覧ください。

http://jsfiddle.net/kingernest/YDQR4/3/

最初にサークルを作成する方法の例:

var circles = svg.selectAll("circle")
    .data(dataset, function(d) { return d.id })
    .enter()    
    .append("circle")
    .sort(function(a, b){    //Sort by radius size, helps reduce obstruction of circles
        return d3.descending(a[14], b[14]);
    })
    .attr("cx", function(d){ //x axis is Req IO, col index 9
        return xScale(d[9]);
    })
    .attr("cy", function(d){ //y axis is Req CPU, col index 8
        return yScale(d[8]);
    })
    .attr("r", function(d){ //radius is based off Impact CPU, col 14

        console.log("Rad: " + d[14])
        return d[14] * 1.5;
    })
    .attr("class", "dataCircle")

現在、半径を変更する方法:

function changeRad() {
     console.log(this.value); 
     var myRadData = [];
     var index = metricHash[this.value];
     var weight; //to adjust data to fit appropriately in graph
    switch(this.value) 
    {
        case "impactcpu": 
            weight = 1.5;
            break;
        case "spool": 
            weight = .0000001;    //spool is normally a very large value
            break;
        case "pji": 
            weight = 8;
            break;
        case "unnecio": 
            weight = 12;
            break;
        case "duration": 
            weight = .0002;
            break;
        default: alert("Invalid value: " + this.value); 
            break;
    }
     for(var i=0; i < dataset.length; i++)
     {         
         console.log(dataset[i][index]);
         myRadData.push(dataset[i][index] * weight);
     }

    myRadData.sort(function(a,b){return b-a});

    d3.selectAll("circle")
        .data(myRadData)
        .transition().duration(500)
        .attr("r", function(d){
            return d;
        });

    circles.data(dataset); //reassign old data set (with all data values)
}
4

2 に答える 2

1

コード全体を把握できるかどうかはわかりませんが(かなり長いです)、解決策は次のようになります。

1-最初に円を作成するときは、キー機能を使用します。よし、あなたはこれをやっている:

.data(dataset, function(d) { return d.id; })

2-同じ機能を使用して円にID属性を与えます。

.attr("ID", function(d) { return d.id; })

3-次に、特定の円を個別に変更する必要がある場合は、次のように選択できます。

svg.select('#' + myCircleID).attr('blahblah', somevalue)

myRadData配列を作成するときに、ID属性が失われていることにも気づきました。これにより、コードがそれらを正しいサークルに結合できなくなります。最初にID属性があるので、並べ替えを使用して並べ替えるよりも、全体でキー機能を使用する方が適切です。

より具体的な回答が必要な場合は、問題を再現する最も単純な形式に例を要約する必要があると思います。

于 2013-03-06T02:07:58.747 に答える
1

私があなたのコードで見る2つのことがあります:

  1. データバインディングのキー機能に一貫性.data(dataset, function(d) { return d.id })がありません-circles()の最初の作成時に正しく使用しますが、更新時に参照しないでください。更新に同じキーを追加すると、同じ要素を更新していることを確認できます。

  2. DOMの並べ替え-最初にサークルを作成するときにselection.sortを使用することは、論理的で適切なようです(.sort(function(a, b){ return d3.descending(a[14], b[14]); }))データを再バインドするのではなく、これを更新関数に拡張することをお勧めします。

私はあなたのコードにこれらのクイックアップデートを行いました、そしてそれはあなたの問題を解決するようです:http: //jsfiddle.net/AbHfk/3/

于 2013-03-06T02:37:08.473 に答える