Я разрабатываю веб-сайты на Python и Flask, используя Bootstrap для стилизации. Недавно мне понадобилось добавить на сайт интерактивные графики. При выборе JavaScript библиотеки для этого, я наткнулся на Chart.js — у неё более 29 000 звёзд на GitHub (на май 2017). И сегодня мы рассмотрим три примера создания графиков с Chart.js в приложении Flask.
Исходные коды примеров из статьи вы можете найти в репозитории GitLab с отдельными тегами (example1, example2 и example3) для каждого примера: https://gitlab.com/patkennedy79/flask_chartjs_example
Структура приложения
.
├── README.md
├── app.py
├── requirements.txt
├── static
│ └── Chart.min.js
└── templates
├── chart.html
├── line_chart.html
└── time_chart.html
В папке templates хранятся следующие шаблоны:
- Пример №1 – chart.html
- Пример №2 – line_chart.html
- Пример №3 – time_chart.html
Пример №1. Простой график
Мы сделаем небольшое приложение Flask, которое сгенерирует данные для их вывода с Chart.js. В файле app.py добавьте такие строки:
from flask import Flask
from flask import render_template
from datetime import time
app = Flask(__name__)
@app.route("/simple_chart")
def chart():
legend = 'Monthly Data'
labels = ["January", "February", "March", "April", "May", "June", "July", "August"]
values = [10, 9, 8, 7, 6, 4, 7, 8]
return render_template('chart.html', values=values, labels=labels, legend=legend)
if __name__ == "__main__":
app.run(debug=True)
Здесь мы создаём приложение Flask с единственным роутом (‘/simple_chart’), который обрабатывает файл chart.html. В шаблон chart.html передаётся набор значений для 8 месяцев года (только для примера).
Шаблон (включая Javascript)
Файл шаблона (chart.html) состоит из нескольких языков:
- HTML
- Шаблонные скрипты Jinja2
- Javascript
Для работы Chart.js нужно вызвать файл ‘Chart.min.js’ в секции ‘head’:
Затем можно задать график как элемент канвы HTML5:
Simple Line Chart
Секция Javascript должна выполнить следующие действия:
- Задать глобальные параметры для всех графиков
- Задать параметры для конкретного графика
- Получить элемент канвы HTML
- Создать график для вывода в канву
Ниже — содержимое секции ‘script’, в которой мы строим график с помощью Chart.js:
// Global parameters:
// do not resize the chart canvas when its container does (keep at 600x400px)
Chart.defaults.global.responsive = false;
// define the chart data
var chartData = {
labels : [{{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} for item in labels {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}}
"{{item}}",
{{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} endfor {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}}],
datasets : [{
label: '{{ legend }}',
fill: true,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data : [{{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} for item in values {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}}
{{item}},
{{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} endfor {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}}],
spanGaps: false
}]
}
// get chart canvas
var ctx = document.getElementById("myChart").getContext("2d");
// create the chart using the chart canvas
var myChart = new Chart(ctx, {
type: 'line',
data: chartData,
});
Большинство параметров Chart.js взяты из документации к библиотеке, вы можете прочитать о них там.
Я лишь изменил параметр ‘responsive’ в глобальных настройках — рекомендую установить его в ‘false’, чтобы график не расползался на разных размерах монитора, а был бы около 600x400px (оптимально для ноутбуков и настольных компьютеров).
Запуск приложения
Для запуска приложения откройте консоль и перейдите в корень проекта. Затем выполните команду
$ python app.py
Затем откройте браузер и введите адрес http://localhost:5000/simple_chart
Вы должны увидеть следующее:
Превосходно! Мы сделали простое приложение, передающее данные в шаблон Chart.js.
Пример №2. Добавляем функции обратного вызова в диаграмму
Читая документацию к Chart.js, вы могли увидеть богатый функционал этой библиотеки. Мне же было интересно поработать с функциями обратного вызова, которые можно повесить на некоторые события (к примеру, при клике на точку графика).
В этом примере мы рассмотрим:
- Функция обновления заголовка выводимой точки графика
- Функция обновления определённой точки графика
Обновим приложение Flask (в нашем файле app.py) для добавления нового роута:
@app.route("/line_chart")
def line_chart():
legend = 'Temperatures'
temperatures = [73.7, 73.4, 73.8, 72.8, 68.7, 65.2,
61.8, 58.7, 58.2, 58.3, 60.5, 65.7,
70.2, 71.4, 71.2, 70.9, 71.3, 71.1]
times = ['12:00PM', '12:10PM', '12:20PM', '12:30PM', '12:40PM', '12:50PM',
'1:00PM', '1:10PM', '1:20PM', '1:30PM', '1:40PM', '1:50PM',
'2:00PM', '2:10PM', '2:20PM', '2:30PM', '2:40PM', '2:50PM']
return render_template('line_chart.html', values=temperatures, labels=times, legend=legend)
Этот роут создаёт более сложный набор данных для вывода в график.
Обратный вызов для обновления заголовка
Файл шаблона line_chart.html для этого примера построен на основе первого шаблона chart.html. Код Javascript также обновлён — добавлен обратный вызов для обновления заголовка при наведении пользователем курсора над точкой графика:
// create the chart using the chart canvas
var myChart = new Chart(ctx, {
type: 'line',
data: chartData,
options: {
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function(tooltipItems, data) {
return tooltipItems.yLabel + ' degrees';
}
}
},
}
});
В этой функции мы добавляем слово ‘degrees’ к значению температуры и выводим это в заголовок.
Добавляем обратный вызов для выбранной точки
Ниже — Javascript код, обновляющий текст для выбранной пользователем точки графика. Вначале создадим переменную для канвы:
// get chart canvas
var holder = document.getElementById("myChart");
Затем создадим переменную для текста, который нужно обновлять:
// get the text element below the chart
var pointSelected = document.getElementById("pointSelected");
И, наконец, функцию обратного вызова:
// create a callback function for updating the selected index on the chart
holder.onclick = function(evt){
var activePoint = myChart.getElementAtEvent(evt);
pointSelected.innerHTML = 'Point selected... index: ' + activePoint[0]._index;
};
Эта функция будет вызываться при клике на любой точке графика и обновлять текст под графиком, в котором будет отображаться индекс выбранной точки. Также добавим запись в журнал о выбранной точке:
console.log(activePoint);
console.log('x:' + activePoint[0]._view.x);
console.log('maxWidth: ' + activePoint[0]._xScale.maxWidth);
console.log('y: ' + activePoint[0]._view.y);
Запускаем приложение
Запустим в консоли
$ python app.py
и откроем в браузере http://localhost:5000/line_chart
Пример №3. Временные графики
Большая проблема с предыдущим примером — то, что время в ней задано строкой. Лучшим решением является использование модуля time из Python и библиотеки Moment.js на стороне Javascript. Moment.js предоставляет удобные методы и структуры данных для управления временными значениями.
Мы создадим шаблон для третьего примера на базе предыдущего шаблона.
Добавьте в начало файла app.py импорт модуля:
from datetime import time
Далее создадим роут ‘/time_chart’, в котором зададим набор некоторых температурных значений и временные данные в формате hh:mm:ss
@app.route("/time_chart")
def time_chart():
legend = 'Temperatures'
temperatures = [73.7, 73.4, 73.8, 72.8, 68.7, 65.2,
61.8, 58.7, 58.2, 58.3, 60.5, 65.7,
70.2, 71.4, 71.2, 70.9, 71.3, 71.1]
times = [time(hour=11, minute=14, second=15),
time(hour=11, minute=14, second=30),
time(hour=11, minute=14, second=45),
time(hour=11, minute=15, second=00),
time(hour=11, minute=15, second=15),
time(hour=11, minute=15, second=30),
time(hour=11, minute=15, second=45),
time(hour=11, minute=16, second=00),
time(hour=11, minute=16, second=15),
time(hour=11, minute=16, second=30),
time(hour=11, minute=16, second=45),
time(hour=11, minute=17, second=00),
time(hour=11, minute=17, second=15),
time(hour=11, minute=17, second=30),
time(hour=11, minute=17, second=45),
time(hour=11, minute=18, second=00),
time(hour=11, minute=18, second=15),
time(hour=11, minute=18, second=30)]
return render_template('time_chart.html', values=temperatures, labels=times, legend=legend)
На стороне Javascript мы импортируем библиотеку Moment.js и будем строить временные значения по шкале x:
Обновим секцию ‘script’, добавив функцию конвертации временных значений в структуру для Moment.js
var timeFormat = 'hh:mm:ss';
function newDateString(hours, minutes, seconds) {
return moment().hour(hours).minute(minutes).second(seconds).format(timeFormat);
}
Эта функция будет обновлять текст на графике:
// define the chart data
var chartData = {
labels : [{{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} for item in labels {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}}
newDateString( {{item.hour}}, {{item.minute}}, {{item.second}} ),
{{33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a} endfor {33d8302486bd10b0fde64d2037652320e6f176a736d71849c0427b0d7398501a}}],
…
Запустим приложение:
$ python app.py
и откроем браузер по адресу http://localhost:5000/time_chart
По материалам «Creating Charts with Chart.js in a Flask Application»
Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.
Пишите: @ighar. Buy me a coffee, please :).