2009-09-14 10 views
21

私は、日付/時刻値軸上のラベルを決定するための「素敵な数字」アルゴリズムを探しています。私はPaul Heckbert's Nice Numbers algorithmに精通しています。時間軸/日付軸のための素晴らしいグラフのラベルのためのアルゴリズム?

私は、X軸に時間/日付を表示するプロットを持っており、ユーザはズームインしてより小さな時間枠を見ることができます。私は、ダニに表示するための素敵な日付を選ぶアルゴリズムを探しています。例えば

:週に見る1/1 12:00、1月1日午前4時00分、1月1日8時...

  • :1日かそこらを見てみると

    • :1/1、1/2、1/3 ...
    • 月を見る:1/09、2月9日、3月9日...

    素敵なラベルのダニがいません第1の可視点に対応する必要があるが、それに近い。

    誰もこのようなアルゴリズムに精通していますか?

  • 答えて

    6

    あなたがそう小数で

    素敵な数字は1、2、5及びこれらの数字のすべての10のべき乗の倍数

    であることを述べたにリンクされている「素敵な数字」の記事私は日付/時刻と同様のことをやって、同様にコンポーネントの部品を分解することから始める必要があると思います。あなたは数秒から数分を見せている場合は(私は20、15、12、6をスキップ1、2、3、5、10、15、30 を使用

    • :だから間隔の各タイプの素敵な要因を取ります彼らは正しいと感じていないからです)。
    • あなたは時間1を使用し日間1、2、3、4、6、8、12
    • を使用して表示している場合は、2、7
    • 週間1、2、4(13、26フィットを使用数ヶ月のためのモデルが、私にはあまりにも奇妙に思える)
    • は今、明らかに1、2、5、10のべき乗の倍数

    を使っ年間、1、2、3、4、6

  • を使用しますあなたが大量になるにつれて、これは崩壊し始める。確かに、あなたは30分といった何かの「きれいな」間隔でさえ、5分間分の価値を見せたいとは思わない。一方、48時間しか持たない場合は、1日の間隔を表示する必要はありません。あなたがすでに指摘したように、トリックは、まともな移行ポイントを見つけることです。

    ちょうど奇妙なことに、合理的なクロスオーバーポイントは次のインターバルの約2倍になると私は言うだろう。あなたは価値が2時間未満を持っている場合は、(1-120)の価値が2分未満

  • 利用分を持っている場合、それはあなたに以下の(分、その後に示す間隔の最大数)

    • 利用秒を与えるだろう(2-120)
    • 使用時間をあなたはあまりを持っている場合は、(2-14)
    • 使用の週の価値が2週間未満がある場合は、(2-48)の価値が2日未満
    • 使用日数を持っている場合2か月以上(2〜8/9)より
    • あなたが2未満の場合は月を使います
    • (2-24)の価値が年間はそうでない場合は残念ながら、私たちの矛盾した時間間隔を使用すると、で終わること年(あなたの範囲はその長くなることがあれば、あなたが何十年、何世紀などを続けることができますが)

    を意味する使用しますいくつかのケースでは100以上のインターバルがあり、他のケースでは最大で8または9である場合があります。したがって、インターバルのサイズは、最大で10〜15インターバルを超えないように選択することをお勧めします(または5未満そのことについては)。また、次の最大間隔の2倍の厳密な定義から逸脱することができます。たとえば、最長3日間(72時間)、週4週間までの時間を使用することができます。少しの試行錯誤が必要かもしれません。

    戻ってくるには、範囲のサイズに基づいて間隔の種類を選択し、5と約15目盛りの間であなたを残す "いい"数字の1つを選んで間隔のサイズを選択します。または、目盛りの間のピクセルの実際の数を知っていて、ダミーの間に許容されるピクセル数の上限と下限を設定することができます(グラフが読みにくくなる場合があります)。グラフが乱雑になり、ラベルが重なり合う可能性があります)。

  • 1

    この質問にまだ答えはありません...私は最初のアイデアを投げます!私はあなたが目に見える軸の範囲を持っていると仮定します。

    これはおそらく私がやる方法です。

    ラフ擬似:その後

    // quantify range 
    rangeLength = endOfVisiblePart - startOfVisiblePart; 
    
    // qualify range resolution 
    if (range < "1.5 day") { 
        resolution = "day"; // it can be a number, e.g.: ..., 3 for day, 4 for week, ... 
    } else if (range < "9 days") { 
        resolution = "week"; 
    } else if (range < "35 days") { 
        resolution = "month"; 
    } // you can expand this in both ways to get from nanoseconds to geological eras if you wish 
    

    、それは各素敵なラベルの目盛りに値を決定することは非常に容易であること(あなたがへの容易なアクセスを持っているものに依存する)必要があります。 「解像度」によっては、別の方法でフォーマットします。例:あなたが言ったように、「週」のMM/DD、「分」のMM:SSなど。

    +0

    "1.5日"、 "9日"などのようなものは、実装の面で(私にとっては)言語依存性が高いです。たとえば、CやC++でも、両方の時間の差をミリ秒単位で保持するにはunsigned longを使用しますが、JavaではおそらくTimeクラスまたはMomentクラスを作成します。 .. – Joanis

    0

    gnuplotまたはRRDTool(またはFlot)のソースコードを入手して、この問題にどう対処するかを調べることをお勧めします。一般的なケースは、プロットの幅に基づいてNラベルが適用される可能性があります。これは、最も近い「nice」番号に何らかの「スナップ」します。

    私はこのようなアルゴリズムを書く度に(実際には何度も)、私は 'preferences'のテーブルを使っています。つまり、プロットの時間範囲に基づいて、週、日、時、分などを主軸として使用します。グラフにプロットした1分ごとの日付をめったに表示したくないので、通常は好きな書式設定が含まれていました。

    数分、時間、日、週の間の時間単位の変化が線形ではないため、誰かが式を使って「いい」を見つけるのは驚いています。

    0

    [編集 - 私はhttp://www.acooke.org/cute/AutoScalin0.htmlでもう少しこれを拡大]

    「素敵な数字」の素朴な拡張は、アルゴリズムは、時間と分のために良い間隔を与えるベース12と60、のために働くようです。あなたは、0から60まで0から5まで

    >>> heckbert(0, 60, limits=LIM60) 
    ['0', '15', '30', '45', '60'] 
    

    や時間を秒を表示したい場合は、例えば、

    LIM10 = (10, [(1.5, 1), (3, 2), (7, 5)], [1, 2, 5]) 
    LIM12 = (12, [(1.5, 1), (3, 2), (8, 6)], [1, 2, 6]) 
    LIM60 = (60, [(1.5, 1), (20, 15), (40, 30)], [1, 15, 40]) 
    
    
    def heckbert_d(lo, hi, ntick=5, limits=None): 
        ''' 
        Heckbert's "nice numbers" algorithm for graph ranges, from "Graphics Gems". 
        ''' 
        if limits is None: 
         limits = LIM10 
        (base, rfs, fs) = limits 
        def nicenum(x, round): 
         step = base ** floor(log(x)/log(base)) 
         f = float(x)/step 
         nf = base 
         if round: 
          for (a, b) in rfs: 
           if f < a: 
            nf = b 
            break 
         else: 
          for a in fs: 
           if f <= a: 
            nf = a 
            break 
         return nf * step 
        delta = nicenum(hi-lo, False) 
        return nicenum(delta/(ntick-1), True) 
    
    
    def heckbert(lo, hi, ntick=5, limits=None): 
        ''' 
        Heckbert's "nice numbers" algorithm for graph ranges, from "Graphics Gems". 
        ''' 
        def _heckbert(): 
         d = heckbert_d(lo, hi, ntick=ntick, limits=limits) 
         graphlo = floor(lo/d) * d 
         graphhi = ceil(hi/d) * d 
         fmt = '%' + '.%df' % max(-floor(log10(d)), 0) 
         value = graphlo 
         while value < graphhi + 0.5*d: 
          yield fmt % value 
          value += d 
        return list(_heckbert()) 
    

    をそう:これは私がちょうど一緒にハッキングコードです

    >>> heckbert(0, 5, limits=LIM12) 
    ['0', '2', '4', '6'] 
    
    0

    理論的には、概念を変更することもできます。視覚化の中心にあるデータではなく、中心にはスケールがあります。

    データの開始日と終了日を知っている場合は、すべての日付のスケールを作成し、このスケールでデータを送信できます。固定されたスケールのように。

    年、月、日、時間などの尺度を持つことができます。自由尺度の概念を削除することを意味します。

    利点は、日付間のギャップを簡単に表示できることです。しかし、多くのギャップがあると、それは役に立たなくなることもあります。

    関連する問題