Reporting mit R The R Bootcamp |
In diesem Practical wirst du das Dashboard der letzten Aufgabe weiter ausbauen, interaktiver und dynamischer gestalten. Am Ende wirst du dieses Dashboard erstellen.
Am Ende des Practicals wirst du wissen wie man:
flexdashboard
in eine shiny
Webapp umwandelt.Öffne dein TheRBootcamp
R project. Es sollte die Ordner 1_Data
, 2_Assets
und 3_Markdown
enthalten.
Lade dieses Markdown Skript herunter und speichere es in deinen 3_Markdown
Ordner.
Öffne das eben heruntergeladene Markdown file. Es enthält das fertige Dashboard der vorherigen Aufgabe. Arbeite mit diesem File weiter, um sicherzustellen, dass alles korrekt implementiert ist.
shiny
Wandle das Markdown Dokument in eine shiny
App um, indem du runtime: shiny
im YAML Header, direkt unter social: ["twitter", "facebook"]
einfügst und speicherst. Ab jetzt wird beim Rendern eine App geöffnet, die deine R-Session als Server verwendet.
Im ersten R Chunk deines Dokuments ändere das setup
in der Chunk Definition des setup
Chunks in global
. Damit wird dein Code, der in diesem Chunk enthalten ist, nur einmal beim Starten der App geladen und so die Performanz verbessert.
Ist die App jetzt bereits dynamisch und reaktiv?
Nein, du musst zuerst Inputs definieren. Füge vor dem Titel der ersten Seite (vor Übersicht der Airbnbs in Berlin {data-orientation=rows}
) eine neue Seite via eine Zeile Gleichheitszeichen und nenne diese Inputs
.
Hinter das Inputs
(aber auf derselben Zeile), schreibe {.sidebar}
. Damit wird eine Sidebar definiert, die über alle drei Seiten der App fix auf der linken Seite bestehen bleibt.
Fülle nun deine Sidebar. Erstelle unterhalb des Inputs
Titels (genauer unterhalb der Gleichheitszeichen) einen neuen Code Chunk.
In diesen Chunk fülle jetzt über die folgenden Tasks vier Inputmöglichkeiten. Füge zunächst mit dem untenstehenden Code einen Slider ein. Im ersten Argument wird die inputID
spezifiziert, unter welcher der Input, also der mit dem Slider ausgewählte Wert, später ansteuerbar ist. Das zweite Argument spezifiziert das label
, also den Titel des Sliders. Setze die inputID
auf "Schlafzimmer"
, und das label
auf "Minimum Anzahl Schlafzimmer"
. Die anderen Argumente spezifizieren Minimum, Maximum, und Standardwert.
# Auswahl Airbnbs über Schlafzimmer
sliderInput("XXX",
"XXX",
min = 0,
max = 12,
value = 0)
log10
) verwendet. Setze die inputID
auf "Preis"
, und das label
auf "Max Preis pro Nacht (log):"
. Das zusätzliche step
Argument spezifiziert die minimalen Schritte, in denen der Slider bewegt werden kann. Setze es auf .01
.# Preis pro Nacht
sliderInput("XXX",
"XXX",
min = 0, max = ceiling(max(log10(airbnb$Preis), na.rm = TRUE)),
value = ceiling(max(log10(airbnb$Preis), na.rm = TRUE)),
step = XXX)
checkboxGroupInput()
Funktion. Setze die inputID
auf "Stadtteile"
, und das label
auf "Wähle Stadtteile:"
. Das choices
Argument definiert, wie viele Checkboxes angezeigt werden sollen, und welche Werte diese annehmen können. Im selected
Argument wird definiere, welche Checkboxes standardmässig angewählt werden (hier alle).# Auswahl der zu Plottenden Stadtteile
checkboxGroupInput("XXX",
"XXX",
choices = sort(unique(airbnb$Stadtteil)),
selected = sort(unique(airbnb$Stadtteil)))
selectInput
wird ein Dropdown-Menu erstellt, aus dem ein Wert ausgewählt wird. choices
definiert die möglichen Werte, selected
den Standardwert. Setze die Werte "viridis"
, "cividis"
, "magma"
, und "inferno"
, beim choices
Argument ein. Das sind die Namen vierer Farbpaletten. Definiere "viridis"
als Standardwert.# Farbpalette
selectInput("Farbpalette", "Wähle Farbpalette:",
choices = c("XXX", "XXX", "XXX", "XXX"),
selected = "XXX")
shiny
müssen R outputs, wie Plots, explizit mit der render*()
Funktionen gerendert werden. Gehe zuerst zum Code Chunk, in dem sich der leaflet
code befindet und packe den gesamten leaflet
Code dieses Chunks in die renderLeaflet({})
Funktion, zwischen die geschwungenen Klammern, wie unten angezeigt.renderLeaflet({
LEAFLET CODE
})
plotly
Grafik erstellt wird. Packe auch hier den Code des gesamten Chunks in die renderPlotly({})
Funktion.renderPlotly({
PLOTLY CODE
})
renderPlot({})
Funktion.renderPlot({
PLOT CODE
})
gauge
der mittleren Gesamtratings definiert wird. Wiederum, packe den Code des gesamten Chunks in die renderGauge({})
Funktion.renderGauge({
GAUGE CODE
})
Wiederhole die Schritte B14 und B15 auch noch für die letzten Chunks (zweimal die Plots und zweimal die Gauges, in abwechselnder Reihenfolge).
Nun kannst du dein Dokument ausführen. Passiert etwas, wenn du die Inputwerte veränderst?
Der Grund weshalb nichts passiert ist, dass zwar Inputs definiert werden, diese aber bei den Plots nicht vorkommen. Du musst also den Code der Plots anpassen. Um, zum Beispiel, die Auswahl der Stadtteile nicht in jedem Plot durchführen zu müssen, können wir reaktive Objekte erstellen, also Objekte, die mit jeder Veränderung der Inputwerte upgedatet werden. Die grundsätzliche Syntax ist wie folgt:
DYNAMISCHES_OBJEKT <- reactive({
MANIPULATION EINES OBJEKTES BASIEREND AUF INPUT
})
reactive()
Funktion unten erstellt ein reaktives Objekt und führt den in der Funktion geschriebenen Code jedes Mal aus, wenn sich einer der darin enthaltenen Inputwert verändert. Der untenstehende Code definiert zwei reaktive Objekte airbnb_dynamic
- eine reaktive Version des airbnb
Datensatzes, gefiltert nach Stadtteil
, Schlafzimmer
, und dem 10er Logarithmus von Preis
- sowie farben_dynamic
und ein reaktives Objekt, welches basierend auf der ausgewählten Farbpalette (aus dem viridis
Paket) und der Anzahl ausgewählter Stadtteile einen Vektor von Farbwerten zurückgibt. Kopiere den Code und füge ihn ganz unten in den R Chunk in dem die Inputs definiert werden (der zweite R Chunk im Dokument) ein.# kreiere reaktives airbnb Objekt
airbnb_dynamic <- reactive({
airbnb %>%
filter(Stadtteil %in% c(input$Stadtteile) &
Schlafzimmer >= as.numeric(input$Schlafzimmer) &
log10(Preis) <= as.numeric(input$Preis))
})
farben_dynamic <- reactive({
## Farbpalette vorbereiten
# Anzahl Stadtteile
n_stadtteile <- length(input$Stadtteile)
# Definiere n_stadtteile verschiedene Farben aus der viridis palette
switch(input$Farbpalette,
viridis = viridis(n_stadtteile),
cividis = cividis(n_stadtteile),
magma = magma(n_stadtteile),
inferno = inferno(n_stadtteile))
})
Um die reaktive Version der airbnb
Daten in den Plots und Gauges zu verwenden, ersetze airbnb
in den Definitionen der Karte (dem leaflet
Plot), der Häufigkeitsverteilung (dem plotly
Plot), der Histogramme (dem ggplot2
Plot), und der Gauges (also alle die Teile, die du vorhin in eine render*()
Funktion gepackt hast) durch airbnb_dynamic()
. Dabei sind die Klammern nach airbnb_dynamic
unbedingt nötig; das ist eine spezielle Syntax der reaktiven Objekte.
Da du das farben_dynamic()
Objekt vorgängig definiert hast, wird das farben
Objekt nicht mehr benötigt. Lösche dessen Definition oberhalb des Codes für die Häufigkeitsverteilung:
### LÖSCHE ALLES VON HIER
# Anzahl Stadtteile
n_stadtteile <- length(unique(airbnb$Stadtteil))
# Definiere n_stadtteile verschiedene Farben aus der viridis palette
farben <- viridis(n_stadtteile)
### BIS HIER
Ersetze ausserdem im Code der Häufigkeitsverteilung (dem plotly
Plot) das Objekt farben
durch farben_dynamic()
. Du findest das Objekt in der Zeile scale_color_manual(values = farben) +
.
Klicke auf Run Document
. Nun solltest du steuern können, welche Daten und welcher Stadtteile gezeigt werden, sowie welche Farbpalette im Plot auf Seite 2 verwendet wird. Cool oder?
leaflet
2Nun ist es an der Zeit, die Karte noch etwas mehr aufzupeppen! Die Datenpunkte sollen nach Stadtteil eingefärbt werden, Popupfenster sollen Informationen über das jeweilige Airbnb anzeigen, und eine Legende soll zeigen, welche Farbe welchem Stadtteil entspricht. Gehe zum leaflet
Code, der die Karte erstellt.
Beginne mit der Einfärbung der Punkte. Mit der colorFactor()
Funktion des leaflet
Pakets kannst du Farbwerte auf Levels einer kategorialen Variable (wie Stadtteil
) mappen. Füge den untenstehenden Code vor dem Code der den leaflet
Plot erstellt (aber innerhalb von renderLeaflet({})
) ein.
dom <- airbnb_dynamic() %>%
pull(Stadtteil) %>% unique()
# Erstelle Farbpalette
pal <- colorFactor(farben_dynamic(),
domain = dom)
Das so erstellte pal
Objekt kann jetzt in der addCircleMarker()
Funktion verwendet werden. Allerdings wird hier eine etwas eigene Syntax verwendet. Füge ein neues Argument color
in die addCircleMarker()
Funktion ein und setze es auf ~pal(Stadtteil)
Die Tilde ~
ersetzt das Gleichheitszeichen nicht, sondern gibt leaflet
lediglich an, dass hier unterschiedliche Werte für die verschiedenen Airbnbs benutzt werden.
Führe die App aus. Jetzt sollten die Punkte nach Stadtteil eingefärbt sein.
Im Moment ist aber noch nicht ersichtlich, welche Farbe zu welchem Stadtteil gehört. Es braucht eine Legende. Das geht in leaflet
ganz einfach mit der addLegend()
Funktion. Dabei muss eine mit colorFactor()
erstellte Farbpalette, sowie die Werte nach denen die Marker eingefärbt werden sollen, als Argumente spezifiziert werden. Füge den untenstehenden Code direkt nach der addCircleMarker()
Funktion ein, sodass die Pipe (%>%
) direkt nach der schliessenden Klammer von addCircleMarker()
(also auf derselben Zeile) steht.
%>%
# Füge Legende hinzu
addLegend(pal = pal, values = ~Stadtteil, opacity = 1)
airbnb_dynamic() %>%
und leaflet() %>%
eine Zeile mit dem untenstehenden Code einfügen. Der erste Teil erstellt dabei eine Variable superhost
, die "Ja"
und "Nein"
anstelle von TRUE
und FALSE
angibt. Der zweite Teil erstellt eine Variable info
, die Informationen aus unterschiedlichen Variablen mithilfe der paste0()
Funktion zusammenfügt. Dabei wird etwas HTML verwendet, damit die Informationen später sauber formatiert untereinander dargestellt werden. mutate(
superhost = case_when(isTRUE(Host_superhost) ~ "Ja",
TRUE ~ "Nein"),
info = paste0("Unterkunft: <b>", Unterkunftsart,
"</b><br>Schlafzimmer: <b>", Schlafzimmer,
"</b><br>Superhost: <b>", superhost,
"</b><br>Preis pro Nacht: <b>", Preis, "€</b>")
) %>%
Die neu erstellte Variable info
muss jetzt noch in addCircleMarkers()
aufgerufen, und der angezeigte Text etwas vergrössert werden. Füge dazu die Argumente label = ~lapply(info, HTML)
und labelOptions = labelOptions(textsize = "15px")
in der addCircleMarkers()
Funktion hinzu. lapply(info, HTML)
wendet die HTML()
Funktion auf jedes Element von info
an, was nötig ist, das der Text von leaflet
als HTML gerendert wird.
Führe die App erneut aus. Jetzt sollte alles klappen. Cool oder?
Das wars mit den vorgegebenen Aufgaben. In diesem Teil wirst du dein Dashboard auf eigene Faust erweitern und uns am Ende kurz zeigen, was du gemacht hast.
Untenstehend findest du einige Vorschläge, wie du dein Dashboard erweitern könntest. Versuche eigenständig weitere Features einzubauen. Dazu kannst du auf die Vorschläge unten zurückgreifen, aber auch gerne eigene Ideen umsetzen; je nach dem was dich am meisten reizt.
Schaue dir die Popupfenster der beiden Plots auf den Seiten 1 und 2 an. Gibt es zusätzliche Dinge die du angezeigt haben möchtest? Das können weitere Variablen, neu kreierte Variablen oder konditionale Variablen sein. Versuche diese zu implementieren.
leaflet
ermöglicht es auch Icons anstatt nur Punkte zu plotten. Eine Anleitung findest du hier (siehe dazu auch das Beispiel in den Slides zu Dashboards I). Du könntest zum Beispiel versuchen, Marker mit unterschiedlichen Icons zu verwenden. Zum Beispiel könntest du ein bestimmtes Icon für Superhosts verwenden und ein weiteres für ganz schlechte Airbnbs, und ein weiteres für den Rest. Eine weiter Möglichkeit wäre, unterschiedliche Icons pro Unterkunftsart zu wählen.
Gestern hast du im Bericht eine Regression gerechnet. Du könntest eine vierte Seite in das Dashboard einbauen, in der du z.B. Inputs für ein Regressionsmodell definierst und dir den jeweiligen Output als Tabelle anzeigen lasst. Zusätzlich könntest du einen Plot mit den vorhergesagten und tatsächlichen Werten einbauen. Hier findest du eine Übersicht der möglichen Inputformate.
Keine der obigen Optionen spricht dich an (oder vielleicht hast du ja bereits alle gemacht)? Überlege dir, wie du das Dashboard weiter aufpeppen kannst. Das kann das Styling betreffen, die Inputs, die angezeigte Information etc… Wir sind gespannt auf deine Kreationen!
Der airbnb.csv Datensatz enthält Zahlen zu 9868 Berliner Airbnbs
Variable | Beschreibung |
---|---|
Preis | Preis pro Nacht |
Erstellungsdatum | Eröffnungsdatum des Airbnbs |
Unterkunftsart | Appartement, Loft, House, etc. |
Schlafplätze | Anzahl Schlafplätze |
Schlafzimmer | Anzahl Schlafzimmer |
Badezimmer | Anzahl Badezimmer |
Reinigungsgebühr | Reinigungsgebühr |
Verfügbarkeit_90Tage | |
Viertel | In welchem Viertel befindet sich das Airbnb |
Stadtteil | In welchem Stadtteil befindet sich das Airbnb |
Breitengrad | Breitengrad |
Längengrad | Längengrad |
Host_id | Host id |
Host_seit | Erfahrung des Hosts |
Host_antwortzeit | Host Antwortzeit |
Host_antwortrate | Host Antwortrate |
Host_superhost | Superhost Ja/Nein |
Host_anzahl | Anzahl Gäste |
Rating_gesamt | Gesamtrating |
Rating_genauigkeit | Genauigkeitsrating |
Rating_sauberkeit | Sauberkeitsrating |
Rating_checkin | Checkinrating |
Rating_kommunikation | Kommunikationsrating |
Rating_lage | Lagerating |
Rating_wertigkeit | Wertigkeitsrating |
Küche | Küche vorhanden TRUE/FALSE |
Wifi | WLAN vorhanden TRUE/FALSE |
TV | TV vorhanden TRUE/FALSE |
Kaffeemaschine | Kaffeemaschine vorhanden TRUE/FALSE |
Geschirrspüler | Geschirrspüler vorhanden TRUE/FALSE |
Terrasse_Balkon | Terrasse/Balkon vorhanden TRUE/FALSE |
Badewanne | Badewanne vorhanden TRUE/FALSE |
Check_in_24h | 24h Check-In vorhanden TRUE/FALSE |
Paket | Installation |
---|---|
tidyverse |
install.packages("tidyverse") |
flexdashboard |
install.packages("flexdashboard") |
plotly |
install.packages("plotly") |
leaflet |
install.packages("leaflet") |
viridis |
install.packages("viridis") |
htmltools |
install.packages("htmltools") |
shiny |
install.packages("shiny") |
Funktion | Paket | Beschreibung |
---|---|---|
gauge() |
flexdashboard |
Erstelle einen gauge. |
renderGauge() |
flexdashboard |
Rendere Gauges in shiny |
valueBox() |
flexdashboard |
Erstelle eine value Box |
ggplotly() |
plotly |
Konvertiere ggplot2 Objekt in plotly Objekt |
renderPlotly() |
plotly |
Rendere plotly Plot in shiny |
leaflet() |
leaflet |
Initiiere leaflet Karte |
setView() |
leaflet |
Definiere Anfangsfenster |
addTiles() |
leaflet |
Zeige Karte |
addCircleMarkers() |
leaflet |
Füge Kreisförmige Marker auf die Karte |
renderLeaflet() |
leaflet |
Rendere leaflet Plot in shiny |
reactive() |
shiny |
Initiiere reaktives Objekt |
XXXInput() |
shiny |
Definiere Inputwidget. Siehe hier für eine Übersicht der möglichen Inputformate. |