Группировка данных в зависимости от выбранного интервала времени в highstock

15 октября 2017 г. 14:17

Как оказалась, в графиках highstock не особо гибкая настройка группировки точек в зависимости от просматриваемого интервала времени. Да, данные могут группироваться, если их очень много (более тысячи) в некотором выбранном отрезке времени. Но когда это произойдёт, точно не понятно.

Настройку группировки вы можете осуществить через параметр plotOptions.series.dataGrouping.units (http://api.highcharts.com/highstock/plotOptions.series.dataGrouping.units), например:

Highcharts.stockChart('chart', {

    plotOptions: {
        series: {
            dataGrouping: {
                forced: true,
                units: units: [[ 'week', [1] ], ]
            },
        }
    },

    ...
});

Но здесь не указывается при каком временном определённом интервале следует выполнять соответствующую группировку (по неделям, месяцам и т. д.).

Для моего графика посещаемости этого сайта (который находится на странице Статистика и история развития сайта) для удобства анализа данных нужно было группировать точки в неделю только тогда, когда выбранный временной интервал составлял не менее 3 месяцев. Посмотрите в действии:

Библиотека Highcharts, тип: Basic line - неподдерживаемый тип диаграммы

Чтобы управлять группировкой данных, я добавил функцию setExtremes (http://api.highcharts.com/highstock/xAxis.events.setExtremes), которая вызывается при изменении временного интервала:

var time_break = 3 * 31 * 24 * 3600 * 1000;

Highcharts.stockChart('chart', {
    xAxis: {
        ...
        events: {
             setExtremes: function (e) {
                 delta = e.max - e.min;
                 if (delta <= time_break) {
                     $.each(this.series, function (index, obj) {
                         obj.options.dataGrouping.units[0] = ['day', [1]];
                     });
                 } else {
                     $.each(this.series, function (index, obj) {
                         obj.options.dataGrouping.units[0] = ['week', [1]];
                     });
                 }
             }
         }
    },

    ...
});

Как я говорил, параметр obj.options.dataGrouping.units отвечает за группировку наших точек. Чтобы посчитать временной интервал, нужно от конечной временной точки отнять начальную: e.max - e.min, а затем полученную разность сравнить с 3 месяцами. Разница e.max - e.min определяется в миллисекундах, поэтому подсчитываем сколько будет 3 месяца в миллисекундах и записываем это значение в time_break. Если time_break меньше 3-х месяцев, то устанавливаем значение ['day', [1]] в obj.options.dataGrouping.units[0], иначе ['week', [1]].

И напоследок, приведу полный листинг кода этого графика:

var time_break = 3 * 31 * 24 * 3600 * 1000;

Highcharts.stockChart('chart_{{ instance.id }}', {
    chart: {
        zoomType: 'x'
    },

    title: {
        text: '{% trans 'Visitors of vivazzi.pro' %}'
    },

    subtitle: {
        text: '{% trans 'Based on Yandex.Metrika' %}'
    },

    rangeSelector : {
        selected : 0,
        buttons: [{
            type: 'month',
            count: 1,
            text: '1{% trans 'm' %}'
        }, {
            type: 'month',
            count: 3,
            text: '3{% trans 'm' %}'
        }, {
            type: 'month',
            count: 6,
            text: '6{% trans 'm' %}'
        }, {
            type: 'year',
            count: 1,
            text: '1{% trans 'y' %}'
        }],
        inputDateFormat: '{% if request.LANGUAGE_CODE == 'ru' %}%e %b %Y{% else %}%b %e, %Y{% endif %}'
    },


    xAxis: {
        type: 'datetime',
        events: {
             setExtremes: function (e) {
                 delta = e.max - e.min;
                 if (delta <= time_break) {
                     $.each(this.series, function (index, obj) {
                         obj.options.dataGrouping.units[0] = ['day', [1]];
                     });
                 } else {
                     $.each(this.series, function (index, obj) {
                         obj.options.dataGrouping.units[0] = ['week', [1]];
                     });
                 }
             }
         }
    },

    yAxis: {
        title: {
            text: '{% trans 'Number' %}'
        }
    },

    legend: {
        layout: 'vertical',
        align: 'right',
        verticalAlign: 'middle'
    },

    plotOptions: {
        series: {
            tooltip: {
                valueDecimals: 0
            },

            dataGrouping: {
                dateTimeLabelFormats: {
                   millisecond: ['%A, %b %e, %H:%M:%S.%L', '%A, %b %e, %H:%M:%S.%L', '-%H:%M:%S.%L'],
                   second: ['%A, %b %e, %H:%M:%S', '%A, %b %e, %H:%M:%S', '-%H:%M:%S'],
                   minute: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
                   hour: ['%A, %b %e, %H:%M', '%A, %b %e, %H:%M', '-%H:%M'],
                   day: ['{% if request.LANGUAGE_CODE == 'ru' %}%A, %e %b %Y{% else %}%A, %b %e, %Y{% endif %}', '%A, %b %e', '-%A, %b %e, %Y'],
                   week: ['{% trans 'Average value in week from' %} {% if request.LANGUAGE_CODE == 'ru' %}%e %b %Y{% else %}%b %e, %Y{% endif %}', '%A, %b %e', '-%A, %b %e, %Y'],
                   month: ['%B %Y', '%B', '-%B %Y'],
                   year: ['%Y', '%Y', '-%Y']
                },

                forced: true,
                units: [
                    ['day', [1]]
                ]
            },

            pointStart: Date.UTC({{ start_year }}, {{ start_month }}, {{ start_day }}),
            pointInterval: 24 * 3600 * 1000 // one day
        }
    },

    series: {{ values }}
});
Примечание:
В фигурных скобках используются django-переменные. Что они выводят - интуитивно понятно, поэтому расписывать не буду.

Оцените статью

5 из 5 (всего 2 оценки)

captcha
Отмеченные звёздочкой поля ( * ) являются обязательными для заполнения.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор статьи

Артём Мальцев

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/it/data-grouping-highstock/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/it/data-grouping-highstock/">https://vivazzi.pro/ru/it/data-grouping-highstock/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

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

Комментарии: 3

Николай
Николай

17.11.2017 13:35 #

Существует и такое решение : https://github.com/highcharts/highcharts/issues/405 0

http://jsfiddle.net/tqyyqmzs/

Ответить

Артём Мальцев
Артём Мальцев автор

18.11.2017 4:16 #

Да, есть такое решение. Мне оно не понравилось, потому что группировка происходит только по клику кнопок зума. Если передвигать ползунок временной шкалы, то группировка сбивается.

Ответить

Николай
Николай

29.11.2017 14:39 #

Да, действительно сбивается группировка при использовании ползунка. Спасибо

Ответить

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте

Выберите валюту для отображения денежных единиц