2009-09-14 7 views
21

Ich suche nach einem "nice numbers" -Algorithmus zum Ermitteln der Beschriftungen auf einer Datums-/Zeitwertachse. Ich bin vertraut mit Paul Heckbert's Nice Numbers algorithm.Algorithmus für schöne Diagrammbeschriftungen für Zeit/Datum Achse?

Ich habe ein Diagramm, das Zeit/Datum auf der X-Achse anzeigt, und der Benutzer kann hineinzoomen und einen kleineren Zeitrahmen betrachten. Ich suche nach einem Algorithmus, der schöne Daten auswählt, die auf den Ticks angezeigt werden.

Zum Beispiel:

  • an einem Tag der Suche oder so: 1/1 12:00, 1/1 04.00, 01.01 08.00 Uhr ...
  • in einer Woche Suche : 1/1, 1/2, 1/3 ...
  • in einem Monat der Suche: 1/09, 2/09, 3/09 ...

Die Zecken schöne Etikett nicht muss dem ersten sichtbaren Punkt entsprechen, aber nahe an ihm.

Kennt jemand solch einen Algorithmus?

Antwort

6

Der Artikel 'schöne Zahlen' Sie erwähnt verbunden, dass

die nettesten Zahlen in dezimal 1, 2, 5 und alle Power-of-10 ein Vielfaches dieser Zahlen

So Ich denke, um etwas ähnliches mit Datum/Zeit zu tun, müssen Sie beginnen, indem Sie auf ähnliche Weise die Einzelteile zerlegen. So nehmen Sie die schönen Faktoren jede Art von Intervall:

  • Wenn Sie zeigt Sekunden oder Minuten verwenden 1, 2, 3, 5, 10, 15, 30 (I 6 übersprungen, 12, 15, 20 weil sie sich nicht richtig fühlen.
  • Wenn Sie Stunden Gebrauch 1 sind zeigt, 2, 3, 4, 6, 8, 12
  • für Tag benutzen 1, 2, 7
  • für Wochen verwenden 1, 2, 4 (13 und 26 fit das Modell aber scheint mir zu ungerade)
  • für Monate verwenden 1, 2, 3, 4, 6
  • jahrelang verwenden 1, 2, 5 und Power-of-10 Multiples

Jetzt offensichtlich Dies beginnt zu brechen, wenn Sie in größere Mengen kommen. Sicherlich wollen Sie keine 5 Wochen Minuten zeigen, auch nicht in "schönen" Intervallen von 30 Minuten oder so. Auf der anderen Seite, wenn Sie nur 48 Stunden Wert haben, wollen Sie keine 1-Tages-Intervalle zeigen. Der Trick, auf den Sie bereits hingewiesen haben, ist, anständige Übergangspunkte zu finden.

Nur auf eine Ahnung, würde ich sagen, ein vernünftiger Crossover-Punkt wäre etwa doppelt so viel wie das nächste Intervall. Das würde Ihnen die folgende (min und max Anzahl der Intervalle danach gezeigt)

  • Verwendung Sekunden, wenn Sie weniger als 2 Minuten im Wert (1-120)
  • Verwendung Minuten, wenn Sie weniger als 2 Stunden im Wert (2-120)
  • Nutzung Stunden, wenn Sie weniger als 2 Tage im wert (2-48)
  • Verwendung Tage, wenn Sie weniger als 2 Wochen im wert von (2-14)
  • Verwendung Wochen, wenn Sie weniger haben als 2 Monate Wert (2-8/9)
  • Verwenden Sie Monate, wenn Sie weniger als 2 haben wert Jahre (2-24)
  • sonst Jahre verwenden (auch wenn Sie mit Jahrzehnten fortsetzen können, Jahrhunderte, etc, wenn Ihre Bereiche so lange sein können)

Leider ist unsere inkonsistenten Zeitintervalle bedeuten, dass Sie am Ende mit einige Fälle, die über 1 hundert Intervalle haben können, während andere höchstens 8 oder 9 haben. Sie sollten also die Größe Ihrer Intervalle so wählen, dass Sie höchstens 10 - 15 Intervalle (oder weniger als 5 Intervalle) haben für diese Angelegenheit). Sie könnten auch von einer strikten Definition des 2-fachen des nächstgrößeren Intervalls abweichen, wenn Sie glauben, dass es einfach ist, den Überblick zu behalten. Zum Beispiel könnten Sie Stunden bis zu 3 Tagen (72 Stunden) und Wochen bis zu 4 Monaten verwenden. Ein wenig Versuch und Irrtum könnte notwendig sein.

