├── gp2.png ├── gp3.png ├── covr.png ├── mango.png ├── oss1.jpg ├── oss2.jpg ├── wtfm.jpg ├── PIKnpbn.png ├── rcmdcheck.png ├── Makefile ├── datatables ├── ui.R └── server.R ├── 050-kmeans-example ├── DESCRIPTION ├── ui.R └── server.R ├── style.css ├── goodPractice1.svg ├── docs └── earl2016-gabor.md └── earl2016-gabor.Rmd /gp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/gp2.png -------------------------------------------------------------------------------- /gp3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/gp3.png -------------------------------------------------------------------------------- /covr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/covr.png -------------------------------------------------------------------------------- /mango.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/mango.png -------------------------------------------------------------------------------- /oss1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/oss1.jpg -------------------------------------------------------------------------------- /oss2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/oss2.jpg -------------------------------------------------------------------------------- /wtfm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/wtfm.jpg -------------------------------------------------------------------------------- /PIKnpbn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/PIKnpbn.png -------------------------------------------------------------------------------- /rcmdcheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/earl2016-gabor/master/rcmdcheck.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | RMD := $(shell ls *.Rmd) 3 | HTML := $(patsubst %.Rmd, %.html, $(RMD)) 4 | 5 | all: $(HTML) 6 | 7 | %.html: %.Rmd style.css 8 | R -e 'rmarkdown::render("$<", output_file = file.path("docs", "$@"))' 9 | -------------------------------------------------------------------------------- /datatables/ui.R: -------------------------------------------------------------------------------- 1 | shinyUI(pageWithSidebar( 2 | headerPanel('Data table example'), 3 | sidebarPanel( 4 | selectInput('dataset', 'Data set', c('iris', 'diamonds', 'mtcars')) 5 | ), 6 | mainPanel( 7 | dataTableOutput('table') 8 | ) 9 | )) 10 | -------------------------------------------------------------------------------- /050-kmeans-example/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Title: Kmeans example 2 | License: MIT 3 | Author: Joe Cheng 4 | AuthorUrl: http://www.rstudio.com/ 5 | Tags: getting-started kmeans plotoutput sliderinput numericinput reactivity 6 | DisplayMode: Showcase 7 | Type: Shiny 8 | -------------------------------------------------------------------------------- /datatables/server.R: -------------------------------------------------------------------------------- 1 | 2 | shinyServer(function(input, output, session) { 3 | 4 | output$table <- renderDataTable( 5 | { 6 | d <- input$dataset 7 | if (d == "iris") { 8 | iris 9 | } else if (d == "mtcars") { 10 | mtcars 11 | } else if (d == "diamonds") { 12 | ggplot2::diamonds 13 | } 14 | }, 15 | options = list(pageLength = 5) 16 | ) 17 | 18 | }) 19 | -------------------------------------------------------------------------------- /050-kmeans-example/ui.R: -------------------------------------------------------------------------------- 1 | shinyUI(pageWithSidebar( 2 | headerPanel('Iris k-means clustering'), 3 | sidebarPanel( 4 | selectInput('xcol', 'X Variable', names(iris)), 5 | selectInput('ycol', 'Y Variable', names(iris), 6 | selected=names(iris)[[2]]), 7 | numericInput('clusters', 'Cluster count', 3, 8 | min = 1, max = 9) 9 | ), 10 | mainPanel( 11 | plotOutput('plot1') 12 | ) 13 | )) 14 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | 2 | /* No underlines on title slide */ 3 | 4 | #1 a:link { 5 | text-decoration: none; 6 | } 7 | 8 | /* Outline page with bigger font */ 9 | 10 | #outline ol { 11 | font-size: 150%; 12 | } 13 | 14 | .slide:after { 15 | content: 'Gábor Csárdi - Principal Consultant\A gcsardi@mango-solutions.com'; 16 | white-space: pre; 17 | line-height: 1; 18 | text-align: right; 19 | color: #ddd; 20 | font-size: 16px; 21 | position: absolute; 22 | right: 20px; 23 | bottom: 30px; 24 | font-family: 'Arial'; 25 | } 26 | 27 | h2.shout { 28 | font-size: 36px; 29 | } 30 | -------------------------------------------------------------------------------- /050-kmeans-example/server.R: -------------------------------------------------------------------------------- 1 | palette(c("#E41A1C", "#377EB8", "#4DAF4A", "#984EA3", 2 | "#FF7F00", "#FFFF33", "#A65628", "#F781BF", "#999999")) 3 | 4 | shinyServer(function(input, output, session) { 5 | 6 | # Combine the selected variables into a new data frame 7 | selectedData <- reactive({ 8 | iris[, c(input$xcol, input$ycol)] 9 | }) 10 | 11 | clusters <- reactive({ 12 | kmeans(selectedData(), input$clusters) 13 | }) 14 | 15 | output$plot1 <- renderPlot({ 16 | par(mar = c(5.1, 4.1, 0.1, 1)) 17 | plot(selectedData(), 18 | col = clusters()$cluster, 19 | pch = 20, cex = 3) 20 | points(clusters()$centers, pch = 4, cex = 4, lwd = 4) 21 | }) 22 | 23 | }) 24 | -------------------------------------------------------------------------------- /goodPractice1.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 31 | 33 | 57 | 62 | 63 | 70 | 72 | 76 | 83 | 89 | 97 | 98 | 104 | 107 | 113 | 119 | 120 | 121 | good practice 132 | 133 | -------------------------------------------------------------------------------- /docs/earl2016-gabor.md: -------------------------------------------------------------------------------- 1 | # R Packages, Just as the Doctor Ordered 2 | Gábor Csárdi 3 | 4 | ## Outline { .nonum } 5 | 6 | 10 | 11 | 12 | 13 | 1. Open source @ Mango 14 | 1. Good practices for R packages 15 | 1. Sneak peek 1: R docs in Markdown 16 | 1. Sneak peek 2: surprise 17 | 18 | # github.com/ MangoTheCat 19 | 20 | ## Why R packages? 21 | 22 | * Reusable code? You want an R package! 23 | * Easiest way to distribute and install 24 | * R code 25 | * Documentation 26 | * Manuals 27 | * Data 28 | * Tests 29 | * Easiest way to specify and recreate environment: other R packages, 30 | system requirements, R version 31 | 32 | ## What could (should?) be an R package? 33 | 34 | * A statistical method 35 | * A utility function (or a collection of them) 36 | * A data analysis project 37 | * An ETL project 38 | * A shiny app 39 | * Every piece of R code that you want to run again. 40 | 41 | # We need to improve the tools 42 | 43 | ## { .fullpage } 44 | 45 | 46 | 47 | # Existing
Tools 48 | 49 | # `R CMD check` { style="font-size: 70%" } 50 | 51 | ## { } 52 | 53 | 54 | # `jimhester/covr` { style="font-size: 70%" } 55 | 56 | ## { } 57 | 58 | 59 | # `jimhester/lintr` { style="font-size: 70%" } 60 | 61 | ## { .fullpage } 62 | 63 | 64 | # `goodpractice` { style="font-size: 70%" } 65 | 66 | ## `goodpractice` features 67 | 68 |
69 |

