R adattermékek

Kategória: Adattudomány R-ben

Shiny

Áttekintés

A kezdéshez az alábbiakra van szükség

Ez utóbbihoz még kell egy beállítás: létre kell hozni a c:\Users\[user]\Documents\.Renviron fájlt az alábbi tartalommal:

PATH="${RTOOLS40_HOME}\usr\bin;${PATH}"

Majd az RStudio-ban telepítsük a shiny library-t, és töltsük be:

install.packages("shiny")
library("shiny")

Shiny alkalmazások készítése: File → New File → Shiny Web App…

Pár szó a Shiny-ról:

  • Egy tipikus alkalmazás két részből áll: az ui.R tartalmazza a megjelenítést, a server.R pedig az üzleti logikát. (Ehhez a Multiple Files opciót válasszuk ki.)
  • Az eredmény HTML + CSS + JavaScript lesz, a Bootstrap keretrendszer használatával.
  • A rendszer reaktív, ami azt jelenti, hogy egy adat megváltozása automatikusan módosítja a másik adatot. Ez a programozásban is megjelenik; ld. később.
  • Mindkét fájlnak tartalmaznia kell a shiny betöltését: library(shiny).
  • Az ui.R fájlban építjük fel a HTML oldalt, R függvényhívások segítségével. A leggyakoribb HTML elemeket használhatjuk. Ehhez segítség: ?builder.
  • Ha létrehozunk egy új Shiny projektet, akkor alapból kapunk egy alkalmazást, amelyben ha módosítjuk a csúszka értékét, akkor automatikusan megváltozik egy hisztogram.
  • Induláskor a konzolra kiírja kb. ezt: Listening on http://127.0.0.1:4587. Ha a böngészővel megnyitjuk a megadott oldalt, akkor ugyanazt látjuk, mint az RStudio-ban.
  • Indítása: felül a Run App gombra kattintva, vagy konzolon a runApp() paranccsal.
  • Eredmény: egy háttérben futó webszerver; az oldalt böngészővel is meg tudjuk nyitni.
  • Az eredményt megoszthatjuk a weboldalunkon, vagy az RStudio oldalán is; ez utóbbit korlátozottan ingyenesen is lehetséges.

Hello, Shiny world!

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Hello, Shiny world!"),
    sidebarLayout(
        sidebarPanel(
            h3("Sidebar Text")
        ),
        mainPanel(
            h3("Main Panel Text")
        )
    )
))

Magyarázat:

  • A shinyUI() függvény az egész grafikus felület.
  • A függvények egymásba ágyazva vannak benne, vesszővel elválasztva.
  • A függvények HTML tag nevekre hasonlítanak.
  • A fenti példa egy gyakori elrendezés.

server.R

library(shiny)

shinyServer(function(input, output) {
})

Magyarázat:

  • A shinyServer() tartalmazza a teljes üzleti logikát.
  • Paraméterként egy olyan függvényt vár, aminek egy input és egy output paramétere van.
  • Ez a példa abszolút minimalista.

Csúszka

Az alábbi példa bal oldalon egy csúszkát tartalmaz, míg jobb oldalon kiírja a csúszka aktuális értéke +10-et:

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Slider App"),
    sidebarLayout(
        sidebarPanel(
            h1("Move the Slider!"),
            sliderInput("slider1", "Slide me", 0, 100, 50)
        ),
        mainPanel(
            h3("Slider Value + 10:"),
            textOutput("text1")
        )
    )
))

server.R

library(shiny)

shinyServer(function(input, output) {
    output$text1 <- renderText(input$slider1 + 10)
})

Magyarázat:

  • Az ui.R forrásban definiáljuk a slider1-et inputként és text1-et outputként.
  • A server.R-ben ezeket felhasználjuk. A renderText() szöveget hoz létre.

Egy összetettebb példa

Az alábbi példa az alábbiakat tartalmazza:

  • szám beviteli mező,
  • két csúszka,
  • három jelölőnégyzet (checkbox),
  • outputként pedig egy 2 dimenziós diagram

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Plot Random Numbers"),
    sidebarLayout(
        sidebarPanel(
            numericInput("numberOfPoints", "How many random points should be plotted?", value = 500, min = 1, max = 1000, step = 1),
            sliderInput("sliderX", "Minimum and maximum X:", -100, 100, value = c(-50, 50)),
            sliderInput("sliderY", "Minimum and maximum Y:", -100, 100, value = c(-50, 50)),
            checkboxInput("showXlab", "Show/Hide X axis label", value = TRUE),
            checkboxInput("showYlab", "Show/Hide Y axis label", value = TRUE),
            checkboxInput("showTitle", "Show/Hide Title", value = FALSE),
        ),
        mainPanel(
            h3("Graph of random points"),
            plotOutput("plotPoints")
        )
    )
))

server.R

library(shiny)

shinyServer(function(input, output) {
    output$plotPoints <- renderPlot({
        set.seed(1)
        numberOfPoints <- input$numberOfPoints
        minX <- input$sliderX[1]
        maxX <- input$sliderX[2]
        minY <- input$sliderY[1]
        maxY <- input$sliderY[2]
        dataX <- runif(numberOfPoints, minX, maxX)
        dataY <- runif(numberOfPoints, minY, maxY)
        xlab = ifelse(input$showXlab, "X axis", "")
        ylab = ifelse(input$showYlab, "Y axis", "")
        main = ifelse(input$showTitle, "Title", "")
        plot(dataX, dataY, xlab = xlab, ylab = ylab, main = main, xlim = c(-100, 100), ylim = c(-100, 100))
    })
})

Érdemes megfigyelni a renderPlot() függvény paraméterét: kapcsos zárójelek között van. Valójában ez egy kód blokk, amit lefuttat.

shiny-example.png

Reaktív függvény

Az alábbi példa azt mutatja be, hogy hogyan tudunk létrehozni reaktív változót. Amit az output használ, annak reaktívnak kell lennie. Az input változók alapból reaktívak. Ha az output kiszámolásakor csak input változót használunk, akkor erre nincs szükség.

A példában két csúszkát tudunk beállítani, az eredmény pedig a kettő összege. A példa kedvéért az eredményt először kiszámoljuk egy reaktív változóba, majd megjelenítjük.

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Slider App"),
    sidebarLayout(
        sidebarPanel(
            h1("Move the Slider!"),
            sliderInput("sliderA", "A", 0, 100, 50),
            sliderInput("sliderB", "B", 0, 100, 50)
        ),
        mainPanel(
            h3("Sum:"),
            textOutput("text")
        )
    )
))

server.R

library(shiny)

shinyServer(function(input, output) {
    sumAB <- reactive({
        input$sliderA + input$sliderB
    })
    output$text <- renderText(sumAB())
})

Egy igazi webalkalmazás: lóerő jóslás

Az alábbi példa már egy "igazi" adattudományos jellegű: azt vizsgáljuk, hogy az autó teljesítménye (a lóereje) hogyan függ a fogyasztástól (az adat mérföld per gallon formában van megadva). Két modellt használunk:

  • az egyikben a lóerőt közvetlenül számoljuk a fogyasztásból, lineáris modell segítségével,
  • a másikban egy mesterséges törést teszünk a 20 mérföldenkénti gallon fogyasztáshoz oly módon, hogy az az alatti esetben ugyanúgy vesszük figyelembe, mint az első modellben, a másodikban viszont a fogyasztás mellett a fogyasztásból kivonunk húszat, és e kettő adat kombinációjaként készítjük a modellt.

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Predict Horsepower from MPG"),
    sidebarLayout(
        sidebarPanel(
            sliderInput("sliderMPG", "What is the MPG of the car?", 10, 35, value = 20),
            checkboxInput("showModel1", "Show/Hide Model 1", value = TRUE),
            checkboxInput("showModel2", "Show/Hide Model 2", value = TRUE)
        ),
        mainPanel(
            plotOutput("plot1"),
            h3("Predicted Horsepower from Model 1:"),
            textOutput("pred1"),
            h3("Predicted Horsepower from Model 2:"),
            textOutput("pred2")
        )
    )
))

server.R

