Chapter 13 Presæntering af datasæt over for andre
13.1 Introduktion til chapter og læringsmålene
I dette chapter beskæftiger vi os med at lave interaktive visualiseringer, som vi kan vise overfor andre, fk. som en del af en presæntation. Til sidste vil der være generalt råd til at lave plots fk. i en powerpoint præsentation.
13.1.1 Læringsmålene
Du skal være i stand til at
- lave interactive plotter med pakken
plot_ly
. - anvende R pakken
Shiny
for at lave en simpel app og gør den interactiv - bygge på appen i
Shiny
- tilføj forskellige inputs, plot typer og panels. - kende generelle råde om presentering af data gennem visualiseringer
Husk evaluering i kurset!
13.2 Video ressourcer
- Video 1 - Introduktion til Shiny
Link her hvis det ikke virker nedenunder: https://player.vimeo.com/video/559363250
- Video 2 - Introduktion til Shiny - interaktiv plots
Link her hvis det ikke virker nedenunder: https://player.vimeo.com/video/559558820
- Video 3 - Introduktion til Shiny - ui layout
Link her hvis det ikke virker nedenunder: https://player.vimeo.com/video/559562153
13.3 Interactiv plots
Der er en nyttig pakke, der hedder plot_ly
, som man kan anvende til at lave interactive plotter. Kig for eksempel på følgende plot og afprøve de forskellige interaktiv muligheder.
library(plotly)
data(diamonds)
plot_ly(diamonds,
x = ~cut)
Her er et scatter plot lavet med plot_ly
:
%>% slice_sample(n = 1000) %>%
diamonds plot_ly(x = ~ carat,
y = ~ price) %>%
add_markers(color = ~ color)
Bemærk at vi har specificeret slice_sample
her, som vælger 1000 tilfældige rækker fra datasættet. Det er fordi diamonds
er en meget stor datasæt og hvis man forsøger at plotte alle observeationer på en gang med plot_ly
kan det være at den crasher eller kører for langsom.
Der er faktisk en nyttig funktion indenfor plot_ly
som hedder ggplotly
- man kan tage et plot som var lavet i ggplot2
og så anvende ggplotly
til at gøre den interaktiv. Her er samme plot:
<- diamonds %>% slice_sample(n = 1000) %>%
my_plot ggplot(aes(x=carat,y=price,colour=color)) +
geom_point() +
theme_minimal()
ggplotly(my_plot)
13.4 Shiny
Man kan anvende Shiny til at lave en interaktiv program. Det er nemt at få din første app op at køre. Her laver jeg en simpel app, som inddrager et plot af noget af data, vi har arbejdet med i kurset.
13.4.1 Eksempeler som viser Shiny
Indenfor pakken shiny
er der nogle eksempler som viser nogle forskellige Shiny apps. Prøve at køre nogle af følgende kode linjer.
library(shiny)
runExample("01_hello") # a histogram
runExample("02_text") # tables and data frames
runExample("03_reactivity") # a reactive expression
runExample("04_mpg") # global variables
runExample("05_sliders") # slider bars
runExample("06_tabsets") # tabbed panels
runExample("07_widgets") # help text and submit buttons
runExample("08_html") # Shiny app built from HTML
runExample("09_upload") # file upload wizard
runExample("10_download") # file download wizard
runExample("11_timer") # an automated timer
I eksempel 1 er der en histogram som viser nogle waiting times, med en slider hvor man kan specificere antallet af bins i det histogram. Man kan således ændre nogle parametre, og så plottet bliver ændret automatiske. Eksempel 2 har en table hvor man kan specificere hvor mange række man gerne vil have, og så kan man også vælger imellem forskellige datasæt.
Disse eksempeler har fordelen af, at man bare kan kopiere koden og så lave egen app og ændre den efter sin egne data.
13.4.2 Create new app
- Man vælger en mappe, og “Single File”. Indenfor mappen skal ligge en skript der hedder “app.R” (det er vigtigt at man ikke ændre navnet af “app.R”).
- Man kan trykke på “Run App” indenfor R Studio for at få den at køre
13.4.3 Struktur af en Shiny App
Her er den grundlæggende struktur af en Shiny app:
Indenfor “app.R” er der tre komponenter som kan skal være opmærksom på. Vi ændrer kun to af de tre komponenter.
Dele | Beskrivelse |
---|---|
ui <- fluidPage() |
“user interface” object: det fortæller Shiny hvordan appen ser ud. |
server <- function(input,output){} |
her skrives R kode, fk til et plot, som skal være en del af den R objekt som hedder output . input er for eksempel antallet af bins som man specificerer med en slider som i det histogram eksempel. |
shinyApp(ui = ui, server = server) |
er altid den sidste linje - den ændre vi ikke. Den få appen til at køre. |
13.4.4 Minimal example (men ikke interaktiv)
Jeg starter med at lave et meget simpelt “minimal” eksempel af hvordan man kan lave et program med Shiny:
- ui komponent: Vi vil gerne viser et plot som hedder “my_plot” - så skriver jeg
plotOutput("my_plot")
<- fluidPage(
ui plotOutput("my_plot") #fortælle, at vi vil fremvise "my_plot".
)
server
komponent: angiver vi koden tilmy_plot
.- Plottet skal være en del af vores
output
, så vi skriveroutput$my_plot <-
. renderPlot({ #plot kode })
fortæl den at det vi lave er et plot og vi skriver koden indenfor.
- Plottet skal være en del af vores
<- function(input, output) {
server #definere "my_plot"
$my_plot <- renderPlot({
output#Skriv plot kode her
}) }
Her er appen med ovenstående kode sæt ind: man godt kan køre den men når vi ikke har nogle data eller plot kode er den meget kedelig.
library(shiny)
library(tidyverse)
<- fluidPage(
ui plotOutput("my_plot") #fortælle, at vi vil fremvise "my_plot".
)
<- function(input, output) {
server #definere "my_plot"
$my_plot <- renderPlot({
output#Skriv plot kode her
})
}# Run the application
shinyApp(ui = ui, server = server)
Tilføje dataseættet iris
og lave et plot
Lad os tilføje nogle data til vores plot i formen af iris
, og skriv nogle kode til et scatter plot:
library(shiny)
library(tidyverse)
data(iris)
#ui: output plottet 'my_plot'
<- fluidPage(
ui plotOutput("my_plot")
)
#server: lav plot og kalde den for output$my_plot
<- function(input, output) {
server $my_plot <- renderPlot({
output%>%
iris ggplot(aes(x=Sepal.Width,y=Petal.Length)) +
geom_point() +
theme_classic()
})
}
# køre appen
shinyApp(ui = ui, server = server)
Hvis vi køre koden kan man se at vi har et plot frem. Appen er dog ikke interaktiv.
13.4.5 Minimal example - interactiv.
Vi vil gerne gøre vores app mere fleksibelt - lad os gøre det interaktiv ved at plotte et subset af Iris for en af de tre species, som vælges fra en “drop-down” box - vi kan anvende en funktion som hedder selectInput
:
Her er koden for vores selectInput
, som skal tilføjes indenfor fluidPage
.
selectInput(inputId = "Species", #giv en id
choices = iris %>% distinct(Species) %>% pull(Species), #setosa, virginica eller versicola
selected = "setosa", #default species
label = "Choose species") #label på plottet
Vi skal også ændre koden på plottet så at det reagerer på vores selectInput
:
- Vi laver en subset
iris_subset
af de data efter “Species” vi valgt i vores “drop-down box” ved at angivSpecies==input$Species
indenfor funktionenfilter
. - Vi laver et scatter plot med
iris_subset
:
<- iris %>%
iris_subset filter(Species==input$Species)
%>%
iris_subset ggplot(aes(x=Sepal.Width,y=Petal.Length)) +
geom_point() +
theme_classic()
Her tilføjer jeg de kode chunks fra ovenpå til vores program:
library(shiny)
library(tidyverse)
data(iris)
<- fluidPage(
ui selectInput(inputId = "Species",
choices = iris %>% distinct(Species) %>% pull(Species),
selected = "setosa",
label = "Choose species"),
plotOutput("my_plot")
)
<- function(input, output) {
server $my_plot <- renderPlot({
output
<- iris %>%
iris_subset filter(Species==input$Species)
%>%
iris_subset ggplot(aes(x=Sepal.Width,y=Petal.Length)) +
geom_point() +
theme_classic()
})
}
# Run the application
shinyApp(ui = ui, server = server)
Som man kan se i screenshot nedenunder, har vi en “drop-down box” hvor vi kan vælge imellem de tre Species
.
13.4.6 Flere plots på samme Shiny app
- Vi laver to plotter, et scatter plot og et histogram, som reagere på
selectInput
som fortæller de subset af de data efterSpecies
som skal plottes. - Vi kalder dem for
p1
ogp2
og plotte dem ved siden af hinanden medgrid.arrange
:
grid.arrange(p1,p2,ncol=2)
library(shiny)
library(tidyverse)
library(gridExtra)
data(iris)
<- fluidPage(
ui selectInput(inputId = "Species",
choices = iris %>% distinct(Species) %>% pull(Species),
selected = "setosa",
label = "Choose species"),
plotOutput("my_plot")
)
<- function(input, output) {
server
$my_plot <- renderPlot({
output
<- iris %>%
iris_subset filter(Species==input$Species)
<- iris_subset %>%
p1 ggplot(aes(x=Sepal.Width,y=Petal.Length)) +
geom_point(colour="steel blue") +
ggtitle(input$Species) +
theme_classic()
<- iris_subset %>%
p2 ggplot(aes(x=Sepal.Width)) +
geom_density(colour="firebrick3") +
ggtitle(input$Species) +
theme_classic()
grid.arrange(p1,p2,ncol=2)
})
}
# Run the application
shinyApp(ui = ui, server = server)
13.4.7 Involvere en table
Vi vil gerne tilføj en table så vi kan se vores data i appen. Jeg vil gerne specificere hvor mange rækker jeg skal vise frem i appen - vi kan gøre den interaktiv ved at giv en numericInput
funktion:
Her er koden for vores numericInput
. Bemærk, at man skriver tableOutput("my_table")
for at fortælle at vi vil viser “my_table” i appen.
numericInput(inputId = "num_rows", #giv id num_rows
label = "Number of observations to view:", #label på selve plottet
value = 5), #default værdi
tableOutput("my_table") #fortæl, at vi vil output "my_table"
Her er koden for my_table
. Bemærk at vi anvender funktion renderTable
i stedet for renderPlot
, og der er en indstilling indenfor head
hvor vi kan specificere hvor mange række vi skal have (med n = input$num_rows
- altså tallet som vi skriver i appen).
$my_table <- renderTable({
output<- iris %>%
iris_subset filter(Species==input$Species)
head(iris_subset, n = input$num_rows)
})
Jeg tilføjer de to kode chunks til vores app i følgende (som kan kopireres og blive kørte):
library(shiny)
library(tidyverse)
library(gridExtra)
data(iris)
<- fluidPage(
ui selectInput(inputId = "Species",
choices = iris %>% distinct(Species) %>% pull(Species),
selected = "setosa",
label = "Choose species"),
numericInput(inputId = "num_rows",
label = "Number of observations to view:",
value = 5),
plotOutput("my_plot"),
tableOutput("my_table")
)
<- function(input, output) {
server
$my_plot <- renderPlot({
output
<- iris %>%
iris_subset filter(Species==input$Species)
<- iris_subset %>%
p1 ggplot(aes(x=Sepal.Width,y=Petal.Length)) +
geom_point(colour="steel blue") +
ggtitle(input$Species) +
theme_classic()
<- iris_subset %>%
p2 ggplot(aes(x=Sepal.Width)) +
geom_density(colour="firebrick3") +
ggtitle(input$Species) +
theme_classic()
grid.arrange(p1,p2,ncol=2)
})
$my_table <- renderTable({
output<- iris %>%
iris_subset filter(Species==input$Species)
head(iris_subset, n = input$num_rows)
})
}
# Run the application
shinyApp(ui = ui, server = server)
13.4.8 Add a slider
- Lad os tilføj en
sliderInput
for at styr punkt eller linje størrelse i plottet. Den ser sådan ud:
- Vores kode ser sådan ud. Vi lave en slider af integer fra 1 til 10.
sliderInput(inputId = "Point", #giv den id Point
label = "Point size", #label på selve plottet
min = 1, #min værdi
max = 10, #max værdi
step = 1, #step size
value = 1), #default værdi
- Vi referer vores point størrelse ind i plottet med
input$Point
:
+ geom_point(size = input$Point, colour="steel blue") + ....
....+ geom_density(colour="firebrick3",lwd=input$Point) + ...... ....
- Vi tilføj ovenstående kode til vores plot:
library(shiny)
library(tidyverse)
library(gridExtra)
data(iris)
<- fluidPage(
ui selectInput(inputId = "Species",
choices = iris %>% distinct(Species) %>% pull(Species),
selected = "setosa",
label = "Choose species"),
numericInput(inputId = "num_rows",
label = "Number of observations to view:",
value = 5),
sliderInput(inputId = "Point",
label = "Point size",
min = 1,
max = 10,
step = 1,
value = 1),
plotOutput("my_plot"),
tableOutput("my_table")
)
<- function(input, output) {
server
$my_plot <- renderPlot({
output
<- iris %>%
iris_subset filter(Species==input$Species)
<- iris_subset %>%
p1 ggplot(aes(x=Sepal.Width,y=Petal.Length)) +
geom_point(size = input$Point, colour="steel blue") +
ggtitle(input$Species) +
theme_classic()
<- iris_subset %>%
p2 ggplot(aes(x=Sepal.Width)) +
geom_density(size = input$Point,colour="firebrick3") +
ggtitle(input$Species) +
theme_classic()
grid.arrange(p1,p2,ncol=2)
})
$my_table <- renderTable({
output<- iris %>%
iris_subset filter(Species==input$Species)
head(iris_subset, n = input$num_rows)
})
}
# Run the application
shinyApp(ui = ui, server = server)
13.4.9 Ekstras som man kan tilføje til ui
Her er nogle ekstra tekst som vi kan tilføj - for eksempel en title. Vi kan også lave nogle forskellige panels for at fremvise de forskellige dele af vores app - for eksempel en side panel og en main panel.
Title
titlePanel("Shiny Text")
Specificier sidebarLayout
sidebarLayout(
sidebarPanel(),
mainPanel()
)
Her er hvordan appen ser ud med titlen samt en sidebarPanel
og mainPanel
Her er fuld kode som man kan copy/paste ind i app.R
:
library(shiny)
library(tidyverse)
library(gridExtra)
data(iris)
<- fluidPage(
ui
titlePanel("My Iris app!"),
sidebarPanel(
selectInput(inputId = "Species",
choices = iris %>% distinct(Species) %>% pull(Species),
selected = "setosa",
label = "Choose species"),
numericInput(inputId = "num_rows",
label = "Number of observations to view:",
value = 5),
sliderInput(inputId = "Point",
label = "Point size",
min = 1,
max = 10,
step = 1,
value = 1)
),mainPanel(
plotOutput("my_plot"),
tableOutput("my_table")
)
)
<- function(input, output) {
server
$my_plot <- renderPlot({
output
<- iris %>%
iris_subset filter(Species==input$Species)
<- iris_subset %>%
p1 ggplot(aes(x=Sepal.Width,y=Petal.Length)) +
geom_point(size = input$Point, colour="steel blue") +
ggtitle(input$Species) +
theme_classic()
<- iris_subset %>%
p2 ggplot(aes(x=Sepal.Width)) +
geom_density(size = input$Point,colour="firebrick3") +
ggtitle(input$Species) +
theme_classic()
grid.arrange(p1,p2,ncol=2)
})
$my_table <- renderTable({
output<- iris %>%
iris_subset filter(Species==input$Species)
head(iris_subset, n = input$num_rows)
})
}
# Run the application
shinyApp(ui = ui, server = server)
13.5 Ekstra generelle råd
- Tilføje hensigtsmæssige title/akse labels etc. og gøre dem til en størrelse som er nem at læse (tænk i PowerPoint - personer bagest i rummet skal kunne læse teksten).
- Fjerne unødvendige legends.
- Anvende colour palettes som er designet til at fungere godt for de fleste (for eksempel undgå grøn og rød ved siden af hinanden).
- Viser kun hvad er nødvendige for at fortælle den historie, du gerne vil videregive til andre. For eksempel undgår ekstra tekst som ikke tilføjer noget til beskeden.
- En historie på en slide hvis man laver en PowerPoint præsentation.
- Andvende hensigtsmæssige akse transformeringer som giver mest mening til de data
- Undgå piecharts, 3D plots osv. medmindre de absolut tilføj noget ekstra til visualisering (meget sjældent).
- Hvis man tilføjer et plot til en PowerPoint, anbefaler jeg at bruge PDFs og ikke PNG/JPG, når en PDF har en højere kvalitet.
- Interaktiv plots kan være sjovt og interessant (men igen sikre at de tilføj nogle ekstra til din præsentation/rapport).
13.6 Andre muligheder/advanceret topics
Lave præsentations i PowerPoint direkte fra RStudio: https://support.rstudio.com/hc/en-us/articles/360004672913-Rendering-PowerPoint-Presentations-with-RStudio
Shiny cheatsheet: https://github.com/rstudio/cheatsheets/raw/master/shiny.pdf
Debugging with RStudio: https://support.rstudio.com/hc/en-us/articles/200713843-Debugging-with-RStudio
Advanced R: https://adv-r.hadley.nz/index.html
13.7 Problemstillinger
Problem 1) Lav interactiv plots
Anvend funktionen ggplotly
fra pakken plotly
til at lave følgende interkative plots:
- Et barplot som viser antallet af biler for de forskellige antal cylinders i variablen
cyl
i datasættetmtcars
. - Et scatter plot som viser
wt
på x-aksen ogqsec
på y-aksen og med farver efter variablengear
.- tilføj lineær trend linjer til plottet.
Problem 2) Shiny
- Indlæs pakken
Shiny
og se på de forskellige eksempler fk.runExample("05_sliders")
. - Lav et nyt app og kør den default app (dvs. uden at redigere på noget).
Problem 3) Shiny
- Slet default tekst og kopi koden fra ovenpå (med slider og to plotter) - kør appen.
- Tilpas koden, hvor du ændrer datasættet fra
Iris
tilPenguins
.
Problem 4) Shiny
- Lav et app som viser de første n rækker i dataframen
mtcars
(numericInput
) - Tilføj også en “drop-down box” med funktionen
selectInput
for at vise en subset af dataframen, efter de forskellige mulige værdier i variablengear
.
Problem 5) Shiny
- Lav et app med en
sliderInput
, hvor du styrer antallet af clusters med funktionenkmeans
i datasættetpenguins
. - Vis clusters som forskellige farver indenfor et scatter plot (det kan være fk. to variabler eller den første to principal components).
- Tilføj også en
selectInput
for at visualisere dine clusterings, i et subsæt af datasættet efter variablenisland
. - Anvend
sidebarPanel
ogmainPanel
til at separere dine inputs fra plotterne. - Tilføj en app titel samt plot-title/akse labels osv. for at bedste viser din app over for andre.
Problem 6) Shiny
Lav egen app og inddrager forskellige datasæt og koncepter fra kurset!