Kapitel 1. Deine erste Shiny App

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Einführung

In diesem Kapitel werden wir eine einfache Shiny-App erstellen. Zunächst zeige ich dir die Mindestanforderungen an eine Shiny-App und dann lernst du, wie du sie startest und stoppst. Als Nächstes lernst du die zwei wichtigsten Komponenten jeder Shiny-App kennen: die UI (kurz für Benutzeroberfläche), die definiert, wie deine App aussieht, und die Serverfunktion, die definiert, wie deine App funktioniert. Shiny nutzt reaktive Programmierung, um die Ausgaben automatisch zu aktualisieren, wenn sich die Eingaben ändern. Deshalb lernen wir zum Abschluss des Kapitels die dritte wichtige Komponente von Shiny-Apps kennen: reaktive Ausdrücke.

Wenn du Shiny noch nicht installiert hast, installiere es jetzt mit:

install.packages("shiny")

Wenn du Shiny bereits installiert hast, kannst du mit packageVersion("shiny") überprüfen, ob du die Version 1.5.0 oder höher hast.

Lade dann deine aktuelle R-Sitzung ein:

library(shiny)

App-Verzeichnis und Datei erstellen

Es gibt mehrere Möglichkeiten, eine Shiny-App zu erstellen. Die einfachste ist, ein neues Verzeichnis für deine App zu erstellen und darin eine einzelne Datei namens app.R abzulegen. Mit dieser app.R-Datei teilst du Shiny mit, wie deine App aussehen und wie sie sich verhalten soll.

Probiere es aus, indem du ein neues Verzeichnis erstellst und eine app.R-Datei hinzufügst, die wie folgt aussieht:

library(shiny)
ui <- fluidPage(
  "Hello, world!"
)
server <- function(input, output, session) {
}
shinyApp(ui, server)

Das ist eine vollständige, wenn auch triviale, Shiny-App! Wenn du dir den vorangegangenen Code genau ansiehst, macht unsere app.R vier Dinge:

  1. Er ruft library(shiny) auf, um das Shiny-Paket zu laden.

  2. Sie definiert die Benutzeroberfläche, also die HTML-Webseite, mit der Menschen interagieren. In diesem Fall ist es eine Seite mit den Worten "Hallo, Welt!".

  3. Sie legt das Verhalten unserer App fest, indem sie eine server Funktion definiert. Im Moment ist sie leer, also tut unsere App nichts, aber wir werden uns das in Kürze noch einmal ansehen.

  4. Sie führt shinyApp(ui, server) aus, um eine Shiny-Anwendung von der Benutzeroberfläche und dem Server aus zu erstellen und zu starten.

Tipp

Es gibt zwei bequeme Möglichkeiten, eine neue App in RStudio zu erstellen:

  • Erstelle in einem Schritt ein neues Verzeichnis und eine app.R Datei, die eine einfache App enthält, indem du auf Datei → Neues Projekt klickst und dann Neues Verzeichnis und Shiny Web Application auswählst.

  • Wenn du die Datei app.R bereits erstellt hast, kannst du die App Boilerplate schnell hinzufügen, indem du shinyapp eintippst undShift+Tab drückst.

Laufen und Anhalten

Es gibt ein paar Möglichkeiten, wie du diese App ausführen kannst:

  • Klicke auf die Schaltfläche App ausführen(Abbildung 1-1) in der Symbolleiste des Dokuments.

  • Verwende ein Tastaturkürzel: Cmd/Strg+Umschalt+Eingabe.

  • Wenn du nicht mit RStudio arbeitest, kannst du (source())1 das gesamte Dokument oder rufe shiny::runApp() mit dem Pfad zum Verzeichnis auf, das app.R enthält.

Abbildung 1-1. Die Schaltfläche App ausführen findest du oben rechts im Quellbereich.

Wähle eine dieser Optionen und überprüfe, ob du die gleiche App wie in Abbildung 1-2 siehst. Herzlichen Glückwunsch! Du hast deine erste Shiny-App erstellt.

Abbildung 1-2. Die sehr einfache Shiny-App, die du siehst, wenn du den obigen Code ausführst.

Bevor du die App schließt, gehe zurück zu RStudio und sieh dir die R-Konsole an. Du wirst feststellen, dass dort etwas steht wie:

#> Listening on http://127.0.0.1:3827

Dies gibt dir die URL an, unter der deine App zu finden ist: 127.0.0.1 ist eine Standardadresse, die "dieser Computer" bedeutet, und 3827 ist eine zufällig zugewiesene Portnummer. Du kannst diese URL in einen beliebigen kompatiblen2 Webbrowser eingeben, um eine andere Kopie deiner App zu öffnen.

