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

Разработка /
Разработка: Создаём графики в приложении Flask с Chart.js
Я разрабатываю веб-сайты на Python и Flask, используя Bootstrap для стилизации. Недавно мне понадобилось добавить на сайт интерактивные графики. При выборе JavaScript библиотеки для этого, я наткнулся на Chart.js — у неё более 29 000 звёзд на GitHub (на май 2017). И сегодня мы рассмотрим три примера создания графиков с Chart.js в приложении Flask.

Исходные коды примеров из статьи вы можете найти в репозитории GitLab с отдельными тегами (example1, example2 и example3) для каждого примера: 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’:

<head>
  <meta charset="utf-8" />
  <title>Chart.js Example</title>
  <!-- import plugin script -->
  <script src='static/Chart.min.js'></script>
</head>

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


<h1>Simple Line Chart</h1>
<!-- bar chart canvas element -->
<canvas id="myChart" width="600" height="400"></canvas>
<p id="caption">The chart is displaying a simple line chart.</p>

Секция 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 : [{% for item in labels %}
             "{{item}}",
            {% endfor %}],
  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 : [{% for item in values %}
                {{item}},
              {% endfor %}],
      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

Затем откройте браузер и введите адрес 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

и откроем в браузере 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:

<head>
  <meta charset="utf-8" />
  <title>Chart.js Example</title>
  <!-- import plugin script -->
  <script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>
  <script src='static/Chart.min.js'></script>
</head>

Обновим секцию ‘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 : [{% for item in labels %}
             newDateString( {{item.hour}}, {{item.minute}}, {{item.second}} ),
            {% endfor %}],
…

Запустим приложение:

$ python app.py

и откроем браузер по адресу localhost:5000/time_chart

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

По материалам «Creating Charts with Chart.js in a Flask Application»
0 комментариев
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.