library(shiny)
shinyServer(function(input, output) {
    mtcars$mpgsp <- ifelse(mtcars$mpg - 20 > 0, mtcars$mpg - 20, 0)
    model1 <- lm(hp ~ mpg, data = mtcars)
    model2 <- lm(hp ~ mpgsp + mpg, data = mtcars)

    model1pred <- reactive({
        mpgInput <- input$sliderMPG
        predict(model1, newdata = data.frame(mpg = mpgInput))
    })

    model2pred <- reactive({
        mpgInput <- input$sliderMPG
        predict(model2, newdata = data.frame(mpg = mpgInput, mpgsp = ifelse(mpgInput - 20 > 0, mpgInput - 20, 0)))
    })

    output$plot1 <- renderPlot({
        mpgInput <- input$sliderMPG
        plot(mtcars$mpg, mtcars$hp, xlab = "Miles Per Gallon", ylab = "Horsepower", bty = "n", pch = 16, xlim = c(10, 35), ylim = c(50, 350))
        if (input$showModel1) {
            abline(model1, col = "red", lwd = 2)
        }
        if (input$showModel2) {
            model2lines <- predict(model2, newdata = data.frame(mpg = 10:35, mpgsp = ifelse(10:35 - 20 > 0, 10:35 - 20, 0)))
            lines(10:35, model2lines, col = "blue", lwd = 2)
        }
        legend(25, 250, c("Model 1 Prediction", "Model 2 Prediction"), pch = 16, col = c("red", "blue"), bty = "n", cex = 1.2)
        points(mpgInput, model1pred(), col = "red", pch = 16, cex = 2)
        points(mpgInput, model2pred(), col = "blue", pch = 16, cex = 2)
    })

    output$pred1 <- renderText({
        model1pred()
    })

    output$pred2 <- renderText({
        model2pred()
    })
})

Itt a szerver kód egész bonyolult lett, tartalmaz reaktív függvényeket is.

shiny-horsepower.png

Fejlett GUI: fülek

Az alábbi példa azt illusztrálja, hogy hogyan tudunk füleket létrehozni az eredmény oldalon. Ezt használva egész összetett oldalakat tudunk készíteni a szokásos két R porgram segítségével.

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Tabs!"),
    sidebarLayout(
        sidebarPanel(
            textInput("box1", "Enter Tab 1 Text:", value = "Tab 1!"),
            textInput("box2", "Enter Tab 2 Text:", value = "Tab 2!"),
            textInput("box3", "Enter Tab 3 Text:", value = "Tab 3!")
        ),
        mainPanel(
            tabsetPanel(type = "tabs",
                        tabPanel("Tab 1", br(), textOutput("out1")),
                        tabPanel("Tab 2", br(), textOutput("out2")),
                        tabPanel("Tab 2", br(), textOutput("out3"))
            )
        )
    )
))

server.R

library(shiny)

shinyServer(function(input, output) {
    output$out1 <- renderText(input$box1)
    output$out2 <- renderText(input$box2)
    output$out3 <- renderText(input$box3)
})

Interaktív alkalmazás

Az alábbi alkalmazás egy interaktív: a felhasználó kijelölhet tetszőleges számú (legalább kettő) pontot a diagramon, amelyre a program lineáris modellt illeszt. Itt tehát a diagram egyszerre input és output is.

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Visualize Many Models"),
    sidebarLayout(
        sidebarPanel(
            h3("Slope"),
            textOutput("slopeOut"),
            h3("Intercept"),
            textOutput("intOut")
        ),
        mainPanel(
            plotOutput("plot1", brush = brushOpts(
                id = "brush1"
            ))
        )
    )
))

server.R

library(shiny)

shinyServer(function(input, output) {
    model <- reactive({
        brushed_data <- brushedPoints(trees, input$brush1, xvar = "Girth", yvar = "Volume")
        if (nrow(brushed_data) < 2) {
            return(NULL)
        }
        lm(Volume ~ Girth, data = brushed_data)
    })

    output$slopeOut <- renderText({
        if (is.null(model())) {
            "No Model Found"
        } else {
            model()[[1]][2]
        }
    })

    output$intOut <- renderText({
        if (is.null(model())) {
            "No Model Found"
        } else {
            model()[[1]][1]
        }
    })

    output$plot1 <- renderPlot({
        plot(trees$Girth, trees$Volume, xlab = "Girth",
             ylab = "Volume", main = "Tree Measurements",
             cex = 1.5, pch = 16, bty = "n")
        if (!is.null(model())) {
            abline(model(), col = "blue", lwd = 2)
        }
    })
})

index.html ui.R helyett

Az ui.R helyett létrehozhatunk index.html fájlt is. Hozzunk létre egy könyvtárat az ui.R mellett www néven, nyissuk meg az alkalmazást egy böngészőben, mentsük le az eredményt a www könyvtárba index.html néven, majd töröljük le az ui.R-t. Az eredmény:

~/myproject/server.R
~/myproject/www/index.html

Ez ekvivalens azzal, ha van ui.R és nincs index.html.

Az alkalmazás közzététele

Az alkalmazást nem egyszerű közzétenni. Két módszert ismerek.

shinyapps.io

install.packages('rsconnect')
library(rsconnect)
  • A fenti oldalon középen kattintsunk a Show Secret nyomógombra. Ez megmutatja a titkos kulcsunkat. Másoljuk a parancsot a vágólapra, és adjuk ki RStudio-ban (a példában a titkos kulcsomat elrejtettem):
rsconnect::setAccountInfo(name='faragocsaba',
              token='321EF51587CF3BB5EE7136F9B6BC7902',
              secret='<SECRET>')
  • Az rsconnect::deployApp() segítségével publikáljuk:
rsconnect::deployApp('~/R/shiny/interactiveexample')

