フルスタック開発–データの取得、D3による視覚化、およびDokkuによる展開
このチュートリアルでは、NASDAQ-100からデータを取得し、それをD3を使用してバブルグラフとして視覚化するWebアプリケーションを構築します。 それから締めくくりに、これをDokku経由でDigital Oceanに展開します。
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
このrepoからファイル_app_boilerplate.zipを見つけてダウンロードすることから始めます。 このファイルには、Flaskボイラープレートが含まれています。 ダウンロードしたら、ファイルとフォルダーを抽出し、virtualenvをアクティブにして、install the dependencies with Pipを実行します。
pip install -r requirements.txt
次に、それが機能することを確認するためにテストします。サーバーを起動し、ブラウザーを開いて、http://localhost:5000/に移動します。 「Hello、world!」と表示されるはずです。あなたを見つめなおします。
データの取得
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:次の手順に従って、独自にスクリプトを作成します。
-
http://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx?render=downloadからCSVをダウンロードします。
-
CSVから関連データを取得します:銘柄名、銘柄記号、現在の価格、正味の変化、パーセントの変化、ボリューム、および値。
-
解析されたデータをPython辞書に変換します。
-
辞書を返します。
どうだった? 助けが必要? 考えられる解決策を1つ見てみましょう。
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
何が起こっていますか?
-
ここでは、GETリクエストを介してURLをフェッチし、Responseオブジェクト
r
をunicodeに変換します。 -
次に、
CSV
ライブラリを使用して、コンマ区切りのテキストをDictReader()
クラスのインスタンスに変換します。このインスタンスは、データをリストではなく辞書にマップします。 -
最後に、データをループして辞書のリストを作成した後(各辞書は異なる株を表します)、
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を実行するには、bower.jsonと.http://bower.io/docs/config/[bowerrc]の2つのファイルが必要です。
後者のファイルは、Bowerの構成に使用されます。 メインディレクトリに追加します。
{
"directory": "static/bower_components"
}
これは、アプリのstaticディレクトリ内のbower_componentsディレクトリ(慣例)に依存関係をインストールすることを指定するだけです。
一方、最初のファイル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のコンボを使用して、実際の視覚化を作成します。 次に、D3の組み込みのデータ駆動型transitionsを介して対話性を追加できます。
公平を期すため、このライブラリは万人向けではありません。 必要なものを自由に作成できるため、学習曲線はかなり高くなります。 クイックスタートをお探しの場合は、D3のラッパーであるPython-NVD3を確認してください。これは、D3での作業をはるかに簡単にするために使用されます。 Python-NVD3はバブルチャートをサポートしていないため、このチュートリアルでは使用していません。
Your turn:D3intro tutorialを通過します。
それでは、コーディングしましょう。
セットアップ
次のコードをmain.jsに追加します。
// Custom JavaScript
$(function() {
console.log('jquery is working!');
createGraph();
});
function createGraph() {
// Code goes here
}
ここでは、最初のページの読み込み後、「jquery isworking!」をコンソールに記録し、createGraph()
という関数を起動します。 これをテストしてください。 サーバーを起動してからhttp://localhost:5000/に移動し、JavaScriptコンソールを開いた状態でページを更新します。 すべてがうまくいけば、「jquery is working!」というテキストが表示されます。
次のタグをindex.htmlファイルの<div>
タグ内のid
のcontainer
(10行目以降)に追加して、D3バブルチャートを保持します。
メイン設定
次のコードをmain.jsのcreateGraph()
関数に追加します。
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!
バブル構成
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構成
次に、次のコードをcreateGraph()
に追加します。これにより、chart
のid
を持つ要素が選択され、いくつかの属性とともに円が追加されます。
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:メタデータを追加します。 関連する他のデータは何ですか? ここで表示しているもの、つまり価格の相対的な変化を考えてください。 おそらく前の価格を計算して表示できます:
-
現在の価格
-
相対的な変化
-
以前の価格
リファクタリング
株式時価総額加重指数(NASDAQ-100ポイントcolumn)が0.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は、Dockerを利用したオープンソースのHerokuのようなPlatform as a Service(PaaS)です。 セットアップしたら、Gitでアプリをプッシュできます。
ホストとしてDigital Oceanを使用しています。 始めましょう。
デジタルオーシャンのセットアップ
新しいドロップレットを作成-名前、サイズ、場所を指定します。 画像については、「アプリケーション」タブをクリックして、Dokkuアプリケーションを選択します。 必ずSSHキーを選択してください。
作成したら、新しく作成したドロップレットのIPをブラウザに入力してセットアップを完了します。これにより、Dokkuのセットアップ画面が表示されます。 公開鍵が正しいことを確認して、「セットアップの完了」をクリックします。
これで、VPSはプッシュを受け入れることができます。
構成の展開
-
次のコードでProcfileを作成します:
web: gunicorn app:app
。 (このファイルには、Webプロセスを開始するために実行する必要があるコマンドが含まれています。) -
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アドレスを追加してください。)ライブアプリが表示されるはずです。 (プレビューについては、この投稿の上部にある画像を参照してください。)
次のステップ
これを次のレベルに上げたいですか? 次の機能をアプリに追加します。
-
エラー処理
-
単体テスト
-
統合テスト
-
継続的な統合/配信
これらの機能(およびその他!)は、2014年10月初旬に予定されているReal Pythonコースの次のエディションに含まれる予定です。
質問がある場合は、以下にコメントしてください。
乾杯!