Beachte auch, dass R beschäftigt ist: Die Eingabeaufforderung ist nicht sichtbar und die Symbolleiste der Konsole zeigt ein Stoppzeichen an. Während eine Shiny-App läuft, "blockiert" sie die R-Konsole. Das bedeutet, dass du keine neuen Befehle auf der R-Konsole ausführen kannst, bis die Shiny-App beendet wird.

Du kannst die App stoppen und den Zugriff auf die Konsole mit einer dieser Optionen wiederherstellen:

  • Klicke auf das Stoppschild-Symbol in der Symbolleiste der R-Konsole.

  • Klicke auf die Konsole und drücke dann Esc (oder drücke Strg+C, wenn du nicht mit RStudio arbeitest).

  • Schließe das Fenster der Shiny-App.

Der grundlegende Arbeitsablauf bei der Entwicklung von Shiny-Apps besteht darin, etwas Code zu schreiben, die App zu starten, mit der App zu spielen, noch mehr Code zu schreiben und dies zu wiederholen. Wenn du RStudio verwendest, musst du die App nicht einmal anhalten und neu starten, um deine Änderungen zu sehen - du kannst entweder die Schaltfläche "App neu laden" in der Toolbox drücken oder die Tastenkombination Cmd/Strg+Umschalt+Eingabe verwenden. Andere Arbeitsabläufe behandle ich in Kapitel 5.

Hinzufügen von UI-Steuerelementen

Als Nächstes fügen wir einige Ein- und Ausgaben zu unserer Benutzeroberfläche hinzu, damit sie nicht ganz so minimalistisch ist. Wir werden eine sehr einfache App erstellen, die dir alle eingebauten Datenrahmen aus dem Datenpaket zeigt.

Ersetze deine ui durch diesen Code:

ui <- fluidPage(
  selectInput("dataset", label = "Dataset", choices = ls("package:datasets")),
  verbatimTextOutput("summary"),
  tableOutput("table")
)

In diesem Beispiel werden vier neue Funktionen verwendet:

fluidPage()

Eine Layout-Funktion, die die grundlegende visuelle Struktur der Seite einrichtet. Mehr darüber erfährst du in "Single-Page Layouts".

selectInput()

Ein Eingabesteuerelement, das dem Nutzer ermöglicht, mit der App zu interagieren, indem er einen Wert eingibt. In diesem Fall ist es ein Auswahlfeld mit der Beschriftung "Datensatz", mit dem du einen der eingebauten Datensätze von R auswählen kannst. Mehr über Eingaben erfährst du unter "Eingaben".

verbatimTextOutput() und tableOutput()

Die Ausgabesteuerelemente sagen Shiny , wo die gerenderte Ausgabe platziert werden soll (auf das Wie gehen wir gleich ein). verbatimTextOutput() zeigt Code an, und tableOutput() zeigt Tabellen an. Mehr über Ausgaben erfährst du unter "Ausgaben".

Layout-Funktionen, Eingaben und Ausgaben haben unterschiedliche Verwendungszwecke, aber im Grunde sind sie alle gleich: Sie sind alle nur ausgefallene Möglichkeiten, HTML zu generieren, und wenn du sie außerhalb einer Shiny-App aufrufst, siehst du auf der Konsole HTML ausgedruckt. Scheue dich nicht, herumzustöbern, um herauszufinden, wie die verschiedenen Layouts und Steuerelemente im Detail funktionieren.

Führe die App erneut aus. Du siehst jetzt das, was in Abbildung 1-3 zu sehen ist: eine Seite mit einem Auswahlfeld. Wir sehen nur die Eingabe und nicht die beiden Ausgaben, weil wir Shiny noch nicht mitgeteilt haben, wie die Eingabe und die Ausgaben zusammenhängen.

Abbildung 1-3. Die Datasets-App mit UI.

Verhalten hinzufügen

Als Nächstes werden wir die Ausgaben zum Leben erwecken, indem wir sie in der Serverfunktion definieren.

Shiny nutzt reaktive Programmierung, um Apps interaktiv zu machen. In Kapitel 3 erfährst du mehr über reaktive Programmierung, aber im Moment geht es darum, Shiny mitzuteilen , wie eine Berechnung ausgeführt werden soll, und nicht darum, Shiny zu befehlen, sie tatsächlich auszuführen. Das ist so, als würdest du jemandem ein Rezept geben und von ihm verlangen, dass er dir ein Sandwich macht.

Wir sagen Shiny, wie es die Ausgaben summary und table in der Beispiel-App ausfüllen soll, indem wir die "Rezepte" für diese Ausgaben bereitstellen. Ersetze deine leere server Funktion durch diese:

server <- function(input, output, session) {
  output$summary <- renderPrint({
    dataset <- get(input$dataset, "package:datasets")
    summary(dataset)
  })

  output$table <- renderTable({
    dataset <- get(input$dataset, "package:datasets")
    dataset
  })
}