gist.github.com

  • Nyissuk meg a https://gist.github.com/ oldalt.
  • Lépjünk be a GitHub azonosítónkkal (hozzunk létre egyet, ha még nincs).
  • A jobb felső sarokban található + jelre kattintva hozzunk létre egy új Gist projektet.
  • Adjunk egy leírást a Gist description… mezőben.
  • A Filename including extension… legyen ui.R, és töltsük fel az UI kódot.
  • Kattintsunk az Add file-ra alul, és ugyanígy töltsük fel a server.R-t.
  • Alul kattintsunk a Create secret gist nyomógombra, és utólag publikáljuk, vagy a legördülő menüből a Create public gist-re.
  • Miután létrehoztuk, az URL-ben a nevünk ellett megjelenik egy hosszú kód, pl. c81c8f345915913022c15e656d74cab3 (az URL-em: https://gist.github.com/faragocsaba/c81c8f345915913022c15e656d74cab3). Ezt másoljuk ki.
  • Adjuk ki RStudio-ból az alábbi parancsot:
runGist('c81c8f345915913022c15e656d74cab3')

Ez lokálisan indít egy webszervert, ahol meg tudjuk nézni az eredményt.

Hello, Shiny Gadgets world!

A Shiny-nak van egy egyszerűsített változata, melynek neve Shiny Gadgets. Itt egy függvényen belül található az ui és a server. Ez csak RStudio-ban fut, böngészőben nem, így leginkább arra alkalmas, hogy elősegítse az adatelemzést.

A használatához szükség van a shiny és a miniUI csomagokra. Az alábbi program lényegáben semmit sem csinál; a Done nypmógombra kattintva be lehet fejezni:

library(shiny)
library(miniUI)

myFirstGadget <- function() {
    ui <- miniPage(
        gadgetTitleBar("My First Gadget")
    )
    server <- function(input, output, session) {
        observeEvent(input$done, {
            stopApp()
        })
    }
    runGadget(ui, server)
}

myFirstGadget()

Shiny Gadgets szorzás

A következő példa két számot szoroz össze. A Done-ra kattintva kiírja az eredményt:

library(shiny)
library(miniUI)

multiplyNumbers <- function(numbers1, numbers2) {
    ui <- miniPage(
        gadgetTitleBar("Multiply Two Numbers"),
        miniContentPanel(
            selectInput("num1", "First Number", choices=numbers1),
            selectInput("num2", "Second Number", choices=numbers2)
        )
    )
    server <- function(input, output, session) {
        observeEvent(input$done, {
            num1 <- as.numeric(input$num1)
            num2 <- as.numeric(input$num2)
            stopApp(num1 * num2)
        })
    }
    runGadget(ui, server)
}

multiplyNumbers(3, 2)

Interaktív Shiny Gadgets

Az alábbi program interaktív: ki tudunk választani pontokat, amit a végén kiír:

library(shiny)
library(miniUI)

pickTrees <- function() {
    ui <- miniPage(
        gadgetTitleBar("Select Points by Dragging your Mouse"),
        miniContentPanel(
            plotOutput("plot", height = "100%", brush = "brush")
        )
    )
    server <- function(input, output, session) {
        output$plot <- renderPlot({
            plot(trees$Girth, trees$Volume, main = "Trees!", xlab = "Girth", ylab = "Volume")
        })
        observeEvent(input$done, {
            stopApp(brushedPoints(trees, input$brush, xvar = "Girth", yvar = "Volume"))
        })
    }

    runGadget(ui, server)
}

pickTrees()

Shiny alkalmazás

Egy kurzusban kellett készíteni egy Shiny applikációt, amely tartalmaz interakciót, reaktív diagramot, dokumentációt. Én a hasznaltauto.hu oldalon 20 véletlenszerű autó 3 adatát töltöttem le:

  • életkor (hónapban kifejezve),
  • a bevallott futott kilométerek száma (1000 km-ben),
  • a hengerűrtartalom (felfelé kerekítve, literben).

Nyilván adja magát a feltételezés, hogy az életkor korrelál a futott kilométerek számával. Volt még egy olyan feltételezés is, hogy a magasabb kategóriás autókat többet használják; ez utóbbi miatt kellett a hengerűrtartalom. (Általában a nagyobb hengerűrtartalom és az autó presztízse szintén korrelál.)

A felhasználó ki tudja választani azt, hogy mely autó kategóriákat szeretné látni. Ezen kívül magán a diagramon is ki tudj jelölni pontokat. A forrás:

ui.R

library(shiny)

shinyUI(fluidPage(
    titlePanel("Used cars - predict mileage"),
    p("The diagram below contains some used cars data: age (months), mileage (1000 kms) and cylinder capacity (see colors). The source of the data: hasznaltauto.hu."),
    p("You can select / deselect cylinder capacity ranges on the left hand side. Additionally you can select points on the right hand side."),
    p("The diagram shows lines indicating the linear model of mileage ~ age. On the left hand side you see how many thousand kms the car ran monthly."),
    sidebarLayout(
        sidebarPanel(
            checkboxInput("show_a", "0.0 < cylinder capacity <= 1.0", value = TRUE),
            checkboxInput("show_b", "1.0 < cylinder capacity <= 2.0", value = TRUE),
            checkboxInput("show_c", "2.0 < cylinder capacity <= 3.0", value = TRUE),
            checkboxInput("show_d", "3.0 < cylinder capacity", value = TRUE),
            textOutput("slopeOut"),
        ),
        mainPanel(
            plotOutput("used_cars_plot", brush = brushOpts(id = "used_cars"))
        )
    )
))

server.R

library(shiny)

shinyServer(function(input, output) {
    used_cars <- reactive({
        used_cars <- data.frame(
            age_month =    c( 46,  53, 163, 160, 144, 164, 176, 163, 189,  55,  68, 144, 122, 128,  34,  58,  87, 104, 251, 232,  41),
            mileage_tkm =  c( 64,  53, 193, 287, 199, 227, 225, 214, 136,  59, 128, 220, 183, 100,  30, 125,  98,  99, 112, 216,  29),
            cyl_capacity = c(3.5, 5.0, 1.6, 2.0, 2.0, 2.0, 1.8, 2.5, 1.4, 1.6, 2.2, 2.2, 4.4, 1.0, 3.0, 2.0, 0.6, 1.6, 1.0, 1.0, 4.6)
        )
        used_cars <- transform(
            used_cars, 
            cyl_category = 
                ifelse(cyl_capacity <= 1.0, "red", 
                       ifelse(cyl_capacity <= 2.0, "green", 
                              ifelse(cyl_capacity <= 3.0, "blue", 
                                     "yellow")))
        )
        if (!input$show_a) {
            used_cars = used_cars[used_cars["cyl_category"] != "red",]
        }
        if (!input$show_b) {
            used_cars = used_cars[used_cars["cyl_category"] != "green",]
        }
        if (!input$show_c) {
            used_cars = used_cars[used_cars["cyl_category"] != "blue",]
        }
        if (!input$show_d) {
            used_cars = used_cars[used_cars["cyl_category"] != "yellow",]
        }
        brushed_data <- brushedPoints(used_cars, input$used_cars, xvar = "age_month", yvar = "mileage_tkm")
        if (nrow(brushed_data) < 2) {
            used_cars
        } else {
            brushed_data
        }
    })

    output$slopeOut <- renderText({
        used_cars = used_cars()
        if (nrow(used_cars) >= 2) {
            model_brushed <- lm(mileage_tkm ~ age_month, data = used_cars)
            slope = model_brushed[[1]][2] * 1000
            slope_str = format(round(slope, 0), nsmall = 0)
            paste(slope_str, "kms / month")
        } else {
            "NA"
        }
    })

    output$used_cars_plot <- renderPlot({
        used_cars = used_cars()
        plot(used_cars$age_month, 
             used_cars$mileage_tkm,
             main = "Used cars for sale",
             xlab = "Age (month)",
             ylab = "Mileage (1000 km)",
             xlim = c(0, 300),
             ylim = c(0, 300),
             cex = 1.5,
             pch = 16,
             col = used_cars$cyl_category)
        legends = c()
        cols = c()
        if (nrow(used_cars) >= 2) {
            legends = c("all cars")
            cols = c("black")
            model_all <- lm(mileage_tkm ~ age_month, data = used_cars)
            abline(model_all, col = "black", lwd = 3)
        }
        if (input$show_a) {
            used_cars_a <- used_cars[used_cars["cyl_category"] == "red",    c("age_month", "mileage_tkm")]
            if (nrow(used_cars_a) >= 2) {
                legends = c(legends, "0.0 < cc <= 1.0")
                cols = c(cols, "red")
                model_a <- lm(mileage_tkm ~ age_month, data=used_cars_a)
                abline(model_a, col="red", lwd = 2)
            }
        }
        if (input$show_b) {
            used_cars_b <- used_cars[used_cars["cyl_category"] == "green",  c("age_month", "mileage_tkm")]
            if (nrow(used_cars_b) >= 2) {
                legends = c(legends, "1.0 < cc <= 2.0")
                cols = c(cols, "green")
                model_b <- lm(mileage_tkm ~ age_month, data=used_cars_b)
                abline(model_b, col="green", lwd = 2)
            }
        }
        if (input$show_c) {
            used_cars_c <- used_cars[used_cars["cyl_category"] == "blue",   c("age_month", "mileage_tkm")]
            if (nrow(used_cars_c) >= 2) {
                legends = c(legends, "2.0 < cc <= 2.0")
                cols = c(cols, "blue")
                model_c <- lm(mileage_tkm ~ age_month, data=used_cars_c)
                abline(model_c, col="blue", lwd = 2)
            }
        }
        if (input$show_d) {
            used_cars_d <- used_cars[used_cars["cyl_category"] == "yellow", c("age_month", "mileage_tkm")]
            if (nrow(used_cars_d) >= 2) {
                legends = c(legends, "3.0 < cc")
                cols = c(cols, "yellow")
                model_d <- lm(mileage_tkm ~ age_month, data=used_cars_d)
                abline(model_d, col="yellow", lwd = 2)
            }
        }
        if (length(legends) > 0) {
            legend(1,
                   300, 
                   legend = legends,
                   col = cols,
                   lty = 1,
                   lwd = 2,
                   cex = 0.8
            )
        }
    })
})

Az eredmény: https://faragocsaba.shinyapps.io/usedcars/.

shiny-usedcars.png

googleVis

Áttekintés

A Google-nek van egy saját diagram készítő JavaScript keretrendszere, melynek segítségével diagramokat tudunk helyezni a weboldalakra. Ízelítőt láthatunk a lehetőségekből az alábbi oldalon: https://developers.google.com/chart/interactive/docs/gallery.

A googleVis egy olyan R csomag, amely R-ből generál Google Chart-okat, azaz olyan HTML oldalt, ami a Google Chartot használja. Telepítése a szokásos:

install.packages("googleVis")

A betöltésekor hosszú jogi szöveget ír ki, de mivel nem szeretünk jogászkodni, ezt célszerű elnémítani:

suppressPackageStartupMessages(library(googleVis))

A Google Chart diagram googleVis megfelelője: gvis előtag, majd a diagram típus.

Az alábbi paranccsal megnézhetjük a lehetőségek széles tárházát:

demo(googleVis)

Oszlopdiagram

Ez ugyan nincs a tananyagban, de indítsunk egy egyszerűbbel! A googleVis csomag tartalmaz egy Exports táblát, ami 3 oszlopot tartalmaz: az országot, a profitot és egy online flag-et:

         Country Profit Online
1        Germany      3   TRUE
2         Brazil      4  FALSE
3  United States      5   TRUE
4         France      4   TRUE
5        Hungary      3  FALSE
6          India      2   TRUE
7        Iceland      1  FALSE
8         Norway      4   TRUE
9          Spain      5   TRUE
10        Turkey      1  FALSE

Érdekessége ennek az, hogy Magyarország is rajta van. Készítsünk ebből egy oszlopdiagramot:

myBarChart <- gvisBarChart(Exports, options=list(width=500, height=400))

Ez automatikusan az országonkénti profit alapján készíti a diagramot.

A következő parancs megjeleníti a böngészőben:

plot(myBarChart)
googlevis-barchart.png

Onnan is le tudjuk menteni a forrást, de közvetlenül is:

print(myBarChart)

Térkép

Igen látványos diagram a térkép:

myGeoChart1 <- gvisGeoChart(Exports, locationvar="Country", colorvar="Profit", options=list(width=600, height=400))

Megjelenítése hasonló a fentihez. Régióként megadhatjuk Európát:

myGeoChart2 <- gvisGeoChart(Exports, locationvar="Country", colorvar="Profit", options=list(width=600, height=400, region="150"))

Opciók

Az opciók megadásával egész jól testre szabható a diagram. Pl. a vonal diagramok lehetőségeiről a https://developers.google.com/chart/interactive/docs/gallery/linechart oldalon olvashatunk. Egy példa:

df <- data.frame(label=c("US", "GB", "BR"), val1=c(1,3,4), val2=c(23,12,32))
myLineChart <- gvisLineChart(df, xvar="label", yvar=c("val1","val2"),
    options=list(
        title="Hello World", legend="bottom",
        titleTextStyle="{color:'red', fontSize:18}",
        vAxis="{gridlines:{color:'red', count:3}}",
        hAxis="{title:'My Label', titleTextStyle:{color:'blue'}}",
        series="[{color:'green', targetAxisIndex: 0},{color: 'blue',targetAxisIndex:1}]",
        vAxes="[{title:'Value 1 (%)', format:'##,######%'}, {title:'Value 2 (\U00A3)'}]",
        curveType="function", width=500, height=300
    )
)
googlevis-example.png

Több diagram egy oldalon

Egy oldalon több diagramot is meg lehet jeleníteni:

myBarLineChart <- gvisMerge(myBarChart, myLineChart, horizontal=FALSE) 
myMultipleCharts <- gvisMerge(myBarLineChart, myGeoChart2, horizontal=TRUE)

Plotly

Áttekintés

JavaScript alapú webes alkalmazásokat lehet ennek segítségével létrehozni. Ehhez tehát nem kell szerver, minden a böngészőben fut. Számos rendszerrel működik, pl. R, Python, Excel. Ebben a fejezetben a Plotly R csomaggal foglalkozunk.

Telepítése a szokásos módon történik.

install.packages("plotly")
library(plotly)

A plot_ly() függvényt kell használnunk. Az eredmény többnyire interaktív. Ha megnyitunk egy diagramot (ld. lejjebb), R Studio-ban az Export → Save as Web Page… menüpont kiválasztásával tudjuk lementeni. Az eredmény egy több megabájtos HTML oldal, ami döntőrészt bináris JavaScriptet tartalmaz.

Pontdiagram

Angolul scatterplot. Az alábbi kód a fogyasztást (mérföld gallononként; itt tehát más a logika, mint a nálunk megszokott, ahol gallon mérföldenként lenne) ábrázolja a fontban mért tömeg függvényében (az mtcars az R belső adata):

plot_ly(mtcars, x = ~wt, y = ~mpg, type = "scatter")

Ha az egyes pontok fölé megyünk, kiírja az x és y értékeket.

Kategorikus változó

Az alábbi paraméterrel a cilinderek száma szerint színezi a pontokat, így 3 adatot is meg tudunk jeleníteni:

plot_ly(mtcars, x = ~wt, y = ~mpg, type = "scatter", color = ~factor(cyl))

Folytonos változó

A következő példában folytonos változóval jelenítjük meg a - ha jól értem - a motor hengerűrtartalmát:

plot_ly(mtcars, x = ~wt, y = ~mpg, type = "scatter", color = ~disp)

Méret

A színen kívül a mérettel is "játszhatunk", ezáltal újabb, immáron negyedik dimenziót adhatunk az ábrához. A példában a következőket használjunk:

  • x-koordináta: tömeg (font)
  • y-koordináta: fogyasztás (mérföld gallononként, a mi logikánkkal: fogyasztás inverze)
  • szín: cilinderek száma
  • méret: teljesítmény (lóerő)
plot_ly(mtcars, x = ~wt, y = ~mpg, type = "scatter", color = ~factor(cyl), size = ~hp)

3 dimenziós pontdiagram

Az alábbi parancs 3 dimenzióban ábrázolja az adatokat:

plot_ly(mtcars, x = ~wt, y = ~mpg, z = ~hp, color = ~factor(cyl), type="scatter3d")

Egész látványos, jól forgatható diagramot eredményez!

plotly-3d.png

Vonaldiagram

Az egyik leggyakoribb diagram típus a vonaldiagram. Példa (az airmiles egy olyan R adat, ami egy évi 24 megfigyelést tartalmazó idősorozat 1937-1960 között; az összes repült mérföldet tartalmazza):

data("airmiles")
plot_ly(x = ~time(airmiles), y = ~airmiles, type = "scatter", mode = "lines")

A diagram interaktív: nagyítható; ha a vonal fölé visszük az egeret, akkor kiírja a koordinátákat.

Több vonal egy diagramon

A tananyag példája kissé nyakatekert, így itt egy általam létrehozott adatkeretet jelenítünk meg:

column_type <- c("A", "A", "A", "A", "B", "B", "B", "B", "C", "C", "C", "C")
column_x <- c(1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)
column_y = c(30, 44, 42, 58, 24, 29, 32, 28, 57, 48, 68, 49)
my_df <- data.frame(type = column_type, x = column_x, y = column_y)
plot_ly(my_df, x = ~x, y = ~y, color = ~type, type = "scatter", mode = "lines")

Hisztogram

A hisztogram példában az USA 70 nagyvárosában mért csapadék mennyiséget jelenítjük meg:

plot_ly(x = ~precip, type = "histogram")

Dobozdiagram

Dobozdiagramként 3 írisz faj szirom hosszát ábrázoljuk:

plot_ly(iris, y = ~Petal.Length, color = ~Species, type = "box")
plotly-boxplot.png

Hőtérkép

A hőtérkép illusztrálására ismét saját példát kerestem:

terrain = matrix(c(1,2,1,3,2, 2,3,4,5,4, 2,3,5,6,4, 3,4,6,7,6, 2,4,5,4,3), nrow = 5, ncol = 5)
plot_ly(z = ~terrain, type = "heatmap")

3D felület

Igen látványos, 3 dimenziós, minden irányba forgatható hőtérképet kapunk akkor, ha a típust "surface"-re állítjuk (itt is eltértem a tanfolyam példájától):

plot_ly(z = ~terrain, type = "surface")

Térkép

A Plotly képes térképeket is megjeleníteni. Itt egy az egyben átvettem a tananyag példáját, ami az USA államainak lakosságát mutatja be, 1975-ben:

# Create data frame
state_pop <- data.frame(State = state.abb, Pop = as.vector(state.x77[,1]))
# Create hover text
state_pop$hover <- with(state_pop, paste(State, '<br>', "Population:", Pop))
# Make state borders white
borders <- list(color = toRGB("red"))
# Set up some mapping options
map_options <- list(
  scope = 'usa',
  projection = list(type = 'albers usa'),
  showlakes = TRUE,
  lakecolor = toRGB('white')
)

plot_ly(z = ~state_pop$Pop, text = ~state_pop$hover, locations = ~state_pop$State, 
        type = 'choropleth', locationmode = 'USA-states', 
        color = state_pop$Pop, colors = 'Blues', marker = list(line = borders)) %>%
        layout(title = 'US Population in 1975', geo = map_options)
plotly-map.png

Leaflet

Áttekintés

A Leaflet egy JavaScript könyvtár, melynek segítségével térképeket tudunk létrehozni. Az R leaflet csomag segítségével ezeket az oldalakat JavaScript tudás nélkül is létre tudjuk hozni. A telepítése a szokásos

install.packages("leaflet")
library(leaflet)

Egy abszolút minimalista forrás, ami kirajzol egy üres OpenStreetMaps világtérképet:

addTiles(leaflet())

Ennek van egy, a dplyr csomagban definiált, ún. pipe operátoros megoldása is:

my_map <- leaflet() %>% addTiles()
my_map

Itt a balra eső rész (jelen esetben a leaflet(), ill. annak az eredménye) a tőle jobbra eső függvény (addTiles()) első paramétere lesz. Látszólag bonyolítja a kódot, viszont ez korlátlanul egymás után írható. Egy tipikus leaflet program tipikusan sok ilyen egymás után írt függvényhívásól áll; emiatt érdemes ezzel a módszerrel megbarátkozni és ezt alkalmazni.

Fontosabb oldalak:

Egyszerű jelölő

Egy térképre tipikusan jelölőket szoktunk helyezni. Lássunk egy példát!

my_map <- leaflet() %>% 
    addTiles() %>%
    addMarkers(lng=19.045669, lat=47.507121, label="Parlament")
my_map

Ha lefuttatjuk, akkor Budapest belvárosának egy részét látjuk csak, megjelölve a Parlamentet. Ha a jelölő fölé megyünk, akkor látjuk a Parlament feliratot.

leaflet-budapest.jpg

Érdemes megjegyezni, hogy a fenti szintaxissal megegyezik az alábbi:

my_map <- leaflet() %>% addTiles()
my_map <- my_map %>% addMarkers(lng=19.045669, lat=47.507121, label="Parlament")
my_map

Tehát így is felépíthetünk egy térképet, lépésről lépésre. Itt láthatjuk igazán a %>% operátor hasznát. Anélkül ugyanis még ezt az egyszerű példát is így kellene használni, ami kevésbé olvasható (és egy tipikus térkép ennél sokkal összetettebb):

addMarkers(addTiles(leaflet()), lng=19.045669, lat=47.507121, label="Parlament")

Ha az információt nem rögtön szeretnénk megjeleníteni, amikor a felhasználó az okon fölé megy, hanem csak akkor, amikor rákattint, a popup paramétert használhatjuk:

my_map <- leaflet() %>% 
    addTiles() %>%
    addMarkers(lng=19.045669, lat=47.507121, popup="Parlament")
my_map

További jelölő beállítások

Lássuk, milyen egyéb jelölő beállítások lehetnek! További részleteket a https://rstudio.github.io/leaflet/markers.html oldalon olvashatunk.

Több jelölő

Lássunk egy példát a több jelölőre! Az alábbi példa a budapesti főpályaudvarokat mutatja meg:

railway_stations_map <- leaflet() %>%
    addTiles() %>%
    addMarkers(
        lng=c(19.0560793, 19.0839882, 19.0247399),
        lat=c(47.5103368, 47.5004423, 47.5002831),
        label=c("Nyugati", "Keleti", "Déli")
    )
railway_stations_map

Adatkeret használata

A fenti kód kicsit strukturáltabb formában, adatkeret használatával:

railway_stations <- data.frame(
    lng = c(19.0560793, 19.0839882, 19.0247399),
    lat = c(47.5103368, 47.5004423, 47.5002831),
    label = c("Nyugati", "Keleti", "Déli")
)
railway_stations_map <- railway_stations %>%
    leaflet() %>%
    addTiles() %>%
    addMarkers(lng=~lng, lat=~lat, label=~label)
railway_stations_map

Mivel egy térképen tipikusan egy-egy elemnek kevés tulajdonsága van (jelen példában: hosszúság, szélesség, címke), viszont sok adatot szeretnénk megjeleníteni (pl. csak Budapesten 41 darab vasútállomás vagy vasúti megálló található), érdemes az oszlopos megadás helyett soronkénti megadást választani. Ezt viszont közvetlenül nem tudjuk megadni; vagy mátrixból konvertálunk több lépésben, van a tibble csomagot használjuk (install.packages("tibble")):

library(leaflet)
library(tibble)

railway_stations <- tribble(
    ~lng, ~lat, ~label,
    19.0560793, 47.5103368, "Nyugati",
    19.0839882, 47.5004423, "Keleti",
    19.0247399, 47.5002831, "Déli"
)
railway_stations_map <- railway_stations %>%
    leaflet() %>%
    addTiles() %>%
    addMarkers(lng=~lng, lat=~lat, label=~label)
railway_stations_map

Különböző színek

Adódik a következő lépés: jó lenne különböző típusú dolgokat különböző színekkel jelölni. Sajnos alapból ezt nem támogatja a leaflet addMarkers() függvénye; ehhez az addAwesomeMarkers() függvényt kell használni, saját ikonkészlettel.

Ikonokat többféleképpen létrehozhatunk, pl. az ikonok URL-ének megadásával; ezekről a https://rstudio.github.io/leaflet/markers.html oldalon olvashatunk bővebben. Ugyancsak ezen az oldalon találtam egy olyan megoldást, amelyhez nem kell saját ikonkészletet feltölteni, hanem az ion könyvtárban definiáltakat tudjuk használni. A példát kibővítjük egyéb vasútállomás típusokkal:

  • piros: főpályaudvar
  • kék: pályaudvar
  • zöld: vasútállomás
  • kék: vasúti megálló

Mindegyikből létrehozunk kettőt-hármat:

library(leaflet)
library(tibble)

railway_stations <- tribble(
    ~lng, ~lat, ~label,
    19.0560793, 47.5103368, "Nyugati",
    19.0839882, 47.5004423, "Keleti",
    19.0247399, 47.5002831, "Déli",
    19.0884682, 47.4687654, "Ferencváros",
    19.0893862, 47.5253531, "Rákosrendező",
    19.1492484, 47.4634574, "Kőbánya-Kispest",
    19.0216216, 47.4651711, "Kelenföld",
    19.1008009, 47.5117573, "Zugló",
    19.2238918, 47.4371316, "Ferihegy"
)
icons <- awesomeIcons(
    icon = 'ios-close',
    iconColor = 'black',
    library = 'ion',
    markerColor = c("red", "red", "red", "blue", "blue", "green", "green", "orange", "orange")
)
railway_stations_map <- railway_stations %>%
    leaflet() %>%
    addTiles() %>%
    addAwesomeMarkers(lng=~lng, lat=~lat, label=~label, icon=icons)
railway_stations_map

A fenti program az adatok további növekedésével nehezen karbantarthatóvá válik. Pl. tegyük fel, hogy felvesszük az összes budapesti vasúti megállót, majd módosítani szeretnénk rajta; a színt elég nehézkes lenne megtalálni. Ehelyett vegyük fel a típust az adatkeretbe, és egy függvény segítségével számoljuk ki a színt!

library(leaflet)
library(tibble)

railway_stations <- tribble(
    ~type, ~lng, ~lat, ~label,
    1, 19.0560793, 47.5103368, "Nyugati",
    1, 19.0839882, 47.5004423, "Keleti",
    1, 19.0247399, 47.5002831, "Déli",
    2, 19.0884682, 47.4687654, "Ferencváros",
    2, 19.0893862, 47.5253531, "Rákosrendező",
    3, 19.1492484, 47.4634574, "Kőbánya-Kispest",
    3, 19.0216216, 47.4651711, "Kelenföld",
    4, 19.1008009, 47.5117573, "Zugló",
    4, 19.2238918, 47.4371316, "Ferihegy"
)
getColor <- function(railway_stations) {
    sapply(railway_stations$type, function(type) {
        switch(
            type,
            "red",
            "blue",
            "green",
            "orange"
        )
    })
}
icons <- awesomeIcons(
    icon = 'ios-close',
    iconColor = 'black',
    library = 'ion',
    markerColor = getColor(railway_stations)
)
railway_stations_map <- railway_stations %>%
    leaflet() %>%
    addTiles() %>%
    addAwesomeMarkers(lng=~lng, lat=~lat, label=~label, icon=icons)
railway_stations_map

Sajnos a példa igen összetetté vált, de egy bizonyos méret felett szükség van erre a karbantarthatóság miatt.

leaflet-railwaystations-colors.jpg

Klaszterezés

Tegyük fel, hogy sok pontunk van, pl. Budapesten ezer. Ez esetben a sok ikon teljesen eltakarja a térképet, és használhatatlanná teszi azt, pl.:

nonclustered_map <- leaflet() %>%
    addTiles() %>%
    addMarkers(
        lng=rnorm(1000, 19.07, 0.08),
        lat=rnorm(1000, 47.5, 0.05)
    )
nonclustered_map

Ilyen esetben az addMarkers() függvényben megadhatjuk a clusterOptions = markerClusterOptions() opciót, és megfelelően összevonja a pontokat:

clustered_map <- leaflet() %>%
    addTiles() %>%
    addMarkers(
        lng=rnorm(1000, 19.07, 0.08),
        lat=rnorm(1000, 47.5, 0.05),
        clusterOptions = markerClusterOptions()
    )
clustered_map
leaflet-cluster.jpg

A klaszterezés az előzővel összekapcsolható, pl.:

railway_stations_map <- railway_stations %>%
    leaflet() %>%
    addTiles() %>%
    addAwesomeMarkers(lng=~lng, lat=~lat, label=~label, icon=icons, clusterOptions = markerClusterOptions())
railway_stations_map

Jelmagyarázat

Jelmagyarázatot az addLegend() függvény segítségével tudunk hozzáfűzni. A fenti példát folytatva:

railway_stations_map <- railway_stations %>%
    leaflet() %>%
    addTiles() %>%
    addAwesomeMarkers(lng=~lng, lat=~lat, label=~label, icon=icons, clusterOptions = markerClusterOptions()) %>%
    addLegend(
        title="Jelmagyarázat", 
        position="topright", 
        color=c("red", "blue", "green", "orange"), 
        label=c("főpályaudvar", "pályaudvar", "vasútállomás", "vasúti megálló")
    )
railway_stations_map

Az egészet egybe rakva, az összes vasúti megállóval kiegészítve és némiképp felokosítva az alábbi eredményt kapjuk. A kódot helytakarékosság miatt összecsukva láthatjuk; ki kell nyitni a megtekintéséhez.

A végeredmény itt található: https://rpubs.com/faragocsaba/bpvasut.

leaflet-railwaystations.jpg

Kör

Jelölők helyett köröket is rajzolhatunk. Ez különösen akkor lehet fontos, ha a kör mérete információt hordoz. Az alábbi példában Magyarország megyéinek a lakosságszámát illusztráljuk, ahol a kör mérete arányos az ott élő lakosok számával.

library(leaflet)
library(tibble)

hungary_county <- tribble(
    ~lng, ~lat, ~population, ~label,
    19.3466886, 46.6058070,  503825, "Bács-Kiskun",
    18.2452050, 46.0639136,  360704, "Baranya",
    21.0917859, 46.6734946,  334264, "Békés",
    20.8316648, 48.2221667,  642447, "Borsod-Abaúj-Zemplén",
    20.3035484, 46.4682023,  399012, "Csongrád-Csanád",
    18.5711316, 47.1688464,  417712, "Fejér",
    17.3104085, 47.7039240,  467144, "Győr-Moson-Sopron",
    21.5630863, 47.5029094,  527989, "Hajdú-Bihar",
    20.1130195, 47.8025447,  294609, "Heves",
    20.4778127, 47.2443900,  370007, "Jász-Nagykun-Szolnok",
    18.3234255, 47.6074306,  299207, "Komárom-Esztergom",
    19.5512564, 47.9928807,  189304, "Nógrád",
    19.4719105, 47.3991153, 1278874, "Pest",
    17.5926396, 46.4571473,  301429, "Somogy",
    22.0552721, 48.0267304,  552964, "Szabolcs-Szatmár-Bereg",
    18.5574856, 46.5192212,  217463, "Tolna",
    16.7706108, 47.1877150,  253551, "Vas",
    17.6978305, 47.1034677,  341317, "Veszprém",
    16.8632767, 46.7118773,  268648, "Zala",
    19.0543713, 47.4826327, 1752286, "Budapest (főváros)",
)
hungary_county_map <- hungary_county %>%
    leaflet() %>%
    addTiles() %>%
    addCircleMarkers(
        ~lng,
        ~lat,
        label=~label,
        radius=sqrt(hungary_county$population) / 50
    )
hungary_county_map

Téglalap

Téglalapot is rajzolhatunk a térképre az addRectangles() függvény segítségével. Itt két átlós csúcs koordinátáit kell megadni. Az alábbi példa azt illusztrálja, hogy a vidékünkön mekkora egy szélességi és hosszúsági kör mérete:

leaflet() %>%
  addTiles() %>%
  addRectangles(lng1=19, lng2=20, lat1=46, lat2=47)

Publikálás

Publikálni ezt is többféleképpen tudjuk:

  • Export → Save as Web Page… → adjunk neki egy nevet, és az így létrejövő HTML fájlt meg tudjuk osztani tetszőleges weboldalon.
  • Publish → Publish HTML… → RPubs → az rpubs.com oldalon tudjuk megosztani (előtte regisztrálnunk kell).

Swirl

Áttekintés

A Swirl egy interaktív oktatási környezet. A Data Science Specialization sorozat szerzői készítették. Ez egy ugyanolyan R csomag, mint a többi, így a szokásos módon kell telepíteni:

install.packages("swirl")
install.packages("stringi")
library(swirl)

Majd az indítása:

swirl()

Érdemes "eljátszani" vele, hogy ráérezzünk a lehetőségekre (és korlátokra). Néhány lényegesen lehetőség:

  • Információt ír ki, és Enter lenyomásával tudunk tovább lépni.
  • Kapunk egy kérdést, és be kell írni a választ.
  • A kérdésre többféle válaszlehetőség közül választhatunk.
  • Végre tud hajtani R parancsokat, beleértve a diagram rajzolást is.
  • Kilépni az Esc nyomógombba tudunk.

A használata során számos problémába ütköztem, nem éreztem kiforrott eszköznek.

Saját Swirl készítése

Saját Swirl készítéséhez fel kell telepíteni a swirlify csomagot:

install.packages("swirlify")
library(swirlify)

Célszerű készítenünk egy külön könyvtárat a Swirl számára, pl.:

dir.create("~/R/swirl")
setwd(file.path("~/R/swirl"))

Saját Swirl tananyagot többféleképpen készíthetünk, és érdemes ezekkel megismerkednünk, ugyanis sajnos nem mindig működik mindegyik.

swirlify()

Normál esetben - ha működik - ez a legegyszerűbb. Indítsuk el a következő parancsot:

swirlify("Lesson 1", "My First Course")

Egy szerkesztő ablak jelenik meg, ahol elég intuitív módon tölthetjük ki a kérdéseket.

  • A jobb felső sarokban töltsük ki értelemszerűen az adatokat. Legalább a nevünket adjuk meg.
  • Bal oldalon válasszuk ki a legördülő menüből a kérdés típusát. Pl. első körben hagyjuk az alapértelmezett Message-en.
  • Az Outputhoz írjunk be valamilyen szöveget, majd kattintsunk az Add Question-re.
  • Figyeljük meg, hogy jobb oldalon megjelenik az új bejegyzés.
  • A bal oldali lehetőségek közül válasszuk most ki a Command-ot.
  • Az Outputhoz most írjunk be egy kérdést.
  • A Correct Answer mezőbe írjuk be a helyes választ.
  • Az Answer Test az ellenőrző. Kattintsunk az alatta levő Make Answer Test from Correct Answer nyomógombra.
  • A Hint-hez írjunk be valamilyen segítséget (akár a helyes választ).
  • Kattintsunk ismét az Add Question-re.
  • Kattintsunk a Save Session-re.
  • Kattintsunk a Demo Lesson-re.
  • Ha mindent jól csináltunk, akkor az ablak bezáródik, és a konzolon ki tudjuk próbálni a leckét.

A swirlify() parancs a már korábban, akár más módon megkezdett lecke folytatására is alkalmas. Az eredmény egy lesson.yaml fájl ehhez hasonló tartalommal:

- Class: meta
  Course: My First Course
  Lesson: Lesson 1
  Author: Csaba
  Type: Standard
  Organization: private
  Version: 2.4.5

- Class: text
  Output: Addition comes.

- Class: cmd_question
  Output: 3 + 2 = 
  CorrectAnswer: 5
  AnswerTests: omnitest(correctExpr='5')
  Hint: 5

new_lesson()

A második leckét a fenti mintájára készítsük el, de most a new_lesson() parancs segítségével:

new_lesson("Lesson 2", "My First Course")

Ennek hatására fent megnyílik a lesson.yaml fájl. A fenti mintájára készítsünk egy kicsit mást, pl. szorzást:

- Class: meta
  Course: My First Course
  Lesson: Lesson 2
  Author: Csaba
  Type: Standard
  Organization: private
  Version: 2.4.5

- Class: text
  Output: Multiplication comes.

- Class: cmd_question
  Output: 3 * 2 = 
  CorrectAnswer: 6
  AnswerTests: omnitest(correctExpr='6')
  Hint: 6

Indítása:

demo_lesson()

Fájlok létrehozása

Ha egy fájlkezelőből megnézzük, akkor a következőt láthatjuk:

  • A könyvtárszerkezet a munkakönyvtárban létrehozott My_First_Course, majd az alatt a Lesson_1 és Lesson_2.
  • Benne található a lesson.yaml, ami a lényeg.
  • De van ott még 3, lényegében üres fájlt is: customTests.R, initLesson.R és dependson.txt.

Készítsük el most "gyalog" módszerrel a következő leckét!

  • Készítsünk egy másolatot a Lesson_2 könyvtár alapján Lesson_3 néven.
  • A lesson.yaml fájlt módosítsuk, a többit hagyjuk úgy, ahogy van. Pl. lehet most kivonás.
- Class: meta
  Course: My First Course
  Lesson: Lesson 3
  Author: Csaba
  Type: Standard
  Organization: private
  Version: 2.4.5

- Class: text
  Output: Subtraction comes.

- Class: cmd_question
  Output: 3 - 2 = 
  CorrectAnswer: 1
  AnswerTests: omnitest(correctExpr='1')
  Hint: 1

A set_lesson() paranccsal tudjuk beállítani az új leckét. Ezt vagy kiadjuk paraméter nélkül, és akkor ki tudjuk választani a megfelelő fájlt, vagy megadhatjuk neki paraméterként:

set_lesson("My_First_Course/Lesson_3/lesson.yaml")

Indítani a fenti alapján a demo_lesson() paranccsal tudjuk.

Egészen elképesztően nehézkes ez a rendszer, szóval tényleg csak a legelszántabbaknak ajánlom. Néhány dolog, amire jó, ha felkészülünk:

  • Ékezetes karaktereket egyáltalán nem fogad el.
  • Gyakran érthetetlen hibát ír ki.
  • Sok esetben logikátlan a felépítése.
  • A swirlify() sok esetben hiányos vagy egyenesen hibás, így a felületen kattingatással megnyert időt könnyen többszörösen elveszítjük a hibák keresésével.

Kérdés típusok

Ismerkedjünk meg néhány kérdés típussal!

Egyszerű üzenet

Ahogy fent láthattuk, a text típussal írhatunk ki olyan üzenetet, melyre nem várunk választ, csak Entert:

- Class: text
  Output: This is just a message. Press Enter to continue.

R parancs

A fenti cmd_question valójában R parancsot ad ki. Egy másik példa:

- Class: cmd_question
  Output: Let x be 3 + 2!
  CorrectAnswer: x <- 3 + 2
  AnswerTests: omnitest(correctExpr='x <- 3 + 2')
  Hint: x <- 3 + 2

Itt ha beírjuk a helyes választ (x <- 3 + 2), akkor az tényleg végrehajtódik az R-ben, tényleg létrejön egy x változó, melynek az értéke a kiszámolt 5 lesz, valamint a kiadott parancs még a history-ban is benne lesz.

Kitöltendő kérdés

Megtévesztő az előző lehetőség, ugyanis az ember azt gondolná, hogy az való a kitöltendő kérdésre. Ahhoz viszont van egy másik, a text_question:

- Class: text_question
  Output: What is the capital of Hungary? 
  CorrectAnswer: Budapest
  AnswerTests: omnitest(correctVal='Budapest')
  Hint: Type Budapest.

Itt hibás a sirlify(), erre ügyeljünk!

Többszörös választási lehetőség

A mult_question többszörös válaszadási lehetőséget biztosít. Ráadásul kellően intelligens ahhoz, hogy a lehetőségeket összekeveri. (Ahhoz már sajnos nem, hogy elég legyen megadni a helyes választ egyszer.)

- Class: mult_question
  Output: Multiple choice question. What is the capital of Germany?
  AnswerChoices: Berlin;Bonn;Munich
  CorrectAnswer: Berlin
  AnswerTests: omnitest(correctVal='Berlin')
  Hint: The capital of Germany is Berlin.

Egész hosszú időt eltöltöttem egyébként itt, mire kiderült, hogy nem tudja kezelni az ékezetes karaktereket (München). Ráadásul nem ennél a kérdésnél írt ki hibát!

Diagram

Diagramot a figure típussal tudunk létrehozni:

- Class: figure
  Output: This is a figure.
  Figure: squareplot.R
  FigureType: new

Ehhez persze szükség van ugyanabban a könyvtárban egy megfelelő squareplot.R fájlra is, pl.:

plot(1:10, (1:10)^2)

Ezt szintén létrehozhatjuk az RStudio-ban: File → New File → R Script, majd lementve a megfelelő könyvtárban. Ezzel kapcsolatos kérdést nem tudunk feltenni közvetlenül, csak a következőben.

A FigureType a new mellett lehet additional is; ez esetben folytatja a már megkezdett ábrát.

További lehetőségeket ill. példákat találunk a http://swirlstats.com/swirlify/writing.html oldalon.

Publikálás

Az elkészített leckék publikálása könnyű nehézkes.

Első körben győződjünk meg arról, hogy a megfelelő kurzuson állunk. Így állíthatjuk be:

set_lesson("My_First_Course/Lesson_4/lesson.yaml")

Majd csomagoljuk be:

pack_course()

Ez valójában nem csak az adott leckét, hanem teljes kurzust becsomagolja, aminek az eredménye egy .swc kiterjesztésű fájl lesz.

A telepítéshez csak a swirl kell, a swirlify nem. A következőképpen tudjuk telepíteni (a fájlt a megfelelő könyvtárba másolva, pl. ~/R/swirl/):

install_course(swc_path = "My_First_Course.swc")

A swirl() parancs hatására ez indul el.

Ide feltöltöttem: https://github.com/faragocsaba/swirl. Indítás: install_course_github("faragocsaba", "swirl/My_First_Course".

A Swirl kurzusoknak ban egy saját központi gyűjtőhelye SCN (Swirl Course Network) néven (http://swirlstats.com/scn/). Onnan az install_course() paranccsal tudunk telepíteni, pl.:

install_course("Getting and Cleaning Data")

R Markdown

Áttekintés

A Markdown egy olyan jelölő nyelv, melyben egyszerű módon tudunk szöveget formázni. Tipikus kiterjesztése .md. A formázással kapcsolatos részleteket olvashatunk a Szövegszerkesztés oldalon. Emlékeztetőül egy egyszerű példa:

Szabad szöveg.

# Első fejezet

## Első alfejezet

Paragrafus szöveg.
Új sor. **Vastag**, *dőlt betűs*, <ins>aláhúzott</ins>, ~~áthúzott~~, `fix karakterszélességű` szöveg.

## Második alfejezet

Felsorolás:
* Első elem
* Második elem
* Harmadik elem

# Második fejezet

Táblázat:

| Név     | Darab |
|---------|-------|
| alma    | 5     |
| banán   | 3     |
| narancs | 6     |

A Markdown önmagában független az R-től. Az R Markdown ennek a jelölő nyelvnek a kiterjesztése oly módon, hogy tartalmazhat R programkódot, amit a rendszer kiértékel.

R Markdown készítése RStudio-ban

A következőképpen készíthetünk R Markdown fájlt RStudio-ban:

File → New File → R Markdown…

Itt adjunk neki valamilyen címet.

Megadhatjuk a dokumentum típusát. Ez lehet dokumentum (HTML, PDF (ehhez kell Latex), Word), prezentáció (kétféle HTML, PDF, PowerPoint), Shiny (dokumentum vagy prezentáció) vagy valamilyen sablon alapú. Itt válasszuk ki ezt:

Presentation → HTML (ioslides)

Itt két lehetőségünk van:

  • Ha az OK-ra kattintunk, akkor létrejön egy egész pofás dokumentum, amely tartalmaz 5 oldalt mindenféle példával.
  • Ha a Create Empty Document-re kattintunk, akkor értelemszerűen egy üres dokumentumot kapunk.

A kódot hamarosan megnézzük részletesebben; most csak próbáljuk ki. Ehhez kattintsunk fent középen erre:

Knit

Ha mindent jól csináltunk, akkor megjelenik egy ablak, melyben a nyilakkal tudunk navigálni az egyes diák között.

Ha más típusú eredményt szeretnénk akkor kattintsunk a Knit melletti lefele mutató nyílra, és válasszuk ki a megfelelő eredményt.

Dia beszúrása

A legtöbb Markdown formázást használhatjuk, ám mivel ez egy prezentáció, egy-két helyen máshogy kell írnunk.

  • Dia beszúrása a sor elején található két kettős kereszt jellel történik (##), amit a cím követ. Pl.
## Új dia

Tartalom.
  • Ebből az is következik, hogy a fejléc méretek "elcsúsznak": dián belül pl. a legnagyobb cím a három kettős kereszt (###) jelenti.
  • Ha cím nélkül szeretnénk beszúrni egy diát, akkor egy sorba három csillagot kell írnunk (***), pl.
***

Tartalom.

R parancsok kezelése

A generált példában a dokumentum elején van egy ilyen rész:

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```

Ezt egyelőre töröljük ki (ill. ha új dokumentumot hozunk létre, akkor ne írjuk bele); később visszatérünk ennek a jelentőségére.

R parancsokat a következő módon szúrhatunk be az R markdown dokumentumba.

```{r myplot}
plot(1:10, 1:10)
```

(A myplot) a diagram neve, melynek egyedinek kell lennie a dokumentumban.)

Ez esetben megjelenik a forrás és az eredmény is. Ha nem szeretnénk azt, hogy megjelenjen a parancs, akkor azt az echo=FALSE megadásával tudjuk megtenni:

```{r myplot, echo = FALSE}
plot(1:10, 1:10)
```

A fentihez hasonlóan, ha nem szeretnénk, hogy kiértékelődjön, akkor az eval=FALSE beállítást kell használnunk:

```{r myplot, eval = FALSE}
plot(1:10, 1:10)
```

És most térjünk vissza az elején kitörölt sorokra. Ha visszaírjuk, akkor azzal azt értjük el, hogy alapértelmezésben a parancs nem jelenik meg, az eredmény viszont igen. Ez esetben ha mégis csak a parancsot szeretnénk megjeleníteni, akkor azt a következőképpen tudjuk megtenni:

```{r myplot, eval = FALSE, echo=TRUE}
plot(1:10, 1:10)
```

Közzététel

Közzétenni az eredményt többféleképpen tudjuk.

Az egyik lehetőség a következő: a Knit parancs hatására keletkezik egy HTML oldal az Rmd fájl mellett; azt tetszőlegesen felhasználhatjuk. Ez egyébként egy binárisan kódolt JavaScript, szóval nem olvasható és nem is szép, de 100%-ban a böngészőben fut, és elvileg akármilyen webszerverre felt tudjuk tölteni.

A másik lehetőség az RPubs oldal, ahova ingyen feltölthetjük. Lépések:

  • Regisztráljunk az RPubs oldalon és lépjünk be.
  • A prezentációban kattintsunk a jobb felső sarokban a Publish gombra.
  • Válasszuk ki az RPub-ot.
  • Kattintsunk a Publish-ra.
  • Adjunk neki címet (Title, pl. My first R markdown project), egy elérést (Slug, pl. mytest) és opcionálisan egy leírást (Description), majd kattintunk a Continue gombra.
  • Megjelenik az eredményt; a böngészőnek az URL sávjában ki tudjuk másolni az URL-t.
  • Ugyanott törölni is tudjuk.

R Prezentáció

Áttekintés

Az R Prezentáció sokban hasonlít az R Markdown-hoz. Létrehozása RStudio-ban: File → New File → R Markdown…. (Megjegyzés: korábbi verziókban van R Presentation. Az éppen használtban nem találtam, de az R Markdown működött.) A fal felső sarokban megjelenik egy sablon, a jobb felsőben pedig az eredmény. Elindulni nem bonyolult; a sablon némiképp módosított változata pl. ez:

My First Presentation
========================================================
author: Csaba
date: 2021-04-05
autosize: true

First Slide
========================================================

This is a text.

- Bullet 1
- Bullet 2
- Bullet 3

Slide With Code
========================================================

```{r}
summary(cars)
```

Slide With Plot
========================================================

```{r, echo=FALSE, fig.width=20, fig.height=12}
plot(cars)
```
rpres-example.png

A jelölő nyelv szinte teljesen megegyezik az R Markdown-nal. A részletes ismertetése nem cél; konkrét problémával - bár ebben az esetben nem egyszerű - a net segíthet. Két funkciót viszont még érdemes megismerni:

  • A jobb felső sarokban a More melletti kis háromszögre kattintva View in Browser: megnyitja böngészőben. Ezt publikálás előtt mindenképpen érdemes megnézni, mert sajnos nem pont úgy néz ki böngészőben mint a gyors nézőben.
  • Publikálás: szintén a jobb felső sarokban, a More mellett van egy kék ikon, és az mellett is van egy kis háromszög; arra kattintva Publish Presentation. Az RPubs-ra tudjuk publikálni.

Feladat megoldása

Egy képzésben a feladat második része egy R prezentáció készítése volt, amely 5 oldalban részletezi a korábbi feladat eredményeit. Az én megoldássom a következő:

Used cars
========================================================
author: Csaba Farago
date: 2021.04.04.
autosize: false

Overview
========================================================

This is the assignment task for the Developing Data Products course. I collected 20 car data from the Hungarian web side about selling used cars, page <https://www.hasznaltauto.hu/>. The collected data are the following:
* Age (in months)
* Mileage (in thousand kms)
* Cylinder capacity (in thousand cm3, rounded up)

In the analysis I checked how the total mileage per age changed totally and also in various categories. I found that the higher the cylinder capacity is, the mileage per month increases.

The added cars are listed on the last slide (Appendix).

Diagram
========================================================

![plot of chunk unnamed-chunk-1](assignment-figure/unnamed-chunk-1-1.png)

Results
========================================================

Here are the results of the analysis:
* **Mileage per month of all cars**: 809 km / month, meaning that an average car runs about 10.000 km in a year
* **Considering cylinder capacity**: the higher the capacity is, it is most likely that the mileage per age increases
* **Mileage on cylinder capacity breakdown**
 * *Low category* (at most 1.0): 409 km / month
 * *Lower-mid category* (between 1.0 and 2.0): 1012 km / month
 * *Upper-mid category* (between 2.0 and 3.0): 1399 km / month
 * *Upper category* (higher than 3.0): 1783 km / month

Appendix
========================================================

* *Low category*: [Suzuki Splash](https://www.hasznaltauto.hu/szemelyauto/suzuki/splash/suzuki_splash_1_0_glx_cd_ac_ujszeru_mo-i_auto_vez_szerv_konyv_teli-nyari_kerek_ulesfutes-16898109), [BMW I3](https://www.hasznaltauto.hu/szemelyauto/bmw/i3/bmw_i3_rex_automata-16894273), [Fiat Uno](https://www.hasznaltauto.hu/szemelyauto/fiat/uno/fiat_uno_1_0_i_e_2_tulajdonos_111_750km_napi_hasznalatban-16874226)
* *Lower-mid category*: [Citroen C2](https://www.hasznaltauto.hu/szemelyauto/citroen/c2/citroen_c2_1_6_by_loeb_vts_hdi_ritkasag_20-tol_hitelre_is-16526608), [Kia Ceed](https://www.hasznaltauto.hu/szemelyauto/kia/ceed/kia_ceed_sw_2_0_crdi_tx_ritkasag_10_legzsak_20-tol_hitelre_is-16549170), [Honda Accord](https://www.hasznaltauto.hu/szemelyauto/honda/accord/honda_accord_tourer_2_0_elegance_automata_automata_20-tol_hitelre_is-16644937), [Honda Accord](https://www.hasznaltauto.hu/szemelyauto/honda/accord/honda_accord_tourer_2_0_elegance_20-tol_hitelre_is-16654142), [Opel Astra](https://www.hasznaltauto.hu/szemelyauto/opel/astra_h/opel_astra_h_tt_1_8_enjoy_hitelre_is_tulajdonostol_tokeletes_tetovel_2_garnitura_kerek_felbor-16779290), [Honda Civic](https://www.hasznaltauto.hu/szemelyauto/honda/civic/honda_civic_1_4_sport_bar_honda-16832550), [Open Cascada](https://www.hasznaltauto.hu/szemelyauto/opel/cascada/opel_cascada_1_6_t_cosmo_automata_euro6-16900947), [Skoda Octavia](https://www.hasznaltauto.hu/szemelyauto/skoda/octavia/skoda_octavia_combi_2_0_tdi_cr_rs_euro_6-16755012), [Ford Focus](https://www.hasznaltauto.hu/szemelyauto/ford/focus/ford_focus_1_6_ti-vct_trend_plus_st_line_magyarorszagi_99e_km_1_tulaj_vegig-16886209)
* *Upper-mid category*: [Volkswagen Crafter](https://www.hasznaltauto.hu/kishaszonjarmu/volkswagen/crafter/volkswagen_crafter_35_2_5_tdi_l3h2_kozep_hosszu_-_kozep_magas_4eu_raklapos-16786397), [Mazda Sport](https://www.hasznaltauto.hu/szemelyauto/mazda/6/mazda_6_sport_2_2_cd_revolution_top_automata_175_le_full_extra_magyarorszagi_tulajdonostol_makulatlan_szervizmult-16890653), [Mercedes Benz](https://www.hasznaltauto.hu/szemelyauto/mercedes-benz/e_220/mercedes-benz_e_220_t_cdi_avantgarde_automata-16900827), [BMW X6](https://www.hasznaltauto.hu/szemelyauto/bmw/x6/bmw_x6_xdrive30d_aut-16840463)
* *Upper category*: [Mercedes Benz](https://www.hasznaltauto.hu/szemelyauto/mercedes-benz/s_500/mercedes-benz_s_500_coupe_4m_9g-tronic-16680172), [Ford Mustang](https://www.hasznaltauto.hu/szemelyauto/ford/mustang/ford_mustang_fastback_5_0_ti-vct_v8_gt_automata-16045215), [BMW 7](https://www.hasznaltauto.hu/szemelyauto/bmw/7-es_sorozat/bmw_7-es_sorozat_7_activehybrid_automata-16832445), [Mercedes Benz](https://www.hasznaltauto.hu/szemelyauto/mercedes-benz/e_400/mercedes-benz_e_400_4matic_9g-tronic_m_o_i_vezetett_szervizkonyv-16896026)

Az eredmény itt található: https://rpubs.com/faragocsaba/usedcars.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License