Question

Je recherche un "nombre intéressant". algorithme pour déterminer les étiquettes sur un axe de valeur date / heure. Je connais l'algorithme Nice Numbers de Paul Heckbert .

J'ai un tracé qui affiche l'heure / la date sur l'axe des abscisses et l'utilisateur peut effectuer un zoom avant et regarder une période plus courte. Je cherche un algorithme qui sélectionne les bonnes dates à afficher sur les ticks.

Par exemple:

  • Regarder un jour ou deux: 1/1 12:00, 1/1 4:00, 1/1 8:00 ...
  • En regardant une semaine: 1/1, 1/2, 1/3 ...
  • En regardant par mois: 1/09, 2/09, 3/09 ...

Les jolis libellés ne doivent pas nécessairement correspondre au premier point visible, mais être proches de celui-ci.

Quelqu'un est-il familier avec un tel algorithme?

Était-ce utile?

La solution

L'article "de bons numéros" que vous avez lié a mentionné que

  

les plus beaux nombres décimaux sont 1, 2, 5 et tous les multiples de 10 de ces nombres

Donc, je pense que pour faire quelque chose de similaire avec la date / heure, vous devez commencer par décomposer de la même manière les composants. Alors, prenez les bons facteurs de chaque type d’intervalle:

  • Si vous affichez les secondes ou les minutes, utilisez 1, 2, 3, 5, 10, 15, 30 (J'ai sauté 6, 12, 15, 20 parce qu'ils ne se sentent pas bien).
  • Si vous affichez les heures, utilisez 1, 2, 3, 4, 6, 8, 12
  • pour les jours, utilisez 1, 2, 7
  • pendant des semaines, utilisez 1, 2, 4 (13 et 26 correspondent au modèle mais me paraissent trop bizarres)
  • pendant des mois, utilisez 1, 2, 3, 4, 6
  • pendant des années, utilisez des multiples 1, 2, 5 et une puissance de 10

Maintenant, évidemment, cela commence à se décomposer à mesure que vous obtenez de plus grandes quantités. Certes, vous ne voulez pas montrer 5 minutes de minutes, même dans "joli". intervalles de 30 minutes ou quelque chose. En revanche, lorsque vous ne disposez que de 48 heures, vous ne souhaitez pas afficher les intervalles d'un jour. L'astuce, comme vous l'avez déjà souligné, consiste à trouver des points de transition décents.

Juste sur un pressentiment, je dirais qu'un point de croisement raisonnable serait environ le double de l'intervalle suivant. Cela vous donnerait ce qui suit (nombre min et max d’intervalles indiqués après)

  • utilisez les secondes si vous avez moins de 2 minutes (1-120)
  • utilisez les minutes si vous avez moins de 2 heures (2-120)
  • utilisez les heures si vous avez moins de 2 jours (2-48)
  • utilisez jours si vous avez moins de 2 semaines (2-14)
  • utilisez semaines si vous avez moins de 2 mois (2-8 / 9)
  • utilisez mois si vous avez moins de 2 ans (2-24)
  • sinon, utilisez des années (bien que vous puissiez continuer avec des décennies, des siècles, etc. si vos plages peuvent être aussi longues)

Malheureusement, nos intervalles de temps incohérents signifient que vous vous retrouvez avec des cas pouvant compter plus de cent intervalles tandis que d'autres en ont au plus 8 ou 9. Vous voulez donc choisir la taille de vos intervalles de sorte que vous ne le fassiez pas t avoir plus de 10-15 intervalles au maximum (ou moins de 5 à cet égard). En outre, vous pouvez rompre avec une définition stricte de 2 fois l'intervalle le plus grand suivant si vous pensez qu'il est facile de le suivre. Par exemple, vous pouvez utiliser des heures allant jusqu'à 3 jours (72 heures) et des semaines jusqu'à 4 mois. Un peu d’essai et d’erreur peut être nécessaire.

Donc, pour revenir en arrière, choisissez le type d'intervalle en fonction de la taille de votre plage, puis choisissez la taille de l'intervalle en choisissant l'un des paramètres "sympa". chiffres qui vous laisseront entre 5 et environ 15 graduations. Ou, si vous connaissez et / ou pouvez contrôler le nombre réel de pixels entre les graduations, vous pouvez définir des limites supérieures et inférieures pour définir le nombre de pixels acceptables entre les graduations (si elles sont trop éloignées les unes des autres, le graphique peut être difficile à lire. il y a trop de ticks, le graphique sera encombré et vos étiquettes pourraient se chevaucher).

Autres conseils

Toujours pas de réponse à cette question ... Je vais y jeter ma première idée! Je suppose que vous avez la plage de l’axe visible.

C’est probablement ce que je ferais.

Pseudo brut:

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

Après cela, il devrait (en fonction de votre accès facile) être assez facile de déterminer la valeur de chaque tick agréable. Selon la "résolution", vous le formatez différemment. Ex .: MM / JJ pour "semaine", MM: SS pour "minute", etc., comme vous l'avez dit.

Regardez

http://tools.netsa.cert.org/netsa -python / doc / index.html

Il a un nice.py (python / netsa / data / nice.py) qui, à mon avis, est autonome et devrait fonctionner correctement.

Je suggérerais que vous récupériez le code source dans gnuplot ou RRDTool (ou même Flot) et que vous examiniez comment ils abordent ce problème. Le cas général est susceptible d’être N étiquettes appliquées en fonction de la largeur de votre tracé, ce qui correspond à une sorte de "capture" sur le nombre "sympa" le plus proche.

Chaque fois que j'ai écrit un tel algorithme (vraiment trop de fois), j'ai utilisé un tableau de 'préférences' ... c'est-à-dire: en fonction de la plage de temps du tracé, décidez si j'utilise Weeks , Jours, heures, minutes, etc. comme point d’axe principal. J'avais l'habitude d'inclure certains formats préférés, car je veux rarement voir la date de chaque minute que je trace sur le graphique.

Je serais heureux mais surpris de trouver quelqu'un qui utilise une formule (comme Heckbert) pour trouver "sympa", car la variation des unités de temps entre les minutes, les heures, les jours et les semaines n'est pas si linéaire.

[Modifier - J'ai développé cela un peu plus à l'adresse http://www.acooke.org /cute/AutoScalin0.html ]

Une extension naïve des "bons numéros" L'algorithme semble fonctionner pour les bases 12 et 60, ce qui donne de bons intervalles pour les heures et les minutes. Voici le code que je viens de pirater ensemble:

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

Ainsi, par exemple, si vous souhaitez afficher les secondes de 0 à 60 secondes,

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

ou heures de 0 à 5:

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

En théorie, vous pouvez également modifier votre concept. Où ce ne sont pas vos données au centre de la visualisation, mais au centre, vous avez votre échelle.

Lorsque vous connaissez le début et la fin des dates de vos données, vous pouvez créer une échelle avec toutes les dates et vous envoyer des données dans cette échelle. Comme une balance fixe.

Vous pouvez avoir une échelle de type année, mois, jour, heures, ... et limiter la mise à l'échelle uniquement à ces échelles, ce qui implique de supprimer le concept de mise à l'échelle libre.

L’avantage est de pouvoir facilement montrer les écarts de dates. Mais si vous avez beaucoup de lacunes, cela peut devenir aussi inutile.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top