Группировка данных в зависимости от выбранного интервала времени в 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 #
Да, действительно сбивается группировка при использовании ползунка. Спасибо
Ответить