Алгоритм для хорошего графика маркирует для оси времени/даты?

Я ищу "хорошие числа" алгоритм для определения маркировок на оси даты/временной стоимости. Я знаком с Хорошим алгоритмом Чисел Paul Heckbert.

У меня есть график, который отображает время/дату на оси X, и пользователь может увеличить масштаб и посмотреть на меньший период времени. Я ищу алгоритм, который выбирает хорошие даты для отображения на галочках.

Например:

  • Рассмотрение приблизительно одного дня: 1/1 12:00, 1/1 4:00, 1/1 8:00...
  • Рассмотрение недели: 1/1, 1/2, 1/3...
  • Рассмотрение месяца: 1/09, 2/09, 3/09...

Хорошие галочки маркировки не должны соответствовать первой видимой точке, но близко к нему.

Действительно ли кто-либо знаком с таким алгоритмом?

21
задан Robert 3 July 2015 в 11:33
поделиться

5 ответов

В статье о "хороших числах", с которой вы связались, упоминалось, что

самыми хорошими числами в десятичной системе являются 1, 2, 5, и вся мощь 10 кратных этих чисел

Поэтому я думаю, что для того, чтобы сделать что-то похожее с датой/временем, вам нужно начать с аналогичного разбиения компонентных частей. Поэтому возьмите хорошие коэффициенты каждого типа интервала:

  • Если вы показываете секунды или минуты, используйте 1, 2, 3, 5, 10, 15, 30. (Я пропустил 6, 12, 15, 20, потому что они не "чувствуют" правильно).
  • Если вы показываете часы использовать 1, 2, 3, 4, 6, 8, 12
  • для использования дней 1, 2, 7
  • для использования недели 1, 2, 4 (13 и 26 подходят для модели, но мне кажется слишком странным)
  • для использования месяцев 1, 2, 3, 4, 6
  • для использования лет 1, 2, 5 и сила-10 кратных

Теперь очевидно, что это начинает ломаться по мере того, как вы получаете в больших количествах. Конечно, вы не хотите показывать 5 недель, которые стоят минут, даже с "красивыми" интервалами в 30 минут или что-то в этом роде. С другой стороны, когда у вас всего 48 часов, вы не хотите показывать интервалы в 1 день. Хитрость, на которую вы уже обратили внимание, состоит в том, чтобы найти приличные точки перехода.

Просто по догадке, я бы сказал, что разумная точка перехода будет примерно в два раза больше, чем следующий интервал. Это даст вам следующее (минимальное и максимальное количество интервалов, показанных после)

  • использовать секунды, если у вас меньше 2-х минут (1-120)
  • использовать минуты, если у вас меньше 2-х часов (2-120)
  • использовать часы, если у вас меньше 2-х дней (2- 48)
  • использовать дни, если у вас менее 2 недель (2-14)
  • использовать недели, если у вас менее 2 месяцев (2-8/9)
  • использовать месяцы, если у вас менее 2 лет (2-24)
  • в противном случае использовать лет (хотя вы можете продолжать десятилетиями, столетия и т.д., если ваши диапазоны могут быть настолько длинными)

К сожалению, наши непоследовательные временные интервалы означают, что в одних случаях вы заканчиваете с более чем 100 интервалами, в то время как в других - с более чем 8 или 9. Таким образом, вы захотите подобрать размер своих интервалов так, чтобы у вас было не более 10-15 интервалов максимум (или менее 5, если уж на то пошло). Кроме того, вы можете отступить от строгого определения 2-х кратного следующего наибольшего интервала, если считаете, что его легко отследить. Например, можно использовать часы до 3 дней (72 часа) и недели до 4 месяцев. Может понадобиться немного проб и ошибок.

Итак, чтобы вернуться назад, выберите тип интервала, исходя из размера вашего диапазона, затем выберите размер интервала, выбрав одно из "хороших" чисел, которое оставит вам от 5 до примерно 15 тиковых знаков. Или, если вы знаете и/или можете контролировать фактическое количество пикселей между тиковыми метками, вы можете поставить верхнюю и нижнюю границы допустимого количества пикселей между тиками (если они находятся слишком далеко друг от друга, граф может быть трудночитаемым, но при слишком большом количестве тиков граф будет загроможден, и ваши метки могут накладываться друг на друга).

8
ответ дан 29 November 2019 в 22:11
поделиться

Все еще нет ответа на этот вопрос ... Я брошу свою первую идею в то же время! Я предполагаю, что у вас есть ассортимент видимой оси.

Это, вероятно, как я бы сделал.

Грубый псевдоа:

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

После этого он должен (в зависимости от того, к чему у вас есть легкий доступ), довольно легко определить значение для каждой славной маркировки. В зависимости от «разрешения» вы отформатируете его по-разному. E.G.: MM / DD для «Неделя», мм: SS для «минуты» и т. Д. Так же, как вы сказали.

1
ответ дан 29 November 2019 в 22:11
поделиться

Я рекомендую вам взять исходный код GNUPLOT или RRDTOOL (или даже flot) и изучить, как они приближаются к этой проблеме. Общий корпус, скорее всего, будет N наклейки, применяемые на основе ширины вашего сюжета, который какой-то «привязанный» к ближайшему «приятному» числу.

Каждый раз, когда я написал такой алгоритм (слишком много раз на самом деле), я использовал таблицу «предпочтений» ... т. Е.: В зависимости от временного диапазона на сюжете, решите, используете ли я недели Дни, часы, минуты и т. Д. В качестве основной точки оси. Я обычно включаю в себя некоторые предпочтительные форматирования, так как я редко хочу увидеть дату каждую минуту, которую я замышляю на график.

Я был бы счастлив, но удивлен, чтобы найти кого-то, используя формулу (например, Хекберт делает), чтобы найти «Ницца», как вариация во временных единицах между протоколами, часами, днями и недельми, не в том числе линейным.

0
ответ дан 29 November 2019 в 22:11
поделиться

Взгляните на

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

Там есть nice.py (python / netsa / data / nice.py ), который я считаю автономным и должен нормально работать.

1
ответ дан 29 November 2019 в 22:11
поделиться

[Edit - я немного расширил это на http://www.acooke.org/cute/AutoScalin0.html ]

Наивное расширение алгоритма "хороших чисел" похоже, работает для базы 12 и 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())

Так, например, если вы хотите отображать секунды от 0 до 60,

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

или часы от 0 до 5:

>>> heckbert(0, 5, limits=LIM12)
['0', '2', '4', '6']
0
ответ дан 29 November 2019 в 22:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: