In diesem Beitrag möchte ich dir zeigen wie du den kleinen Währungsrechner um einen Graph erweiterst welcher die historischen Daten anzeigt.
Im letzten Beitrag Python Flask – Währungsrechner Teil2 – Umrechnungskurse online beziehen habe ich dir gezeigt wie du Umrechnungskurse vom deutschen Zoll im XML Format beziehen und parsen kannst. Nun soll es darum gehen diese Daten lokal zu speichern und in einem Graph anzeigen zu lassen.
speichern der Daten in einer CSV Datei auf dem Server
Damit wir später die Daten in einem Liniendiagramm darstellen können müssen wir zunächst die bereits geladenen Daten lokal speichern. Man könnte sicherlich dazu eine Datenbank nutzen aber das wäre wie sprichwörtlich “mit Kanonen auf Spatzen schießen”, es reicht daher für unseren Fall aus, die Daten in einer kommaseparierten Datei (*.csv) speichern.
Die CSV Datei soll lediglich die 4 Spalten: Monat, Jahr, ISO3* und Wert enthalten. (Von der Schnittstelle des deutschen Zolls erhalten wir die Umrechnungskurse auf dem Monat genau.)
*Den ISO3 Wert speichern wir uns zusätzlich ab, damit wir später einfacher den Währungsrechner um eine zusätzliche Währung ergänzen können.
laden der historischen Daten beim starten des Servers
Die gespeicherten Daten müssen wir nun laden und für die spätere Darstellung ein wenig aufbereiten.
Die Aufbereitung beinhaltet in diesem Beispiel lediglich die Zuordnung der Werte (Monat,Jahr, ISO3, Wert) zu Feldern in einer geeigneten Klasse.
class Currency: def __init__(self, month, year, iso3, value): self.month = int(month) self.year = int(year) self.iso3 = str(iso3) self.value = float(value)
Die Daten laden wir in der Funktion “loadData” welche beim starten des Servers ausgeführt wird. Dieses hat den großen Vorteil das der Besucher gewöhnlich keine zusätzliche Wartezeit hat.
historyCurrencys = []; def loadData(): global currencys with open("static/data.csv", "r") as file: for line in file: values = line.strip().split(";") print(values) if(len(values)==4): historyCurrencys .append(Currency(values[0],values[1],values[2],values[3])) app.before_first_request(loadData);
In der Funktion “loadData” prüfen wir zusätzlich ob der aktuelle Monat in der Liste vorhanden ist und wenn dieses nicht so ist, werden die Daten geladen und gespeichert.
def historyListContainsElement(month, year, iso3): return findHistoryElement(month, year, iso3) != None def findHistoryElement(month, year, iso3): for c in historyCurrencys: if c.month == month and c.year == year and c.iso3 == iso3: return c return None def loadData(): ... year = datetime.date.today().year month = datetime.date.today().month iso3 = currencys["USD"]["iso3code"] if historyListContainsElement(month, year, iso3): iso2 = currencys["USD"]["iso2code"] value = loadDataFromCustoms(iso2, month, year) appendHistoryData(month, year, iso3, value)
Die neuen Daten für den aktuellen Monat müssen nun in die Liste sowie in die CSV Datei gespeichert werden.
def appendHistoryData(month, year, iso3, value): if findHistoryElement(month, year, iso3) != None: historyCurrencys.append(Currency(month, year, iso3, value)) with open("static/data.csv", "a") as file: file.write(str(month) +';' + str(year) + ';' + str(iso3) + ';' + str(value))
laden der Daten für das berechnen der Umrechnungskurse
Beim Serverstart laden wir bereits die historischen Daten nun müssen wir noch prüfen ob der aktuelle Monat enthalten ist. Für diesen recht einfachen Anwendungsfall müssen wir nur die Liste durchlaufen und prüfen ob ein Eintrag enthalten ist bei welchem der Monat und das Jahr mit dem aktuellen identisch ist.
Wenn dieses nicht so ist dann wird die Liste um genau diesen Eintrag erweitert und die CSV Datei aktualisiert.
@app.route('/') def start(): ... currentYear = datetime.date.today().year currentMonth = datetime.date.today().month currentDateStr = getFormatedDate(currentMonth, currentYear) isPresent = False for c in historyCurrencys: if c.month == currentMonth and c.year == currentYear: isPresent = True usDollar = c.value if isPresent == False: usDollar = loadDataFromCustoms(currencys["USD"]["iso2code"], currentMonth, currentYear) appendHistoryData(currentMonth, currentYear, currencys["USD"]["iso3code"], usDollar)
darstellen eines Graphen in HTML
Unser Währungsrechner ist auf einer kleinen HTML Seite welche mit Python Flask & Jinja2 entwickelt wurde. Auf dieser Seite möchte ich nun zusätzlich einen Graph, also ein Diagramm anzeigen lassen.
Für das darstellen eines Diagramms auf einer Webseite gibt es diverse Frameworks. Ich als Lösung für dieses “Problem” gerne die JavaScript Google Chart Bibliothek welche ich schon in diverse Projekte mit dem ESP8266 eingesetzt habe.
Zum Beispiel habe ich die Daten eines Temperatur & rel. Luftfeuchtigskeits Sensors mit hilfe der Google Gauges auf einer kleinen Webseite angezeigt, siehe WEMOS D1 – WLAN Thermometer mit DHT11 Sensor.
Jedoch möchten wir in unseren Währungsrechner ein Liniendiagramm anzeigen lassen. Welches aber genauso einfach zu implementieren ist. Es wird lediglich eine JavaScript Bibliothek benötigt.
Die Ressourcen zur Google Chart Bibliothek liegen leider nicht als Offline Version vor, d.h. es ist nur möglich diese als externe Ressource einzubinden.
übergeben der historischen Daten in das Template
Die historischen Daten laden wir bereits beim starten des Flask Servers, diese Daten wollen wir nun in das Template übergeben.
historyCurrencys = []; @app.route('/') def start(): return render_template("template.html", historyCurrencys =historyCurrencys )
zeichnen der historischen Daten in ein Liniendiagramm
Nachdem wir nun die Daten in einer CSV Datei gespeichert und die Werte in das Template übergeben haben möchten wir diese historischen Daten in ein Google Line Chart zeichnen.
Dazu müssen wir zunächst die bereits benannte JavaScript Bibliothek laden. Dazu fügen wir nachfolgende Zeile in den HEAD Tag im HTML Dokument wie folgt ein.
<html> <head> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> </head> ...
Hier nun der JavaScript Code zum zeichnen eines Liniendiagramms wie im Teaserbild gezeigt.
<script type = "text/javascript" > google.charts.load('current', {'packages': ['corechart']}); google.charts.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Monat-Jahr', 'Wert'], {% for value in historyCurrencys %} ['{{ value.month }}-{{ value.year }}', {{ value.value }}], {% endfor %} ]); var options = { title: 'Wechselkurs EURO > US-Dollar ({{historyCurrencys[0].month}}-{{historyCurrencys[0].year}} bis heute)', titlePosition: 'out', curveType: 'none', backgroundColor: '#edf6ff', legend: 'none', colors: ['#E59400'], hAxis: { slantedText: true, slantedTextAngle: 45, gridlines: { count: 7 } }, vAxis: { format: '#.000$' } }; var chart = new google.visualization.LineChart(document.getElementById('curve_chart')); chart.draw(data, options); } </script>
Besonderes Hauptaugenmerk möchte ich auf die Generierung der Daten für das Diagramm hinweisen.
Für jeden Eintrag in der Liste mit historischen Währungsdaten wird ein JavaScript Array Eintrag generiert.
{% for value in historyCurrencys %} ['{{ value.month }}-{{ value.year }}', {{ value.value }}], {% endfor %}
Release 0.4 auf GitHub
In der Rubrik Releases auf meinem GitHub Repository findest du die nun neue Version 0.4 mit dem Liniendiagramm inkl. historischer Daten.