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

StackOverflow https://stackoverflow.com/questions/1419194

  •  07-07-2019
  •  | 
  •  

Вопрос

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

У меня есть график, который отображает время / дату по оси 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...

Галочки на красивой метке не обязательно должны соответствовать первой видимой точке, но близко к ней.

Кто-нибудь знаком с таким алгоритмом?

Это было полезно?

Решение

В статье "приятные цифры", на которую вы ссылались, упоминалось, что

самыми приятными числами в десятичной системе счисления являются 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)
  • в противном случае используйте годы (хотя вы могли бы продолжить с десятилетиями, столетиями и т.д., если ваши диапазоны могут быть такими длинными)

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

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

Другие советы

До сих пор нет ответа на этот вопрос...Тогда я подкину свою первую идею!Я предполагаю, что у вас есть диапазон видимой оси.

Вероятно, именно так я бы и поступил.

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

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

После этого должно быть (в зависимости от того, к чему у вас есть легкий доступ) довольно легко определить значение для каждой галочки nice label.В зависимости от "разрешения" вы форматируете его по-разному.Например.:ММ / ДД для "недели", ММ: СС для "минуты" и т.д., как вы и сказали.

Взгляните на

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

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

Я бы посоветовал вам загрузить исходный код в gnuplot или RRDTool (или даже Flot) и изучить, как они подходят к этой проблеме.Общим случаем, вероятно, будет N меток, нанесенных в зависимости от ширины вашего графика, которые каким-то образом "привязываются" к ближайшему "хорошему" числу.

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

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

[Редактировать - я расширил это немного больше в 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']

Теоретически вы также можете изменить свою концепцию.Где в центре визуализации находятся не ваши данные, а в центре у вас есть свой масштаб.

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

У вас может быть шкала типа год, месяц, день, часы, ...и ограничьте масштабирование только этими масштабами, подразумевая, что вы удаляете концепцию свободного масштабирования.

Преимущество заключается в том, что вы можете легко показывать пробелы в датах.Но если у вас много пробелов, это тоже может стать бесполезным.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top