├── .gitignore ├── img ├── georgia.png ├── monash.png ├── tsibble.png ├── alison-jsm.png ├── ts-model.png ├── rladiesakl20.png ├── tsibble-useR.png ├── cat-eye-rolling.gif ├── tsibble-model.png ├── rstudio-xaringan.png └── kunoichi.svg ├── figure ├── ggplot-1.png ├── unnamed-chunk-2-1.png └── unnamed-chunk-3-1.png ├── libs ├── countdown │ ├── smb_stage_clear.mp3 │ ├── countdown.css │ └── countdown.js ├── macros.js ├── typed.js ├── header-attrs │ └── header-attrs.js ├── panelset │ ├── panelset.css │ └── panelset.js └── remark.css ├── README.md ├── R └── theme.R ├── rladiesakl20.Rproj ├── deploy.sh ├── index.Rmd └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | cache/ 3 | *.run.xml 4 | -------------------------------------------------------------------------------- /img/georgia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/georgia.png -------------------------------------------------------------------------------- /img/monash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/monash.png -------------------------------------------------------------------------------- /img/tsibble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/tsibble.png -------------------------------------------------------------------------------- /img/alison-jsm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/alison-jsm.png -------------------------------------------------------------------------------- /img/ts-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/ts-model.png -------------------------------------------------------------------------------- /figure/ggplot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/figure/ggplot-1.png -------------------------------------------------------------------------------- /img/rladiesakl20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/rladiesakl20.png -------------------------------------------------------------------------------- /img/tsibble-useR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/tsibble-useR.png -------------------------------------------------------------------------------- /img/cat-eye-rolling.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/cat-eye-rolling.gif -------------------------------------------------------------------------------- /img/tsibble-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/tsibble-model.png -------------------------------------------------------------------------------- /img/rstudio-xaringan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/img/rstudio-xaringan.png -------------------------------------------------------------------------------- /figure/unnamed-chunk-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/figure/unnamed-chunk-2-1.png -------------------------------------------------------------------------------- /figure/unnamed-chunk-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/figure/unnamed-chunk-3-1.png -------------------------------------------------------------------------------- /libs/countdown/smb_stage_clear.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/earowang/rladiesakl20/HEAD/libs/countdown/smb_stage_clear.mp3 -------------------------------------------------------------------------------- /libs/macros.js: -------------------------------------------------------------------------------- 1 | remark.macros.scale = function (percentage) { 2 | var url = this; 3 | return ''; 4 | }; 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rladiesakl20 2 | 3 | [![License: CC BY NC 4.0](https://img.shields.io/badge/License-CC%20BY%20NC%204.0-green.svg)](https://creativecommons.org/licenses/by-nc/4.0/) 4 | 5 | Rendered slides: 6 | -------------------------------------------------------------------------------- /R/theme.R: -------------------------------------------------------------------------------- 1 | ## ---- theme-remark 2 | theme_remark <- function() { 3 | theme_grey() + 4 | theme( 5 | axis.text = element_text(size = 14), 6 | strip.text = element_text(size = 16), 7 | axis.title = element_text(size = 16), 8 | legend.title = element_text(size = 16), 9 | legend.text = element_text(size = 16), 10 | legend.position = "bottom" 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /rladiesakl20.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | Encoding: UTF-8 9 | 10 | AutoAppendNewline: Yes 11 | StripTrailingWhitespace: Yes 12 | LineEndingConversion: Posix 13 | 14 | BuildType: Package 15 | PackageUseDevtools: Yes 16 | PackageInstallArgs: --no-multiarch --with-keep.source 17 | PackageRoxygenize: rd,collate,namespace 18 | -------------------------------------------------------------------------------- /libs/typed.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | repo=${PWD##*/} 4 | 5 | mkdir -p ~/Web/slides/_site/$repo 6 | 7 | # Sync folders to slides 8 | rsync -arvzc index.html ~/Web/slides/_site/$repo/index.html 9 | rsync -arvzc figure/* ~/Web/slides/_site/$repo/figure/ 10 | rsync -arvzc img/* ~/Web/slides/_site/$repo/img/ 11 | rsync -arvzc libs/* ~/Web/slides/_site/$repo/libs/ 12 | 13 | # Commit changes. 14 | msg="Deploying updates to GitHub... `date`" 15 | git add . 16 | git commit -m "$msg" 17 | 18 | # Push source and build repos. 19 | git push origin master 20 | -------------------------------------------------------------------------------- /libs/header-attrs/header-attrs.js: -------------------------------------------------------------------------------- 1 | // Pandoc 2.9 adds attributes on both header and div. We remove the former (to 2 | // be compatible with the behavior of Pandoc < 2.8). 3 | document.addEventListener('DOMContentLoaded', function(e) { 4 | var hs = document.querySelectorAll("div.section[class*='level'] > :first-child"); 5 | var i, h, a; 6 | for (i = 0; i < hs.length; i++) { 7 | h = hs[i]; 8 | if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6 9 | a = h.attributes; 10 | while (a.length > 0) h.removeAttribute(a[0].name); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /libs/countdown/countdown.css: -------------------------------------------------------------------------------- 1 | .countdown { 2 | background: inherit; 3 | position: absolute; 4 | cursor: pointer; 5 | font-size: 3em; 6 | line-height: 1; 7 | border-color: #ddd; 8 | border-width: 3px; 9 | border-style: solid; 10 | border-radius: 15px; 11 | box-shadow: 0px 4px 10px 0px rgba(50, 50, 50, 0.4); 12 | -webkit-box-shadow: 0px 4px 10px 0px rgba(50, 50, 50, 0.4); 13 | margin: 0.6em; 14 | padding: 10px 15px; 15 | text-align: center; 16 | } 17 | .countdown { 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | } 22 | .countdown .countdown-time { 23 | background: none; 24 | font-size: 100%; 25 | padding: 0; 26 | } 27 | .countdown-digits { 28 | color: inherit; 29 | } 30 | .countdown.running { 31 | border-color: #3C9A5F; 32 | background-color: #43AC6A; 33 | } 34 | .countdown.running .countdown-digits { 35 | color: #102B1A; 36 | } 37 | .countdown.finished { 38 | border-color: #D83A20; 39 | background-color: #F04124; 40 | } 41 | .countdown.finished .countdown-digits { 42 | color: #3C1009; 43 | } 44 | .countdown.running.warning { 45 | border-color: #CFAE24; 46 | background-color: #E6C229; 47 | } 48 | .countdown.running.warning .countdown-digits { 49 | color: #39300A; 50 | } 51 | 52 | @-webkit-keyframes blink { 53 | from {opacity: 1} 54 | 50% {opacity: 0.1} 55 | to {opacity: 1} 56 | } 57 | 58 | @keyframes blink { 59 | from {opacity: 1} 60 | 50% {opacity: 0.1} 61 | to {opacity: 1} 62 | } 63 | 64 | .countdown.running.blink-colon .countdown-digits.colon { 65 | -webkit-animation: blink 2s steps(1, end) 0s infinite; 66 | animation: blink 2s steps(1, end) 0s infinite; 67 | } 68 | -------------------------------------------------------------------------------- /libs/panelset/panelset.css: -------------------------------------------------------------------------------- 1 | /* prefixed by https://autoprefixer.github.io (PostCSS: v7.0.23, autoprefixer: v9.7.3) */ 2 | 3 | .panelset { 4 | width: 100%; 5 | position: relative; 6 | --panel-tabs-border-bottom: #ddd; 7 | --panel-tab-color: currentColor; 8 | --panel-tab-color-active: currentColor; 9 | --panel-tab-color-hover: currentColor; 10 | --panel-tab-inactive-opacity: 0.5; 11 | --panel-tab-font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace; 12 | } 13 | 14 | .panelset * { 15 | box-sizing: border-box; 16 | } 17 | 18 | .panel-tabs { 19 | display: -webkit-box; 20 | display: flex; 21 | -webkit-box-orient: horizontal; 22 | -webkit-box-direction: normal; 23 | flex-direction: row; 24 | -webkit-box-pack: start; 25 | justify-content: start; 26 | -webkit-box-align: center; 27 | align-items: center; 28 | border-bottom: 2px solid var(--panel-tabs-border-bottom); 29 | } 30 | 31 | .panel-tabs * { 32 | -webkit-transition: opacity 0.5s ease; 33 | transition: opacity 0.5s ease; 34 | } 35 | 36 | .panel-tab { 37 | min-height: 50px; 38 | display: -webkit-box; 39 | display: flex; 40 | -webkit-box-pack: center; 41 | justify-content: center; 42 | -webkit-box-align: center; 43 | align-items: center; 44 | padding: 0.5em 1em; 45 | font-family: var(--panel-tab-font-family); 46 | opacity: var(--panel-tab-inactive-opacity); 47 | border-top: 2px solid transparent; 48 | border-bottom: 2px solid transparent; 49 | margin-bottom: -2px; 50 | color: var(--panel-tab-color); 51 | } 52 | 53 | .panel-tab:hover { 54 | border-bottom-color: currentColor; 55 | color: var(--panel-tab-color-hover); 56 | opacity: 1; 57 | cursor: pointer; 58 | } 59 | 60 | .panel-tab:focus { 61 | outline: none; 62 | border-bottom-color: var(--panel-tab-color-active); 63 | } 64 | 65 | .panel-tab.panel-tab-active { 66 | border-top-color: currentColor; 67 | color: var(--panel-tab-color-active); 68 | opacity: 1; 69 | } 70 | 71 | .panel { 72 | display: none; 73 | } 74 | 75 | .panel-active { 76 | display: block; 77 | } 78 | -------------------------------------------------------------------------------- /libs/countdown/countdown.js: -------------------------------------------------------------------------------- 1 | var counters = {timer: {}}; 2 | var update_timer = function(timer, force = false) { 3 | var secs = timer.value; 4 | 5 | // check if we should update timer or not 6 | noup = timer.div.className.match(/noupdate-\d+/); 7 | if (!force && noup != null) { 8 | noup = parseInt(noup[0].match(/\d+$/)); 9 | if (secs > noup * 2 && secs % noup > 0) { return; } 10 | } 11 | 12 | // should we apply or remove warning class? 13 | warnwhen = timer.div.dataset.warnwhen; 14 | if (warnwhen && warnwhen > 0) { 15 | if (secs <= warnwhen && !timer.div.classList.contains("warning")) { 16 | timer.div.classList.add("warning"); 17 | } else if (secs > warnwhen && timer.div.classList.contains("warning")) { 18 | timer.div.classList.remove("warning"); 19 | } 20 | } 21 | 22 | var mins = Math.floor(secs / 60); // 1 min = 60 secs 23 | secs -= mins * 60; 24 | 25 | // Update HTML 26 | timer.min.innerHTML = String(mins).padStart(2, 0); 27 | timer.sec.innerHTML = String(secs).padStart(2, 0); 28 | } 29 | var countdown = function (e) { 30 | target = e.target; 31 | if (target.classList.contains("countdown-digits")) { 32 | target = target.parentElement; 33 | } 34 | if (target.tagName == "CODE") { 35 | target = target.parentElement; 36 | } 37 | 38 | // Init counter 39 | if (!counters.timer.hasOwnProperty(target.id)) { 40 | counters.timer[target.id] = {}; 41 | // Set the containers 42 | counters.timer[target.id].min = target.getElementsByClassName("minutes")[0]; 43 | counters.timer[target.id].sec = target.getElementsByClassName("seconds")[0]; 44 | counters.timer[target.id].div = target; 45 | } 46 | 47 | if (!counters.timer[target.id].running) { 48 | if (!counters.timer[target.id].end) { 49 | counters.timer[target.id].end = parseInt(counters.timer[target.id].min.innerHTML) * 60; 50 | counters.timer[target.id].end += parseInt(counters.timer[target.id].sec.innerHTML); 51 | } 52 | 53 | counters.timer[target.id].value = counters.timer[target.id].end; 54 | update_timer(counters.timer[target.id]); 55 | if (counters.ticker) counters.timer[target.id].value += 1; 56 | 57 | // Start if not past end date 58 | if (counters.timer[target.id].value > 0) { 59 | base_class = target.className.replace(/\s?(running|finished)/, "") 60 | target.className = base_class + " running"; 61 | counters.timer[target.id].running = true; 62 | 63 | if (!counters.ticker) { 64 | counters.ticker = setInterval(counter_update_all, 1000); 65 | } 66 | } 67 | } else { 68 | // Bump timer value if running & clicked 69 | counters.timer[target.id].value += counter_bump_increment(counters.timer[target.id].end); 70 | update_timer(counters.timer[target.id], force = true); 71 | counters.timer[target.id].value += 1; 72 | } 73 | }; 74 | 75 | var counter_bump_increment = function(val) { 76 | if (val <= 30) { 77 | return 5; 78 | } else if (val <= 300) { 79 | return 15; 80 | } else if (val <= 3000) { 81 | return 30; 82 | } else { 83 | return 60; 84 | } 85 | } 86 | 87 | var counter_update_all = function() { 88 | // Iterate over all running timers 89 | for (var i in counters.timer) { 90 | // Stop if passed end time 91 | console.log(counters.timer[i].id) 92 | counters.timer[i].value--; 93 | if (counters.timer[i].value <= 0) { 94 | counters.timer[i].min.innerHTML = "00"; 95 | counters.timer[i].sec.innerHTML = "00"; 96 | counters.timer[i].div.className = counters.timer[i].div.className.replace("running", "finished"); 97 | counters.timer[i].running = false; 98 | } else { 99 | // Update 100 | update_timer(counters.timer[i]); 101 | 102 | // Play countdown sound if data-audio=true on container div 103 | let audio = counters.timer[i].div.dataset.audio 104 | if (audio && counters.timer[i].value == 5) { 105 | counter_play_sound(audio); 106 | } 107 | } 108 | } 109 | 110 | // If no more running timers, then clear ticker 111 | var timerIsRunning = false; 112 | for (var t in counters.timer) { 113 | timerIsRunning = timerIsRunning || counters.timer[t].running 114 | } 115 | if (!timerIsRunning) { 116 | clearInterval(counters.ticker); 117 | counters.ticker = null; 118 | } 119 | } 120 | 121 | var counter_play_sound = function(url) { 122 | if (typeof url === 'boolean') { 123 | url = 'libs/countdown/smb_stage_clear.mp3'; 124 | } 125 | sound = new Audio(url); 126 | sound.play(); 127 | } 128 | 129 | var counter_addEventListener = function() { 130 | if (!document.getElementsByClassName("countdown").length) { 131 | setTimeout(counter_addEventListener, 2); 132 | return; 133 | } 134 | var counter_divs = document.getElementsByClassName("countdown"); 135 | console.log(counter_divs); 136 | for (var i = 0; i < counter_divs.length; i++) { 137 | counter_divs[i].addEventListener("click", countdown, false); 138 | } 139 | }; 140 | 141 | counter_addEventListener(); 142 | -------------------------------------------------------------------------------- /libs/panelset/panelset.js: -------------------------------------------------------------------------------- 1 | /* global slideshow */ 2 | (function () { 3 | const ready = function (fn) { 4 | /* MIT License Copyright (c) 2016 Nuclei */ 5 | /* https://github.com/nuclei/readyjs */ 6 | const completed = () => { 7 | document.removeEventListener('DOMContentLoaded', completed) 8 | window.removeEventListener('load', completed) 9 | fn() 10 | } 11 | if (document.readyState !== 'loading') { 12 | setTimeout(fn) 13 | } else { 14 | document.addEventListener('DOMContentLoaded', completed) 15 | window.addEventListener('load', completed) 16 | } 17 | } 18 | 19 | ready(function () { 20 | [...document.querySelectorAll('.panel-name')] 21 | .map(el => el.textContent.trim()) 22 | 23 | const randId = () => { 24 | // https://gist.github.com/6174/6062387 25 | return Math.random().toString(36).substring(2, 8) + 26 | Math.random().toString(36).substring(2, 8) 27 | } 28 | 29 | const processPanelItem = (item) => { 30 | const nameDiv = item.querySelector('.panel-name') 31 | let name = 'Panel' 32 | if (nameDiv) { 33 | name = nameDiv.textContent.trim() 34 | if (nameDiv.tagName === 'SPAN' && nameDiv.parentNode.tagName === 'P') { 35 | item.removeChild(nameDiv.parentNode) 36 | } else { 37 | item.removeChild(nameDiv) 38 | } 39 | } 40 | return { name, content: item.children, id: randId() } 41 | } 42 | 43 | const reflowPanelSet = (panels) => { 44 | const res = document.createElement('div') 45 | res.className = 'panelset' 46 | 47 | // create header row 48 | const headerRow = document.createElement('div') 49 | headerRow.className = 'panel-tabs' 50 | panels 51 | .map((p, idx) => { 52 | const panelHeaderItem = document.createElement('div') 53 | panelHeaderItem.className = 'panel-tab' 54 | panelHeaderItem.tabIndex = 0 55 | panelHeaderItem.classList.toggle('panel-tab-active', idx === 0) 56 | panelHeaderItem.innerHTML = p.name 57 | panelHeaderItem.dataset.for = p.id 58 | return panelHeaderItem 59 | }) 60 | .forEach(el => headerRow.appendChild(el)) 61 | 62 | res.appendChild(headerRow) 63 | 64 | panels 65 | .map((p, idx) => { 66 | const panelContent = document.createElement('div') 67 | panelContent.className = 'panel' 68 | panelContent.classList.toggle('panel-active', idx === 0) 69 | panelContent.id = p.id 70 | Array.from(p.content).forEach(el => panelContent.appendChild(el)) 71 | return panelContent 72 | }) 73 | .forEach(el => res.appendChild(el)) 74 | 75 | return res 76 | } 77 | 78 | const togglePanel = (clicked) => { 79 | if (!clicked.classList.contains('panel-tab')) return 80 | if (clicked.classList.contains('panel-tab-active')) return 81 | 82 | const tabs = clicked.parentNode 83 | .querySelectorAll('.panel-tab') 84 | const panels = clicked.parentNode.parentNode 85 | .querySelectorAll('.panel') 86 | 87 | Array.from(tabs) 88 | .forEach(t => t.classList.remove('panel-tab-active')) 89 | Array.from(panels) 90 | .forEach(p => p.classList.toggle('panel-active', p.id === clicked.dataset.for)) 91 | 92 | clicked.classList.add('panel-tab-active') 93 | } 94 | 95 | const initPanelSet = (panelset) => { 96 | const panels = Array.from(panelset.querySelectorAll('.panel')) 97 | const contents = panels.map(processPanelItem) 98 | const newPanelSet = reflowPanelSet(contents) 99 | panelset.parentNode.insertBefore(newPanelSet, panelset) 100 | panelset.parentNode.removeChild(panelset) 101 | 102 | newPanelSet 103 | .querySelector('.panel-tabs') 104 | .addEventListener('click', (ev) => togglePanel(ev.target)) 105 | 106 | newPanelSet 107 | .querySelector('.panel-tabs') 108 | .addEventListener('keydown', (ev) => { 109 | const self = ev.target 110 | if (ev.code === 'Space' || ev.code === 'Enter') { 111 | togglePanel(self) 112 | ev.stopPropagation() 113 | } else if (ev.code === 'ArrowLeft' && self.previousSibling) { 114 | togglePanel(self.previousSibling) 115 | self.previousSibling.focus() 116 | ev.stopPropagation() 117 | } else if (ev.code === 'ArrowRight' && self.nextSibling) { 118 | togglePanel(self.nextSibling) 119 | self.nextSibling.focus() 120 | ev.stopPropagation() 121 | } 122 | }) 123 | } 124 | 125 | Array.from( 126 | document.querySelectorAll('.panelset') 127 | ).map(initPanelSet) 128 | 129 | if (typeof slideshow !== 'undefined') { 130 | slideshow.on('afterShowSlide', slide => { 131 | // clear focus if we had a panel-tab selected 132 | document.activeElement.blur() 133 | 134 | const slidePanel = document 135 | .querySelector('.remark-visible .panel-tab-active') 136 | 137 | if (slidePanel) slidePanel.focus() 138 | }) 139 | } 140 | }) 141 | })() 142 | -------------------------------------------------------------------------------- /libs/remark.css: -------------------------------------------------------------------------------- 1 | /* colour scheme */ 2 | /* http://metrocolor.live */ 3 | @import url('https://fonts.googleapis.com/css?family=Assistant:400,700'); 4 | @import url('https://fonts.googleapis.com/css?family=Rosario'); 5 | @import url('https://fonts.googleapis.com/css?family=Caveat'); 6 | @import url(https://fonts.googleapis.com/css?family=Source+Code+Pro:400,500,600); 7 | @import url("https://use.fontawesome.com/releases/v5.13.0/css/all.css"); 8 | @import url("https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css"); 9 | @import url('https://fonts.googleapis.com/css2?family=Libre+Barcode+128+Text&display=swap'); 10 | 11 | body { 12 | font-family: 'Assistant', sans-serif; 13 | color: #1a2a3a; 14 | } 15 | h1, h2, h3 { 16 | margin-top: 5px; 17 | margin-bottom: 0; 18 | } 19 | .remark-slide-content h1 { font-size: 68px; } 20 | .remark-slide-content h2 { font-size: 58px; } 21 | .remark-slide-content h3 { font-size: 42px; } 22 | .remark-slide-content { 23 | background-color: #f2f1f6; 24 | background-position: center; 25 | background-repeat: no-repeat; 26 | display: table-cell; 27 | font-size: 36px; 28 | padding: 0px 30px; 29 | } 30 | .footnote { 31 | position: absolute; 32 | bottom: 1em; 33 | font-style: italic; 34 | font-size: 70%; 35 | } 36 | 37 | li { line-height: 1.65em; } 38 | li p { line-height: 1.25em; } 39 | ol { 40 | list-style: none; 41 | counter-reset: li; 42 | } 43 | ol li { 44 | counter-increment: li 45 | } 46 | ol li::before { 47 | content: ". "counter(li); 48 | color: #a84d18; 49 | display: inline-block; 50 | width: 1em; 51 | margin-right: 0.5em; 52 | text-align: right; 53 | direction: rtl; 54 | } 55 | ul li { 56 | list-style-type: none; 57 | } 58 | ul li:before { 59 | content: "\f201"; 60 | font-family: "Font Awesome\ 5 Free"; 61 | margin-right: 10px; 62 | color: #4ba946; 63 | font-weight: 900; 64 | } 65 | ul li li:before { 66 | content: "\f1fe"; 67 | font-family: "Font Awesome\ 5 Free"; 68 | margin-right: 10px; 69 | font-weight: 900; 70 | } 71 | .x ul li:before { 72 | content: "\f00d"; 73 | font-family: "Font Awesome\ 5 Free"; 74 | color: #D00000; 75 | font-weight: 900; 76 | } 77 | .checked ul li:before { 78 | content: "\f00c"; 79 | font-family: "Font Awesome\ 5 Free"; 80 | color: #31a354; 81 | font-weight: 900; 82 | } 83 | 84 | .purple{ color: #c077af; } 85 | .red { color: #ef342a; } 86 | .orange { color: #f57125; } 87 | .blue { color: #22b6ed; } 88 | .green { color: #1fb27f; } 89 | .yellow { color: #faca07; } 90 | .brown {color: #a84d18; } 91 | 92 | .rotate-45 {transform: rotate(45deg); } 93 | .large { font-size: 120%; } 94 | .small { font-size: 80%; } 95 | 96 | .center { 97 | text-align: center; 98 | } 99 | 100 | a, a > code { 101 | text-decoration: none; 102 | color: #f45f7c; 103 | } 104 | code { 105 | background: #f8f8f8; 106 | border-radius: 5px; 107 | } 108 | .remark-code, .remark-inline-code { font-family: 'Source Code Pro'; font-size: 80%; } 109 | .remark-code, .remark-code-line { font-family: 'Source Code Pro'; font-size: 82%; } 110 | .remark-code-line-highlighted { 111 | background-color: #d0e4a9; 112 | } 113 | 114 | .pull-left { 115 | float: left; 116 | width: 49%; 117 | } 118 | .pull-right { 119 | float: right; 120 | width: 49%; 121 | } 122 | .pull-right ~ p { 123 | clear: both; 124 | } 125 | #slideshow .slide .content code { 126 | font-size: 0.8em; 127 | } 128 | #slideshow .slide .content pre code { 129 | font-size: 0.9em; 130 | padding: 15px; 131 | } 132 | .inverse { 133 | background: #69686d; 134 | color: #f2f2f6; 135 | } 136 | .inverse a { 137 | color: #b2d68c; 138 | } 139 | .inverse h1, .inverse h2 { 140 | color: #f2f2f6; 141 | font-size: 72px; 142 | line-height: 1.2em; 143 | } 144 | 145 | /* Slide-specific styling */ 146 | #slide-inverse .footnote { 147 | bottom: 12px; 148 | left: 20px; 149 | } 150 | #slide-how .slides { 151 | font-size: 0.9em; 152 | position: absolute; 153 | top: 151px; 154 | right: 140px; 155 | } 156 | #slide-how .slides h3 { 157 | margin-top: 0.2em; 158 | } 159 | #slide-how .slides .first, #slide-how .slides .second { 160 | padding: 1px 20px; 161 | height: 90px; 162 | width: 120px; 163 | -moz-box-shadow: 0 0 10px #777; 164 | -webkit-box-shadow: 0 0 10px #777; 165 | box-shadow: 0 0 10px #777; 166 | } 167 | #slide-how .slides .first { 168 | background: #fff; 169 | position: absolute; 170 | top: 20%; 171 | left: 20%; 172 | z-index: 1; 173 | } 174 | #slide-how .slides .second { 175 | position: relative; 176 | background: #fff; 177 | z-index: 0; 178 | } 179 | 180 | /* Two-column layout */ 181 | .left-column { 182 | color: #777; 183 | width: 20%; 184 | height: 92%; 185 | float: left; 186 | } 187 | .left-column h2:last-of-type, .left-column h3:last-child { 188 | color: #000; 189 | } 190 | .right-column { 191 | width: 75%; 192 | float: right; 193 | } 194 | 195 | .title-slide { 196 | background: #4dc7ec; 197 | } 198 | 199 | .title-slide h1 { 200 | font-family: 'Rosario', sans-serif; 201 | font-size: 92px; 202 | line-height: 1.2em; 203 | color: #f2f1f6; 204 | text-align: left !important; 205 | vertical-align: middle !important; 206 | } 207 | 208 | .title-slide h3 { 209 | font-family: 'Caveat', cursive; 210 | font-size: 62px; 211 | color: #f8c9cb; 212 | text-align: right !important; 213 | border-top: 5px solid #f2f1f6; 214 | } 215 | 216 | .title-slide .remark-slide-number { 217 | display: none; 218 | } 219 | 220 | .remark-slide-number { 221 | position: inherit; 222 | } 223 | 224 | .remark-slide-number .progress-bar-container { 225 | position: absolute; 226 | bottom: 0; 227 | height: 4px; 228 | display: block; 229 | left: 0; 230 | right: 0; 231 | } 232 | 233 | .remark-slide-number .progress-bar { 234 | height: 100%; 235 | background-color: #ef342a; 236 | } 237 | 238 | blockquote { 239 | background: #f9f9f9; 240 | border-left: 10px solid #ccc; 241 | margin: 50px 10px; 242 | padding: 10px 30px; 243 | quotes: "\201C""\201D""\2018""\2019"; 244 | font-style: italic; 245 | font-size: 42px; 246 | } 247 | 248 | blockquote:before { 249 | color: #ccc; 250 | content: open-quote; 251 | font-size: 4em; 252 | line-height: 0.1em; 253 | margin-right: 0.25em; 254 | vertical-align: -0.4em; 255 | } 256 | 257 | .alert { 258 | border-color: #ef342a; 259 | border-width: 2px; 260 | border-style: solid; 261 | } 262 | 263 | .card { 264 | display: inline-block; 265 | background: #fff; 266 | box-shadow: 0 2px 4px 0 #00000033; 267 | transition: all 0.2s ease-out; 268 | border-radius: 5px; 269 | padding: 5px; 270 | margin: 5px; 271 | } 272 | 273 | .card img { 274 | display: block; 275 | padding-bottom: 10px; 276 | height: 180px; 277 | width: auto; 278 | margin-left: auto; 279 | margin-right: auto; 280 | } 281 | 282 | /* talk-specific */ 283 | 284 | .title-slide img { 285 | height: 6.5rem; 286 | width: auto; 287 | display: inline; 288 | } 289 | 290 | .pipeline img { 291 | display: block; 292 | position: absolute; 293 | margin-left: 28%; 294 | margin-top: 20%; 295 | } 296 | 297 | .encoding { 298 | font-family: 'Libre Barcode 128 Text', cursive; 299 | } 300 | -------------------------------------------------------------------------------- /img/kunoichi.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /index.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Presenting like a kunoichi ![kunoichi](img/kunoichi.svg) with `r emo::ji('crossed_swords')`aringan" 3 | type: "meetup" 4 | author: "Earo Wang" 5 | date: "" 6 | output: 7 | xaringan::moon_reader: 8 | includes: 9 | after_body: "libs/typed.js" 10 | css: ["libs/remark.css"] 11 | lib_dir: libs 12 | nature: 13 | ratio: 16:9 14 | highlightStyle: github 15 | highlightLines: true 16 | countIncrementalSlides: false 17 | beforeInit: "libs/macros.js" 18 | slideNumberFormat: | 19 |
20 |
21 |
22 |
23 | --- 24 | 25 | class: middle 26 | 27 | ```{r setup, echo = FALSE, cache = FALSE, results = 'hide'} 28 | library(knitr) 29 | options( 30 | htmltools.dir.version = FALSE, tibble.width = 60, tibble.print_min = 6, 31 | crayon.enabled = TRUE 32 | ) 33 | opts_chunk$set( 34 | echo = FALSE, warning = FALSE, message = FALSE, comment = "#>", 35 | fig.path = 'figure/', fig.align = 'center', fig.height = 8.5, 36 | out.width = '100%', fig.show = 'hold', fig.retina = 3, 37 | cache = TRUE, cache.path = 'cache/' 38 | ) 39 | ``` 40 | 41 | .pull-left[ 42 | ```{r hello} 43 | cowsay::say("Kia Ora! I'm Earo.", by = "anxiouscat") 44 | ``` 45 | ] 46 | 47 | -- 48 | 49 | .pull-right[ 50 |
51 |
52 |
53 | I'm a ~~lecturer~~ zoomer. 54 | 55 | package developer 56 | 57 | .typed[] 58 | ] 59 | 60 | ??? 61 | 62 | * Kia ora koutou. 63 | * Most of us will feel nervous when start presenting, like this anxious cat. But will calm down 64 | * Joined as a lecturer, turned out a zoomer, lecturer in pyjamas 65 | * The only thing I managed to upskill is zoom in the past 6 months. 66 | * At Uni, I teach data science, do research on data str, data wrangling, data vis 67 | * I make my research methods available in the form of R packages, developed a bunch of R packages. 68 | 69 | --- 70 | 71 | ## My PhD timeline 72 | 73 | ![:scale 100%](https://thesis.earo.me/img/phd-commits.png) 74 | 75 | ??? 76 | 77 | * Completed my PhD at Monash U 78 | * This beeswarm plot: gh commits 79 | * As a PhD student, my academic activities are roughly grouped into 3 cat: writing, coding, and presenting 80 | * 3 chapters, 3 packages, presenting those packages for ts. 81 | * In the past 3 years, I've given 15 talks, formal or informal. Academic seminars, conferences, meetups, workshops. 82 | * I started trying out html5 slides when I started PhD in 2016. I was bored with latex beamer. 83 | * The most impressive h5 slides is impress.js. It's a competing distraction from your talk for audience. They get excited not for your work but this presentation format. 84 | * I finally settled with xaringan when it was first out in 2016 Dec. 85 | * Interestingly, the first public talk I gave using xaringan, at the wombat conference. Yihui was sitting there. He was invited for the keynote. 86 | 87 | --- 88 | 89 | class: inverse middle center 90 | 91 | .pull-left[ 92 |
93 | # Opinionated kunoichi 94 |
95 | # Non-opinionated xaringan 96 | ] 97 | .pull-right[ 98 | ![:scale 45%](img/kunoichi.svg) 99 | 100 | ![:scale 45%](https://upload.wikimedia.org/wikipedia/commons/b/be/Sharingan_triple.svg) 101 | ] 102 | 103 | ??? 104 | 105 | * divided into 2 parts 106 | * first: how to be a kunoichi presenter, which is quite opinionated 107 | * Bc I'm going to share what I've learnt while presenting. No hard rules about presenting 108 | * Grad schools deliver workshops on presentation tips, 109 | * We learn presenting by presenting ourself 110 | * And the second part is not opinionated. It's about xaringan. 111 | 112 | --- 113 | 114 | class: inverse middle center 115 | 116 | .pull-left[ 117 | .animate__animated.animate__bounceInDown[ 118 | ![kunoichi](img/kunoichi.svg) 119 | ] 120 | ] 121 | .pull-right[ 122 |
123 |
124 | # HTML.orange[] 125 |
126 | # Creative 127 | # Unconventional 128 | ] 129 | 130 | ??? 131 | 132 | * Kunoichi is a Japanese word for female ninja, an unconventional presenter 133 | * We can creatively use our tones, gestures, facial expressions, but mostly visuals on the slides to express our thoughts, and communicate our findings. 134 | * To design those visuals, we need to choose tools, and tools shouldn't be a constraint, when we want to be creative and expressive. 135 | * Using latex beamer, I can't embed youtube videos, interactive graphics. 136 | * But HTML5 slides leverages the whole web technology, and allow me to produce creative visuals when needed. 137 | * JSM talk, your presentation is so different. Why not present different? 138 | 139 | ## Creative formats 140 | 141 | * Lightning talk vs TikTok 142 | * 20 minutes talk vs Youtube 143 | * 1 hour talk vs Documentary 144 | 145 | ## Onsite vs remote presentations 146 | 147 | * Laugh alone (no passive laugh) 148 | * Presentation vs conversation tone 149 | * Not sure when to pause 150 | 151 | --- 152 | 153 | ## .right[`r emo::ji("hammer_and_wrench")` Crafting] 154 | 155 |
156 | .alert[ 157 | .large[ 158 | 1. Opening slide 159 | 2. Motivating slide 160 | 3. Closing slide 161 | ] 162 | ] 163 | 164 | ??? 165 | 166 | * No matter what type of talk we give, (lightning) we'll have these 3 slides: 167 | * We do want to craft them well. Bc they are on the screen much longer than the rest of the slides. 168 | * I'll use my own slides as case studies. 169 | 170 | --- 171 | 172 | .pull-left[ 173 |
174 | ## .center[Designing title slide] 175 | 176 | 1. Bigger than big font size 177 | 2. Background image 178 | 3. Google fonts 179 | 4. Handles 180 | 5. URLs 181 | ] 182 | .pull-right[ 183 | ![:scale 100%](https://slides.earo.me/rstudioconf19/img/slides-title.png) 184 | ![:scale 100%](img/alison-jsm.png) 185 | ] 186 | 187 | ??? 188 | 189 | * Title slide stays longer on the screen, bc you set up the computer 190 | * In short talks, you introduce yourself in the beginning without an extra intro slide. 191 | * font: cliche 192 | * image: evocative. I don't do it, lazy, rearrange the text positions. 193 | * Occasionally, I chose evocative fonts. Another good thing about H5 slides is we can use google fonts on the fly. 991 194 | * FA icon, but now have no idea why I chose a Halloween colour theme for a conference held in Jan. 195 | * wondering if I presented tidy ts, or spooky ts 196 | * handles: live tweeting 197 | * URLs (I don't share my slides url upfront anymore, to focus on my talk atm) 198 | * But venue is big, screen is small, URLs first 199 | 200 | --- 201 | 202 | class: inverse middle 203 | 204 | # Motivating ???? .blue[`beta`] 205 |
206 | ## `r emo::ji("woman_facepalming")` 207 | 208 | ??? 209 | 210 | * A critical lesson I learnt from my past talks is motivation matters. 211 | * Motivating well will help set the tone for a successful talk. Bc motivation slides come after the title. 212 | * To accumulate audience's interest and grab their attention, the first 5 minutes is the key. 213 | * I'll give you a facepalming version of how I motivated the tsibble package 214 | 215 | --- 216 | 217 | class: center middle 218 | 219 | background-image: url(img/tsibble-useR.png) 220 | background-size: cover 221 | 222 | -- 223 | 224 | ![:scale 30%](img/cat-eye-rolling.gif) 225 | 226 | ??? 227 | 228 | * My first tsibble talk was an internal department talk. This is the motivation page of tsibble in the early stage. 229 | * The targeted audience is my PhD committee, a small group of faculties and PhD students. 230 | * I thought I was telling my committee. Look I'm not talking about software, I'm talking about matrix. I'm doing serious research. 231 | * The problem is I repeated this slide at useR! and NYC R meetups. Diverse backgrounds 232 | * This slide is made for insiders who know ts in R well, and a narrow focus. 233 | * As you could imagine, half of my audience would lost the interests after this slide. 234 | 235 | --- 236 | 237 | class: inverse middle 238 | 239 | ## Motivating well .blue[`v1.0.0`] 240 |
241 | ## `r emo::ji("dancer")` 242 | 243 | ??? 244 | 245 | * Rethink and Redesign tsibble motivation 246 | * After a couple of iterations, I'm finally happy with the current version, helped me to write my tsibble paper too. 247 | 248 | --- 249 | 250 | .left-column[ 251 |
252 |
253 | ## .center[.red[time series verse]] 254 | ] 255 | .right-column[ 256 |
257 |
258 | ![:scale 100%](img/ts-model.png) 259 | ] 260 | 261 | ### .center[WAT!`r emo::ji("scream")`] 262 | 263 | ??? 264 | 265 | Include audience who are not just insiders, but also data scientists in general. 266 | 267 | --- 268 | 269 | background-image: url(img/tsibble-model.png) 270 | background-size: 70% 271 | background-position: 91% 38% 272 | 273 | .left-column[ 274 |
275 |
276 |
277 |
278 | ## .center[tidyver.red[ts]] 279 | ] 280 | .right-column[ 281 | .animate__animated.animate__rollIn.animate__slower[ 282 | .pipeline[] 283 | ] 284 | ] 285 | 286 | ??? 287 | 288 | * I switched my focus for tsibble, more than a matrix vs a data frame, but a workflow facilitator 289 | * Particularly designed this cool animation for tsibble to fill the gap and drop into a larger context 290 | * Attract users who don't play with time series data. 291 | * Now I spend lots of time on designing motivation slide. 292 | 293 | --- 294 | 295 | class: center middle inverse 296 | 297 | # Thank you! 298 | 299 | -- 300 | 301 | # Questions? 302 | 303 | -- 304 | 305 | # Fin 306 | 307 | --- 308 | 309 | class: center middle inverse 310 | 311 | .animate__animated.animate__hinge[ 312 | # Thank you! 313 | # Questions? 314 | # Fin 315 | ] 316 | 317 | ??? 318 | 319 | * The closing slide is an important background when you answering questions. 320 | * But almost zero information. 321 | 322 | --- 323 | 324 | ## .center[`r emo::ji("camera_flash")` Closing slide with `r emo::ji("link")``r emo::ji("link")``r emo::ji("link")`] 325 | 326 | .pull-left[ 327 |
328 | .center[.card[ 329 | ![](img/rladiesakl20.png) 330 | .small[[slides.earo.me/rladiesakl20](https://slides.earo.me/rladiesakl20)] 331 | ] 332 | ] 333 | ] 334 | .pull-right[ 335 |
336 | `r emo::ji("memo")` [Carpe Talk](https://www.tidyverse.org/blog/2018/07/carpe-talk/) by Jenny Bryan and Mara Averick 337 |
338 | `r emo::ji("memo")` [Guidelines I follow when giving talks](https://www.amelia.mn/blog/misc/2020/04/16/presentations.html) by Amelia McNamara 339 |
340 | `r emo::ji("memo")` [How to Present Good](http://www.rebeccabarter.com/blog/2017-02-02-how-to-present-good/) by Rebecca Barter 341 | ] 342 | 343 | ??? 344 | 345 | * Ending talks with resources, I'll say "Thank you" 346 | * If useful and helpful, they take out their phones and fire up the cameras. They will do their homeworks 347 | * 3 blog posts and 4 great presenters in the R community. 348 | * Bc slides are in html, you probably would like a short URL to link to the slides. 349 | 350 | --- 351 | 352 | class: inverse middle 353 | 354 | .right[ 355 | # Presenting is fun 356 | # `r emo::ji("crossed_swords")`aringan is .purple[creative fun] 357 | ] 358 | 359 | -- 360 | 361 | .large[ 362 | .blue[1.] Jot down in 363 | 364 | .blue[2.] Prettify with 365 | 366 | .blue[3.] Interact with 367 | ] 368 | 369 | ??? 370 | 371 | * Presenting is fun, and xaringan adds more creative fun on top it. 372 | * I hope I accumulate your interests for xaringan, time to talk about it. 373 | * You might think, xaringan is cool, fancy, and dynamic 374 | * The most appealing reason to use xaringan for me is it naturally fits into presentation workflow. 375 | 376 | 1. pour down all your thoughts and ideas in markdown 377 | 2. style them with css 378 | 3. for more engaging slides, add js 379 | 380 | Unlike other h5 slides or latex beamer, e.g slidyfy, it's highly customisable and easy to customise. 381 | 382 | --- 383 | 384 | ## Learn? Unbox and use! 385 | 386 | .pull-left[ 387 | ```r 388 | install.packages("xaringan") 389 | ``` 390 | .center[![:scale 75%](img/rstudio-xaringan.png)] 391 | ] 392 | .pull-right[ 393 | ```yml 394 | --- 395 | title: "Presentation Ninja" 396 | subtitle: "⚔
with xaringan" 397 | author: "Yihui Xie" 398 | institute: "RStudio, PBC" 399 | date: "2016/12/12 (updated: `r Sys.Date()`)" 400 | output: 401 | * xaringan::moon_reader: 402 | lib_dir: libs 403 | nature: 404 | highlightStyle: github 405 | highlightLines: true 406 | countIncrementalSlides: false 407 | --- 408 | ``` 409 | ] 410 | 411 | ??? 412 | 413 | * We don't learn markdown. Similarly, we don't learn xaringan. No such a thing called "learning curve" 414 | * install 415 | * in rstudio, create rmarkdown 416 | * It generates an example document for you, full of markdown tips 417 | * Like other RMarkdown documents, yaml, go through yaml 418 | * Click "knit" button, you'll get this slide 419 | 420 | --- 421 | 422 | .center[ 423 | `r emo::ji("point_down")` (nested) slides 424 | 426 | ] 427 | 428 | .footnote[`