13

d3js を使用して、Web サイトのビューをリアルタイムで表示しています。このためにスタック レイアウトを使用し、現時点では JSON でデータセットを更新しています。

グラフ内のビューの量に動的に関連する y 軸に 1 つまたは 2 つのビューしか表示されていない場合、軸ラベルは次のようになります: 1 => 0, 0.2, 0.4, 0.6, 0.8, 1、軸ラベルは次のとおりです: 2 =>0, 0.5, 1, 1.5, 2これは意味がありませんページのビューを表示し、半分のビューを持つことはできないため、私のデータセットです。

私はy軸のベースとなるd3jsに線形スケールを持っています

var y_inverted = d3.scale.linear().domain([0, 1]).rangeRound([0, height]); 

rangeRound() のドキュメントによると、このスケールから全体の値のみを取得する必要があります。私の軸を描くために私は使用します:

var y_axis = svg.append("g")
    .attr("class", "y axis")
    .attr("transform", "translate(0,0)")
    .call(y_inverted.axis = d3.svg.axis()
        .scale(y_inverted)
        .orient("left")
        .ticks(5));

これはリアルタイム アプリケーションであるため、次のように呼び出して毎秒更新します。

function update(){
    y_inverted.domain([yStackMax, 0]);
    y_axis.transition()
        .duration(interval)
        .ease("linear")
        .call(y_inverted.axis);
}

yStackMax は、y 値に使用されるデータに整数のみが含まれていることがわかっている限り、スタックレイアウトから計算されます。

var yStackMax = d3.max(layers, function(layer) {
    return d3.max(layer, function(d) {
        return d.y0 + d.y;
    });
});

y 軸の適切な値を取得するために、いくつかのことを試しました。

d3.svg.axis()
    .scale(y_inverted)
    .orient("left")
    .ticks(5).tickFormat(d3.format(",.0f"))

一番近いソファを手に入れたが、まだ表示されている0, 0, 0, 1, 1, 1

基本的に私が望むのは、1の場合は1ティック、2の場合は2ティックだけですが、 12または1,000,000yStackMaxの場合にも機能するはずですyStackMax

4

5 に答える 5

12

簡単な答え:ティック数を動的に設定できます。12 つの目盛りラベルのみを表示するには、 に設定します。

var maxTicks = 5, minTicks = 1;
if (yStackMax < maxTicks) {
    y_axis.ticks(minTicks)
}
else {
    y_axis.ticks(maxTicks)
}

長い回答(トピックから少し外れます):あなたの例で遊んでいるときに、すべてのフォーマットの問題に対するかなり「完全な解決策」を思いつきました。気軽に使ってください:)

var svg = d3.select("#svg")
var width = svg.attr("width")
var height = svg.attr("height")
var yStackMax = 100000
var interval = 500
var maxTicks = 5
var minTicks = 1

var y_inverted = d3.scale.linear().domain([0, 1]).rangeRound([0, height])
var defaultFormat = d3.format(",.0f")

var format = defaultFormat

var y_axis = d3.svg.axis()
    .scale(y_inverted)
    .orient("left")
    .ticks(minTicks)
    .tickFormat(doFormat)

var y_axis_root;
var decimals = 0;

function countDecimals(v){
    var test = v, count = 0;
    while(test > 10) {
        test /= 10
        count++;
    }
    return count;
}

function doFormat(d,i){
    return format(d,i)
}

function init(){
    y_axis_root = svg.append("g")
        .attr("class", "y axis")
        // I modified your example to move the axis to a visible part of the screen
        .attr("transform", "translate(150,0)")
        .call(y_axis)
}

// custom formatting functions:
function toTerra(d) { return (Math.round(d/10000000000)/100) + "T" }
function toGiga(d)  { return (Math.round(d/10000000)/100) + "G" }
function toMega(d)  { return (Math.round(d/10000)/100) + "M" }
function toKilo(d)  { return (Math.round(d/10)/100) + "k" }

// the factor is just for testing and not needed if based on real world data
function update(factor){
    factor = (factor) || 0.1;
    yStackMax*=factor
    decimals = countDecimals(yStackMax)
    console.log("yStackMax decimals:",decimals, factor)
    if     (yStackMax < maxTicks) {
        format = defaultFormat
        y_axis.ticks(minTicks)
    }
    else {
        y_axis.ticks(maxTicks)
        if     (decimals < 3 ) format = defaultFormat
        else if(decimals < 6 ) format = toKilo
        else if(decimals < 9 ) format = toMega
        else if(decimals < 12) format = toGiga
        else                   format = toTerra
    }

    y_inverted.domain([yStackMax, 0]);
    y_axis_root.transition()
        .duration(interval)
        .ease("linear")
        .call(y_axis);
}

init()
setTimeout(update, 200)
setTimeout(update, 400)
setTimeout(update, 600)

次の HTML スニペットと一緒に試すことができます。

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.js"></script>
    </head>

    <body>
        <div><svg id="svg" width="200" height="300"></svg></div>
        <script src="axis.js"></script>
        <button id="button1" onclick="update(10)">+</button>
        <button id="button2" onclick="update(0.1)">-</button>
    </body>
</html>

私はそれが少し話題から外れていることを知っていますが、私は通常、実行中の例/解決策を提供したいと思っています. 追加の書式設定は、実際の問題のボーナスと見なしてください。

于 2012-11-23T15:08:48.723 に答える
5

( axis.ticks() を介して)特定の数の目盛りを要求すると、d3はその数の目盛りを提供しようとしますが、きれいな値を使用しようとします。あなたのデータとは何の関係もありません。

あなたの解決策は、あなたが行ったように tickFormat を使用して、すべての値を整数値に丸め、Juve が答えたように 1 つの目盛りだけを要求するか、axis.tickValues([...])を使用して目盛り値を明示的に設定することです。 d3.rangeと組み合わせて簡単に使用

rangeRound は、スケールの出力範囲に関連しているため、この場合は役に立ちません。この場合は、0 と高さの間でプロットするピクセル オフセットです。

于 2012-11-26T14:36:55.113 に答える
4

Superbogglyの答えから外れて、これが私にとってうまくいきました。最初に、次を使用して y ドメインから最大 (最大) 数を取得しy.domain().slice(-1)[0]、次にそれを使用して目盛り値の配列を作成しましたd3.range()...

  var y_max = y.domain().slice(-1)[0]
  var yAxis = d3.svg.axis()
      .scale(y)
      .tickValues(d3.range(y_max+1))
      .tickFormat(d3.format(",.0f"))
于 2012-12-27T22:58:16.427 に答える
3

または、目盛りをそのままにして、10進数を「非表示」にします

d3.svg.axis()
    .scale(y_inverted)
    .orient("left")
    .ticks(5).tickFormat(function(d) {
              if (d % 1 == 0) {
                return d3.format('.f')(d)
              } else {
                return ""
              }
            });
于 2015-06-15T08:05:56.213 に答える