Руководство для программистов Python без фреймворков
Делиться
Создание панели мониторинга данных для ваших клиентов, заказчиков или коллег становится неотъемлемой частью набора навыков, необходимых разработчикам программного обеспечения, специалистам по анализу данных, специалистам по машинному обучению и инженерам данных. Даже если вы занимаетесь преимущественно бэкенд-обработкой, обрабатываемые вами данные обычно в какой-то момент должны быть доступны пользователям. Если повезет, в вашей организации может быть специальная команда фронтенд-разработчиков, которая этим занимается, но зачастую это ваша задача.
Быть чистым разработчиком Python без опыта работы с HTML, JavaScript и т. д. больше не является оправданием, поскольку за последние несколько лет появилось много библиотек Python, таких как Streamlit и Gradio.
Но эта статья не о них, потому что я один из тех, кто работает исключительно на Python, и уже поработал со Streamlit и Gradio. Пришло время засучить рукава и посмотреть, смогу ли я освоить новые навыки и создать панель управления, используя проверенные временем инструменты фронтенд-разработки: HTML, JavaScript и CSS.
Данные для нашей панели мониторинга будут поступать из локальной базы данных SQLite. Я создал таблицу sales_data в SQLite, содержащую фиктивные данные о продажах. Вот эти данные в табличной форме.
Ниже приведен код, который вы можете использовать для продолжения и создания собственной базы данных SQLite и таблицы с данными, как показано.
Если вам интересно, почему я добавляю в базу данных лишь несколько записей, то дело не в том, что я считаю, что код не справится с большими объёмами данных. Просто я хотел сосредоточиться на функциональности панели мониторинга, а не отвлекаться на данные. При желании вы можете использовать скрипт, который я привёл ниже, для добавления дополнительных записей во входной набор данных.
Итак, мы еще немного останемся в мире Python и настроим базу данных SQLite программным способом.
import sqlite3 # Определите имя базы данных DATABASE_NAME = «C:\Users\thoma\projects\my-dashboard\sales_data.db» # Подключитесь к базе данных SQLite conn = sqlite3.connect(DATABASE_NAME) # Создайте объект курсора cursor = conn.cursor() # SQL для создания таблицы 'sales' create_table_query = ''' CREATE TABLE IF NOT EXISTS sales ( order_id INTEGER PRIMARY KEY, order_date TEXT, customer_id INTEGER, customer_name TEXT, product_id INTEGER, product_names TEXT, categories TEXT, quantity INTEGER, price REAL, total REAL ); ''' # Выполнить запрос на создание таблицы cursor.execute(create_table_query) # Образец данных для вставки в таблицу 'sales' sample_data = [ (1, «2022-08-01», 245, «Клиент_884», 201, «Смартфон», «Электроника», 3, 90.02, 270.06), (2, «2022-02-19», 701, «Клиент_1672», 205, «Принтер», «Электроника», 6, 12.74, 76.44), (3, «2017-01-01», 184, «Клиент_21720», 208, «Блокнот», «Канцелярские товары», 8, 48.35, 386.80), (4, «2013-03-09», 275, «Клиент_23770», 200, «Ноутбук», «Электроника», 3, 74,85, 224,55), (5, «2022-04-23», 960, «Клиент_23790», 210, «Шкаф», «Офис», 6, 53,77, 322,62), (6, «2019-07-10», 197, «Клиент_25587», 202, «Стол», «Офис», 3, 47,17, 141,51), (7, «2014-11-12», 510, «Клиент_6912», 204, «Монитор», «Электроника», 5, 22,5, 112.5), (8, «2016-07-12», 150, «Customer_17761», 200, «Ноутбук», «Электроника», 9, 49.33, 443.97) ] # SQL для вставки данных в таблицу 'sales' insert_data_query = ''' INSERT INTO sales (order_id, order_date, customer_id, customer_name, product_id, product_names, categories, quantity, price, total) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''' # Вставка образца данных cursor.executemany(insert_data_query, sample_data) # Зафиксировать транзакцию conn.commit() # Закрыть соединение conn.close() print(f»База данных '{DATABASE_NAME}' создана и заполнена успешно.»)
Функциональность панели инструментов
Наша панель управления будет иметь следующую функциональность.
Ключевые показатели. Общий доход, общее количество заказов, средняя стоимость заказа, высшая категория.
Различные типы диаграмм. Доход с течением времени (линейная диаграмма), Доход по категориям (столбчатая диаграмма), Лучшие продукты по доходу (горизонтальная столбчатая диаграмма)
Фильтрация. По дате и категории.
Таблица данных. Отображает наши записи данных в виде постраничной таблицы с возможностью поиска.
Создание нашей среды
Далее нам предстоит выполнить ряд шагов по настройке нашей среды.
1/ Установите Node.js.
Node.js — это среда выполнения, которая позволяет запускать JavaScript вне браузера, что позволяет использовать JavaScript для создания быстрых и масштабируемых серверных приложений.
Итак, убедитесь, что Node.js установлен в вашей системе, чтобы иметь возможность запустить локальный сервер и управлять пакетами. Вы можете скачать его с официального сайта Node.js.
2/ Создайте основную папку проекта и подпапки
Откройте командный терминал и выполните следующие команды. Я использую Ubuntu на своём компьютере с Windows, но вы можете изменить настройки в соответствии со своей предпочитаемой утилитой командной строки и системой.
SQLite — это легкая реляционная база данных на основе файлов, которая хранит все ваши данные в одном переносимом файле, устраняя необходимость в отдельном сервере.
Express — это минималистичная, гибкая среда веб-приложений для Node.js, которая упрощает создание API и веб-серверов с помощью маршрутизации и промежуточного программного обеспечения.
Мы можем установить оба варианта с помощью команды ниже.
$ npm install express sqlite3
Теперь мы можем приступить к разработке кода. Для этого проекта нам понадобятся четыре файла кода: index.html, server.js, client.js и script.js.
Давайте рассмотрим каждый из них шаг за шагом.
1) клиент/index.html
Панель мониторинга эффективности продаж
Панель мониторинга эффективности продаж
Ключевые показатели
Общий доход
$0
Общее количество заказов
0
Средняя стоимость заказа
$0
Верхняя категория
Нет
Необработанные данные
В этом HTML-файле определены основные визуальные элементы нашей панели показателей продаж, включая интерактивные фильтры по дате и категории, раздел, отображающий ключевые показатели продаж, раскрывающееся меню для выбора типов диаграмм и таблицу для необработанных данных.
Для стилизации используется Bootstrap . Для ввода данных используется Flatpickr . Для визуализации используется Chart.js , а для табличного отображения — DataTables . Интерактивность обеспечивается внешним файлом script.js , который мы вскоре рассмотрим.
Bootstrap — популярный фреймворк front-end, изначально разработанный Twitter, который помогает вам проще и быстрее создавать адаптивные и визуально согласованные веб-интерфейсы.
DataTables — это плагин на основе jQuery, который улучшает стандартные элементы HTML
, превращая их в полностью интерактивные, многофункциональные таблицы.
Flatpickr — это лёгкий, настраиваемый JavaScript-конструктор дат и времени. Он позволяет пользователям выбирать даты (и, при необходимости, время) из удобного всплывающего календаря, а не вводить их вручную.
Chart.js — простая, но мощная библиотека JavaScript для создания интерактивных анимированных диаграмм в веб-приложениях с использованием элемента
Мы используем каскадную таблицу стилей (CSS) для стилизации основных визуальных компонентов нашей панели управления, например, цветов кнопок и текста, интервалов между элементами и т. д.
Файл style.css определяет внешний вид и общий вид панели управления. Это чистая, лёгкая тема с достаточными интервалами и настройками макета для ясности и читабельности. Файл style.css также настраивает внешний вид кнопок пагинации DataTables, делая их более удобными для пользователя и визуально соответствующими дизайну Bootstrap.
3) сервер/сервер.js
const express = require('express'); const sqlite3 = require('sqlite3').verbose(); const path = require('path'); const app = express(); const PORT = 3000; // Полный путь к вашей базе данных SQLite const DB_PATH = «C:\Users\thoma\projects\my-dashboard\sales_data.db»; // Обслуживать статические файлы из клиентского каталога app.use(express.static(path.join(__dirname, '..', 'client'))); // Маршрут для извлечения данных из базы данных SQLite app.get('/data', (req, res) => { const db = new sqlite3.Database(DB_PATH, sqlite3.OPEN_READONLY, (err) => { if (err) { console.error(«Ошибка подключения к базе данных:», err.message); res.status(500).json({ error: «Ошибка подключения к базе данных» }); return; } }); // Запрос к базе данных const query = «SELECT * FROM sales;»; // Замените 'sales' именем вашей таблицы db.all(query, [], (err, rows) => { if (err) { console.error(«Ошибка выполнения запроса:», err.message); res.status(500).json({ error: «Ошибка запроса» }); } else { res.json(rows); // Отправьте результат запроса в формате JSON } }); db.close((err) => { if (err) { console.error(«Ошибка закрытия базы данных:», err.message); } }); }); // Маршрут перехвата для обслуживания основного HTML-файла app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '..', 'client', 'index.html')); }); // Запуск сервера app.listen(PORT, () => { console.log(`Server running at http://localhost:${PORT}`); });
Этот скрипт Node.js содержит код JavaScript, который настраивает базовый сервер Express, обеспечивающий работу панели мониторинга эффективности продаж. Он выполняет две основные функции:
Обслуживает статические файлы (такие как HTML, CSS и JS) из клиентской подпапки, чтобы интерфейс загружался в браузере.
Предоставляет конечную точку /data , которая считывает данные из локальной базы данных SQLite (sales_data.db) и возвращает всю таблицу продаж в формате JSON, что позволяет использовать динамическую визуализацию данных и таблицы на внешнем интерфейсе.
4) клиент/скрипт.js
пусть chartInstance = null; // Глобальная переменная для хранения текущего экземпляра Chart.js // Дождитесь полной загрузки DOM document.addEventListener('DOMContentLoaded', function () { // Извлеките данные о продажах из API бэкэнда fetch('/data') .then((response) => response.json()) .then((data) => { // Обработка случая, когда данные не возвращаются if (!data || data.length === 0) { const app = document.getElementById('app'); if (app) { app.innerHTML = «
Нет доступных данных.
«; } return; } // Инициализируйте фильтры и содержимое панели мониторинга setupFilters(data); initializeDashboard(data); // Повторно отрисуйте диаграммы при изменении типа диаграммы document.getElementById('chart-type-selector').onchange = () => filterAndRenderData(data); }) .catch((error) => { // Обработка ошибки выборки console.error('Ошибка выборки данных:', error); const app = document.getElementById('app'); if (app) { app.innerHTML = «
Не удалось получить данные.
«; } }); }); // Инициализация выборщиков дат Flatpickr и функции фильтра категорий setupFilters(data) { // Преобразование строк даты в объекты JS Date const dates = data.map((item) => new Date(item.order_date.split('/').reverse().join('-'))); const minDate = new Date(Math.min(…dates)); const maxDate = new Date(Math.max(…dates)); // Настраиваем выбор начальной даты flatpickr(«#start-date», { defaultDate: minDate.toISOString().slice(0, 10), dateFormat: «Ymd», altInput: true, altFormat: «F j, Y», onChange: function () { filterAndRenderData(data); }, }); // Настраиваем выбор конечной даты flatpickr(«#end-date», { defaultDate: maxDate.toISOString().slice(0, 10), dateFormat: «Ymd», altInput: true, altFormat: «F j, Y», onChange: function () { filterAndRenderData(data); }, }); // Настраиваем прослушиватель изменений выпадающего списка категорий const categoryFilter = document.getElementById('category-filter'); if (categoryFilter) { categoryFilter.onchange = () => filterAndRenderData(data); } } // Инициализируем панель мониторинга после установки фильтров function initializeDashboard(data) { populateCategoryFilter(data); // Заполняем выпадающий список категорий filterAndRenderData(data); // Первоначальная визуализация со всеми данными } // Применяем фильтры и обновляем ключевые показатели, диаграмму и таблицу function filterAndRenderData(data) { const chartType = document.getElementById('chart-type-selector').value; const startDate = document.getElementById('start-date')._flatpickr.selectedDates[0]; const endDate = document.getElementById('end-date')._flatpickr.selectedDates[0]; const selectedCategory = document.getElementById('category-filter').value; // Фильтрация данных по дате и категории const filteredData = data.filter((item) => { const itemDate = new Date(item.order_date.split('/').reverse().join('-')); return ( itemDate >= startDate && itemDate <= endDate && (selectedCategory === 'all' || item.categories === selectedCategory) ); }); updateKeyMetrics(filteredData); // Обновление метрик, таких как доход и заказы drawChart(filteredData, 'chart-canvas', chartType); // Отображение диаграммы populateDataTable(filteredData); // Обновление таблицы } // Обновление метрик панели мониторинга (общий доход, количество заказов и т. д.) function updateKeyMetrics(data) { const totalRevenue = data.reduce((acc, item) => acc + parseFloat(item.total), 0); const totalOrders = data.length; const averageOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0; // Рассчитаем общий доход по категориям, чтобы найти лучшую из них const incomeByCategory = data.reduce((acc, item) => { const category = item.categories || «Без категории»; acc[category] = (acc[category] || 0) + parseFloat(item.total); return acc; }, {}); // Определим категорию с наибольшим общим доходом const topCategory = Object.keys(revenueByCategory).reduce( (a, b) => (revenueByCategory[a] > incomeByCategory[b] ? a : b), «Нет» ); // Отображение показателей в DOM document.getElementById('total-revenue').textContent = `$${totalRevenue.toFixed(2)}`; document.getElementById('total-orders').textContent = `${totalOrders}`; document.getElementById('average-order-value').textContent = `$${averageOrderValue.toFixed(2)}`; document.getElementById('top-category').textContent = topCategory || 'None'; } // Рисуем выбранный тип диаграммы с помощью функции Chart.js drawChart(data, elementId, chartType) { const ctx = document.getElementById(elementId).getContext('2d'); // Уничтожаем предыдущую диаграмму, если она существует if (chartInstance) { chartInstance.destroy(); } switch (chartType) { case 'revenueOverTime': // Линейная диаграмма, показывающая доход по дате заказа chartInstance = new Chart(ctx, { type: 'line', data: { labels: data.map((item) => item.order_date), datasets: [{ label: 'Доход за период', data: data.map((item) => parseFloat(item.total)), fill: false, borderColor: 'rgb(75, 192, 192)', tension: 0.1, }], }, options: { scales: { y: { beginAtZero: true }, }, }, }); break; case 'revenueByCategory': // Столбчатая диаграмма, показывающая общий доход по категориям const categories = […new Set(data.map((item) => item.categories))]; const incomeByCategory = categories.map((category) => { return { category, income: data .filter((item) => item.categories === category) .reduce((acc, item) => acc + parseFloat(item.total), 0), }; }); chartInstance = new Chart(ctx, { type: 'bar', data: { labels: incomeByCategory.map((item) => item.category), datasets: [{ label: 'Доход по категориям', data: incomeByCategory.map((item) => item.revenue), backgroundColor: 'rgba(255, 99, 132, 0.2)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1, }], }, options: { scales: { y: { beginAtZero: true }, }, }, }); break; case 'topProducts': // Горизонтальная столбчатая диаграмма, показывающая 10 лучших продуктов по доходу const productRevenue = data.reduce((acc, item) => { const productName = item.product_names || 'Неизвестный продукт'; acc[productName] = (acc[productName] || 0) + parseFloat(item.total); return acc; }, {}); const topProducts = Object.entries(productRevenue) .sort((a, b) => b[1] — a[1]) .slice(0, 10); chartInstance = new Chart(ctx, { type: 'bar', data: { labels: topProducts.map((item) => item[0]), // Названия продуктов datasets: [{ label: 'Лучшие продукты по доходу', data: topProducts.map((item) => item[1]), // Доход backgroundColor: 'rgba(54, 162, 235, 0.8)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1, }], }, options: { indexAxis: 'y', // Горизонтальные полосы scales: { x: { beginAtZero: true }, }, }, }); break; } } // Отображение отфильтрованных данных в DataTable function populateDataTable(data) { const tableElement = $('#data-table'); // Уничтожаем существующую таблицу, если она существует if ($.fn.DataTable.isDataTable(tableElement)) { tableElement.DataTable().clear().destroy(); } // Создаем новую DataTable с соответствующими столбцами tableElement.DataTable({ data: data.map((item) => [ item.order_id, item.order_date, item.customer_id, item.product_names, item.categories, `$${parseFloat(item.total).toFixed(2)}`, ]), columns: [ { title: «ID заказа» }, { title: «Дата заказа» }, { title: «ID клиента» }, { title: «Продукт» }, { title: «Категория» }, { title: «Итого» }, ], }); } // Заполнить раскрывающийся список фильтра категорий доступными категориями function populateCategoryFilter(data) { const categoryFilter = document.getElementById('category-filter'); categoryFilter.innerHTML = ''; categoryFilter.appendChild(new Option('All Categories', 'all', true, true)); // Извлечь уникальные категории const categories = new Set(data.map((item) => item.categories)); categories.forEach((category) => { categoryFilter.appendChild(new Option(category, category)); }); }
Это наш самый сложный файл кода, но он должен выполнять множество функций. Этот файл JavaScript обеспечивает интерактивность и визуализацию данных для панели мониторинга эффективности продаж. Короче говоря, он…
1/ Извлекает данные о продажах
Когда страница загружается (DOMContentLoaded), она вызывает внутренний API в конечной точке /data.
Если данные не возвращены, отображается сообщение «Нет доступных данных».
2/ Устанавливает фильтры
Использует средства выбора дат Flatpickr для выбора начальной и конечной даты на основе минимальных/максимальных дат заказов набора данных.
Добавляет раскрывающийся список категорий, позволяющий пользователям фильтровать по категории продукта.
Добавляет селектор типа диаграммы для переключения между различными визуализациями диаграмм.
Запускает первый рендеринг с полным набором данных.
4/ Применяет фильтры и выполняет повторную визуализацию
Каждый раз, когда пользователь меняет фильтр (диапазон дат, категорию или тип диаграммы), он:
Фильтрует набор данных по диапазону дат и категории.
Обновляет ключевые показатели : общий доход, количество заказов, среднюю стоимость заказа и категорию максимального дохода.
Перерисовывает выбранную диаграмму Chart.js .
Обновляет таблицу данных .
5/ Рисует диаграммы с помощью Chart.js
Доход с течением времени → Линейный график, показывающий тенденции дохода по датам.
Доход по категориям → Столбчатая диаграмма, показывающая общий доход по категориям.
Самые популярные продукты → Горизонтальная столбчатая диаграмма, показывающая 10 самых популярных продуктов по выручке.
6/ Отображает табличные данные
Использует DataTables (плагин jQuery) для отображения таблицы отфильтрованных заказов со столбцами для идентификатора заказа, даты, идентификатора клиента, продукта, категории и общей суммы.
7/ Поддерживает синхронизацию пользовательского интерфейса
Уничтожает и заново создает диаграммы/таблицы при изменении фильтров, чтобы избежать дубликатов.
Поддерживает метрики, диаграммы и таблицы в соответствии с активными фильтрами.
Запуск нашей панели управления
Теперь, когда весь наш код отсортирован, пришло время запустить панель управления, поэтому перейдите в подпапку сервера и введите следующую команду.
$ узел server.js
Вы получите ответ на указанную выше команду, что-то вроде:
Сервер работает по адресу http://localhost:3000
Откройте веб-браузер и перейдите по адресу http://localhost:3000 . Вы увидите панель управления, заполненную данными из базы данных SQLite, как показано на рисунке ниже.
Все фильтры, выбор диаграмм и т. д. должны работать так, как заявлено.
Краткое содержание
В этой статье я расскажу вам о создании полнофункциональной интерактивной панели мониторинга эффективности продаж с использованием основных веб-технологий — HTML, CSS, JavaScript, Node.js, Express и локальной базы данных SQLite.
Мы обсудили технологический стек и настройку.
Бэкэнд: Node.js, Express, SQLite
Внешний вид: HTML, Bootstrap (для макета), Chart.js (для диаграмм), Flatpickr (выбор даты), DataTables (для табличных данных)
Я показал вам, как создать и заполнить базу данных SQLite в коде, которую можно использовать в качестве источника данных для нашей панели мониторинга. Мы также обсудили настройку среды и процессы разработки front-end и back-end, а также кратко коснулись функциональности нашей панели мониторинга данных.
Наконец, я подробно объяснил вам, как создать четыре файла кода, а затем показал, как запустить панель управления в браузере.
Астрономы будут получать оповещения о небесных явлениях в течение нескольких минут после их обнаружения. Теренс О'Брайен, редактор раздела «Выходные». Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной…
Обзор компактного пресса для мягкого пластика Clear Drop — и что будет дальше. Шон Холлистер, старший редактор Публикации этого автора будут добавляться в вашу ежедневную рассылку по электронной почте и в ленту новостей на главной странице вашего…
Учёные из Университета штата Северная Каролина представили композит нового поколения, способный самостоятельно восстанавливаться после серьёзных повреждений. Речь идёт о модифицированном армированном волокном полимере (FRP), который не просто сохраняет прочность при малом весе, но и способен «залечивать» внутренние…
Круглый 7-дюймовый сенсорный дисплей от Waveshare создан для разработчиков и дизайнеров, которым нужен нестандартный экран. Это IPS-панель с разрешением 1 080×1 080 пикселей, поддержкой 10-точечного ёмкостного сенсора, оптической склейкой и защитным закалённым стеклом, выполненная в круглом форм-факторе.…