70 | 71 |    72 | Package building advice 73 | 74 |    75 | Test coverage (`covr`) 76 | 77 |    78 | Code style linting (`lintr`) 79 | 80 |    81 | Code complexity 82 | 83 |

84 | 85 |    86 | Anti-patterns, anti-functions 87 | 88 |    89 | Documentation quality (soon) 90 | 91 |    92 | Custom rule sets 93 | 94 |    95 | Use on a CI 96 | 97 |

98 |
99 | 100 | ## { } 101 | 102 | 103 | ## { } 104 | 105 | 106 | # `xmlparsedata` { style="font-size: 70%" } 107 | 108 | ## Linting: labeled subgraph isomorphisms 109 | 110 | Example: search for `1:nrow()` 111 | 112 | ``` 113 | 114 | +-- 115 | +-- NUM_CONST: 1 116 | +-- ':' 117 | +-- 118 | +-- 119 | +-- SYMBOL_FUNCTION_CALL nrow 120 | +-- '(' 121 | +-- 122 | +-- ')' 123 | ``` 124 | 125 | ## Easy with `XPath` 126 | 127 | Example: search for `1:nrow()` 128 | 129 | ``` 130 | //expr 131 | [expr[NUM_CONST[text()='1']]] 132 | [OP-COLON] 133 | [expr[expr[SYMBOL_FUNCTION_CALL[text()='nrow']]]] 134 | ``` 135 | 136 | Just convert the R parse tree to XML with `xmlparsedata`. 137 | 138 | # R docs in Markdown 139 | 140 | ## w/o `roxygen2` 141 | 142 | ``` 143 | \name{make_style} 144 | \alias{make_style} 145 | \title{Create an ANSI color style} 146 | \usage{ 147 | make_style(..., bg = FALSE, grey = FALSE, colors = num_colors()) 148 | } 149 | \usage{ 150 | \arguments{ 151 | \item{\dots}{\itemize{ 152 | \item An R color name, see \code{\link{colors}}. 153 | \item A 6- or 8-digit hexa color string, e.g. \code{#ff0000} means 154 | red. Transparency (alpha channel) values are ignored. 155 | \item A one-column matrix with three rows for the red, green 156 | and blue channels, as returned by 157 | \code{\link[grDevices]{col2rgb}}. 158 | }} 159 | ... 160 | } 161 | ``` 162 | 163 | ## w/ `roxygen2` 164 | 165 | ```r 166 | #' Create an ANSI color style 167 | #' 168 | #' @param ... Anything of the following:\itemize{ 169 | #' \item An R color name, see \code{\link{colors}}. 170 | #' \item A 6- or 8-digit hexa color string, e.g. \code{#ff0000} means 171 | #' red. Transparency (alpha channel) values are ignored. 172 | #' \item A one-column matrix with three rows for the red, green 173 | #' and blue channels, as returned by \code{\link[grDevices]{col2rgb}}. 174 | #' } 175 | 176 | make_style <- function(..., bg = FALSE, grey = FALSE, 177 | colors = num_colors()) { 178 | ... 179 | ``` 180 | 181 | ## w/ `roxygen2` 6.0.0 (soon) 182 | 183 | ```r 184 | #' Create an ANSI color style 185 | #' 186 | #' @param Anything of the following: 187 | #' * An R color name, see [colors]. 188 | #' * A 6- or 8-digit hexa color string, e.g. `#ff0000` means 189 | #' red. Transparency (alpha channel) values are ignored. 190 | #' * A one-column matrix with three rows for the red, green 191 | #' and blue channels, as returned by [grDevices::col2rgb]. 192 | 193 | make_style <- function(..., bg = FALSE, grey = FALSE, 194 | colors = num_colors()) { 195 | ... 196 | ``` 197 | 198 | # Like Shiny apps? 199 | 200 | ## { } 201 | 202 |
203 | 206 |
207 | 208 | ## { } 209 | 210 |
211 | 214 |
215 | 216 | # How do you test this app? 217 | 218 | ## The `shinytest` package (WIP) 219 | 220 | ```r 221 | library(shinytest) 222 | 223 | test_that("the kmeans app updates the plot", { 224 | app <- shinyapp$new("050-kmeans-example") 225 | 226 | expect_equal(app$get_value("xcol"), "Sepal.Length") 227 | expect_equal(app$get_value("ycol"), "Sepal.Width") 228 | expect_equal(app$get_value("clusters"), 3) 229 | 230 | expect_update(app, xcol = "Sepal.Width", output = "plot1") 231 | expect_update(app, ycol = "Petal.Width", output = "plot1") 232 | expect_update(app, clusters = 4, output = "plot1") 233 | }) 234 | ``` 235 | 236 | ## { } 237 | 238 |
239 | 242 |
243 | 244 | ## The `shinytest` package 245 | 246 | ```r 247 | library(shinytest) 248 | 249 | test_that("table is rendered and updated", { 250 | app <- shinyapp$new("myapp") 251 | expect_update(app, dataset = "iris", output = "table") 252 | expect_equal( 253 | nrow(app$get_value("table")), 254 | 5 255 | ) 256 | }) 257 | 258 | ``` 259 | 260 | # github.com/ MangoTheCat 261 | -------------------------------------------------------------------------------- /earl2016-gabor.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "R Packages, Just as the Doctor Ordered" 3 | author: "Gábor Csárdi" 4 | maketitle: true 5 | output: 6 | rmdshower::shower_presentation: 7 | self_contained: true 8 | theme: earl2016 9 | keep_md: true 10 | css: style.css 11 | ratio: 4x3 12 | --- 13 | 14 | ## Outline { .nonum } 15 | 16 | 20 | 21 | 22 | 23 | 1. Open source @ Mango 24 | 1. Good practices for R packages 25 | 1. Sneak peek 1: R docs in Markdown 26 | 1. Sneak peek 2: surprise 27 | 28 | # github.com/ MangoTheCat 29 | 30 | ## Why R packages? 31 | 32 | * Reusable code? You want an R package! 33 | * Easiest way to distribute and install 34 | * R code 35 | * Documentation 36 | * Manuals 37 | * Data 38 | * Tests 39 | * Easiest way to specify and recreate environment: other R packages, 40 | system requirements, R version 41 | 42 | ## What could (should?) be an R package? 43 | 44 | * A statistical method 45 | * A utility function (or a collection of them) 46 | * A data analysis project 47 | * An ETL project 48 | * A shiny app 49 | * Every piece of R code that you want to run again. 50 | 51 | # We need to improve the tools 52 | 53 | ## { .fullpage } 54 | 55 | 56 | 57 | # Existing
Tools 58 | 59 | # `R CMD check` { style="font-size: 70%" } 60 | 61 | ## { } 62 | 63 | 64 | # `jimhester/covr` { style="font-size: 70%" } 65 | 66 | ## { } 67 | 68 | 69 | # `jimhester/lintr` { style="font-size: 70%" } 70 | 71 | ## { .fullpage } 72 | 73 | 74 | # `goodpractice` { style="font-size: 70%" } 75 | 76 | ## `goodpractice` features 77 | 78 |
79 |