Um zurückzugehen, wählen Sie den Intervalltyp basierend auf der Größe Ihres Bereichs, und wählen Sie dann die Intervallgröße, indem Sie eine der "netten" Zahlen wählen, die zwischen 5 und etwa 15 Tickmarkierungen liegen. Oder wenn Sie die tatsächliche Anzahl der Pixel zwischen den Markierungen kennen und/oder steuern können, können Sie obere und untere Grenzen setzen, wie viele Pixel zwischen den Markierungen zulässig sind (wenn sie zu weit voneinander entfernt sind, ist die Grafik möglicherweise schwer zu lesen) Es gibt zu viele Ticks, die Grafik wird unübersichtlich und Ihre Labels können sich überlappen.

1

Noch keine Antwort auf diese Frage ... Ich werde dann meine erste Idee in werfen! Ich nehme an, Sie haben den Bereich der sichtbaren Achse.

Dies ist wahrscheinlich, wie ich es tun würde.

Raue pseudo:

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

Danach sollte es (je nachdem, was Ihnen einen einfachen Zugang zu haben) sein ganz leicht, den Wert zu jedem schönen Etikett tick zu bestimmen. Abhängig von der 'Auflösung' formatieren Sie es anders. ZB: MM/DD für "woche", MM: SS für "minute", etc., genau wie du gesagt hast.

+0

Dinge wie "1,5 Tage", "9 Tage" usw. sind in Bezug auf die Implementierung (für mich) sehr sprachabhängig. Zum Beispiel würde ich in C oder C++ einfach eine nicht signierte long verwenden, um den Unterschied in Millisekunden zwischen beiden Zeiten zu halten, während ich in Java wahrscheinlich eine Time- oder Moment-Klasse erstellen würde, und wahrscheinlich gibt es bereits einige davon irgendwo. .. – Joanis

0

Ich würde vorschlagen, dass Sie den Quellcode zu gnuplot oder RRDTool (oder sogar Flot) greifen und untersuchen, wie sie dieses Problem angehen. Der allgemeine Fall ist wahrscheinlich, dass es sich um N-Labels handelt, die basierend auf der Breite des Plots angewendet werden, wobei eine Art "Schnappen" auf die nächste "nette" Zahl erfolgt.

Jedes Mal, wenn ich einen solchen Algorithmus geschrieben habe (zu viele Male wirklich), habe ich eine Tabelle mit "Einstellungen" verwendet ... dh: Entscheide, ob ich den Zeitbereich der Handlung nutze Wochen, Tage, Stunden, Minuten usw. als Hauptachsenpunkt. Ich habe normalerweise eine bevorzugte Formatierung eingefügt, da ich selten das Datum für jede Minute sehen möchte, die ich auf dem Diagramm zeichne.

Ich wäre glücklich, aber überrascht, jemanden zu finden, der eine Formel verwendet (wie Heckbert), um "nett" zu finden, da die Variation in Zeiteinheiten zwischen Minuten, Stunden, Tagen und Wochen nicht so linear ist.

0

[Edit - ich erweiterte diese ein wenig mehr an http://www.acooke.org/cute/AutoScalin0.html]

Eine naive Erweiterung der „schönen Zahlen“ Algorithmus scheint für die Basis 12 und 60, die für Stunden und Minuten gut Abstände gibt zu arbeiten.Dies ist Code, den ich zusammen nur gehackt:

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()) 

So zum Beispiel, wenn Sie Sekunden von 0 bis 60 angezeigt werden sollen,

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

oder Stunden von 0 bis 5:

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

In der Theorie können Sie auch Ihr Konzept ändern. Wo nicht Ihre Daten im Mittelpunkt der Visualisierung stehen, sondern in der Mitte, haben Sie Ihre Skalierung.

Wenn Sie den Anfang und das Ende der Daten Ihrer Daten kennen, können Sie eine Skala mit allen Daten erstellen und Daten in dieser Skala versenden. Wie eine feste Waage.

Sie können eine Skalierung vom Typ Jahr, Monat, Tag, Stunden, ... haben und die Skalierung auf diese Skalen beschränken, was bedeutet, dass Sie das Konzept der freien Skalierung entfernen.

Der Vorteil ist, dass Daten Lücken leicht zeigen können. Aber wenn Sie viele Lücken haben, kann das auch nutzlos werden.