In diesem Tutorial möchte ich zeigen, wie in Python mit der Bokeh-Bibliothek Daten visualisiert werden können. Der Datensatz liegt als CSV-Datei vor, die mit requests
aus dem Internet geladen wird. Als Ergebnis erhält man eine HTML-Datei. Bei den Daten handelt es sich um Baugenehmigungen in Kiel (1988-2023). Die CSV-Daten werden mit Pandas gelesen, um anschließend mithilfe von Bokeh als Liniendiagramm dargestellt zu werden.
Es beginnt mit den Import-Anweisungen:
from io import StringIO
from bokeh.plotting import ColumnDataSource, figure, save, show
import pandas as pd
import requests
from requests.exceptions import (
ConnectionError,
RequestException,
Timeout,
TooManyRedirects,
)
Neben dem Import von bokeh
, pandas
und requests
, kommt noch StringIO
hinzu. Diese Bibliothek ermöglicht es, aus dem heruntergeladenen Datensatz ein Datei-ähnliches Objekt zu erstellen, das im Arbeitsspeicher verbleibt. Dadurch wird keine CSV-Datei im Dateisystem gespeichert.
Der nachfolgende Code lässt sich im Grunde in drei Abschnitte teilen:
- Der Datensatz (CSV-Datei) wird mit
requests
heruntergeladen. - Unter Verwendung von Pandas wird ein DataFrame erstellt.
- Zum Schluß werden die Daten mit Bokeh visualisiert.
Datensatz mit requests laden
Das Herunterladen der Daten bzw. der CSV-Datei wird für diese Aufgabe eine Funktion verwendet, die einige Ausnahmebehandlungen enthält, um etwaige Fehler abzufangen.
URL = (
"https://www.kiel.de/opendata/kiel_infrastruktur_bauen_wohnen_baugenehmigungen.csv"
)
def fetch_csv_data():
"""Fetch CSV data from given URL
Returns:
str -- CSV data
"""
try:
response = requests.get(URL)
# Falls der Status-Code nicht 200 ist,
# wird eine HTTPError-Ausnahme erzeugt.
response.raise_for_status()
return response.text
except ConnectionError as e:
print(f"Connection error: {e}")
except Timeout as e:
print(f"Request timed out: {e}")
except TooManyRedirects as e:
print(f"Too many redirects: {e}")
except RequestException as e:
print(f"An error occurred: {e}")
csv_data = fetch_csv_data()
DataFrame erstellen
Aus den heruntergeladenen Daten wird dann ein Pandas-DataFrame erzeugt, das später Bokeh als Datenquelle dient. Hier kommt die bereits erwähnte Bibliothek StringIO
zum Einsatz.
csv_content = StringIO(csv_data)
df = pd.read_csv(csv_content, sep=";")
Daten visualisieren
Da wir nun eine Datenquelle (Pandas-DataFrame) haben, die von Bokeh für die Visualisierung genutzt werden kann, können wir das Liniendiagramm erstellen. In diesem Beispiel wird uns das Ergebnis mit show(plot)
im Browser angezeigt und zusätzlich aufgrund der Zeile save(plot)
gespeichert.
plot = figure(
title="Baugenehmigungen in Kiel (1988 - 2023)",
width=1000,
x_axis_label="Jahr",
y_axis_label="Baugenehmigungen",
)
datenquelle = ColumnDataSource(df)
plot.line(source=datenquelle, x="Jahr", y="Wohnungen gesamt")
show(plot)
save(plot)
Zum Schluß dieses Artikels zeige ich noch den kompletten Code:
#!/usr/bin/env python3
from io import StringIO
from bokeh.plotting import ColumnDataSource, figure, save, show
import pandas as pd
import requests
from requests.exceptions import (
ConnectionError,
RequestException,
Timeout,
TooManyRedirects,
)
URL = (
"https://www.kiel.de/opendata/kiel_infrastruktur_bauen_wohnen_baugenehmigungen.csv"
)
def fetch_csv_data():
"""Fetch CSV data from given URL
Returns:
str -- CSV data
"""
try:
response = requests.get(URL)
# Falls der Status-Code nicht 200 ist,
# wird eine HTTPError-Ausnahme erzeugt.
response.raise_for_status()
return response.text
except ConnectionError as e:
print(f"Connection error: {e}")
except Timeout as e:
print(f"Request timed out: {e}")
except TooManyRedirects as e:
print(f"Too many redirects: {e}")
except RequestException as e:
print(f"An error occurred: {e}")
csv_data = fetch_csv_data()
csv_content = StringIO(csv_data)
df = pd.read_csv(csv_content, sep=";")
plot = figure(
title="Baugenehmigungen in Kiel (1988 - 2023)",
width=1000,
x_axis_label="Jahr",
y_axis_label="Baugenehmigungen",
)
datenquelle = ColumnDataSource(df)
plot.line(source=datenquelle, x="Jahr", y="Wohnungen gesamt")
show(plot)
save(plot)