Vollständige Stapelentwicklung - Abrufen von Daten, Visualisieren mit D3 und Bereitstellen mit Dokku

Vollständige Stapelentwicklung - Abrufen von Daten, Visualisieren mit D3 und Bereitstellen mit Dokku

In diesem Tutorial erstellen wir eine Webanwendung, um Daten ausNASDAQ-100zu erfassen und sie mit D3 als Blasendiagramm zu visualisieren. Um das Ganze abzurunden, werden wir dies über Dokku auf Digital Ocean bereitstellen.

Note: Blasendiagramme eignen sich perfekt zur Visualisierung von Hunderten von Werten auf kleinem Raum. Sie sind jedoch schwerer zu lesen, da es schwierig sein kann, Kreise ähnlicher Größe zu unterscheiden. Wenn Sie nur mit wenigen Werten arbeiten, ist ein Balkendiagramm wahrscheinlich die bessere Option, da es viel einfacher zu lesen ist.

In diesem Lernprogramm verwendete Hauptwerkzeuge: Python v2.7.8, Flask v0.10.1,Requests v2.4.1, D3 v3.4.11, Dokku v0.2.3 und Bower v1.3.9

Suchen und laden Sie zunächst die Datei_app_boilerplate.zip von dieserrepo herunter. Diese Datei enthält eine Flaschenkesselplatte. Extrahieren Sie nach dem Herunterladen die Datei und die Ordner, aktivieren Sie eine virtuelle Umgebung undinstall the dependencies with Pip:

pip install -r requirements.txt

Testen Sie dann, ob es funktioniert: Starten Sie den Server, öffnen Sie Ihren Browser und navigieren Sie zuhttp://localhost:5000/. Sie sollten "Hallo Welt!" Sehen. starrte dich an.

Daten abrufen

Erstellen Sie eine neue Routen- und Ansichtsfunktion in der Dateiapp.py:

@app.route("/data")
def data():
    return jsonify(get_data())

Aktualisieren Sie die Importe:

from flask import Flask, render_template, jsonify
from stock_scraper import get_data

Wenn diese Route aufgerufen wird, konvertiert sie den zurückgegebenen Wert von einer Funktion namensget_data() in JSON und gibt ihn dann zurück. Diese Funktion befindet sich in einer Datei namensstock_scraper.py, was - Überraschung! - ruft Daten vom NASDAQ-100 ab.

Das Skript

Fügen Siestock_scraper.py zum Hauptverzeichnis hinzu.

Your turn: Erstellen Sie das Skript selbst, indem Sie die folgenden Schritte ausführen:

  1. Laden Sie die CSV vonhttp://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx?render=download herunter.

  2. Holen Sie sich die relevanten Daten aus der CSV: Aktienname, Aktiensymbol, aktueller Preis, Nettoveränderung, prozentuale Änderung, Volumen und Wert.

  3. Konvertieren Sie die analysierten Daten in ein Python-Wörterbuch.

  4. Geben Sie das Wörterbuch zurück.

Wie ist es gelaufen? Brauchen Sie Hilfe? Schauen wir uns eine mögliche Lösung an:

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

Was ist los?

  1. Hier rufen wir die URL über eine GET-Anforderung ab und konvertieren dann das Antwortobjektr inunicode.

  2. Wir arbeiten dann mit der BibliothekCSV, um das Komma getrennte Text in eine Instanz der KlasseDictReader() zu konvertieren, die die Daten einem Wörterbuch anstatt einer Liste zuordnet.

  3. Nachdem wir die Daten durchlaufen und eine Liste von Wörterbüchern erstellt haben (wobei jedes Wörterbuch einen anderen Bestand darstellt), geben wir schließlich das Diktat vonRESULTSzurück.

Note
Sie können auch ein Diktatverständnis verwenden, um die einzelnen Wörterbücher zu erstellen. Dies ist eine viel effizientere Methode, Sie opfern jedoch die Lesbarkeit. Ihr Anruf.

Time to test: Starten Sie den Server und navigieren Sie zuhttp://localhost:5000/data. Wenn alles gut gegangen ist, sollten Sie ein Objekt sehen, das die relevanten Bestandsdaten enthält.

Mit den vorliegenden Daten können wir nun daran arbeiten, sie im Frontend zu visualisieren.

Visualisieren

Zusammen mit HTML und CSS verwenden wirBootstrap, Javascript / jQuery undD3, um unser Front-End zu betreiben. Wir werden auch das clientseitige Abhängigkeitsmanagement-ToolBower verwenden, um diese Bibliotheken herunterzuladen und zu verwalten.

Your turn: Befolgen Sie dieinstallation instructions, um Bower auf Ihrem Computer einzurichten. Hint: You will need to install Node.js before you install Bower.

Bereit?

Laube

Zwei Dateien werden benötigt, um die Laube zum Laufen zu bringen -bower.json und.http://bower.io/docs/config/[bowerrc].

