Группировка данных в зависимости от выбранного интервала времени в 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-переменные. Что они выводят - интуитивно понятно, поэтому расписывать не буду.
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 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 #
Да, действительно сбивается группировка при использовании ползунка. Спасибо
Ответить