80 | 81 |    82 | Package building advice 83 | 84 |    85 | Test coverage (`covr`) 86 | 87 |    88 | Code style linting (`lintr`) 89 | 90 |    91 | Code complexity 92 | 93 |

94 | 95 |    96 | Anti-patterns, anti-functions 97 | 98 |    99 | Documentation quality (soon) 100 | 101 |    102 | Custom rule sets 103 | 104 |    105 | Use on a CI 106 | 107 |

108 |
109 | 110 | ## { } 111 | 112 | 113 | ## { } 114 | 115 | 116 | # `xmlparsedata` { style="font-size: 70%" } 117 | 118 | ## Linting: labeled subgraph isomorphisms 119 | 120 | Example: search for `1:nrow()` 121 | 122 | ``` 123 | 124 | +-- 125 | +-- NUM_CONST: 1 126 | +-- ':' 127 | +-- 128 | +-- 129 | +-- SYMBOL_FUNCTION_CALL nrow 130 | +-- '(' 131 | +-- 132 | +-- ')' 133 | ``` 134 | 135 | ## Easy with `XPath` 136 | 137 | Example: search for `1:nrow()` 138 | 139 | ``` 140 | //expr 141 | [expr[NUM_CONST[text()='1']]] 142 | [OP-COLON] 143 | [expr[expr[SYMBOL_FUNCTION_CALL[text()='nrow']]]] 144 | ``` 145 | 146 | Just convert the R parse tree to XML with `xmlparsedata`. 147 | 148 | # R docs in Markdown 149 | 150 | ## w/o `roxygen2` 151 | 152 | ``` 153 | \name{make_style} 154 | \alias{make_style} 155 | \title{Create an ANSI color style} 156 | \usage{ 157 | make_style(..., bg = FALSE, grey = FALSE, colors = num_colors()) 158 | } 159 | \usage{ 160 | \arguments{ 161 | \item{\dots}{\itemize{ 162 | \item An R color name, see \code{\link{colors}}. 163 | \item A 6- or 8-digit hexa color string, e.g. \code{#ff0000} means 164 | red. Transparency (alpha channel) values are ignored. 165 | \item A one-column matrix with three rows for the red, green 166 | and blue channels, as returned by 167 | \code{\link[grDevices]{col2rgb}}. 168 | }} 169 | ... 170 | } 171 | ``` 172 | 173 | ## w/ `roxygen2` 174 | 175 | ```r 176 | #' Create an ANSI color style 177 | #' 178 | #' @param ... Anything of the following:\itemize{ 179 | #' \item An R color name, see \code{\link{colors}}. 180 | #' \item A 6- or 8-digit hexa color string, e.g. \code{#ff0000} means 181 | #' red. Transparency (alpha channel) values are ignored. 182 | #' \item A one-column matrix with three rows for the red, green 183 | #' and blue channels, as returned by \code{\link[grDevices]{col2rgb}}. 184 | #' } 185 | 186 | make_style <- function(..., bg = FALSE, grey = FALSE, 187 | colors = num_colors()) { 188 | ... 189 | ``` 190 | 191 | ## w/ `roxygen2` 6.0.0 (soon) 192 | 193 | ```r 194 | #' Create an ANSI color style 195 | #' 196 | #' @param Anything of the following: 197 | #' * An R color name, see [colors]. 198 | #' * A 6- or 8-digit hexa color string, e.g. `#ff0000` means 199 | #' red. Transparency (alpha channel) values are ignored. 200 | #' * A one-column matrix with three rows for the red, green 201 | #' and blue channels, as returned by [grDevices::col2rgb]. 202 | 203 | make_style <- function(..., bg = FALSE, grey = FALSE, 204 | colors = num_colors()) { 205 | ... 206 | ``` 207 | 208 | # Like Shiny apps? 209 | 210 | ## { } 211 | 212 |
213 | 216 |
217 | 218 | ## { } 219 | 220 |
221 | 224 |
225 | 226 | # How do you test this app? 227 | 228 | ## The `shinytest` package (WIP) 229 | 230 | ```r 231 | library(shinytest) 232 | 233 | test_that("the kmeans app updates the plot", { 234 | app <- shinyapp$new("050-kmeans-example") 235 | 236 | expect_equal(app$get_value("xcol"), "Sepal.Length") 237 | expect_equal(app$get_value("ycol"), "Sepal.Width") 238 | expect_equal(app$get_value("clusters"), 3) 239 | 240 | expect_update(app, xcol = "Sepal.Width", output = "plot1") 241 | expect_update(app, ycol = "Petal.Width", output = "plot1") 242 | expect_update(app, clusters = 4, output = "plot1") 243 | }) 244 | ``` 245 | 246 | ## { } 247 | 248 |
249 | 252 |
253 | 254 | ## The `shinytest` package 255 | 256 | ```r 257 | library(shinytest) 258 | 259 | test_that("table is rendered and updated", { 260 | app <- shinyapp$new("myapp") 261 | expect_update(app, dataset = "iris", output = "table") 262 | expect_equal( 263 | nrow(app$get_value("table")), 264 | 5 265 | ) 266 | }) 267 | 268 | ``` 269 | 270 | # github.com/ MangoTheCat 271 | --------------------------------------------------------------------------------