4 Tipps für automatisierte Grafiken mit DatawRappr

Das Coronavirus hat im digitalen Journalismus viel angeschoben. Zum Beispiel beim Thema automatisierte Grafiken. Ein paar Tipps, wie ich mit Skripten und Datawrapper Grafiken update.

Dieser Blogpost ist schamlose Werbung für mein R-Package DatawRappr. Das hatte ich zufällig Ende 2019 entwickelt, hauptsächlich um die API von Datawrapper aus R heraus nutzen zu können.

Inzwischen nutzen es viele DatenjournalistInnen, um ihre Grafiken für das Coronavirus zu updaten. Seit Beginn der Pandemie habe ich einige Lösungen damit entwickelt, um „fancy“ Sachen zu machen – ein paar davon wollte ich hier teilen. Ein bisschen nerdiger Post diesmal.

1. Viele Grafiken auf einmal erstellen

Ein klassischer Anwendungsfall: Wir haben eine Grafik und hätten die gerne für verschiedene Ausprägungen ausgegeben. Zum Beispiel: Ein Liniendiagramm der Neuinfektionen für alle Länder in der EU. Wie kann ich diese Grafiken – die alle gleich aussehen – am einfachsten hintereinander weg erstellen?

Das geht ganz einfach über einen For-Loop (R-Enthusiasten werden an dieser Stelle darauf hinweisen, dass man dafür doch auf jeden Fall die apply-Familie oder das Package purrr verwenden sollte. Macht auch Sinn, aber vermutlich ist es für Leute aus anderen Programmiersprachen einfacher, wenn wir erstmal bei for bleiben.)

Wie gehen wir vor?

  1. Wir erstellen für ein Land die Grafik in Datawrapper so, wie sie aussehen soll.
  2. Lade die Metadaten dieser Grafik in R: metadata_chart <- dw_retrieve_chart_metadata(chart_id, api_key)
  3. Wir speichern den visualize-Abschnitt der Metadaten lokal ab. Zum Beispiel als visualize.RData:
    visualize <- metadata_chart[["content"]][["metadata"]][["visualize"]]
    saveRDS(visualize, "visualize.RData")
  4. Visualize enthält alle optischen Vorgaben unserer Grafik. Wir können die der API mitgeben, wenn wir eine neue Grafik erstellen.
    Jetzt geht also der Loop los – über einen Vektor mit den Ländern. Grundsätzlich sieht der irgendwie so aus:
    for (Land in Laender_liste) {
    rohdaten %>%
    filter(Staat_in_Rohdaten == Land)
    }
  5. Für jedes dieser Länder erstellen wir eine neue Datawrapper-Grafik mit dw_create_chart(). Die neue Chart-ID bekommen wir direkt von der API zurückgeliefert und können sie im weiteren Verlauf benutzen:
    current_chart <- dw_create_chart(title = paste0("Chart für ", Land),type = "d3-lines")
  6. Damit auch die Visualisierungen richtig angezeigt werden, schicken wir der neuen Grafik direkt noch ein dw_edit_chart() hinterher:
    dw_edit_chart(chart_id = current_chart, visualize = visualize)
    [Eventuell kann man an dieser Stelle auch schon Daten mit dw_data_to_chart() hochladen.]
  7. Praktisch wäre es jetzt noch, wenn wir einen Überblick bekämen über alle Iframes und URLs unserer neu erstellten Grafiken. Dafür nutzen wir die dw_publish-chart-Funktion. Die kann ein Objekt zurückgeben, das die gewünschten Infos enthält und die wir abspeichern.
    Vor unseren Loop erstellen wir dafür eine leere Liste…
    result_list <- list()
    … die wir in jedem Loop-Durchgang (also für jedes Land) weiter befüllen:
    published_chart <- dw_publish_chart(current_chart)

    result_list[[i]] <- data.frame(id = area_id, country = area_name, url = published_chart$publicUrl, iframe = published_chart$iframeCode, chart_id = published_chart[["content"]][["data"]][[1]][["id"]])
  8. Die Grafiken sind erstellt. Damit wir beim Aktualisieren auch alle Chart-IDs beisammen haben, speichern wir result_list am besten irgendwo lokal als Dataframe ab:
    result_df <- dplyr::bind_rows(result_list)
    saveRDS(result_df, "chart_ids.RData")
  9. Für die Aktualisierung loopen wir dann einfach über result_list und verändern die Charts: die Daten mit dw_data_to_chart, die Titel, Introtexte oder Anmerkungen mit dw_edit_chart.

Den gesamten Code für so einen Loop habe ich hier in einem Github Gist verlinkt.