Die letztere Datei wird zum Konfigurieren von Bower verwendet. Fügen Sie es dem Hauptverzeichnis hinzu:

{
  "directory": "static/bower_components"
}

Dies gibt nur an, dass die Abhängigkeiten im Verzeichnisbower_components(Konvention) im Verzeichnisstaticder App installiert werden sollen.

In der ersten Dateibower.json wird das Bower-Manifest gespeichert. Dies bedeutet, dass es Metadaten zu den Bower-Komponenten sowie zur Anwendung selbst enthält. Die Datei kann interaktiv mit dem Befehlbower initerstellt werden. Mach das jetzt. Akzeptieren Sie einfach alle Standardeinstellungen.

Jetzt können wir die Abhängigkeiten installieren.

$ bower install bootstrap#3.2.0 jquery#2.1.1 d3#3.4.11 --save

Das Flag--save fügt die Pakete dem Abhängigkeitsarraybower.jsonhinzu. Hör zu. Stellen Sie außerdem sicher, dass die Abhängigkeitsversionen inbower.json mit den von uns angegebenen Versionen übereinstimmen - d. H.bootstrap#3.20.

Lassen Sie uns unsere installierten Abhängigkeiten in unserer App zugänglich machen.

index.html aktualisieren



  
    Flask Stock Visualizer
    
    
    
  
  
    

D3

WarumD3 bei so vielen Datenvisualisierungs-Frameworks? Nun, D3 ist ein ziemlich niedriges Level, sodass Sie die Art von Framework erstellen können, die Sie möchten. Sobald Sie Ihre Daten an das DOM angehängt haben, verwenden Sie eine Kombination aus CSS3, HTML5 und SVG, um die eigentliche Visualisierung zu erstellen. Anschließend können Sie Interaktivität über die in D3 integrierten datengesteuertentransitionshinzufügen.

Um fair zu sein, ist diese Bibliothek nicht jedermanns Sache. Da Sie viel Freiheit haben, das zu bauen, was Sie wollen, ist die Lernkurve ziemlich hoch. Wenn Sie nach einem schnellen Start suchen, lesen SiePython-NVD3, einen Wrapper für D3, der die Arbeit mit D3 erheblich erleichtert. Wir verwenden es jedoch nicht für dieses Tutorial, da Python-NVD3 keine Blasendiagramme unterstützt.

Your turn: Gehen Sie durch die D3intro tutorial.

Jetzt lasst uns codieren.

Konfiguration

Fügen Siemain.js den folgenden Code hinzu:

// Custom JavaScript

$(function() {
  console.log('jquery is working!');
  createGraph();
});

function createGraph() {
  // Code goes here
}

Hier protokollieren wir nach dem ersten Laden der Seite "jquery funktioniert!" In der Konsole und starten dann eine Funktion namenscreateGraph(). Testen Sie dies. Starten Sie den Server, navigieren Sie zuhttp://localhost:5000/ und aktualisieren Sie die Seite bei geöffneter JavaScript-Konsole. Sie sollten den Text "jquery funktioniert!" Sehen, wenn alles gut gegangen ist.

Fügen Sie derindex.html-Datei innerhalb des<div>-Tags mit einemid voncontainer (nach Zeile 10) das folgende Tag hinzu, um das D3-Blasendiagramm zu speichern:

Hauptkonfiguration

Fügen Sie dercreateGraph()-Funktion inmain.js den folgenden Code hinzu:

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

Lesen Sie unbedingt die Codekommentare für eine Explantation sowie die offiziellen D3documentation. Suchen Sie nach etwas, das Sie nicht verstehen. 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

Fügen Sie den obigen Code erneut zur FunktioncreateGraph() hinzu und überprüfen Sie diedocs auf Fragen.

SVG-Konfiguration

Fügen Sie als Nächstes den folgenden Code zucreateGraph() hinzu, wählen Sie das Element mitid vonchart aus und hängen Sie die Kreise zusammen mit einer Reihe von Attributen an:

var svg = d3.select("#chart").append("svg")
  .attr("width", width)
  .attr("height", height)
  .attr("class", "bubble");

Wenn wir mit dercreateGraph()-Funktion fortfahren, müssen wir jetzt die Daten abrufen, was asynchron mit D3 erfolgen kann.

Fordern Sie die Daten an

// 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; });
});

Wir haben also den Endpunkt von/dataerreicht, den wir zuvor eingerichtet haben, um die Daten zurückzugeben. Der Rest dieses Codes fügt einfach die Blasen und den Text zum DOM hinzu. Dies ist die Standard-Kesselplattecode, die für unsere Daten geringfügig geändert wurde.

Tooltips

Da der Platz im Diagramm begrenzt ist und sich noch innerhalb dercreateGraph()-Funktion befindet, fügen wir einige Tooltips hinzu, die zusätzliche Informationen zu den einzelnen Aktien enthalten.

// 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");

