├── LICENSE ├── .gitignore ├── tests ├── testthat.R └── testthat │ └── test-package.R ├── img ├── open-data-bingo.png ├── bingo-01-open-data.png └── bingo-01-superbowl-50-2016.png ├── NAMESPACE ├── .travis.yml ├── .Rbuildignore ├── codecov.yml ├── man ├── launch.Rd ├── get_topics.Rd ├── get_topic.Rd ├── bingo.Rd └── plot.bingo.Rd ├── R ├── Colors.R ├── launch.R ├── utils.R ├── Eurovision_bingo.R ├── topics.R └── bingo.R ├── bingo.Rproj ├── inst ├── topics │ ├── MN_backyardLife.R │ ├── Random_Bike_Topics.R │ ├── IndianaGeology.R │ ├── july4th.R │ ├── Bingo_Flowers.R │ ├── game-of-thrones.R │ ├── iowa.R │ ├── dorm-room.R │ ├── WeeklyJump.R │ ├── math-proofs.R │ ├── boring-meeting.R │ ├── csama.R │ ├── open-data.R │ ├── news-nerd.R │ ├── conference-call.R │ ├── manuscript-review.R │ ├── stat-ecology.R │ ├── bad-data.R │ ├── useR-conf.R │ ├── olympic-sports.R │ └── football.R └── shiny │ ├── www │ └── app.css │ ├── global.R │ ├── server.R │ └── ui.R ├── DESCRIPTION ├── CONTRIBUTING.md ├── appveyor.yml ├── README.Rmd └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2016 2 | COPYRIGHT HOLDER: Jennifer Bryan 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | bingo-*.pdf 5 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(bingo) 3 | 4 | test_check("bingo") 5 | -------------------------------------------------------------------------------- /img/open-data-bingo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jennybc/bingo/HEAD/img/open-data-bingo.png -------------------------------------------------------------------------------- /img/bingo-01-open-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jennybc/bingo/HEAD/img/bingo-01-open-data.png -------------------------------------------------------------------------------- /img/bingo-01-superbowl-50-2016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jennybc/bingo/HEAD/img/bingo-01-superbowl-50-2016.png -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(plot,bingo) 4 | export(bingo) 5 | export(get_topic) 6 | export(get_topics) 7 | export(launch) 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | cache: packages 5 | 6 | after_success: 7 | - Rscript -e 'covr::codecov()' 8 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^\.travis\.yml$ 2 | ^.*\.Rproj$ 3 | ^\.Rproj\.user$ 4 | ^README\.Rmd$ 5 | ^README-.*\.png$ 6 | ^bingo-.*\.pdf$ 7 | ^img$ 8 | ^CONTRIBUTING\.md$ 9 | ^codecov\.yml$ 10 | ^appveyor\.yml$ 11 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | patch: 10 | default: 11 | target: auto 12 | threshold: 1% 13 | -------------------------------------------------------------------------------- /man/launch.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/launch.R 3 | \name{launch} 4 | \alias{launch} 5 | \title{Launch the Shiny app that generates bingo cards} 6 | \usage{ 7 | launch() 8 | } 9 | \description{ 10 | Launch the Shiny app that generates bingo cards 11 | } 12 | -------------------------------------------------------------------------------- /R/Colors.R: -------------------------------------------------------------------------------- 1 | c("pink", 2 | "purple", 3 | "blue", 4 | "green", 5 | "orange", 6 | "yellow", 7 | "chartreuse", 8 | "turquoise", 9 | "brown", 10 | "black", 11 | "white", 12 | "peach", 13 | "lilac", 14 | "gray", 15 | "periwinkle", 16 | "beige", 17 | "silver", 18 | "gold", 19 | "bronze", 20 | "charcoal", 21 | "burgundy", 22 | "olive", 23 | "lime", 24 | "lemon") 25 | -------------------------------------------------------------------------------- /man/get_topics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/topics.R 3 | \name{get_topics} 4 | \alias{get_topics} 5 | \title{Get all bingo card topics} 6 | \usage{ 7 | get_topics() 8 | } 9 | \value{ 10 | A character vector containing the names of all the bingo card topics 11 | } 12 | \description{ 13 | Get all bingo card topics 14 | } 15 | \examples{ 16 | get_topics() 17 | } 18 | -------------------------------------------------------------------------------- /bingo.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /man/get_topic.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/topics.R 3 | \name{get_topic} 4 | \alias{get_topic} 5 | \title{Get the words of a bingo card topic} 6 | \usage{ 7 | get_topic(topic) 8 | } 9 | \arguments{ 10 | \item{topic}{Name of a topic (a string)} 11 | } 12 | \value{ 13 | A character vector containing all the possible words of a bingo card 14 | topic 15 | } 16 | \description{ 17 | Get the words of a bingo card topic 18 | } 19 | \examples{ 20 | get_topic("open-data") 21 | } 22 | -------------------------------------------------------------------------------- /inst/topics/MN_backyardLife.R: -------------------------------------------------------------------------------- 1 | ## Aim : bingo card proposal for animals 2 | ## Author : Larissa Stanberry 3 | c('cat', 4 | 'dog', 5 | 'snapping turtle', 6 | 'painted turtle', 7 | 'muskrat', 8 | 'mallard duck', 9 | 'chipmunk', 10 | 'squirrel', 11 | 'deer', 12 | 'cardinal', 13 | 'red-winged blackbird', 14 | 'blue jay', 15 | 'swan', 16 | 'deer', 17 | 'monarch butterfly', 18 | 'snake', 19 | 'bee', 20 | 'loon', 21 | 'owl', 22 | 'woodpecker', 23 | 'wasp yellow jacket', 24 | 'northern cardinal', 25 | 'eagle', 26 | 'hawk') 27 | -------------------------------------------------------------------------------- /man/bingo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bingo.R 3 | \name{bingo} 4 | \alias{bingo} 5 | \title{Generate bingo cards} 6 | \usage{ 7 | bingo(n_cards = 1, words, n = 5) 8 | } 9 | \arguments{ 10 | \item{n_cards}{number of cards} 11 | 12 | \item{words}{text for the bingo squares} 13 | 14 | \item{n}{number of rows/columns for one card} 15 | } 16 | \value{ 17 | a \code{bingo} object, which is really just a character matrix 18 | } 19 | \description{ 20 | Generate bingo cards 21 | } 22 | \examples{ 23 | bingo() 24 | } 25 | -------------------------------------------------------------------------------- /tests/testthat/test-package.R: -------------------------------------------------------------------------------- 1 | context("bingo") 2 | 3 | test_that("duplicate squares are removed", { 4 | x <- c("a", "a", "b") 5 | expect_identical(c("a", "b"), vet_squares(x)) 6 | }) 7 | 8 | 9 | test_that("each topic contains at least 24 unique values", { 10 | expect_topic_length <- function(topic) { 11 | nt <- length(get_topic(topic)) 12 | expect( 13 | nt >= 24, 14 | sprintf("'%s' has length %i", topic, nt) 15 | ) 16 | invisible(topic) 17 | } 18 | 19 | topics <- get_topics() 20 | for (t in topics) expect_topic_length(t) 21 | }) 22 | -------------------------------------------------------------------------------- /inst/topics/Random_Bike_Topics.R: -------------------------------------------------------------------------------- 1 | ## Aim : bingo card proposal for bike thoughts 2 | ## Author : Darvish Shadravan 3 | 4 | c( 5 | "Jersey", 6 | "Tires", 7 | "Water Bottle", 8 | "Energy Drink", 9 | "Carbon Frame", 10 | "Mountain Bike", 11 | "Gravel Bike", 12 | "Snow Tires", 13 | "Grips", 14 | "Lycra Shorts", 15 | "Gloves", 16 | "Helmet", 17 | "Race Day", 18 | "Pedals", 19 | "Chain Lube", 20 | "Wind Vest", 21 | "Sunburn", 22 | "Tubeless", 23 | "Beer", 24 | "Pizza", 25 | "Bonk", 26 | "Studded Tires", 27 | "GPS", 28 | "100 miles" 29 | ) 30 | -------------------------------------------------------------------------------- /inst/topics/IndianaGeology.R: -------------------------------------------------------------------------------- 1 | # Indiana Geology themed bingo 2 | c("normal fault", 3 | "crystal lattice", 4 | "beer", 5 | "fold-thrust fault", 6 | "generic carbonate", 7 | "exposure", 8 | "brachiopod", 9 | "trilobite", 10 | "marine facies", 11 | "geode", 12 | "pyrite", 13 | "anticline", 14 | "syncline", 15 | "shale", 16 | "coal seam", 17 | "horn coral", 18 | "bryozoan", 19 | "karst", 20 | "till", 21 | "glacial outwash", 22 | "quaternary sediment", 23 | "quartz vug", 24 | "calcite vug", 25 | "stromatolite", 26 | "cars honking at roadcut" 27 | ) 28 | -------------------------------------------------------------------------------- /inst/topics/july4th.R: -------------------------------------------------------------------------------- 1 | ## Aim : bingo card proposal for July 4th 2 | ## Author : Gabrielle Weinrott 3 | 4 | c( 5 | "Barbecue", 6 | "Neighborhood", 7 | "America", 8 | "Declaration of Independence", 9 | "Fireworks", 10 | "Parade", 11 | "Red, white and blue", 12 | "Sunburn", 13 | "USA", 14 | "Water balloons", 15 | "Swimming", 16 | "Nation", 17 | "July 4th", 18 | "Day off", 19 | "crackle", 20 | "Banners", 21 | "Anthem", 22 | "Camping", 23 | "Stars", 24 | "Stripes", 25 | "Liberty", 26 | "Flag", 27 | "Patriot", 28 | "Summer", 29 | "County fairground", 30 | "Lemonade" 31 | ) 32 | -------------------------------------------------------------------------------- /R/launch.R: -------------------------------------------------------------------------------- 1 | #' Launch the Shiny app that generates bingo cards 2 | #' @export 3 | launch <- function() { 4 | if (!requireNamespace("shiny", quietly = TRUE)) { 5 | stop("Install 'shiny' via 'install.packages(\"shiny\")' to run this function.", 6 | call. = FALSE) 7 | } 8 | if (!requireNamespace("shinyjs", quietly = TRUE)) { 9 | stop("Install 'shinyjs' via 'install.packages(\"shinyjs\")' to run this function.", 10 | call. = FALSE) 11 | } 12 | shiny::runApp(system.file("shiny", package = "bingo"), 13 | display.mode = "normal", 14 | launch.browser = TRUE) 15 | } 16 | -------------------------------------------------------------------------------- /inst/topics/Bingo_Flowers.R: -------------------------------------------------------------------------------- 1 | ## Aim : bingo card proposal for flowers 2 | ## Author : Brittany Lopez Barreto 3 | c( 4 | "Lily", 5 | "Rose", 6 | "Carnation", 7 | "Baby's Breath", 8 | "Orchid", 9 | "Marigold", 10 | "Sunflower", 11 | "Hydrangea", 12 | "Tulip", 13 | "Peony", 14 | "Daisy", 15 | "Alstromeria", 16 | "Lavender", 17 | "Hibiscus", 18 | "Birds of Paradise", 19 | "Moonflower", 20 | "Pansy", 21 | "Hyacinth", 22 | "Petunia", 23 | "Poppy", 24 | "Snapdragon", 25 | "Violet", 26 | "Cosmos", 27 | "Calendula", 28 | "Azalea", 29 | "Begonia" 30 | ) 31 | -------------------------------------------------------------------------------- /inst/topics/game-of-thrones.R: -------------------------------------------------------------------------------- 1 | # creating Game of Thrones theme of events 2 | 3 | c( 4 | "Winter is Coming", 5 | "Cersei smirks as she talks", 6 | "Arya assassinates", 7 | "Dire Wolf", 8 | "The Hound vs. Clegane", 9 | "M' Lady", 10 | "Tyrion drinks wine", 11 | "Ravens", 12 | "Nightwatch", 13 | "Dragon(s) burn army", 14 | "Ice Dragon", 15 | "Needle", 16 | "Melisandre sees the Lord of Light", 17 | "Kingslayer", 18 | "Soldier(s) freezes", 19 | "Wights", 20 | "Free Folk", 21 | "Night King", 22 | "Wildlings", 23 | "The Wall", 24 | "King of the North", 25 | "Unsully", 26 | "Theon Greyjoy has PTSD attack", 27 | "Dragons fight each other" 28 | ) 29 | -------------------------------------------------------------------------------- /inst/topics/iowa.R: -------------------------------------------------------------------------------- 1 | # Iowa related things 2 | c("corn", 3 | "grinnell", 4 | "raygun", 5 | "I-80", 6 | "state fair", 7 | "Traveler's umbrella", 8 | "American Gothic", 9 | "Is this heaven?", 10 | "Zombie Burger", 11 | "Local foods", 12 | "Schnitzelbank", 13 | "RAGBRAI", 14 | "Jordan Creek Mall", 15 | "Hy-Vee", 16 | "Hawkeyes", 17 | "Cyclones", 18 | "Go West", 19 | "Clear Lake", 20 | "75% vowels, 100% Awesome", 21 | "Idiots out...", 22 | "John Deere", 23 | "John Wayne", 24 | "Hawkeye vodka", 25 | "Toppling Goliath", 26 | "Dari Barn", 27 | "Dairy Zone", 28 | "Surf Ballroom", 29 | "Saint's Rest", 30 | "The Musicman", 31 | "Iowa's best burger" 32 | ) 33 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: bingo 2 | Title: Generate Bingo Cards 3 | Version: 0.0.0.9007 4 | Authors@R: c( 5 | person("Jennifer", "Bryan", , "jenny@stat.ubc.ca", c("cre", "aut")), 6 | person("Dean", "Attali", , "daattali@gmail.com", "aut") 7 | ) 8 | Description: Generate bingo cards for fun and profit. Comes with built-in 9 | bingo squares for SuperBowl 50 and 'open' data / spreadsheet hell. You 10 | can also provide your own squares. Comes with a Shiny app. 11 | License: MIT + file LICENSE 12 | Depends: 13 | R (>= 3.2.1) 14 | Imports: 15 | grDevices, 16 | grid, 17 | utils 18 | Suggests: 19 | covr, 20 | shiny, 21 | shinyjs, 22 | testthat 23 | Encoding: UTF-8 24 | LazyData: true 25 | RoxygenNote: 6.1.1 26 | -------------------------------------------------------------------------------- /inst/topics/dorm-room.R: -------------------------------------------------------------------------------- 1 | ## inspired by https://staff.tumblr.com/post/150094456055/dorm-room-bingo 2 | # issue 58 3 | 4 | c("chat noir poster", 5 | "mint edition infinite jest", 6 | "dvds", 7 | "terrible hamper", 8 | "plug-in air freshener", 9 | "doomed printer", 10 | "fear & loathing poster", 11 | "christmas lights (the bad kind)", 12 | "soil", 13 | "framed quote", 14 | "klimt", 15 | "decorative wall initial", 16 | "this basket", 17 | "christmas lights (the cute kind)", 18 | "vornado", 19 | "awful lamp", 20 | "eternal sunshine poster", 21 | "bag", 22 | "dusty old tea", 23 | "power strip", 24 | "t-shirt from a bank", 25 | "well-meaning bottle", 26 | "lotion", 27 | "plastic hangers", 28 | "headphones") 29 | -------------------------------------------------------------------------------- /inst/topics/WeeklyJump.R: -------------------------------------------------------------------------------- 1 | # Japanese Mange in Weekly Syonen Jump 2 | # Authors (Toshiyuki Bandai): 3 | 4 | c( 5 | "Black Clover", 6 | "My Hero Academia", 7 | "Haikyu!!", 8 | "Food Wars!: Shokugeki no Soma", 9 | "Dr. Stone", 10 | "One Piece", 11 | "Dragon Ball", 12 | "Hikaru no Go", 13 | "Bleach", 14 | "Yu-Gi-Oh!", 15 | "Buso Renkin", 16 | "Assassination Classroom", 17 | "Death Note", 18 | "Rurouni Kenshin", 19 | "Psyren", 20 | "Nisekoi", 21 | "D.Grey-man", 22 | "Kuroko's Basketball", 23 | "The Prince of Tennis", 24 | "Toriko", 25 | "Dr. Slump", 26 | "Black Cat", 27 | "Bakuman", 28 | "Naruto", 29 | "Rokudenashi Blues", 30 | "Yu Yu Hakusho", 31 | "Hunter x Hunter", 32 | "Fist of the North Star", 33 | "Captain Tsubasa", 34 | "JoJo's Bizarre Adventure", 35 | "Slam Dunk" 36 | ) 37 | -------------------------------------------------------------------------------- /inst/topics/math-proofs.R: -------------------------------------------------------------------------------- 1 | # Common phrases and notation (good or bad) in math proofs 2 | # Submitted by Stephanie Reinders 3 | c("Let ... ", 4 | "Let epsilon be given", 5 | "Greek letters", 6 | "For each", 7 | "For all", 8 | "There exists", 9 | "Clearly", 10 | "Obviously", 11 | "Therefore", 12 | "Moreover", 13 | "Hence", 14 | "Thus", 15 | "So", 16 | "QED", 17 | "w.l.o.g.", 18 | "w.r.t.", 19 | "proof without words", 20 | "variables with subscripts", 21 | "variables with subscripts with subscripts", 22 | "variables with subscripts, superscripts, and hats", 23 | "e used as a variable", 24 | "necessary and sufficient", 25 | "Theorem", 26 | "Corollary", 27 | "by definition", 28 | "proof by induction", 29 | "proof by contrapositive", 30 | "proof by contradiction" 31 | ) 32 | -------------------------------------------------------------------------------- /inst/topics/boring-meeting.R: -------------------------------------------------------------------------------- 1 | # "Boring meeting" work bank - from http://bingo.saksena.net/bingo 2 | 3 | c( 4 | "low-risk", 5 | "client", 6 | "best practice", 7 | "initiative", 8 | "vision", 9 | "task force", 10 | "alternative", 11 | "market", 12 | "schedule", 13 | "milestone", 14 | "performance", 15 | "brainstorm", 16 | "scalable", 17 | "synergy", 18 | "action item", 19 | "passdown", 20 | "back-end", 21 | "braindump", 22 | "cross-platform", 23 | "customer", 24 | "deliver", 25 | "eyeballs", 26 | "revenue", 27 | "money", 28 | "incentive", 29 | "leverage", 30 | "value-add", 31 | "PUMA (please use more acronyms)", 32 | "committee", 33 | "mute the call", 34 | "forgot to mute the call", 35 | "at the table", 36 | "guru", 37 | "unicorn", 38 | "transformative" 39 | ) 40 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | We happily accept contributions to our collection of bingo cards! If you'd like to add a card, simply submit a [pull request](https://help.github.com/articles/using-pull-requests) following these guidelines: 2 | - Create an R file under the [`inst/topics/`](./inst/topics/) directory 3 | - The name of the R file will be used as the name of the topic of bingo cards 4 | - The file should return a character vector containing the words or phrases to put in the squares 5 | - There should be at least 24 squares, in order to make 5 x 5 bingo cards 6 | - Optional: at the top of the file, add your name and a short description of the card as a comment 7 | - You can look at the [existing examples](./inst/topics/) 8 | 9 | We'll try to be as responsive as possible in reviewing and accepting pull requests. We appreciate your contributions! 10 | -------------------------------------------------------------------------------- /inst/topics/csama.R: -------------------------------------------------------------------------------- 1 | # Things you expect to encounter in CSAMA course 2 | # http://www.huber.embl.de/csama2016/ 3 | # Contributed by CSAMA 2016 students after successful Git/GitHub lab :) 4 | # Authors (GitHub handles): 5 | # nkurzawa, KaBach 6 | c( 7 | "edgeR vs. DEseq2", 8 | "Hadley Wickham", 9 | "Portugal vs. France", 10 | "Hypothesis Testing", 11 | "Mountainbiking", 12 | "Twitter", 13 | "RStudio", 14 | "Julia", 15 | "Bioconductor", 16 | "Differential Expression", 17 | "GitHub", 18 | "data.frame", 19 | "git vs. svn", 20 | "data_frame", 21 | "tibble", 22 | "dplyr", 23 | "pirates vs. ninjas", 24 | "vignette", 25 | "vino", 26 | "espresso", 27 | "Pizza", 28 | "sun burn", 29 | "sun creme", 30 | "Jenny Bryan", 31 | "commit", 32 | "push", 33 | "pull", 34 | "add", 35 | "stage", 36 | "I haven't installed all necessary packages", 37 | "charging device" 38 | ) 39 | -------------------------------------------------------------------------------- /man/plot.bingo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bingo.R 3 | \name{plot.bingo} 4 | \alias{plot.bingo} 5 | \title{Plot bingo cards} 6 | \usage{ 7 | \method{plot}{bingo}(x, dir = ".", fontsize = 14, 8 | pdf_base = "bingo-", ...) 9 | } 10 | \arguments{ 11 | \item{x}{a \code{\link{bingo}} object containing one or more bingo cards} 12 | 13 | \item{dir}{directory where you want to write files} 14 | 15 | \item{fontsize}{size of bingo square font} 16 | 17 | \item{pdf_base}{base of the sequential filenames for the printable bingo card 18 | files} 19 | 20 | \item{...}{not used} 21 | } 22 | \value{ 23 | Vector containing the filenames of all the generated cards 24 | (invisibly) 25 | } 26 | \description{ 27 | Plot bingo cards 28 | } 29 | \note{ 30 | Does not actually plot the cards to the graphics device 31 | } 32 | \examples{ 33 | bc <- bingo() 34 | plot(bc) 35 | } 36 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | vet_squares <- function(words) { 2 | if (!inherits(words, "character")) words <- as.character(words) 3 | words <- unique(words) 4 | words 5 | } 6 | 7 | wrap_one <- function(x, w = 13) { 8 | stopifnot(length(x) == 1L) 9 | paste(strwrap(x, width = w), collapse = "\n") 10 | } 11 | wrap_it <- Vectorize(wrap_one, "x", USE.NAMES = FALSE) 12 | 13 | make_grid <- function(n) { 14 | gridlines <- grid::unit( (0:n) / n, "npc") 15 | grid::grid.grill(h = gridlines, v = gridlines) # gp = gpar(col="grey")) 16 | gridlines 17 | } 18 | 19 | ## write something to compute n from a vector or matrix of bingo card data 20 | infer_n <- function(bc) { 21 | m <- if (length(dim(bc) == 2)) nrow(bc) else length(bc) 22 | n_ok <- 3:6 23 | n_sq <- n_ok ^ 2 24 | n <- n_ok[match(m, n_sq)] 25 | if (is.na(n)) 26 | stop("Sorry, we are only prepared to plot square bingo cards ", 27 | "with ", min(n_ok), " to ", max(n_ok), " rows/cols.", call. = FALSE) 28 | n 29 | } 30 | -------------------------------------------------------------------------------- /inst/topics/open-data.R: -------------------------------------------------------------------------------- 1 | #' The agony of other people's data. 2 | 3 | c( 4 | "duplicate rows", 5 | "website maze", 6 | "session has timed out", 7 | "broken formula", 8 | "mystery column", 9 | "metadata mixed with data", 10 | "out of date docs", 11 | ".XLSB", 12 | "assumed knowledge", 13 | "non-standard country names", 14 | "blank rows", 15 | "hidden cells", 16 | "circular references", 17 | "split cells", 18 | "long fieldnames are long", 19 | "metadata at end of spreadsheet", 20 | "arcane codes", 21 | "please enable macros", 22 | "colour as data", 23 | "merged cells", 24 | "acronym WTF?", 25 | "starred numbers*", 26 | "PDF tables", 27 | "numbers formatted as text", 28 | "metadata expressed as fieldnames", 29 | "fieldname EDA", 30 | "regex-driven workflow", 31 | "named region non-sequiturs", 32 | "dates formatted as numbers", 33 | "ununiform date format", 34 | "scanned tables", 35 | "password-protected files", 36 | "screenshot of report" 37 | ) 38 | -------------------------------------------------------------------------------- /inst/topics/news-nerd.R: -------------------------------------------------------------------------------- 1 | ### inspired by https://twitter.com/bizweekgraphics/status/1116385470534045696/photo/1 2 | ### address issue #56 3 | 4 | c("has spoken at NICAR for the last 3 years", 5 | "RTs any map with hillshades", 6 | "worships Amanda Cox", 7 | "d3 v4 4ever", 8 | "some personal news", 9 | "googling flexbox", 10 | "srccon community call", 11 | "relies on a guy named kyng chaos", 12 | "Census update dates in calendar", 13 | "very strong opinions about the Data Visualization Society", 14 | "\"we are not a service desk\"", 15 | "Havre de Grace", 16 | "writes?", 17 | "has googled \"how to center div\" 300 times", 18 | "has had canvas on resume for three years but never used it", 19 | "blocked by edward tufte", 20 | "Knight Foundation fellowship", 21 | "loves observable", 22 | "has a tinyletter", 23 | "spend three weeks installing qgis", 24 | "forgot to test in IE", 25 | "tweets about cocktails", 26 | "snd bronze", 27 | "hates obervable", 28 | "newsnerdery" 29 | ) 30 | -------------------------------------------------------------------------------- /inst/topics/conference-call.R: -------------------------------------------------------------------------------- 1 | c("Can you see my screen?", 2 | "Can you hear me?", 3 | "Could everyone mute their phones?", 4 | "Someone forgets they are on mute", 5 | "I'm getting an echo", 6 | "Laggy screen", 7 | "Who just joined?", 8 | "Background noise", 9 | "Making a mistake in the dial-in code", 10 | "Someone in the room mutes to talk over the call", 11 | "Starting late", 12 | "Running over", 13 | "Small talk", 14 | "Someone randomly joins the wrong call", 15 | "People start talking at the same time", 16 | "Someone loses the connection and re-joins", 17 | "Hold music", 18 | "Bad signal", 19 | "Let's do a round of introductions", 20 | "Someone in a car", 21 | "Dog barking", 22 | "Crying baby", 23 | "Siren in the background", 24 | "Circle back on that", 25 | "Take this offline", 26 | "Hard stop", 27 | "Switching between calls", 28 | "Someone takes another call and forgets to mute", 29 | "Keyboard sounds", 30 | "Moves the microphone", 31 | "Someone is eating" 32 | ) 33 | -------------------------------------------------------------------------------- /inst/shiny/www/app.css: -------------------------------------------------------------------------------- 1 | @media print { 2 | .noprint { 3 | display: none; 4 | } 5 | } 6 | 7 | body > .container-fluid { 8 | margin: 0; 9 | padding: 0; 10 | } 11 | 12 | body { 13 | padding-bottom: 20px; 14 | } 15 | 16 | #authors { 17 | margin-bottom: 15px; 18 | margin-top: -5px; 19 | font-style: italic; 20 | } 21 | 22 | #form { 23 | background: #f9f9f9; 24 | padding: 10px 20px 20px; 25 | border-bottom: 1px solid #aaa; 26 | font-size: 1.2em; 27 | } 28 | 29 | #apptitle { 30 | margin-top: 0; 31 | } 32 | 33 | #wordsinput { 34 | margin-top: -10px; 35 | } 36 | 37 | #wordsinput .form-group, #wordsinput .progress { 38 | margin-bottom: 0; 39 | } 40 | 41 | #error { 42 | margin-top: 10px; 43 | color: red; 44 | } 45 | 46 | table.bingo-card { 47 | border-collapse: collapse; 48 | table-layout: fixed; 49 | margin-top: 20px; 50 | margin-left: 20px; 51 | float: left; 52 | } 53 | 54 | .bingo-card td { 55 | border: 1px solid black; 56 | text-align: center; 57 | word-break: break-word; 58 | } 59 | -------------------------------------------------------------------------------- /R/Eurovision_bingo.R: -------------------------------------------------------------------------------- 1 | #Eurovision Bingo (for usein the grand final, because certain cells pertain to voting results) 2 | c("Costume change/reveal", 3 | "Multilingual song", 4 | "Wink at camera", 5 | "Pyrotechnics", 6 | "Fog machine", 7 | "Background interpretive dancers", 8 | "Dramatic high note", 9 | "Sparkle/sequin outfit", 10 | "Crazy hair/hat", 11 | "Voice crack", 12 | "Dance break", 13 | "Song not in English", 14 | "Hair flip", 15 | "Awkward green room interview", 16 | "Hosts are cringy", 17 | "Seizure inducing lights", 18 | "Wind machine", 19 | "Dramatic solo ballad", 20 | "Dizzying LED backdrop", 21 | "Someone cries", 22 | "Shirtless male dancers", 23 | "Song has vague uplifting message", 24 | "Flag waved at camera", 25 | "Leather pants", 26 | "Synchronized dance routine", 27 | "Country outside of Europe performs", 28 | "Previous contestant makes an apperance", 29 | "Obviously fake instruments on stage", 30 | "Clapping during a song", 31 | "Love song", 32 | "Technical difficulties", 33 | "'Heart hands' to the camera", 34 | "Huge props") 35 | -------------------------------------------------------------------------------- /inst/topics/manuscript-review.R: -------------------------------------------------------------------------------- 1 | # Common issues in manuscript reviews 2 | # Submitted by Haley Hedlin 3 | c("No limitations described", 4 | "Figure legends missing", 5 | "Statistical software not specified", 6 | "Acronym not defined", 7 | "Not clear what test used to calculate a result", 8 | "Table/figure not mentioned in results", 9 | "Parameterization of statistical model not clear", 10 | "CONSORT diagram missing", 11 | "Inclusion/exclusion criteria unclear", 12 | "Not clear whether analyses chosen a priori", 13 | "Handling of missing data not described", 14 | "No confidence intervals provided", 15 | "Not clear if model assumptions were checked", 16 | "Bad graphs (eg pie charts, 3d bar charts)", 17 | "Hypotheses not clear", 18 | "Level of significance reported", 19 | "Unclear statistical methods", 20 | "Unclear or missing baseline characteristics/Table 1", 21 | "Improper use of statistical terms", 22 | "Not clear if significant results are clinically or statistically significant", 23 | "Measured values expressed to the appropriate precision", 24 | "R packages not cited", 25 | "Need to cite more papers by [me]", 26 | "Unclear significance of work" 27 | ) 28 | -------------------------------------------------------------------------------- /inst/topics/stat-ecology.R: -------------------------------------------------------------------------------- 1 | # Statistical ecology themed bingo 2 | c("population dynamics", 3 | "life history", 4 | "state-space model", 5 | "Bayesian", 6 | "Poisson", 7 | "binomial", 8 | "species", 9 | "R (software)", 10 | "collaboration", 11 | "environmental drivers", 12 | "animal behavior", 13 | "genetic diversity", 14 | "operational taxonomic unit", 15 | "keystone species", 16 | "reproductive success", 17 | "model selection", 18 | "survival probability", 19 | "life stage", 20 | "density dependence", 21 | "reproducible research", 22 | "regression", 23 | "R-squared", 24 | "mixed effects", 25 | "manuscript", 26 | "noisy data", 27 | "hierarchical model", 28 | "conference", 29 | "sample design", 30 | "p-value problem", 31 | "statistical significance", 32 | "statistical significance vs. scientific significance", 33 | "confidence interval", 34 | "beta regression on proportions", 35 | "ecological network", 36 | "bipartite network", 37 | "interaction network", 38 | "Lotka-Volterra equations", 39 | "exponential growth", 40 | "generalized linear model", 41 | "logistic regression", 42 | "heteroscedastic", 43 | "ordination", 44 | "community detection" 45 | ) 46 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | environment: 17 | NOT_CRAN: true 18 | # env vars that may need to be set, at least temporarily, from time to time 19 | # see https://github.com/krlmlr/r-appveyor#readme for details 20 | USE_RTOOLS: true 21 | # R_REMOTES_STANDALONE: true 22 | 23 | # Adapt as necessary starting from here 24 | 25 | build_script: 26 | - travis-tool.sh install_deps 27 | 28 | test_script: 29 | - travis-tool.sh run_tests 30 | 31 | on_failure: 32 | - 7z a failure.zip *.Rcheck\* 33 | - appveyor PushArtifact failure.zip 34 | 35 | artifacts: 36 | - path: '*.Rcheck\**\*.log' 37 | name: Logs 38 | 39 | - path: '*.Rcheck\**\*.out' 40 | name: Logs 41 | 42 | - path: '*.Rcheck\**\*.fail' 43 | name: Logs 44 | 45 | - path: '*.Rcheck\**\*.Rout' 46 | name: Logs 47 | 48 | - path: '\*_*.tar.gz' 49 | name: Bits 50 | 51 | - path: '\*_*.zip' 52 | name: Bits 53 | -------------------------------------------------------------------------------- /R/topics.R: -------------------------------------------------------------------------------- 1 | # Environment containing all the word lists of all topics 2 | topics <- new.env(parent = emptyenv()) 3 | 4 | #' Get all bingo card topics 5 | #' 6 | #' @return A character vector containing the names of all the bingo card topics 7 | #' @export 8 | #' 9 | #' @examples 10 | #' get_topics() 11 | get_topics <- function() { 12 | ls(topics) 13 | } 14 | 15 | #' Get the words of a bingo card topic 16 | #' 17 | #' @param topic Name of a topic (a string) 18 | #' 19 | #' @return A character vector containing all the possible words of a bingo card 20 | #' topic 21 | #' @export 22 | #' 23 | #' @examples 24 | #' get_topic("open-data") 25 | get_topic <- function(topic) { 26 | if (!topic %in% get_topics()) { 27 | stop("Topic '", topic, "' does not exist", call. = FALSE) 28 | } 29 | topics[[topic]] 30 | } 31 | 32 | # When the package loads, load all the topics words 33 | .onLoad <- function(libname, pkgname) { 34 | rm(list = ls(topics), envir = topics) 35 | topics_dir <- system.file("topics", package = "bingo") 36 | all_topics <- list.files(topics_dir, full.names = FALSE, pattern = "\\.R$") 37 | all_topics <- sub("\\.R$", "", all_topics) 38 | 39 | lapply(all_topics, function(x) { 40 | tryCatch({ 41 | topic_file <- file.path(topics_dir, paste0(x, ".R")) 42 | words <- source(topic_file)$value 43 | assign(x, words, topics) 44 | }, error = function(err) { 45 | warning("Topic '", x, "' is mal-formed", call. = FALSE) 46 | }) 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /inst/topics/bad-data.R: -------------------------------------------------------------------------------- 1 | # Inspired by the \href{https://github.com/Quartz/bad-data-guide}{Quartz Guide 2 | # to Bad Data}. Identifies bad data smells that should make you extremely 3 | # vigilant in your cleaning and sanity checks. 4 | c( 5 | "Blank/null values aren't explained", 6 | "Data that \"must exist\" does not, in fact, exist", 7 | "Data that \"cannot exist\" does, in fact, exist", 8 | "Duplicate rows", 9 | "Metric? Imperial? Ask the dust ...", 10 | "65,535 or 2,147,483,647 or 4,294,967,295", 11 | "555-3485 or 867-5309", 12 | "1970-01-01\nT00:00:00Z or 1969-12-31\nT23:59:59Z", 13 | "January 1st, 1900 or January 1st, 1904", 14 | "Data is \"helpfully\" pre-aggregated", 15 | "Aggregates and computed totals don't match", 16 | "Line ending chaos ... \\n vs \\r\\n vs \\r", 17 | "Yo, I hear you like metadata mixed with your data", 18 | "Spreadsheet has exactly 65,536 rows", 19 | "Missing data that passes for real data, eg 0 or 99", 20 | "Leading zeroes stripped to convert text to numbers", 21 | "Inexplicable outliers", 22 | ## this does not work well with grid and PDF 23 | ## http://stackoverflow.com/questions/28746938/ggsave-losing-unicode-charaters-from-ggplotgridextra 24 | #"\uFFFD\uFFFD\uFFFD Mojibake \uFFFD\uFFFD\uFFFD", 25 | "Garbled text suggests encoding problems", 26 | "Data disguised as formatting", 27 | "Ambiguous American date formats, eg 03/04/16", 28 | "\"Virgin Birth\", ie no provenance", 29 | "Location of 0\u00B0N 0\u00B0E, ie \"Null Island\"", 30 | "Spelling mistakes that reek of hand-typed data", 31 | "US zip codes 12345 or 90210", 32 | "There's no unique identifier", 33 | "Password-protected data" 34 | ) 35 | -------------------------------------------------------------------------------- /inst/shiny/global.R: -------------------------------------------------------------------------------- 1 | # Given a string with comma-separated phrases, extract the phrases 2 | getWordsText <- function(text) { 3 | trimws(strsplit(text, ",")[[1]]) 4 | } 5 | 6 | # Given a file with comma-separated or newline-separated phrases, 7 | # extract the phrases 8 | getWordsFile <- function(file) { 9 | getWordsText(paste(readLines(file), collapse = ",")) 10 | } 11 | 12 | 13 | # Make sure there are enough phrases to fill at least one card 14 | validateSize <- function(words, size) { 15 | if (length(words) < (size * size - 1)) { 16 | stop(sprintf("You need at least %s phrases to fill a %sx%s bingo card (you provided %s)", 17 | size * size - 1, size, size, length(words))) 18 | } 19 | } 20 | 21 | # Create CSS that is needed to customize the appearance of the bingo cards 22 | generateCardCSS <- function(length = 10, textSize = 16) { 23 | tags$style(paste0( 24 | "table.bingo-card {", 25 | " width: ", length, "cm;", 26 | " height: ", length, "cm;", 27 | " font-size: ", textSize, "px;", 28 | "}" 29 | )) 30 | } 31 | 32 | # Generate HTML for a bingo card 33 | generateCard <- function(words = LETTERS, size = 5) { 34 | # Randomly select phrases and insert "FREE" in the middle 35 | words <- sample(words, size * size - 1) 36 | middle <- size * size / 2 + 1 37 | middleWord <- words[middle] 38 | words[middle] <- "FREE" 39 | words[length(words) + 1] <- middleWord 40 | # Just for convenience, make the phrases a 2D matrix instead of 1D vector 41 | dim(words) <- c(size, size) 42 | 43 | tags$table( 44 | class = "bingo-card", 45 | tags$tbody( 46 | lapply(seq(size), function(row) { 47 | tags$tr( 48 | lapply(seq(size), function(col) { 49 | tags$td(words[row, col]) 50 | }) 51 | ) 52 | }) 53 | ) 54 | ) 55 | } 56 | -------------------------------------------------------------------------------- /inst/topics/useR-conf.R: -------------------------------------------------------------------------------- 1 | # Things you expect to encounter in useR conference 2 | # Authors (GitHub handles): 3 | # bearloga, corynissen, rmflight, Luke4130, barryrowlingson, hrbrmstr, spholmes, 4 | # trestletech, daroczig, kylehamilton, petestmarie, yanlesin 5 | c( 6 | "R vs. Python", 7 | "hadleyverse", 8 | "pipe", 9 | "A slide with a cat on it", 10 | "rmarkdown", 11 | "shiny", 12 | "bookdown", 13 | "grammar of", 14 | "R inferno", 15 | "%>%", 16 | "CRANdalf", 17 | "RConsortium", 18 | "mtcars", 19 | "diamonds", 20 | "Hadleyverse", 21 | "ArrCeePeePee", 22 | "cats", 23 | "kittens", 24 | "StackOverflow", 25 | "Data Science", 26 | "rainbow", 27 | "pie chart", 28 | "SAS", 29 | "SPSS", 30 | "Excel", 31 | "R4", 32 | "R5", 33 | "R6", 34 | "Splus", 35 | "Tibco", 36 | "R-forge", 37 | "library!=package", 38 | "%<>%", 39 | "sell out", 40 | "cloud", 41 | "language war", 42 | "Julia", 43 | "R-bloggers", 44 | "analytics", 45 | "docker", 46 | "A failed live demo", 47 | "two people exchanging business cards", 48 | "in the cloud", 49 | "AWS", 50 | "A laptop with > 5 R themed stickers", 51 | "A t-shirt from a past R conference", 52 | "Microsoft Windows running on a PC", 53 | "Somebody coding in emacs / vi", 54 | "spark / sparkr", 55 | "notebook", 56 | "repo", 57 | "base (as in base vs ggplot2)", 58 | "virtually every dplyr verb", 59 | "literate", 60 | "sankey", 61 | "contour", 62 | "flowchart", 63 | "reproducible", 64 | "interactive", 65 | "stata", 66 | "structural equation", 67 | "credible", 68 | "big data", 69 | "subversion", 70 | "cloud scale", 71 | "Beamer slides", 72 | "GitHub", 73 | "CRAN", 74 | "install", 75 | "development", 76 | "version", 77 | "bug(fix)", 78 | "devtools", 79 | "roxygen", 80 | "Rcpp", 81 | "benchmark", 82 | "profiling", 83 | "is that Hadley Wickham?", 84 | "Bayesian" 85 | ) 86 | -------------------------------------------------------------------------------- /inst/topics/olympic-sports.R: -------------------------------------------------------------------------------- 1 | # "olympic sports" past and present word bank - source https://en.wikipedia.org/wiki/Olympic_sports 2 | 3 | c( 4 | "Diving", 5 | "Marathon swimming", 6 | "Swimming", 7 | "Synchronized swimming", 8 | "Water polo", 9 | "3-on-3 basketball", 10 | "Basketball", 11 | "Canoe/kayak (sprint)", 12 | "Canoe/kayak (slalom)", 13 | "BMX freestyle", 14 | "BMX racing", 15 | "Mountain biking", 16 | "Road cycling", 17 | "Track cycling", 18 | "Gymnanastics - Artistic", 19 | "Gymnanastics - Rhythmic", 20 | "Gymnanastics - Trampoline", 21 | "Volleyball (beach)", 22 | "Volleyball (indoor)", 23 | "Equestrian / Dressage", 24 | "Equestrian / Eventing", 25 | "Equestrian / Jumping", 26 | "Freestyle wrestling", 27 | "Greco-Roman wrestling", 28 | "Archery", 29 | "Athletics", 30 | "Badminton", 31 | "Baseball", 32 | "Boxing", 33 | "Fencing", 34 | "Field hockey", 35 | "Football", 36 | "Golf", 37 | "Handball", 38 | "Judo", 39 | "Karate", 40 | "Modern pentathlon", 41 | "Rowing", 42 | "Rugby sevens", 43 | "Sailing", 44 | "Shooting", 45 | "Skateboarding", 46 | "Softball", 47 | "Sport climbing", 48 | "Surfing", 49 | "Table tennis", 50 | "Taekwondo", 51 | "Tennis", 52 | "Triathlon", 53 | "Weightlifting", 54 | "Equestrian / Vaulting", 55 | "Handball / Field Handball", 56 | "Rugby / Rugby union", 57 | "Basque pelota", 58 | "Cricket", 59 | "Croquet", 60 | "Lacrosse", 61 | "Jeu de paume", 62 | "Polo", 63 | "Rackets", 64 | "Roque", 65 | "Tug of war", 66 | "Water motorsports", 67 | "Figure skating", 68 | "Ice hockey", 69 | "Figure skating", 70 | "Speed skating", 71 | "Short track speed skating", 72 | "Curling", 73 | "Cross-country skiing", 74 | "Alpine skiing", 75 | "Ski jumping", 76 | "Nordic combined", 77 | "Freestyle skiing", 78 | "Snowboarding", 79 | "Biathlon", 80 | "Luge", 81 | "Bobsleigh", 82 | "Skeleton", 83 | "Biathlon / Military Patrol" 84 | ) 85 | -------------------------------------------------------------------------------- /R/bingo.R: -------------------------------------------------------------------------------- 1 | #' Generate bingo cards 2 | #' 3 | #' @param n_cards number of cards 4 | #' @param words text for the bingo squares 5 | #' @param n number of rows/columns for one card 6 | #' 7 | #' @return a \code{bingo} object, which is really just a character matrix 8 | #' @export 9 | #' 10 | #' @examples 11 | #' bingo() 12 | bingo <- function(n_cards = 1, words, n = 5) { 13 | stopifnot(n %% 2 == 1) 14 | 15 | if (missing(words)) { 16 | words <- topics[['open-data']] 17 | } 18 | 19 | words <- vet_squares(words) 20 | m <- length(words) 21 | n_sq <- (n ^ 2) - 1 22 | stopifnot(m >= n_sq) 23 | 24 | cards <- replicate(n_cards, words[sample.int(m, size = n_sq)]) 25 | up_to <- trunc(n_sq/2) 26 | cards <- rbind(utils::head(cards, up_to), 27 | rep("FREE", n_cards), 28 | utils::tail(cards, up_to)) 29 | row.names(cards) <- NULL 30 | structure(cards, class = c("bingo", "matrix")) 31 | } 32 | 33 | #' Plot bingo cards 34 | #' 35 | #' @param x a \code{\link{bingo}} object containing one or more bingo cards 36 | #' @param dir directory where you want to write files 37 | #' @param fontsize size of bingo square font 38 | #' @param pdf_base base of the sequential filenames for the printable bingo card 39 | #' files 40 | #' @param ... not used 41 | #' 42 | #' @export 43 | #' @note Does not actually plot the cards to the graphics device 44 | #' @return Vector containing the filenames of all the generated cards 45 | #' (invisibly) 46 | #' @examples 47 | #' bc <- bingo() 48 | #' plot(bc) 49 | plot.bingo <- function(x, dir = ".", fontsize = 14, pdf_base = "bingo-", ...) { 50 | bc <- x 51 | n <- infer_n(bc) 52 | n_cards <- ncol(bc) 53 | bc_wrapped <- apply(bc, 2, wrap_it) 54 | message("Writing to file ...") 55 | filenames <- c() 56 | for (i in seq_len(n_cards)) { 57 | fname <- file.path(dir, paste0(pdf_base, sprintf("%02d", i), ".pdf")) 58 | message(" ", fname) 59 | filenames <- c(filenames, fname) 60 | grDevices::pdf(fname, width = 7, height = 7) 61 | plot_one(bc_wrapped[ , i], n = n, fontsize = fontsize) 62 | grDevices::dev.off() 63 | } 64 | invisible(filenames) 65 | } 66 | 67 | plot_one <- function(x, n, fontsize = 14) { 68 | grid::grid.newpage() 69 | g <- make_grid(n) 70 | centers <- g[-1] - grid::unit(1/(n * 2),"npc") 71 | grid::grid.text(label = x, x = rep(centers, each = n), y = centers, 72 | gp = grid::gpar(fontsize = fontsize)) 73 | 74 | } 75 | -------------------------------------------------------------------------------- /inst/shiny/server.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(shinyjs) 3 | 4 | source("global.R") 5 | 6 | function(input, output, session) { 7 | 8 | values <- reactiveValues(cardsHTML = NULL) 9 | 10 | # show/hide the advanced options 11 | observeEvent(input$advancedBtn, { 12 | toggle("advanced", anim = TRUE) 13 | }) 14 | 15 | # show an error message when an error occurs 16 | observeEvent(values$error, { 17 | html("errormsg", values$error) 18 | show("error", anim = TRUE) 19 | }) 20 | 21 | # disable the Generate button when no words are entered 22 | observe({ 23 | submitEnabled <- TRUE 24 | if ( (input$uploadType == "box" && !nzchar(input$wordsBox)) || 25 | (input$uploadType == "file" && is.null(input$wordsFile)) 26 | ) { 27 | submitEnabled <- FALSE 28 | } 29 | toggleState("generatePdf", condition = submitEnabled) 30 | toggleState("generateHtml", condition = submitEnabled) 31 | }) 32 | 33 | # Generate PDF cards 34 | output$generatePdf <- downloadHandler( 35 | filename = function() { 36 | "bingo-cards.zip" 37 | }, 38 | content = function(file) { 39 | tryCatch({ 40 | # make sure there are enough phrases to fill at least one card 41 | size <- as.integer(input$size) 42 | validateSize(words(), size) 43 | 44 | # generate the cards 45 | cards <- bingo::bingo(n_cards = input$numberToMake, words = words(), n = size) 46 | filenames <- plot(cards, dir = tempdir(), fontsize = input$textSize) 47 | wd <- setwd(dirname(filenames[1])) 48 | zip(file, basename(filenames)) 49 | setwd(wd) 50 | }, 51 | error = function(err) { 52 | stop(err$message) 53 | }) 54 | } 55 | ) 56 | 57 | words <- reactive({ 58 | if (input$uploadType == "box") { 59 | words <- getWordsText(input$wordsBox) 60 | } else if (input$uploadType == "file") { 61 | words <- getWordsFile(input$wordsFile$datapath) 62 | } else { 63 | words <- bingo::get_topic(input$uploadType) 64 | } 65 | }) 66 | 67 | # Generate HTML cards 68 | observeEvent(input$generateHtml, { 69 | tryCatch({ 70 | size <- as.integer(input$size) 71 | validateSize(words(), size) 72 | 73 | hide("error") 74 | show("print") 75 | 76 | # Joe Cheng won't like, but I have to use reactiveValues here 77 | values$cardsHTML <- 78 | tagList( 79 | generateCardCSS(input$length, input$textSize), 80 | lapply(seq(input$numberToMake), function(i) { 81 | generateCard(words(), size) 82 | }) 83 | ) 84 | }, 85 | error = function(err) { 86 | values$error <- err$message 87 | }) 88 | }) 89 | 90 | # render the cards HTML when it changes 91 | output$cards <- renderUI({ 92 | values$cardsHTML 93 | }) 94 | } 95 | -------------------------------------------------------------------------------- /inst/topics/football.R: -------------------------------------------------------------------------------- 1 | # Denver Broncos vs. Carolina Panthers 2 | c( 3 | 4 | ## gameplay, generic 5 | ## TO DO: move out to generic football 6 | "Quarterback run for 1st down or TD", 7 | "Missed field goal", 8 | "Dropped pass", 9 | "Fumble!", 10 | "Interception!", 11 | "Passing interference", 12 | "Challenge", 13 | "QB kneel or sneak", 14 | "Bootleg or reverse", 15 | "Special teams TD", 16 | "Team goes for it on 4th down", 17 | "Roughing the passer", 18 | "Pick Six", 19 | "Lineman gets to run with football", 20 | "Kick return of 35+ yards", 21 | "Player dives for pylon", 22 | 23 | ## gameplay, team or player specific 24 | "Someone besides Peyton or Cam passes", 25 | ## TO DO: these could be templated 26 | "Gain of 30+ yds for Broncos", 27 | "Gain of 30+ yds for Panthers", 28 | "Panthers passing touchdown", 29 | "Broncos passing touchdown", 30 | "Panthers rushing touchdown", 31 | "Broncos rushing touchdown", 32 | "Holding against the Broncos", 33 | "Holding against the Panthers", 34 | "Panthers field goal", 35 | "Broncos field goal", 36 | "Panthers call timeout", 37 | "Broncos call timeout", 38 | 39 | ## the game of football, generic 40 | "\"concussion protocol\"", 41 | "Fan holding sign with pun", 42 | "Coach removes headphones in anger/disgust", 43 | "Commentator calls someone \"great guy\"", 44 | "Shot of a celeb in crowd", 45 | "Gratuitous cheerleader close-up", 46 | "Shirtless fan with body paint", 47 | "Shot of team owner", 48 | "Lip-readable expletive from player or coach", 49 | "Over-the-top celebration from special teams", 50 | "Military flyover", 51 | "Shot of US soldiers watching from abroad", 52 | "Implication that God cares about football", 53 | "Player/coach slaps other player's butt", 54 | "Elaborate touchdown celebration", 55 | "Non-football player gets knocked down", 56 | "Either score or total score divisible by 11", 57 | "Animal playing cutely on field", 58 | 59 | ## specific to this game, non-gameplay 60 | "Shot or interview of Eli or Archie Manning", 61 | "Reference to Cam's off-field fashion", 62 | "Commentary on Peyton's alleged drug use", 63 | "Mention of Cam and BFF Stephen Curry", 64 | "Shot of Golden Gate Bridge", 65 | "\"Silicon Valley and tech\" blah blah blah", 66 | "Mike Carey is WRONG", 67 | "Unexpected artist joins Beyonc\u00E9", 68 | "Cam's Superman shirt-opening thing", 69 | "Idle speculation it's Peyton's last game" 70 | ) 71 | 72 | ## lying around from past 73 | ## Troy Aikman says something inane 74 | ## NFL Labor dispute mentioned 75 | ## Aaron Rodgers Matador/put on the belt move 76 | ## Shot of a fan in a Cheesehead hat 77 | ## Rothlisberger avoids what looked like a sure sack 78 | ## Big Ben throws an interception 79 | ## Clay Mathews sacks Big Ben 80 | ## Reference to Clay Matthew's "football family" 81 | -------------------------------------------------------------------------------- /inst/shiny/ui.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | 3 | fluidPage( 4 | shinyjs::useShinyjs(), 5 | tags$head( 6 | tags$link(href = "app.css", rel = "stylesheet") 7 | ), 8 | 9 | div( 10 | class = "noprint", 11 | id = "form", 12 | h1(id = "apptitle", "Bingo card generator"), 13 | div(id = "authors", 14 | "By", a("Jenny Bryan", href = "https://twitter.com/jennybryan"), 15 | "and", a("Dean Attali", href = "http://deanattali.com"), 16 | HTML("•"), 17 | "Code", a("on GitHub", href = "https://github.com/jennybc/bingo") 18 | ), 19 | selectInput("cardType", NULL, 20 | c("Create HTML cards to print" = "html", 21 | "Create PDF cards to download" = "pdf") 22 | ), 23 | numericInput("numberToMake", "Number of cards to generate", 5, 1), 24 | selectInput("uploadType", "Phrases to use", 25 | c(bingo::get_topics(), 26 | "(Type phrases into a box)" = "box", 27 | "(Upload text file)" = "file")), 28 | div( 29 | id = "wordsinput", 30 | conditionalPanel( 31 | condition = "input.uploadType == 'box'", 32 | 33 | div(class = "form-group shiny-input-container", 34 | tags$textarea(id = "wordsBox", rows = 7, class = "form-control", 35 | paste(LETTERS, collapse = ",")) 36 | ), 37 | helpText("Phrases must be separated by commas") 38 | ), 39 | conditionalPanel( 40 | condition = "input.uploadType == 'file'", 41 | fileInput("wordsFile", NULL), 42 | helpText("Phrases must be separated by commas") 43 | ) 44 | ), 45 | actionLink("advancedBtn", "More options"), br(), 46 | shinyjs::hidden( 47 | div( 48 | id = "advanced", 49 | selectInput("size", "Number of cells", selected = "5", 50 | c("3x3" = "3", "5x5" = "5")), 51 | numericInput("textSize", "Text size (in pixels)", 14, 8), 52 | conditionalPanel( 53 | condition = "input.cardType == 'html'", 54 | numericInput("length", "Card size (in centimeters)", 20, 5) 55 | ) 56 | ) 57 | ), 58 | br(), 59 | conditionalPanel( 60 | condition = "input.cardType == 'pdf'", 61 | downloadButton('generatePdf', 'Download cards!', class = "btn-primary btn-lg") 62 | ), 63 | conditionalPanel( 64 | condition = "input.cardType == 'html'", 65 | actionButton("generateHtml", "Generate cards!", class = "btn-primary btn-lg"), 66 | shinyjs::hidden( 67 | actionButton("print", "Print these cards", icon("print"), 68 | onclick = "javascript:window.print()", class = "btn-lg") 69 | ) 70 | ), 71 | br(), 72 | conditionalPanel( 73 | condition = "input.cardType == 'html'", 74 | shinyjs::hidden( 75 | div( 76 | id = "error", 77 | strong("Error: "), 78 | span(id = "errormsg") 79 | ) 80 | ) 81 | ) 82 | ), 83 | conditionalPanel( 84 | condition = "input.cardType == 'html'", 85 | uiOutput("cards") 86 | ) 87 | ) 88 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: 3 | github_document: 4 | toc: true 5 | toc_depth: 2 6 | --- 7 | 8 | 9 | 10 | 11 | [![Travis build status](https://travis-ci.org/jennybc/bingo.svg?branch=master)](https://travis-ci.org/jennybc/bingo) 12 | [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/jennybc/bingo?branch=master&svg=true)](https://ci.appveyor.com/project/jennybc/bingo) 13 | [![Codecov test coverage](https://codecov.io/gh/jennybc/bingo/branch/master/graph/badge.svg)](https://codecov.io/gh/jennybc/bingo?branch=master) 14 | 15 | 16 | ```{r, echo = FALSE} 17 | knitr::opts_chunk$set( 18 | collapse = TRUE, 19 | comment = "#>", 20 | fig.path = "README-" 21 | ) 22 | # so that the same bingo card will be generated every time 23 | set.seed(10) 24 | ``` 25 | 26 | # bingo 27 | 28 | Generate Bingo cards. 29 | 30 | Currently has built-in squares for SuperBowl 50 :football: and data / spreadsheet craziness :chart_with_downwards_trend: and more. Or you can provide your own text for the squares. 31 | 32 | Make printable Bingo cards **without installing anything** via this Shiny app: 33 | 34 | * 35 | * It's also included in the package (see [below](#run-shiny-app-locally)). 36 | 37 | Feel free to help us make these cards less ugly or to explore new bingo topics! PRs welcome :grin:. 38 | 39 | ## Installation 40 | 41 | Install from GitHub with: 42 | 43 | ```{r eval = FALSE} 44 | # install.packages("devtools") 45 | devtools::install_github("jennybc/bingo") 46 | ``` 47 | 48 | ## SuperBowl Example 49 | 50 | ```{r} 51 | library(bingo) 52 | 53 | ## see some of the SuperBowl 50 squares 54 | tail(get_topic("football")) 55 | 56 | ## make 8 bingo cards 57 | bc <- bingo(n_cards = 8, words = get_topic("football")) 58 | 59 | ## print them to PDF 60 | plot(bc) 61 | ``` 62 | 63 | Here's what one looks like: 64 | 65 | ![](img/bingo-01-superbowl-50-2016.png) 66 | 67 | ## "Open" and Bad Data Examples 68 | 69 | We offer two sets of squares inspired by the ~~pain~~ joy of dealing with [`#otherpeoplesdata`](https://twitter.com/search?q=%23otherpeoplesdata&src=tyah) 70 | 71 | Use `get_topic("open-data")` to get squares based on this tweet from Chris McDowall: 72 | 73 | > For two weeks I noted issues encountered as I used NZ govt data. Today I collected enough to make a bingo card. *[\@fogonwater, January 3, 2016](https://twitter.com/fogonwater/status/683785398112260097)* 74 | 75 | Use `get_topic("bad-data")` to get squares inspired by the [Quartz guide to bad data](https://github.com/Quartz/bad-data-guide): 76 | 77 | > An exhaustive reference to problems seen in real-world data along with suggestions on how to resolve them.... Most of these problems can be solved. Some of them can't be solved and that means you should not use the data. Others can't be solved, but with precautions you can continue using the data. 78 | 79 | ```{r} 80 | ## see some Open Data squares 81 | tail(get_topic("open-data")) 82 | 83 | ## see some Bad Data squares 84 | tail(get_topic("bad-data")) 85 | 86 | ## make a single Open Data bingo card 87 | ## Note that "open-data" is the default topic, so you could alternatively use: bc <- bingo(). 88 | bc <- bingo(words = get_topic("open-data")) 89 | 90 | ## make a custom bingo blend from the open and bad data squares 91 | bc <- bingo(words = c(get_topic("open-data"), get_topic("bad-data"))) 92 | 93 | ## print it 94 | plot(bc, pdf_base = "open-data-") 95 | ``` 96 | 97 | Here's an Open Data bingo card: 98 | 99 | ![](img/bingo-01-open-data.png) 100 | 101 | ```{r clean-up, include = FALSE} 102 | crap <- c(list.files(pattern = "bingo-[0-9]+.pdf"), 103 | list.files(pattern = "open-data-[0-9]+.pdf")) 104 | file.remove(crap) 105 | ``` 106 | 107 | ## Run Shiny app locally 108 | 109 | To run [the app we're running remotely](http://daattali.com/shiny/bingo/) on your own machine, do this: 110 | 111 | ```{r eval = FALSE} 112 | launch() 113 | ``` 114 | 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | [![Travis build 7 | status](https://travis-ci.org/jennybc/bingo.svg?branch=master)](https://travis-ci.org/jennybc/bingo) 8 | [![AppVeyor build 9 | status](https://ci.appveyor.com/api/projects/status/github/jennybc/bingo?branch=master&svg=true)](https://ci.appveyor.com/project/jennybc/bingo) 10 | [![Codecov test 11 | coverage](https://codecov.io/gh/jennybc/bingo/branch/master/graph/badge.svg)](https://codecov.io/gh/jennybc/bingo?branch=master) 12 | 13 | 14 | # bingo 15 | 16 | Generate Bingo cards. 17 | 18 | Currently has built-in squares for SuperBowl 50 :football: and data / 19 | spreadsheet craziness :chart\_with\_downwards\_trend: and more. Or you 20 | can provide your own text for the squares. 21 | 22 | Make printable Bingo cards **without installing anything** via this 23 | Shiny app: 24 | 25 | - 26 | - It’s also included in the package (see 27 | [below](#run-shiny-app-locally)). 28 | 29 | Feel free to help us make these cards less ugly or to explore new bingo 30 | topics\! PRs welcome :grin:. 31 | 32 | ## Installation 33 | 34 | Install from GitHub with: 35 | 36 | ``` r 37 | # install.packages("devtools") 38 | devtools::install_github("jennybc/bingo") 39 | ``` 40 | 41 | ## SuperBowl Example 42 | 43 | ``` r 44 | library(bingo) 45 | 46 | ## see some of the SuperBowl 50 squares 47 | tail(get_topic("football")) 48 | #> [1] "Shot of Golden Gate Bridge" 49 | #> [2] "\"Silicon Valley and tech\" blah blah blah" 50 | #> [3] "Mike Carey is WRONG" 51 | #> [4] "Unexpected artist joins Beyoncé" 52 | #> [5] "Cam's Superman shirt-opening thing" 53 | #> [6] "Idle speculation it's Peyton's last game" 54 | 55 | ## make 8 bingo cards 56 | bc <- bingo(n_cards = 8, words = get_topic("football")) 57 | 58 | ## print them to PDF 59 | plot(bc) 60 | #> Writing to file ... 61 | #> ./bingo-01.pdf 62 | #> ./bingo-02.pdf 63 | #> ./bingo-03.pdf 64 | #> ./bingo-04.pdf 65 | #> ./bingo-05.pdf 66 | #> ./bingo-06.pdf 67 | #> ./bingo-07.pdf 68 | #> ./bingo-08.pdf 69 | ``` 70 | 71 | Here’s what one looks like: 72 | 73 | ![](img/bingo-01-superbowl-50-2016.png) 74 | 75 | ## “Open” and Bad Data Examples 76 | 77 | We offer two sets of squares inspired by the ~~pain~~ joy of dealing 78 | with 79 | [`#otherpeoplesdata`](https://twitter.com/search?q=%23otherpeoplesdata&src=tyah) 80 | 81 | Use `get_topic("open-data")` to get squares based on this tweet from 82 | Chris McDowall: 83 | 84 | > For two weeks I noted issues encountered as I used NZ govt data. Today 85 | > I collected enough to make a bingo card. *[@fogonwater, 86 | > January 3, 2016](https://twitter.com/fogonwater/status/683785398112260097)* 87 | 88 | Use `get_topic("bad-data")` to get squares inspired by the [Quartz guide 89 | to bad data](https://github.com/Quartz/bad-data-guide): 90 | 91 | > An exhaustive reference to problems seen in real-world data along with 92 | > suggestions on how to resolve them…. Most of these problems can be 93 | > solved. Some of them can’t be solved and that means you should not use 94 | > the data. Others can’t be solved, but with precautions you can 95 | > continue using the data. 96 | 97 | ``` r 98 | ## see some Open Data squares 99 | tail(get_topic("open-data")) 100 | #> [1] "PDF tables" "numbers formatted as text" 101 | #> [3] "metadata expressed as fieldnames" "fieldname EDA" 102 | #> [5] "regex-driven workflow" "named region non-sequiturs" 103 | 104 | ## see some Bad Data squares 105 | tail(get_topic("bad-data")) 106 | #> [1] "Data disguised as formatting" 107 | #> [2] "Ambiguous American date formats, eg 03/04/16" 108 | #> [3] "\"Virgin Birth\", ie no provenance" 109 | #> [4] "Location of 0°N 0°E, ie \"Null Island\"" 110 | #> [5] "Spelling mistakes that reek of hand-typed data" 111 | #> [6] "US zip codes 12345 or 90210" 112 | 113 | ## make a single Open Data bingo card 114 | ## Note that "open-data" is the default topic, so you could alternatively use: bc <- bingo(). 115 | bc <- bingo(words = get_topic("open-data")) 116 | 117 | ## make a custom bingo blend from the open and bad data squares 118 | bc <- bingo(words = c(get_topic("open-data"), get_topic("bad-data"))) 119 | 120 | ## print it 121 | plot(bc, pdf_base = "open-data-") 122 | #> Writing to file ... 123 | #> ./open-data-01.pdf 124 | ``` 125 | 126 | Here’s an Open Data bingo card: 127 | 128 | ![](img/bingo-01-open-data.png) 129 | 130 | ## Run Shiny app locally 131 | 132 | To run [the app we’re running 133 | remotely](http://daattali.com/shiny/bingo/) on your own machine, do 134 | this: 135 | 136 | ``` r 137 | launch() 138 | ``` 139 | --------------------------------------------------------------------------------