2. Datawrapper-Grafiken als Bilder ausgeben

In einem weiteren Schritt können wir aus den vielen Grafiken auch Bilder erstellen. Zum Beispiel für einen Small-Multiple-Überblick sein. Also viele kleine Grafiken nebeneinander.

Wir können dafür wieder den vorherigen Loop verwenden. Dazu die Funktion dw_export_chart():
png_chart <- dw_export_chart(
chart_id = current_chart,
type = "png",
unit = "px",
mode = "rgb",
width = 200,
height = 300,
plain = TRUE,
scale = 2)

In diesem Beispiel geben wir ein PNG mit 200 Pixeln Breite und 300 Pixeln Höhe aus, doppelt skaliert (scale), Titel und Anmerkungen werden nicht angezeigt (wegen: plain = TRUE). Mit der Funktion image_write aus dem magick-Package können wir die Grafiken dann lokal speichern:

image_write(png_chart, "output.png")

Dann laden wir die Bilder irgendwo hoch, und bauen mit HTML eine Überblicksseite, in die wir alle einbinden.

3. Tooltips über die Datawrapper-API verändern

Karten und Scatterplots in Datawrapper können beim Hovern oder Klicken Tooltips anzeigen. Auch die kann man ziemlich einfach über die API verändern. Das kann zum Beispiel praktisch sein, wenn man bestimmte Daten dynamisch dazugibt oder eben nicht.

Ein Beispiel: Ich scrape für eine Zusatzinfo eine bestimmte Seite. Diese Info will ich eigentlich immer in meiner Grafik anzeigen, aber was, wenn die Seite plötzlich offline ist? Ich könnte auf ein Fallback zurückspringen, ich kann mich aber auch entscheiden, diese Info dann nicht anzuzeigen. Dafür muss ich die Tooltips verändern können.

Am einfachsten ist das Vorgehen, wenn ich die Tooltips über das grafische Nutzerinterface anlege. Ich kann sie dann über dw_retrieve_chart_metadata() ganz einfach abrufen und verändern. Der Tooltip liegt unter: metadata_chart[["content"]][["metadata"]][["visualize"]] und besteht aus drei Abschnitten:

  • body: ist der Haupttext des Tooltipps. Der Inhalt kann mit HTML und CSS strukturiert werden (wie auch im GUI). Um Variablen aus den Daten zu verwenden nutzt man dieses Format: {{ variable_name }}.
  • title: ist – wie der Name vermuten lässt – die Überschrift des Tooltips. Auch hier kann man Variablen verwenden, wie im body.
  • fields: ist eine Liste, die die Zuordnung von Variablen im Tooltip und Variablen in den Daten festlegt. Zum Beispiel so:
    fields = list(
    "variableTooltip1" = "VariableData1",
    "variableTooltip2" = "VariableData2"
    )
    Im einfachsten Fall heißen die beiden Variablen einfach auf beiden Seiten gleich.

Um den Tooltip zu verändern nutzen wir dw_edit_chart():

dw_edit_chart(chart_id, visualize = list(
tooltip = list(
body = "{{ variableTooltip1 }} has value {{ variableTooltip2 }}.",
title = "{{ variableTooltip1 }}",

fields = list(
"variableTooltip1" = "VariableData1",
"variableTooltip2" = "VariableData2"
)
)))

Screenshot einer Datawrapper-Grafik mit einem Tooltip über einer Deutschland-Karte

4. Kartenlegende handy-freundlich

Datawrapper hat inzwischen richtig viele Möglichkeiten, Karten zu erstellen. Gerade bei Choroplethenkarten gibt es aber ein Problem: Auf kleinen Bildschirmen wird die Karte so weit zusammengestaucht, dass die Legend oft Teile der Daten überlagert – und manche Bereich dadurch nur schwer zu lesen sind. Ein Workaround ist es, den Zoom einzuschalten. [Edit: Am 29.09.20 hat Datawrapper ein großes Update veröffentlicht – mit neuer Legende]