Die linke Seite des Zuweisungsoperators (<-), output$ID, zeigt an, dass du das Rezept für die Shiny-Ausgabe mit dieser ID bereitstellst. Die rechte Seite der Zuweisung verwendet eine bestimmte Renderfunktion, um einen von dir bereitgestellten Code zu verpacken. Jede render{Type} Funktion dient dazu, eine bestimmte Art von Ausgabe zu erzeugen (z. B. Text, Tabellen und Diagramme) und ist oft mit einer {type}Output Funktion gekoppelt. In dieser App ist zum Beispiel renderPrint() mit verbatimTextOutput() gepaart, um eine statistische Zusammenfassung mit Text in fester Breite (wortwörtlich) anzuzeigen, und renderTable() ist mit tableOutput() gepaart, um die Eingabedaten in einer Tabelle anzuzeigen.

Starte die App erneut und beobachte, was mit der Ausgabe passiert, wenn du eine Eingabe änderst. Abbildung 1-4 zeigt, was du sehen solltest, wenn du die App öffnest.

Abbildung 1-4. Jetzt, da wir eine Serverfunktion bereitgestellt haben, die Ausgänge und Eingänge miteinander verbindet, haben wir eine voll funktionsfähige App.

Beachte, dass die Zusammenfassung und die Tabelle immer dann aktualisiert werden, wenn du den Eingabedatensatz änderst. Diese Abhängigkeit entsteht implizit, weil wir in den Ausgabefunktionen auf input$dataset verweisen. input$dataset wird mit dem aktuellen Wert der UI-Komponente mit der ID dataset gefüllt und bewirkt, dass die Ausgaben automatisch aktualisiert werden, wenn sich dieser Wert ändert. Dies ist das Wesen der Reaktivität: Die Ausgaben reagieren automatisch (berechnen neu), wenn sich ihre Eingaben ändern.

Vermeidung von Doppelarbeit mit reaktiven Ausdrücken

Auch in diesem einfachen Beispiel gibt es Code, der doppelt vorhanden ist: Die folgende Zeile ist in beiden Ausgaben enthalten:

dataset <- get(input$dataset, "package:datasets")

In jeder Art von Programmierung ist es eine schlechte Praxis, doppelten Code zu haben; es kann rechnerisch verschwenderisch sein und, was noch wichtiger ist, es erhöht die Schwierigkeit, den Code zu warten oder zu debuggen. Das ist hier nicht so wichtig, aber ich wollte die Grundidee in einem sehr einfachen Kontext veranschaulichen.

Bei der traditionellen R-Skripterstellung verwenden wir zwei Techniken, um mit doppeltem Code umzugehen: Entweder wir erfassen den Wert mit einer Variablen oder wir erfassen die Berechnung mit einer Funktion. Leider funktioniert keiner dieser beiden Ansätze. Die Gründe dafür erfährst du in "Warum brauchen wir reaktive Programmierung?

Du erstellst eine reaktive Expression, indem du einen Codeblock in reactive({...}) einwickelst und ihn einer Variablen zuweist, und du benutzt eine reaktive Expression, indem du sie wie eine Funktion aufrufst. Obwohl es so aussieht, als würdest du eine Funktion aufrufen, hat ein reaktiver Ausdruck einen wichtigen Unterschied: Er wird nur beim ersten Aufruf ausgeführt und speichert sein Ergebnis, bis es aktualisiert werden muss.

Wir können unsere server() aktualisieren, um reaktive Ausdrücke zu verwenden, wie im folgenden Code gezeigt. Die App verhält sich identisch, arbeitet aber etwas effizienter, weil sie den Datensatz nur einmal und nicht zweimal abrufen muss:

server <- function(input, output, session) {
  # Create a reactive expression
  dataset <- reactive({
    get(input$dataset, "package:datasets")
  })

  output$summary <- renderPrint({
    # Use a reactive expression by calling it like a function
    summary(dataset())
  })

  output$table <- renderTable({
    dataset()
  })
}

Wir werden noch mehrmals auf die reaktive Programmierung zurückkommen, aber selbst mit einem flüchtigen Wissen über Eingaben, Ausgaben und reaktive Ausdrücke ist es möglich, ziemlich nützliche Shiny-Apps zu bauen!

Zusammenfassung

In diesem Kapitel hast du eine einfache App erstellt - sie ist nicht besonders aufregend oder nützlich, aber du kannst sehen, wie einfach es ist, mit deinem vorhandenen R-Wissen eine Web-App zu erstellen. In den nächsten beiden Kapiteln erfährst du mehr über Benutzeroberflächen und reaktive Programmierung, die beiden Grundbausteine von Shiny. Jetzt ist ein guter Zeitpunkt, um dir den Shiny Spickzettel zu besorgen. Er hilft dir dabei, dir die wichtigsten Komponenten einer Shiny-App zu merken.

