Создаём графики в приложении Flask с Chart.js

Создаём графики в приложении Flask с Chart.js
Я разрабатываю веб-сайты на 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’:



Chart.js Example



Затем можно задать график как элемент канвы HTML5:

Simple Line Chart


The chart is displaying a simple line chart.


Секция Javascript должна выполнить следующие действия:

  1. Задать глобальные параметры для всех графиков
  2. Задать параметры для конкретного графика
  3. Получить элемент канвы HTML
  4. Создать график для вывода в канву

Ниже — содержимое секции ‘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

Вы должны увидеть следующее:

Создаём графики в приложении Flask с Chart.js
Превосходно! Мы сделали простое приложение, передающее данные в шаблон Chart.js.

Пример №2. Добавляем функции обратного вызова в диаграмму

Читая документацию к Chart.js, вы могли увидеть богатый функционал этой библиотеки. Мне же было интересно поработать с функциями обратного вызова, которые можно повесить на некоторые события (к примеру, при клике на точку графика).

В этом примере мы рассмотрим:

  1. Функция обновления заголовка выводимой точки графика
  2. Функция обновления определённой точки графика

Обновим приложение 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

Создаём графики в приложении Flask с Chart.js

Пример №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:



Chart.js Example




Обновим секцию ‘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

Создаём графики в приложении Flask с Chart.js

По материалам «Creating Charts with Chart.js in a Flask Application»

Leave a Comment