Eine andere Variante: Die Legende in die Unterzeile der Grafik zu verlagern. So geht man dafür vor:

  1. Erstelle eine Choroplethenkarte in Datawrapper: Suche eine Basiskarte aus, und verbinde die Karte mit den Daten (über eine gemeinsame Spalte, z.B. die AGS, oder ISO-Codes). Überprüfe dann einmal kurz, ob die Legende auf der Karte richtig angezeigt wird. [Das geht auch mit DatawRappr]
  2. Lade die Metadaten der Karte in einem R-Skript: metadata_chart <- dw_retrieve_chart_metadata(chart_id, api_key)
  3. In metadata_chart finden wir dann alle Infos, die unsere Karte beschreiben. Die Legende finden wir im Abschnitt metadata_chart[["content"]][["metadata"]][["visualize"]][["categories"]]. Der Einfachheit halber können wir diesen Abschnitt auch einfach schnell als Variable rausziehen:
    new_legend <- metadata_chart[["content"]][["metadata"]][["visualize"]][["categories"]]
  4. Diesen Abschnitt geben wir in die neue Funktion dw_legend_to_string. Sie gibt die Legende dann als HTML-Code zurück (alternativ auch als Textstring oder Vektor), die wir einfach als Unterzeile in Datawrapper hinterlegen können:
    intro_text <- dw_legend_to_string(new_legend, return_val = "html")
  5. Wir updaten die Grafik mit:
    dw_edit_chart(chart_id, api_key, intro = intro_text)

So sieht das Ergebnis aus:

Screenshot einer Datawrapper-Karte mit einer Legend, die handyfreundlich ist.

Introducing DatawRappr

Datawrapper ist eines der erfolgreichsten Visualisierungstools für Journalisten. Mit einer neuen Erweiterung können die Daten aus R jetzt auch ohne Umwege in Datawrapper-Grafiken geladen werden.

Nein, dieser Blogpost soll keine Werbung für Datawrapper werden. Und der „Tippfehler“ im Titel ist gar keiner (na, wer hat sich gewundert?). Ich will in diesem Post kurz beschreiben, warum ich eine Bibliothek für die Statistiksoftware R geschrieben habe, die auf die Datawrapper-API zugreift. Und weil viele dieser R-Erweiterungen gerne mit dem Namen der Software spielen (ihr Vorgänger hieß übrigens S), wollte ich dem in nichts nachstehen: DatawRappr.

In vielen meiner Arbeitsstellen wurde Datawrapper eingesetzt. In meinem aktuellen Job visualisieren wir damit alle möglichen Grafiken auf der Homepage, oder erstellen damit schnelle Karten in Breaking-News-Situationen.

Inzwischen tauchen die Grafiken sogar schon in der gedruckten Zeitung auf:

https://twitter.com/Datawrapper/status/1175365864406822912

[/cookie]

In der Regel nutzen wir Datenjournalisten für unsere Auswertungen die Software R. Sie ist frei verfügbar und hat eine riesige Community, die für jeden Anwendungsfall eigene Erweiterungen geschrieben hat. (Vor allem aus der Informatik-Richtung kommt Python, die Sprache kann quasi dasselbe. Manche Leute mögen die eine, andere die andere mehr.)

[Mehr zu R habe ich in einem eigenen Blogpost aufgeschrieben.]

Um die Daten von R in Datawrapper zu bekommen, ist momentan noch ein Umweg nötig:

  • Entweder wir speichern die Ergebnisse für die Grafik als CSV und copy&pasten sie in Datawrapper (oder laden die CSV dort hoch)
  • Oder wir nutzen die Bibliothek clipr, die die Ergebnisse der Berechnungen in die Zwischenablage kopiert:

In einem aktuellen Projekt wollen wir aber automatisiert und regelmäßig Berechnungen durchführen (die Daten verändern sich ständig), und daraus Datawrapper-Grafiken generieren. Wir wollen aber ungern dauernd selbst daran denken müssen, die Grafiken zu aktualisieren. Außerdem müssen wir manchmal nicht nur die Daten, sondern auch die Beschreibungstexte ändern.

Die Datawrapper-API

Zum Glück hat Datawrapper dafür eine Lösung: Die API.

Über diese Schnittstelle können wir auf alle Funktionen zugreifen, die Datawrapper auch über sein Web-Interface anbietet. Gerade wurde die API von Version 1 auf Version 3 geupgradet. (Mehr dazu hat Datawrapper hier gebloggt)

Damit man direkt aus R darauf zugreifen kann, habe ich also die R-Erweiterung geschrieben. Mit ihr kann man zum Beispiel:

Was genau DatawRappr kann – und wie es genau funktioniert, steht in der Dokumentation. Zwar ist die Erweiterung schon in Version 1.0, aber vermutlich wäre 0.9 – also eher eine Beta-Version – angebrachter. Noch ist sie einfach zu wenig getestet, vor allem auf Windowssystemen. Aber: Sie geht! 😉

Infos zu DatawRappr

Der Code von DatawRappr steht auf Github. Es gibt eine eigene Dokumentation dazu.

Installiert wird es ganz einfach in R mit dem Package devtools:

Wie sich das Grundgesetz in 70 Jahren verändert hat