Abbildung 1-5. Der Shiny Spickzettel.

Übungen

  1. Erstelle eine App, die den Benutzer mit seinem Namen begrüßt. Du kennst noch nicht alle Funktionen, die du dafür brauchst, deshalb habe ich hier ein paar Codezeilen eingefügt. Überlege dir, welche Zeilen du verwenden willst, und kopiere sie dann und füge sie an der richtigen Stelle in eine Shiny-App ein:

    tableOutput("mortgage")
    output$greeting <- renderText({
      paste0("Hello ", input$name)
    })
    numericInput("age", "How old are you?", value = NA)
    textInput("name", "What's your name?")
    textOutput("greeting")
    output$histogram <- renderPlot({
      hist(rnorm(1000))
    }, res = 96)
  2. Angenommen, dein Freund möchte eine App entwerfen, die es dem Benutzer ermöglicht, eine Zahl (x) zwischen 1 und 50 einzustellen und das Ergebnis der Multiplikation dieser Zahl mit 5 anzuzeigen. Dies ist sein erster Versuch:

    library(shiny)
    
    ui <- fluidPage(
      sliderInput("x", label = "If x is", min = 1, max = 50, value = 30),
      "then x times 5 is",
      textOutput("product")
    )
    
    server <- function(input, output, session) {
      output$product <- renderText({
        x * 5
      })
    }
    
    shinyApp(ui, server)

    Aber leider hat es einen Fehler:

    Kannst du ihnen helfen, den Fehler zu finden und zu korrigieren?

  3. Erweitere die App aus der vorherigen Übung so, dass der Nutzer den Wert des Multiplikators y einstellen kann, damit die App den Wert x * y ausgibt. Das Endergebnis sollte so aussehen:.

  4. Nimm die folgende App, die der in der letzten Übung beschriebenen App einige zusätzliche Funktionen hinzufügt. Was ist neu? Wie kannst du die Menge an doppeltem Code in der App reduzieren, indem du einen reaktiven Ausdruck verwendest?

    library(shiny)
    
    ui <- fluidPage(
      sliderInput("x", "If x is", min = 1, max = 50, value = 30),
      sliderInput("y", "and y is", min = 1, max = 50, value = 5),
      "then, (x * y) is", textOutput("product"),
      "and, (x * y) + 5 is", textOutput("product_plus5"),
      "and (x * y) + 10 is", textOutput("product_plus10")
    )
    
    server <- function(input, output, session) {
      output$product <- renderText({
        product <- input$x * input$y
        product
      })
      output$product_plus5 <- renderText({
        product <- input$x * input$y
        product + 5
      })
      output$product_plus10 <- renderText({
        product <- input$x * input$y
        product + 10
      })
    }
    
    shinyApp(ui, server)
  5. Die folgende Anwendung ähnelt einer, die du bereits in diesem Kapitel gesehen hast: Du wählst einen Datensatz aus einem Paket aus (dieses Mal verwenden wir das ggplot2-Paket) und die Anwendung gibt eine Zusammenfassung und Darstellung der Daten aus. Außerdem folgt sie der guten Praxis und verwendet reaktive Ausdrücke, um redundanten Code zu vermeiden. Im folgenden Code gibt es jedoch drei Fehler. Kannst du sie finden und beheben?

    library(shiny)
    library(ggplot2)
    
    datasets <- c("economics", "faithfuld", "seals")
    ui <- fluidPage(
      selectInput("dataset", "Dataset", choices = datasets),
      verbatimTextOutput("summary"),
      tableOutput("plot")
    )
    
    server <- function(input, output, session) {
      dataset <- reactive({
        get(input$dataset, "package:ggplot2")
      })
      output$summary <- renderPrint({
        summary(dataset())
      })
      output$plot <- renderPlot({
        plot(dataset)
      }, res = 96)
    }
    
    shinyApp(ui, server)

1 Die zusätzlichen () auf der Außenseite sind wichtig. shinyApp() erstellt nur eine App, wenn sie gedruckt wird, und () erzwingt den Druck des letzten Ergebnisses in der Datei, die gesourct wird, das ansonsten unsichtbar zurückgegeben wird.

2 Shiny ist bestrebt, alle modernen Browser zu unterstützen. Beachte, dass Internet Explorer-Versionen vor IE11 nicht kompatibel sind, wenn du Shiny direkt in deiner R-Sitzung ausführst. Shiny-Apps, die auf Shiny Server oder ShinyApps.io bereitgestellt werden, können jedoch mit IE10 funktionieren (frühere Versionen des IE werden nicht mehr unterstützt).

Get Glänzend meistern now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.