Dies sind nur die CSS-Stile, die dem Tooltip zugeordnet sind. Wir müssen noch die tatsächlichen Daten hinzufügen. Aktualisieren Sie den Code, in dem wir die Kreise an das DOM anhängen:

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");});

Testen Sie dies und navigieren Sie zuhttp://localhost:5000/. Wenn Sie jetzt über einen Kreis fahren, werden einige zugrunde liegende Metadaten angezeigt - Firmenname und Aktienkurs.

Your turn: Fügen Sie weitere Metadaten hinzu. Welche anderen Daten halten Sie für relevant? Denken Sie an das, was wir hier anzeigen - die relative Preisänderung. Sie könnten vielleicht den vorherigen Preis berechnen und zeigen:

  1. Derzeitiger Preis

  2. Relative Veränderung

  3. Vorheriger Preis

Refactor

Aktien Was wäre, wenn wir nur Aktien mit einem modifizierten marktwertgewichteten Index visualisieren wollten - den NASDAQ-100 Pointscolumn - größer als 0,1?

Fügen Sie der Funktionget_data()eine Bedingung hinzu:

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

Erhöhen wir nun den Radius jeder Blase im Abschnitt "Blasenkonfiguration" vonmain.js. Ändern Sie den Code entsprechend:

// Radius for each circle
.radius(function(d) { return 20 + (sizeOfRadius(d) * 60); });

CSS

Zum Schluss fügen wirmain.css einige grundlegende Stile hinzu:

body {
  padding-top: 20px;
  font: 12px sans-serif;
  font-weight: bold;
}

Gut aussehen? Bereit zur Bereitstellung?

Bereitstellen

Dokku ist eine Open-Source-Plattform wie eine Plattform, die Heroku ähnelt und von Docker unterstützt wird. Nach dem Einrichten können Sie Ihre App mit Git darauf übertragen.

Wir verwendenDigital Ocean als Host. Lass uns anfangen.

Digital Ocean einrichten

Sign up für ein Konto, falls Sie noch keines haben. Folgen Sie dann diesenguide, um einen öffentlichen Schlüssel hinzuzufügen.

Erstellen Sie ein neues Droplet - geben Sie einen Namen, eine Größe und einen Ort an. Klicken Sie für das Bild auf die Registerkarte "Anwendungen" und wählen Sie die Dokku-Anwendung aus. Stellen Sie sicher, dass Sie Ihren SSH-Schlüssel auswählen.

Schließen Sie das Setup nach der Erstellung ab, indem Sie die IP-Adresse des neu erstellten Droplets in Ihren Browser eingeben. Daraufhin gelangen Sie zum Dokku-Setup-Bildschirm. Vergewissern Sie sich, dass der öffentliche Schlüssel korrekt ist, und klicken Sie dann auf "Setup beenden".

Jetzt kann der VPS Pushs akzeptieren.

Bereitstellen von Config

  1. Erstellen Sie ein Procfile mit dem folgenden Code:web: gunicorn app:app. (Diese Datei enthält den Befehl, der ausgeführt werden muss, um den Webprozess zu starten.)

  2. Installieren Sie das Gunicorn:pip install gunicorn

  3. Aktualisieren Sie die Dateirequirements.txt:pip freeze > requirements.txt

  4. Initialisieren Sie ein neues lokales Git-Repo:git init

  5. Fügen Sie eine Fernbedienung hinzu:git remote add dokku [email protected]:app_name (Fügen Sie unbedingt Ihre eigene IP-Adresse hinzu.)

Updateapp.py:

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)

Daher versuchen wir zunächst, den Port aus der App-Umgebung abzurufen. Wenn er nicht gefunden wird, wird standardmäßig Port 5000 verwendet.

Stellen Sie sicher, dass auch die Importe aktualisiert werden:

import os

Bereitstellen!

Übernehmen Sie Ihre Änderungen und drücken Sie dann:git push dokku master. Wenn alles gut gegangen ist, sollte die URL der Anwendung in Ihrem Terminal angezeigt werden:

=====> Application deployed:
       http://192.241.208.61:49155

Probieren Sie es aus. Navigieren Sie zuhttp://192.241.208.61:49155. (Achten Sie auch hier darauf, Ihre eigene IP-Adresse zusammen mit dem richtigen Port hinzuzufügen.) Sie sollten Ihre Live-App sehen! (Eine Vorschau finden Sie im Bild oben in diesem Beitrag.)

Nächste Schritte

Möchten Sie dies auf die nächste Stufe bringen? Fügen Sie der App die folgenden Funktionen hinzu:

  1. Fehlerbehandlung

  2. Unit Testing

  3. Integrationstests

  4. Kontinuierliche Integration / Lieferung

Diese Funktionen (und mehr!) Werden in der nächsten Ausgabe derReal Python-Kurse Anfang Oktober 2014 enthalten sein!

Kommentar unten, wenn Sie Fragen haben.

Prost!