Unsere Verfassung feiert runden Geburtstag – wie stark der Text seit 1949 umgeschrieben wurde, habe ich in einem Projekt recherchiert.

Rund 70 000 Zeichen hatte das Grundgesetz im Jahr 1949. Heute sind es deutlich mehr, denn in insgesamt 63 Änderungen wurde viel gestrichen und vor allem hinzugefügt.

In der SZ haben wir zum Verfassungsjubiläum eine Sonderbeilage gemacht. Darin war auch eine Seite voller Grafiken. Unsere Idee dafür: Können wir zeigen, wie sehr sich das Gesetz von heute und das Gesetz von damals unterscheiden?

Ein CCC-Projekt will das Grundgesetz versionieren

Ein bisschen Glück hatten wir in diesem Fall, denn die Daten waren schon zum großen Teil da. Ein Projekt des chaospott in Essen hat vor einigen Jahren versucht, das Grundgesetz versionierbar zu machen – also jede Änderung im Text nachvollziehbar zu speichern. Ähnlich wie Computercode (aus der Richtung kommen die chaospott-Leute auch).

Für das Projekt haben sie extra die Software DocPatch geschrieben (hier auf Github). Die sorgt dafür, dass aus den einzelnen Dateien, die jede Änderung im Text beschreiben (sogenannte Patches) am Ende wieder ein kompletter Text wird – und sogar in verschiedenen Ausgabeformaten ausgegeben werden kann (zum Beispiel in PDF, Word, Markdown, Plaintext).

Mit dem Versionskontrolltool quilt tracken die Leute vom chaospott jede Änderung, die eine neue Version des Grundgesetzes enthält. Und das kann auf einmal gleich mehrere Artikel betreffen. Sie spielen quasi jede Version einmal durch, damit quilt weiß, was es für eine bestimmte Version verändern muss.

Auf einem Githubrepository werden dann alle Versionen Patches gespeichert, die geben an, was vom ursprünglichen Text verändert werden muss, damit der jeweilige Text rauskommt. Der Vorteil: DocPatch kann ganz einfach auch andere Versionen als die aktuelle ausgeben.

So sieht ein solcher Patch aus:

Die Zeilen mit + und - geben jeweils an, welcher Text hinzugefügt oder entfernt werden soll. Der Ausschnitt bezieht sich auf 013.md – also Artikel 13. md ist der Dateiname für Markdown-Dateien. Die lassen sich sehr einfach in andere Dateiformate umwandeln.

Die Daten waren da – und dann?

Wir hatten also eine gute Datengrundlage für die jeweiligen Versionen des Grundgesetzes – aber wie konnten wir zwei Versionen vergleichen? Dafür habe ich die Software wdiff genutzt.

Anders als die Patches, die versuchen, möglichst große Bereiche zu finden, die sich unterscheiden, vergleicht wdiff auf einer Wort-zu-Wort-Basis. Ist ein Wort, oder nur ein Buchstabe anders, wird die Änderung ausgegeben. Der Vorteil: wdiff gibt den kompletten Text aus, markiert aber, was eingefügt und was gelöscht wurde. Hier am Beispiel einer kleinen Änderung in Artikel 1 Abs. 3:

In R mussten wir also nur noch für jeden Artikel die Zeichen zwischen [--] und {++} zählen – und kamen so auf die Gesetzesteile, die verändert wurden.

Der R-Code für diese Zählung sieht kompliziert aus. Aber hauptsächlich, weil man mit sogenanntem RegEx (Regular Expressions) die Texte zwischen den Klammern extrahieren muss. nchar() berechnet die Zahl der einzelnen Zeichen. Und aus denen kann man hinterher ganz einfach einen Anteil berechnen.

Das klingt eigentlich ganz einfach. Trotzdem hat das Projekt mehrere Wochen gedauert. Denn zuerst wollte ich jeweils den kompletten Grundgesetztext vergleichen. Das hat überhaupt nicht funktioniert, weil wdiff immer ein Problem damit hatte, wenn neue Artikel eingefügt wurden (also alles mit Kleinbuchstaben: 16a, etc.). Die Lösung war relativ einfach: Immer nur einzelne Artikel vergleichen. In quilt lassen sich diese neuen Artikel auch anlegen, sie werden aber bei der Ausgabe von früheren Versionen des Grundgesetzes nicht mit angezeigt, wenn sie damals noch nicht drinstanden. Ziemlich cooles Tool.

Das Ergebnis fand in der Zeitung auf einer Grafikseite statt – und kann sich sehen lassen, finde ich:

Durch die weitere Nutzung der Seite stimmst Du der Verwendung von Cookies zu. Weitere Informationen

Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklärst du sich damit einverstanden.

Schließen