Полная разработка стека - выборка данных, визуализация с помощью D3 и развертывание с помощью Dokku
В этом руководстве мы создадим веб-приложение, которое будет собирать данные изNASDAQ-100 и визуализировать их в виде пузырьковой диаграммы с помощью D3. Затем, в довершение всего, мы развернем это в Digital Ocean через Dokku.
Note: Пузырьковые диаграммы идеально подходят для визуализации сотен значений на небольшом пространстве. Тем не менее, их труднее читать, потому что может быть трудно различить круги одинакового размера. Если вы работаете только с несколькими значениями, гистограмма, вероятно, является лучшим вариантом, поскольку ее гораздо легче читать.
Основные инструменты, используемые в этом руководстве: Python v2.7.8, Flask v0.10.1,Requests v2.4.1, D3 v3.4.11, Dokku v0.2.3 и Bower v1.3.9.
Начните с поиска и загрузки файла_app_boilerplate.zip из этогоrepo. Этот файл содержит шаблон Flask. После загрузки извлеките файл и папки, активируйте virtualenv иinstall the dependencies with Pip:
pip install -r requirements.txt
Затем проверьте, работает ли он: запустите сервер, откройте браузер и перейдите кhttp://localhost:5000/. Вы должны увидеть «Привет, мир!» уставившись на тебя.
Получение данных
Создайте новый маршрут и функцию просмотра в файлеapp.py:
@app.route("/data")
def data():
return jsonify(get_data())
Обновить импорт:
from flask import Flask, render_template, jsonify
from stock_scraper import get_data
Итак, когда этот маршрут вызывается, он преобразует возвращаемое значение из функции с именемget_data()
в JSON, а затем возвращает его. Эта функция находится в файле с именемstock_scraper.py, что - сюрприз! - получает данные с NASDAQ-100.
Сценарий
Добавьтеstock_scraper.py в основной каталог.
Your turn: Создайте сценарий самостоятельно, выполнив следующие действия:
-
Загрузите CSV изhttp://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx?render=download.
-
Соберите соответствующие данные из CSV: название акции, символ акции, текущая цена, чистое изменение, процентное изменение, объем и стоимость.
-
Преобразуйте проанализированные данные в словарь Python.
-
Верните словарь.
Как прошло? Нужна помощь? Давайте посмотрим на одно из возможных решений:
import csv
import requests
URL = "http://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx?render=download"
def get_data():
r = requests.get(URL)
data = r.text
RESULTS = {'children': []}
for line in csv.DictReader(data.splitlines(), skipinitialspace=True):
RESULTS['children'].append({
'name': line['Name'],
'symbol': line['Symbol'],
'symbol': line['Symbol'],
'price': line['lastsale'],
'net_change': line['netchange'],
'percent_change': line['pctchange'],
'volume': line['share_volume'],
'value': line['Nasdaq100_points']
})
return RESULTS
Что происходит?
-
Здесь мы получаем URL-адрес с помощью запроса GET, а затем конвертируем объект Response,
r
, вunicode. -
Затем мы работаем с библиотекой
CSV
, чтобы преобразовать текст, разделенный запятыми, в экземпляр классаDictReader()
, который отображает данные в словарь, а не в список. -
Наконец, после перебора данных и создания списка словарей (где каждый словарь представляет разные акции) мы возвращаем dict
RESULTS
.
NoteВы также можете использовать понимание диктовки для создания отдельных словарей. Это гораздо более эффективный метод, однако вы жертвуете удобочитаемостью. Ваш звонок.
Time to test: запустите сервер, а затем перейдите кhttp://localhost:5000/data. Если все прошло хорошо, вы должны увидеть объект, содержащий соответствующие данные о запасах.
Имея данные под рукой, мы можем теперь работать с их визуализацией во внешнем интерфейсе.
Визуальное
Наряду с HTML и CSS мы будем использоватьBootstrap, Javascript / jQuery иD3 для поддержки нашего интерфейса. Мы также будем использовать клиентский инструмент управления зависимостямиBower для загрузки этих библиотек и управления ими.
Your turn: Следуйтеinstallation instructions, чтобы настроить Bower на вашем компьютере. Hint: You will need to install Node.js before you install Bower.
Готовы?
Беседка
Для запуска беседки необходимы два файла -bower.json и.http://bower.io/docs/config/[bowerrc].
Последний файл используется для настройки Bower. Добавьте его в основной каталог:
{
"directory": "static/bower_components"
}
Это просто указывает на то, что мы хотим, чтобы зависимости были установлены в каталогеbower_components (соглашение) внутри каталога приложенияstatic.
Между тем, первый файл,bower.json, хранит манифест Bower, то есть он содержит метаданные о компонентах Bower, а также о самом приложении. Файл можно создать в интерактивном режиме с помощью командыbower init
. Сделай это сейчас. Просто примите все значения по умолчанию.
Теперь мы можем установить зависимости.
$ bower install bootstrap#3.2.0 jquery#2.1.1 d3#3.4.11 --save
Флаг--save
добавляет пакеты в массив зависимостейbower.json. Проверьте это. Кроме того, убедитесь, что версии зависимостей вbower.json соответствуют указанным нами версиям, т.е.bootstrap#3.20
.
Установив наши зависимости, давайте сделаем их доступными в нашем приложении.
Обновитьindex.html
Flask Stock Visualizer
D3
Почему существует так много фреймворков визуализации данных, почемуD3? Ну, D3 - это довольно низкий уровень, поэтому он позволяет вам создавать тот тип фреймворка, который вы хотите. Когда вы добавляете свои данные в DOM, вы используете комбинацию CSS3, HTML5 и SVG для создания фактической визуализации. Затем вы можете добавить интерактивности через встроенный в D3transitions, управляемый данными.
Если честно, эта библиотека не для всех. Поскольку у вас есть большая свобода строить то, что вы хотите, кривая обучения довольно высока. Если вам нужен быстрый старт, посмотритеPython-NVD3, оболочку для D3, которая значительно упрощает работу с D3. Мы не используем его для этого урока, так как Python-NVD3 не поддерживает пузырьковые диаграммы.
Your turn: пройти D3intro tutorial.
Теперь давайте код.
Настроить
Добавьте следующий код вmain.js:
// Custom JavaScript
$(function() {
console.log('jquery is working!');
createGraph();
});
function createGraph() {
// Code goes here
}
Здесь, после начальной загрузки страницы, мы регистрируем "jquery is working!" В консоли, а затем запускаем функцию с именемcreateGraph()
. Проверьте это. Запустите сервер, затем перейдите кhttp://localhost:5000/ и с открытой консолью JavaScript обновите страницу. Вы должны увидеть текст «jquery работает!», Если все прошло хорошо.
Добавьте следующий тег в файлindex.html внутри тега<div>
, который имеетid
изcontainer
(после строки 10), чтобы удерживать пузырьковую диаграмму D3:
Главный Конфиг
Добавьте следующий код в функциюcreateGraph()
вmain.js:
var width = 960; // chart width
var height = 700; // chart height
var format = d3.format(",d"); // convert value to integer
var color = d3.scale.category20(); // create ordinal scale with 20 colors
var sizeOfRadius = d3.scale.pow().domain([-100,100]).range([-50,50]); // https://github.com/mbostock/d3/wiki/Quantitative-Scales#pow
Обязательно ознакомьтесь с комментариями к коду для объяснения, а также с официальным D3documentation. Посмотри что-нибудь, чего ты не понимаешь. A coder must be self-reliant!
Bubble Config
var bubble = d3.layout.pack()
.sort(null) // disable sorting, use DOM tree traversal
.size([width, height]) // chart layout size
.padding(1) // padding between circles
.radius(function(d) { return 20 + (sizeOfRadius(d) * 30); }); // radius for each circle
Опять же, добавьте приведенный выше код в функциюcreateGraph()
и проверьтеdocs на наличие вопросов.
SVG Config
Затем добавьте следующий код вcreateGraph()
, который выбирает элемент сid
изchart
, а затем добавляет кружки вместе с рядом атрибутов:
var svg = d3.select("#chart").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "bubble");
Продолжая работу с функциейcreateGraph()
, теперь нам нужно получить данные, что можно сделать асинхронно с помощью D3.
Запрос данных
// REQUEST THE DATA
d3.json("/data", function(error, quotes) {
var node = svg.selectAll('.node')
.data(bubble.nodes(quotes)
.filter(function(d) { return !d.children; }))
.enter().append('g')
.attr('class', 'node')
.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'});
node.append('circle')
.attr('r', function(d) { return d.r; })
.style('fill', function(d) { return color(d.symbol); });
node.append('text')
.attr("dy", ".3em")
.style('text-anchor', 'middle')
.text(function(d) { return d.symbol; });
});
Итак, мы достигли конечной точки/data
, которую мы настроили ранее для возврата данных. Оставшаяся часть этого кода просто добавляет пузыри и текст в DOM. Это стандартный шаблонcode, немного измененный для наших данных.
Всплывающие
Поскольку у нас ограниченное пространство на графике, по-прежнему в пределах функцииcreateGraph()
, давайте добавим несколько всплывающих подсказок, которые показывают дополнительную информацию о каждой конкретной акции.
// tooltip config
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.style("color", "white")
.style("padding", "8px")
.style("background-color", "rgba(0, 0, 0, 0.75)")
.style("border-radius", "6px")
.style("font", "12px sans-serif")
.text("tooltip");
Это просто стили CSS, связанные с подсказкой. Нам все еще нужно добавить фактические данные. Обновите код, где мы добавляем круги в DOM:
node.append("circle")
.attr("r", function(d) { return d.r; })
.style('fill', function(d) { return color(d.symbol); })
.on("mouseover", function(d) {
tooltip.text(d.name + ": $" + d.price);
tooltip.style("visibility", "visible");
})
.on("mousemove", function() {
return tooltip.style("top", (d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");
})
.on("mouseout", function(){return tooltip.style("visibility", "hidden");});
Проверьте это, перейдите кhttp://localhost:5000/. Теперь, когда вы наведите курсор на кружок, вы увидите некоторые основные метаданные - название компании и цену акций.
Your turn: добавить больше метаданных. Какие еще данные вы считаете актуальными? Подумайте о том, что мы показываем здесь - относительное изменение цены. Возможно, вы могли бы рассчитать предыдущую цену и показать:
-
Текущая цена
-
Относительное изменение
-
Предыдущая цена
Refactor
акции Что, если бы мы просто хотели визуализировать акции с модифицированным индексом, взвешенным по рыночной стоимости - NASDAQ-100 Pointscolumn - больше, чем .1?
Добавьте условное выражение к функцииget_data()
:
def get_data():
r = requests.get(URL)
data = r.text
RESULTS = {'children': []}
for line in csv.DictReader(data.splitlines(), skipinitialspace=True):
if float(line['Nasdaq100_points']) > .01:
RESULTS['children'].append({
'name': line['Name'],
'symbol': line['Symbol'],
'symbol': line['Symbol'],
'price': line['lastsale'],
'net_change': line['netchange'],
'percent_change': line['pctchange'],
'volume': line['share_volume'],
'value': line['Nasdaq100_points']
})
return RESULTS
Теперь давайте увеличим радиус каждого пузыря в разделе конфигурации пузыряmain.js; измените код соответствующим образом:
// Radius for each circle
.radius(function(d) { return 20 + (sizeOfRadius(d) * 60); });
CSS
Наконец, давайте добавим несколько основных стилей вmain.css:
body {
padding-top: 20px;
font: 12px sans-serif;
font-weight: bold;
}
Хорошо выглядишь? Готовы к развертыванию?
Развертывание
Dokku - это платформа с открытым исходным кодом, подобная Heroku, Platform as a Service (PaaS), работающая на Docker. После настройки вы можете добавить приложение в Git.
Мы используемDigital Ocean в качестве хоста. Давайте начнем.
Настройка Digital Ocean
Sign up для учетной записи, если у вас ее еще нет. Затем следуйте этомуguide, чтобы добавить открытый ключ.
Создайте новую каплю - укажите имя, размер и местоположение. Для изображения нажмите вкладку «Приложения» и выберите приложение Dokku. Обязательно выберите свой SSH-ключ.
После создания завершите настройку, введя IP-адрес недавно созданной капли в браузере, после чего откроется экран настройки Dokku. Убедитесь, что открытый ключ верен, затем нажмите «Завершить настройку».
Теперь VPS может принимать толчки.
Развернуть Config
-
Создайте Procfile со следующим кодом:
web: gunicorn app:app
. (Этот файл содержит команду, которая должна быть запущена для запуска веб-процесса.) -
Установите gunicorn:
pip install gunicorn
-
Обновите файлrequirements.txt:
pip freeze > requirements.txt
-
Инициализировать новый локальный репозиторий Git:
git init
-
Добавьте пульт:
git remote add dokku [email protected]:app_name
(обязательно добавьте свой IP-адрес.)
Обновитьapp.py:
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
Итак, сначала мы пытаемся извлечь порт из среды приложения, и если он не найден, по умолчанию используется порт 5000.
Не забудьте обновить импорт также:
import os
Развертывание!
Зафиксируйте свои изменения, затем нажмите:git push dokku master
. Если все прошло хорошо, вы должны увидеть URL приложения в своем терминале:
=====> Application deployed:
http://192.241.208.61:49155
Проверьте это. Перейдите кhttp://192.241.208.61:49155. (Опять же, не забудьте добавить свой собственный IP-адрес вместе с правильным портом.) Вы должны увидеть свое живое приложение! (Смотрите изображение в верхней части этого поста для предварительного просмотра.)
Следующие шаги
Хотите поднять это на следующий уровень? Добавьте в приложение следующие функции:
-
Обработка ошибок
-
Модульное тестирование
-
Интеграционное тестирование
-
Непрерывная интеграция / доставка
Эти функции (и многое другое!) Будут включены в следующий выпуск курсовReal Python, который выйдет в начале октября 2014 года!
Комментарий ниже, если у вас есть вопросы.
Ура!