├── .gitignore ├── 2022-04-07-inf406demo.R ├── HOCKING-exercises.R ├── HOCKING-handout.pdf ├── HOCKING-handout.tex ├── HOCKING-solutions.R ├── IntGraph-example-animint.R ├── IntGraph.Rmd ├── IntGraph.html ├── Makefile ├── README-old.org ├── README.org ├── README.tex ├── animation ├── README.org └── WorldBank │ ├── animation.R │ ├── animint.R │ ├── ggvis │ ├── server.r │ ├── test.r │ └── ui.r │ ├── shiny │ ├── server.r │ └── ui.r │ └── shinyDX │ ├── global.r │ ├── server.r │ └── ui.r ├── app2.R ├── contacts.org ├── img ├── HOCKING-lab-2015.jpg ├── Logo_D3.png ├── RJavaHtml.png ├── RJavaHtml.svg ├── Rlogo.png ├── client.png ├── clientserver.png ├── danstat.png ├── dygraphs.png ├── ekstrom-2014.jpg ├── fedtsyre.pdf ├── fedtsyre.png ├── fedtsyrer1.pdf ├── fedtsyrer1.png ├── fedtsyrer2.pdf ├── fedtsyrer2.png ├── frustration20logo.jpg ├── highcharter.png ├── html5-css3-js-logo.png ├── kahoot.png ├── leaflet.png ├── metgraph.png ├── napoleon.jpg ├── nature.png ├── nvd3.jpg ├── plotly.png ├── primer-image.jpg ├── primer-image.png ├── wally.png └── wordcloud_DKnewbornnames_2014.png ├── intreg.Rmd ├── introduction-vocabulary.Rmd ├── packages-old.R ├── packages.R ├── syllabus.tex ├── tutorial-prop.tex └── useR2016pack.R /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .Rhistory 3 | .httr-oauth 4 | -------------------------------------------------------------------------------- /2022-04-07-inf406demo.R: -------------------------------------------------------------------------------- 1 | library(animint2) 2 | data(WorldBank, package="animint2") 3 | years <- unique(WorldBank[, "year", drop=FALSE]) 4 | y1960 <- subset(WorldBank, year==1960) 5 | viz <- animint( 6 | title="Linked scatterplot and time series", #web page title. 7 | time=list(variable="year",ms=3000), #variable and time delay used for animation. 8 | duration=list(year=1000), #smooth transition duration in milliseconds. 9 | selector.types=list(country="multiple"), #single/multiple selection for each variable. 10 | first=list( #selected values to show when viz is first rendered. 11 | country=c("Canada", "Japan"), 12 | year=1970), 13 | ## ggplots are rendered together for an interactive data viz. 14 | ts=ggplot()+ 15 | theme_animint(width=500)+ 16 | make_tallrect(WorldBank, "year")+ 17 | geom_text(aes( 18 | year, life.expectancy, label=country), 19 | showSelected="country", 20 | clickSelects="country", 21 | hjust=1, 22 | data=y1960)+ 23 | scale_x_continuous(limits=c(1950, NA))+ 24 | geom_line(aes( 25 | year, life.expectancy, group=country, color=region), 26 | clickSelects="country", 27 | data=WorldBank, 28 | size=4, 29 | alpha=0.55), 30 | scatter=ggplot()+ 31 | geom_point(aes( 32 | fertility.rate, life.expectancy, 33 | key=country, colour=region, size=population), 34 | showSelected="year", 35 | clickSelects="country", 36 | data=WorldBank)+ 37 | geom_text(aes( 38 | fertility.rate, life.expectancy, 39 | key=country, 40 | label=country), 41 | showSelected=c("country", "year"), 42 | data=WorldBank)+ 43 | geom_text(aes( 44 | 5, 80, key=1, label=paste("year =", year)), 45 | showSelected="year", 46 | data=years)+ 47 | scale_size_animint(pixel.range=c(2,20), breaks=10^(4:9))) 48 | 49 | WorldBank1975 <- subset(WorldBank, year==1975) 50 | WorldBankBefore1975 <- subset(WorldBank, 1970 <= year & year <= 1975) 51 | two.layers <- ggplot()+ 52 | geom_point( 53 | mapping=aes(x=life.expectancy, y=fertility.rate, color=region), 54 | data=WorldBank1975)+ 55 | geom_path(aes( 56 | x=life.expectancy, y=fertility.rate, color=region, 57 | group=country), 58 | data=WorldBankBefore1975) 59 | (viz.two.layers <- animint(two.layers)) 60 | 61 | 62 | timeSeries <- ggplot()+ 63 | geom_line(aes( 64 | x=year, y=fertility.rate, 65 | color=region, group=country), 66 | data=WorldBank) 67 | 68 | animint(two.layers, timeSeries) 69 | 70 | animint(ggplot()+ 71 | facet_grid(. ~ panel, scales="free")+ 72 | geom_point( 73 | mapping=aes(x=life.expectancy, y=fertility.rate, color=region), 74 | data=data.frame(panel="life expectancy", WorldBank1975))+ 75 | geom_path(aes( 76 | x=life.expectancy, y=fertility.rate, color=region, 77 | group=country), 78 | data=data.frame(panel="life expectancy", WorldBankBefore1975))+ 79 | geom_line(aes( 80 | x=year, y=fertility.rate, 81 | color=region, group=country), 82 | data=data.frame(panel="year", WorldBank))) 83 | -------------------------------------------------------------------------------- /HOCKING-exercises.R: -------------------------------------------------------------------------------- 1 | library(animint) 2 | data(WorldBank, package="animint") 3 | WorldBank1975 <- subset(WorldBank, year==1975) 4 | 5 | ## Ch2 Exercise 1: try changing the aes mapping of the ggplot, and 6 | ## then making a new animint. Quantitative variables like population 7 | ## are best shown using the x/y axes or point size. Qualitative 8 | ## variables like lending are best shown using point color or fill. 9 | viz.1975 <- list( 10 | scatter=ggplot()+ 11 | geom_point( 12 | mapping=aes( 13 | x=life.expectancy, 14 | y=fertility.rate, 15 | color=region), 16 | data=WorldBank1975)) 17 | structure(viz.1975, class="animint") 18 | 19 | ## Ch2 Exercise 2: use animint to create a data viz with three plots, 20 | ## by creating a list with three ggplots. 21 | WorldBankBefore1975 <- subset(WorldBank, 1970 <= year & year <= 1975) 22 | viz.several.plots <- list( 23 | scatter=ggplot()+ 24 | geom_point( 25 | mapping=aes( 26 | x=life.expectancy, 27 | y=fertility.rate, 28 | color=region), 29 | data=WorldBank1975)+ 30 | geom_path( 31 | aes( 32 | x=life.expectancy, 33 | y=fertility.rate, 34 | color=region, 35 | group=country), 36 | data=WorldBankBefore1975), 37 | tsFert=ggplot()+ 38 | geom_line(aes(x=year, y=fertility.rate, color=region, group=country), 39 | data=WorldBank)) 40 | structure(viz.several.plots, class="animint") 41 | 42 | ## Ch3 Exercise 1: add another geom or plot with 43 | ## aes(showSelected=year) to the following data viz. 44 | viz.scatter <- list( 45 | scatter=ggplot()+ 46 | geom_point(aes(x=life.expectancy, y=fertility.rate, color=region, 47 | showSelected=year), 48 | data=WorldBank)) 49 | structure(viz.scatter, class="animint") 50 | 51 | ## Ch3 Exercise 2: make an animated data viz that does NOT use smooth 52 | ## transitions. 53 | 54 | ## Ch4 Exercise 1: how to get the geom_text to disappear along with 55 | ## the point when the region legend is clicked? Hint: add one aes to 56 | ## the geom_text. 57 | viz.text <- list( 58 | scatter=ggplot()+ 59 | geom_point(aes(x=life.expectancy, y=fertility.rate, color=region, 60 | key=country, 61 | showSelected=year, 62 | clickSelects=country), 63 | data=WorldBank)+ 64 | geom_text(aes(x=life.expectancy, y=fertility.rate, label=country, 65 | key=country, 66 | showSelected=year, 67 | showSelected2=country), 68 | data=WorldBank), 69 | duration=list(year=2000)) 70 | structure(viz.text, class="animint") 71 | 72 | ## Ch4 Exercise 2: how to get the geom_text to disappear when you 73 | ## click it? Hint: add one aes to the geom_text. 74 | viz.multiple <- list( 75 | scatter=ggplot()+ 76 | geom_point(aes(x=life.expectancy, y=fertility.rate, color=region, 77 | key=country, 78 | showSelected=year, 79 | clickSelects=country), 80 | data=WorldBank)+ 81 | geom_text(aes(x=life.expectancy, y=fertility.rate, label=country, 82 | key=country, 83 | showSelected=year, 84 | showSelected2=country, 85 | showSelected3=region), 86 | data=WorldBank), 87 | first=list( 88 | year=1970, 89 | country="United States", 90 | region=c("North America", "South Asia")), 91 | selector.types=list(country="multiple"), 92 | duration=list(year=2000)) 93 | structure(viz.multiple, class="animint") 94 | 95 | ## Ch4 Exercise 3: add layers to the scatterplot in the following data 96 | ## viz, and animate it! 97 | viz.timeSeries <- viz.multiple 98 | years <- data.frame(year=unique(WorldBank$year)) 99 | viz.timeSeries$timeSeries <- ggplot()+ 100 | geom_tallrect(aes(xmin=year-0.5, xmax=year+0.5, 101 | clickSelects=year), 102 | alpha=0.5, 103 | data=years)+ 104 | geom_line(aes(x=year, y=fertility.rate, group=country, color=region, 105 | clickSelects=country), 106 | size=3, 107 | alpha=0.6, 108 | data=WorldBank) 109 | structure(viz.timeSeries, class="animint") 110 | -------------------------------------------------------------------------------- /HOCKING-handout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/HOCKING-handout.pdf -------------------------------------------------------------------------------- /HOCKING-handout.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[cm]{fullpage} 4 | \usepackage{hyperref} 5 | 6 | \begin{document} 7 | 8 | \title{90-minute animint tutorial} \author{Toby Dylan Hocking} 9 | \maketitle 10 | \thispagestyle{empty} 11 | 12 | \subsection*{Intro to animation and direct manipulation (5 min)} 13 | 14 | \url{https://github.com/tdhock/interactive-tutorial} 15 | 16 | \subsection*{Animint manual Ch2: basics of ggplot2 (25 min)} 17 | 18 | \url{http://cbio.ensmp.fr/~thocking/animint-book/Ch02-ggplot2.html} 19 | 20 | %\subsection*{Translating sketches to ggplots and animints} 21 | \hrulefill 22 | 23 | \textbf{Sketching} a data viz on paper can be useful, since the sketch 24 | can be directly translated into R+ggplot2 code. 25 | 26 | A \textbf{ggplot} consists of one or more geoms, each with its own 27 | data set and aesthetic mapping. 28 | 29 | An \textbf{animint} \texttt{viz} is a list of ggplots and options 30 | which can be rendered via \verb|structure(viz, class="animint")|. 31 | 32 | \textbf{Exercise:} re-make interactive scatterplot of World Bank data, 33 | using a different aes mapping. 34 | 35 | \hrulefill 36 | 37 | %\subsection*{Multi-layer and multi-plot animints} 38 | 39 | \textbf{Multi-layer} graphics consist of ggplots with several geoms. 40 | 41 | A \textbf{multi-plot} animint \texttt{viz} list contains more than one 42 | ggplot. 43 | 44 | \textbf{Exercise:} create an animint with three ggplots. 45 | 46 | \subsection*{Animint manual Ch3: showSelected (25 min)} 47 | 48 | \url{http://cbio.ensmp.fr/~thocking/animint-book/Ch03-showSelected.html} 49 | 50 | \hrulefill 51 | 52 | \texttt{aes(showSelected=variable)} means to only show data for the 53 | selected value of \texttt{variable}. 54 | 55 | \textbf{Exercise:} add another geom or plot to the previous data viz. 56 | 57 | \hrulefill 58 | 59 | \textbf{Smooth transitions} can be specified using 60 | e.g. \texttt{duration=list(year=2000)},\\and then for each geom with 61 | \texttt{aes(showSelected=year)}, you should specify \texttt{aes(key)}. 62 | 63 | \textbf{Animation} can be specified using 64 | e.g. \texttt{time=list(variable="year", ms=2000)}. 65 | 66 | \textbf{Exercise:} make a data viz with animation but without smooth 67 | transitions. 68 | 69 | \subsection*{Animint manual Ch4: clickSelects (25 min)} 70 | \url{http://cbio.ensmp.fr/~thocking/animint-book/Ch04-clickSelects.html} 71 | 72 | \hrulefill 73 | 74 | \texttt{aes(clickSelects=variable)} means clicking the geom changes 75 | the selected value of \texttt{variable}. 76 | 77 | \textbf{Exercise:} make the country text label disappear when the 78 | corresponding region is de-selected. 79 | 80 | \hrulefill 81 | 82 | \texttt{first=list(year=1970)} means that the year 1970 should be 83 | selected when the data viz is first rendered. 84 | 85 | \texttt{selector.types=list(country="multiple")} means to use multiple 86 | selection for the \texttt{country} variable. 87 | 88 | \textbf{Exercise:} make clicking a country text label de-select that 89 | country. 90 | 91 | \hrulefill 92 | 93 | \verb|geom_tallrect| occupies the entire vertical space, so only 94 | \texttt{aes(xmin,xmax)} need to be specified. 95 | 96 | \textbf{Exercise:} add layers to the scatterplot, and animate the data viz. 97 | 98 | \end{document} 99 | -------------------------------------------------------------------------------- /HOCKING-solutions.R: -------------------------------------------------------------------------------- 1 | library(animint) 2 | data(WorldBank, package="animint") 3 | WorldBank1975 <- subset(WorldBank, year==1975) 4 | 5 | ## Ch2 Exercise 1: try changing the aes mapping of the ggplot, and 6 | ## then making a new animint. Quantitative variables like population 7 | ## are best shown using the x/y axes or point size. Qualitative 8 | ## variables like lending are best shown using point color or fill. 9 | viz.1975 <- list( 10 | scatter=ggplot()+ 11 | geom_point( 12 | mapping=aes( 13 | x=as.numeric(paste(longitude)), 14 | y=as.numeric(paste(latitude)), 15 | color=region, 16 | size=population), 17 | data=WorldBank1975)+ 18 | scale_size_animint(breaks=10^(9:5))) 19 | structure(viz.1975, class="animint") 20 | 21 | ## Ch2 Exercise 1: use animint to create a data viz with three plots, 22 | ## by creating a list with three ggplots. 23 | WorldBankBefore1975 <- subset(WorldBank, 1970 <= year & year <= 1975) 24 | viz.three.plots <- list( 25 | scatter=ggplot()+ 26 | geom_point( 27 | mapping=aes( 28 | x=life.expectancy, 29 | y=fertility.rate, 30 | color=region), 31 | data=WorldBank1975)+ 32 | geom_path( 33 | aes( 34 | x=life.expectancy, 35 | y=fertility.rate, 36 | color=region, 37 | group=country), 38 | data=WorldBankBefore1975), 39 | tsFert=ggplot()+ 40 | geom_line(aes(x=year, y=fertility.rate, color=region, group=country), 41 | data=WorldBank), 42 | tsLife=ggplot()+ 43 | geom_line(aes(x=year, y=life.expectancy, color=region, group=country), 44 | data=WorldBank)) 45 | structure(viz.three.plots, class="animint") 46 | 47 | ## Ch3 Exercise 1: add another geom. Just add some more geoms with 48 | ## aes(showSelected=year) to the data viz. 49 | years <- data.frame(year=unique(WorldBank$year)) 50 | tails.list <- list() 51 | WorldBank$other.year <- WorldBank$year 52 | for(year.value in years$year){ 53 | ## For every year, compute the tail (geom_path) which is the data 54 | ## for the previous 5 years. 55 | one.tail <- subset( 56 | WorldBank, year.value-5 <= other.year & other.year <= year.value) 57 | one.tail$year <- year.value 58 | tails.list[[paste(year.value)]] <- one.tail 59 | } 60 | tails <- do.call(rbind, tails.list) 61 | viz.scatter <- list( 62 | scatter=ggplot()+ 63 | geom_path(aes(x=life.expectancy, y=fertility.rate, color=region, 64 | group=country, 65 | showSelected=year), 66 | data=tails)+ 67 | geom_point(aes(x=life.expectancy, y=fertility.rate, color=region, 68 | showSelected=year), 69 | data=WorldBank)+ 70 | geom_text(aes(55, 9, label=paste("year =", year), 71 | showSelected=year), 72 | data=years)) 73 | structure(viz.scatter, class="animint") 74 | 75 | ## Ch3 Exercise 1: add another plot. Just add another ggplot to the 76 | ## viz list. 77 | viz.scatter.ts <- viz.scatter 78 | viz.scatter.ts$tsFert <- ggplot()+ 79 | geom_line(aes(x=year, y=fertility.rate, color=region, group=country), 80 | data=WorldBank)+ 81 | geom_vline(aes(xintercept=year, showSelected=year), data=years) 82 | structure(viz.scatter.ts, class="animint") 83 | 84 | ## Ch3 Exercise 2: make an animated data viz that does NOT use smooth 85 | ## transitions. Just add the "time" option to the viz list. 86 | viz.anim.only <- viz.scatter.ts 87 | viz.anim.only$time <- list(variable="year", ms=1000) 88 | structure(viz.anim.only, class="animint") 89 | 90 | ## Ch4 Exercise 1: how to get the geom_text to disappear along with 91 | ## the point when the region legend is clicked? Add 92 | ## aes(showSelected=region). 93 | viz.click <- list( 94 | scatter=ggplot()+ 95 | geom_point(aes(x=life.expectancy, y=fertility.rate, color=region, 96 | key=country, 97 | showSelected=year, 98 | clickSelects=country), 99 | data=WorldBank)+ 100 | geom_text(aes(x=life.expectancy, y=fertility.rate, label=country, 101 | key=country, 102 | showSelected=year, 103 | showSelected2=country, 104 | showSelected3=region), #added! 105 | data=WorldBank), 106 | duration=list(year=2000)) 107 | structure(viz.click, class="animint") 108 | 109 | ## Ch4 Exercise 2: how to get the geom_text to disappear when you 110 | ## click it? Add aes(clickSelects=country). 111 | viz.multiple <- list( 112 | scatter=ggplot()+ 113 | geom_point(aes(x=life.expectancy, y=fertility.rate, color=region, 114 | key=country, 115 | showSelected=year, 116 | clickSelects=country), 117 | data=WorldBank)+ 118 | geom_text(aes(x=life.expectancy, y=fertility.rate, label=country, 119 | key=country, 120 | clickSelects=country, #added! 121 | showSelected=year, 122 | showSelected2=country, 123 | showSelected3=region), 124 | data=WorldBank), 125 | first=list( 126 | year=1970, 127 | country="United States", 128 | region=c("North America", "South Asia")), 129 | selector.types=list(country="multiple"), 130 | duration=list(year=2000)) 131 | structure(viz.multiple, class="animint") 132 | 133 | ## Ch4 Exercise 3: add animation and layers. 134 | viz.timeSeries <- viz.multiple 135 | viz.timeSeries$timeSeries <- ggplot()+ 136 | geom_tallrect(aes(xmin=year-0.5, xmax=year+0.5, 137 | clickSelects=year), 138 | alpha=0.5, 139 | data=years)+ 140 | geom_line(aes(x=year, y=fertility.rate, group=country, color=region, 141 | clickSelects=country), 142 | size=3, 143 | alpha=0.6, 144 | data=WorldBank) 145 | viz.timeSeries$time <- list(variable="year", ms=1000) 146 | viz.timeSeries$scatter <- viz.multiple$scatter+ 147 | geom_path(aes(x=life.expectancy, y=fertility.rate, color=region, 148 | group=country, 149 | key=country, 150 | clickSelects=country, 151 | showSelected=year), 152 | size=3, 153 | data=tails)+ 154 | geom_text(aes(55, 9, label=paste("year =", year), 155 | showSelected=year), 156 | data=years) 157 | structure(viz.timeSeries, class="animint") 158 | -------------------------------------------------------------------------------- /IntGraph-example-animint.R: -------------------------------------------------------------------------------- 1 | ##```{r animintWorldBankEx, echo=FALSE} 2 | library(animint) 3 | data(WorldBank) 4 | WorldBank$region <- sub(" [(].*", "", WorldBank$region) 5 | years <- data.frame(year=unique(WorldBank$year)) 6 | not.na <- subset(WorldBank, !is.na(fertility.rate)) 7 | by.country <- split(not.na, not.na$country) 8 | min.years <- do.call(rbind, lapply(by.country, subset, year == min(year))) 9 | min.years$year <- 1959 10 | add.x.var <- function(df, x.var){ 11 | data.frame(df, x.var=factor(x.var, c("life expectancy", "year"))) 12 | } 13 | viz.facets <- list( 14 | duration=list(year=500), 15 | time=list(variable="year", ms=1000), 16 | selector.types=list(country="multiple"), 17 | first=list(country=c( 18 | "United States", "France", "Japan", "Oman", "Timor-Leste")), 19 | scatterTS=ggplot()+ 20 | theme_bw()+ 21 | theme(panel.margin=grid::unit(0, "lines"))+ 22 | theme_animint(width=700)+ 23 | scale_size_animint(breaks=10^(10:1))+ 24 | geom_text(aes(x=55, y=9, label=paste("year =", year), showSelected=year), 25 | data=add.x.var(years, "life expectancy"))+ 26 | geom_point(aes(x=life.expectancy, y=fertility.rate, color=region, 27 | size=population, 28 | key=country, 29 | showSelected=year, 30 | clickSelects=country), 31 | data=add.x.var(WorldBank, "life expectancy"))+ 32 | geom_text(aes(x=life.expectancy, y=fertility.rate, label=country, 33 | key=country, 34 | clickSelects=country, 35 | showSelected=year, 36 | showSelected2=country, 37 | showSelected3=region), 38 | data=add.x.var(WorldBank, "life expectancy"))+ 39 | facet_grid(. ~ x.var, scales="free")+ 40 | xlab("")+ 41 | ylab("fertility rate (children per mother)")+ 42 | geom_tallrect(aes(xmin=year-0.5, xmax=year+0.5, 43 | clickSelects=year), 44 | alpha=0.5, 45 | data=add.x.var(years, "year"))+ 46 | geom_text(aes(year, fertility.rate, label=country, clickSelects=country, 47 | hjust=1, 48 | showSelected=country), 49 | data=add.x.var(min.years, "year"))+ 50 | geom_line(aes(x=year, y=fertility.rate, group=country, color=region, 51 | clickSelects=country), 52 | size=3, 53 | alpha=0.6, 54 | data=add.x.var(WorldBank, "year"))+ 55 | geom_point(aes(x=year, y=fertility.rate, group=country, color=region, 56 | size=population, 57 | showSelected=country, 58 | clickSelects=country), 59 | alpha=0.6, 60 | data=add.x.var(not.na, "year"))) 61 | structure(viz.facets, class="animint") 62 | ##``` 63 | 64 | -------------------------------------------------------------------------------- /IntGraph.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Interactive graphics" 3 | author: "Toby Hocking and Claus Ekstrøm" 4 | date: "27 June 2016" 5 | output: 6 | ioslides_presentation: 7 | widescreen: true 8 | --- 9 | 10 | ## Why? Presenting research results {.flexbox .vcenter} 11 | 12 | 13 | 14 | ```{r setup, include=FALSE} 15 | knitr::opts_chunk$set(echo = FALSE) 16 | # source("packages.R") 17 | ``` 18 | 19 | 20 | ```{r, out.width = 600, fig.retina = NULL} 21 | knitr::include_graphics("img/nature.png") 22 | ``` 23 | 24 | Nature, October 2014 25 | 26 | 27 | ## Why? Teaching {.columns-2} 28 | 29 | Least squares estimation 30 | 31 | Linear regression model 32 | 33 | $$ 34 | y_i = \alpha + \beta x_i + \epsilon 35 | $$ 36 | 37 | Estimates for the intercept and slope can be found by minimizing the squared residuals. 38 | 39 | $$ 40 | \arg\min_{\alpha, \beta} \sum_i \left(y_i - (\alpha + \beta x_i) \right)^2 41 | $$ 42 | 43 |



44 | 45 | 46 | ```{r, out.width = 400, fig.retina = NULL} 47 | knitr::include_graphics("img/fedtsyre.png") 48 | ``` 49 | 50 | 51 | ## Why? Teaching {.centered} 52 | 53 | ```{r, out.width = 500, fig.retina = NULL} 54 | knitr::include_graphics("img/fedtsyre.png") 55 | ``` 56 | 57 | ## Why? Teaching {.centered} 58 | 59 | ```{r, out.width = 500, fig.retina = NULL} 60 | knitr::include_graphics("img/fedtsyrer1.png") 61 | ``` 62 | 63 | ## Why? Teaching {.centered} 64 | 65 | ```{r, out.width = 500, fig.retina = NULL} 66 | knitr::include_graphics("img/fedtsyrer2.png") 67 | ``` 68 | 69 | ## Why? Teaching 70 | 71 | Shiny 72 | 73 | ```{r eval=FALSE, echo=TRUE} 74 | library(shiny) 75 | runGitHub('ekstroem/ShinyLeastSquares') 76 | ``` 77 | 78 | 79 | The "role" of graphics is changing and expanding 80 | 81 | 82 | 83 | ## Background { .columns-2 .center .smaller } 84 | 85 | ### **Toby** 86 | 87 | ```{r, out.width = 150, fig.retina = NULL} 88 | knitr::include_graphics("img/HOCKING-lab-2015.jpg") 89 | ``` 90 | 91 | - Dept. Human Genetics, McGill University. 92 | - R packages: `directlabels`, `animint`, `plotly`, ... 93 | - Animint book in progress https://github.com/tdhock/animint-book 94 | - Uses interactive graphics for machine learning model visualization. 95 | 96 |


97 | 98 | ### **Claus** 99 | 100 | ```{r, out.height = 150, fig.retina = NULL} 101 | knitr::include_graphics("img/ekstrom-2014.jpg") 102 | ``` 103 | 104 | - Dept. Biostatistics, UCPH 105 | - R packages: ` MESS `, ` MethComp `, ` SuperRanker `, ... 106 | - R book: The R Primer 107 | - Happy/**frustrated** interactive graphics enthusiast 108 | 109 | 110 | ## Outline for the tutorial { .smaller .columns-2 } 111 | 112 | |Topic | 113 | |------| 114 | | Introduction (**10 min.**) 115 | | Interactive graphics/javascript (htmlwidgets, **30 min**) | 116 | | Interactive graphics (ggplotly/ggiraph) **20 minutes** | 117 | | Shiny **20 minutes** | 118 | | Intro to animation and direct manipulation **5 minutes** | 119 | | Basics of ggplot2 and animint **25 minutes** | 120 | | aes(showSelected), animation **25 minutes** | 121 | | aes(clickSelects), direct manipulation **25 minutes** | 122 | 123 | 124 |


125 | 126 | 127 | 128 | **Tutorial goals:** 129 | 130 | 1. Explain and emphasize the role that interactive graphics have in reporting, scientific journals, and in teaching. 131 | 2. Give overview of existing R packages for interactive graphics. 132 | 3. Explain the strengths and weaknesses of the existing R packages, to highlight directions for future work. 133 | 134 |


135 | 136 | 137 | ## Necessary stuff 138 | 139 | ```{r echo=TRUE, eval=FALSE} 140 | CRANpackages <- c("MESS", "dplyr", "shiny", "plotly", "xts", "highcharter" 141 | "DiagrammeR", "dygraphs", "ggplot2", "htmlwidgets", 142 | "leaflet", "viridis") 143 | 144 | install.packages(CRANpackages) 145 | 146 | devtools::install_github('ramnathv/rCharts') 147 | ``` 148 | 149 | Or run 150 | 151 | ```{r echo=TRUE, eval=FALSE} 152 | source("http://biostatistics.dk/useR2016pack.R") 153 | ``` 154 | 155 | 156 | ## The role of the graphics/viewer 157 | 158 |
159 | ```{r, out.height = 250, fig.retina = NULL} 160 | knitr::include_graphics("img/napoleon.jpg") 161 | ``` 162 |
163 |
164 | ```{r out.height=200, out.width = 500} 165 | library(DiagrammeR) 166 | grViz(" 167 | digraph neato { 168 | 169 | rankdir=LR; 170 | node[width=.5,height=.5,fixedsize=false]; 171 | { rank=same; A ; B} 172 | 173 | node [shape = circle] 174 | A -> {B} 175 | B -> {C} 176 | 177 | A[label='Data',shape=circle,fillcolor='lightblue',style='filled', fontsize=10]; 178 | B[label='Researcher',shape=circle,fillcolor='lightblue',style='filled', fontsize=10]; 179 | C[label='Viewer',shape=circle,fillcolor='lightblue',style='filled', fontsize=10]; 180 | 181 | }") 182 | ``` 183 | ```{r out.height=200, out.width = 500} 184 | library(DiagrammeR) 185 | grViz(" 186 | digraph neato { 187 | 188 | rankdir=LR; 189 | node[width=.5,height=.5,fixedsize=FALSE]; 190 | { rank=same; A ; B} 191 | 192 | node [shape = circle] 193 | A -> {B C} 194 | B -> {C} 195 | B -> {C} 196 | B -> {C} 197 | 198 | C -> {A} 199 | A[label='Data',shape=circle,fillcolor='lightblue',style='filled', fontsize=10]; 200 | B[label='Researcher',shape=circle,fillcolor='lightblue',style='filled', fontsize=10]; 201 | C[label='Viewer',shape=circle,fillcolor='lightblue',style='filled', fontsize=10]; 202 | 203 | 204 | }") 205 | ``` 206 |
207 | 208 | 209 | ## Interactive graphics architechture { .center } 210 | 211 |
212 | ```{r out.width = 650} 213 | grViz(" 214 | digraph neato { 215 | 216 | rankdir=LR; 217 | node[width=1,height=1,fixedsize=true]; 218 | 219 | edge[weight=20]; 220 | A -> B ; 221 | B -> A ; 222 | 223 | edge[weight=1]; 224 | 225 | A -> { A } 226 | 227 | A[label='Client/\nuser',shape=circle,fillcolor='lightblue',style='filled']; 228 | B[label='Server',shape=circle,fillcolor='lightblue',style='filled']; 229 | }") 230 | ``` 231 |
232 | - Distribution and viewing 233 | - Dedicated server vs. local server 234 | 235 | 236 | # Javascript-based libraries (htmlwidgets) 237 | 238 | ## R and Javascript architecture { .columns-2 } 239 | 240 |
241 | ```{r, out.height = 100, fig.retina = NULL} 242 | knitr::include_graphics("img/Logo_D3.png") 243 | ``` 244 |
245 | 246 | [D3.js](https://d3js.org/) doesn’t ship with any pre-built charts out of the box. However, go to website to get an overview of the possibilities. 247 | 248 | - ChartJS 249 | - Chartist.js 250 | - [n3] 251 | - [plotly](https://plot.ly/) 252 | 253 |


254 | 255 |
256 | ```{r, out.width = 400, fig.retina = NULL} 257 | knitr::include_graphics("img/RJavaHtml.png") 258 | ``` 259 |
260 | 261 | 262 | ## Highlevel interactive graphics { .columns-2 .smaller } 263 | 264 | Numerous possibilities in R packages 265 | 266 | - [**rCharts**](https://github.com/ramnathv/rCharts) (oldish - mix of libraries) 267 | - [**highcharter**](http://jkunst.com/highcharter/) (standard plot types, mature library, maps, time series) 268 | - [**dygraphs**](https://rstudio.github.io/dygraphs/) (mostly time series. well documented. Rich features) 269 | - [**metricsgraphics**](https://github.com/hrbrmstr/metricsgraphics) (also time series) 270 | - [**leaflet**](https://rstudio.github.io/leaflet/) (maps) 271 | - [**htmlwidgets**](http://www.htmlwidgets.org/) Javascript framework (many are part of this). **Super important!** 272 | 273 | - [**plotly**](https://plot.ly/ggplot2/user-guide/) (general plots - like ggplot) 274 | - [**ggiraph**](https://github.com/davidgohel/ggiraph) (ggplot graphics interactive) 275 | 276 |

277 | 278 |
279 | ```{r, out.height = 200, fig.retina = NULL} 280 | knitr::include_graphics("img/frustration20logo.jpg") 281 | ``` 282 |
283 | 284 | - No standard interface 285 | - Not easily extendable from R 286 | - Pick a library and learn it! 287 | 288 | ## rCharts interfaces 289 | 290 | | library | R function | Functionality | 291 | |:---------|-----|------------| 292 | |[polychart](http://www.polychart.com/js/) | rPlot | ggplot2-like | 293 | |[Morris](http://morrisjs.github.io/morris.js/) | mPlot | Pretty time series | 294 | |[nvd3](http://nvd3.org) | nPlot | Lines/areas/bars | 295 | |[xCharts](http://tenxer.github.io/xcharts/) | xPlot | Various graphs | 296 | |[Highcharts](http://www.highcharts.com/)| hPlot | Interactive charts | 297 | |[Leaflet](http://leafletjs.com/) | new() | Interactive Maps | 298 | |[Rickshaw](http://code.shutterstock.com/rickshaw/) | new() | Real-time ts graphs | 299 | |[Dimple](http://www.dimplejs.org) | dPlot | Business analytics | 300 | 301 | 302 | ## polychart (from rCharts package) { .columns-2 .smaller } 303 | 304 | `plot`/`lattice`-like function. 305 | 306 | ```{r warning=FALSE, echo=TRUE, message=FALSE, eval=FALSE} 307 | library(rCharts) 308 | library(MESS) 309 | data(happiness) 310 | mydf <- happiness 311 | mydf$size <- sqrt(mydf$population)/8 312 | r1 <- rPlot(x = "tax", 313 | y = "happy", 314 | data = mydf, 315 | type = "point", 316 | color = "continent", 317 | size = "size") 318 | r1 319 | ``` 320 | 321 | Type: point, bar, line, ... 322 | 323 | Add layers: `r1$layer(y= ..., copy_layer=TRUE, type="line")` 324 | 325 | 326 | ```{r warning=FALSE, results='asis', message=FALSE, echo=FALSE} 327 | library(dplyr) 328 | library(viridis) 329 | library(rCharts) 330 | library(MESS) 331 | library(xts) 332 | data(happiness) 333 | mydata <- happiness 334 | mydata$size <- sqrt(mydata$population)/8 335 | r1 <- rPlot(x = "tax", y = "happy", data = mydata, type = "point", 336 | color = "continent", size = "size") 337 | r1$addParams(width = 400, height = 500) 338 | #h1 <- hPlot(x = "tax", y = "happy", data = mydata, type = "bubble", 339 | # group = "continent", size = "size") 340 | r1$show('inline', include_assets = TRUE) 341 | #r1 342 | ``` 343 | 344 | 345 | ## polychart (from rCharts package) { .columns-2 .smaller } 346 | 347 | `plot`/`lattice`-like function. Add layers and guides to plot .. 348 | 349 | ```{r warning=FALSE, echo=TRUE, message=FALSE, eval=FALSE} 350 | mydf2 <- data.frame(tax=c(1, 50), 351 | happy=c(4.93, 7.09)) 352 | 353 | r1$layer(x = "tax", 354 | y = "happy", 355 | data = mydf2, 356 | type = "line", 357 | size=list(const=4)) 358 | 359 | r1$guides(y = list(title="New label", 360 | min=0, max=12)) 361 | 362 | r1 363 | ``` 364 | 365 | - `layer` $\approx$ points/lines 366 | - `guides` $\approx$ axis 367 | - `addParams` $\approx$ title, plot size 368 | 369 | 370 | ```{r warning=FALSE, results='asis', message=FALSE, echo=FALSE} 371 | mydf2 <- data.frame(tax=c(1, 50), happy=c(4.93976, 7.09233)) 372 | 373 | r2 <- rPlot(x = "tax", y = "happy", data = mydata, type = "point", 374 | color = "continent", size = "size") 375 | r2$addParams(width = 400, height = 500) 376 | 377 | r2$layer(x = "tax", 378 | y = "happy", 379 | data = mydf2, 380 | type = "line", 381 | size=list(const=4)) 382 | 383 | r2$guides(y = list(title = "New label", 384 | min=0, max = 12)) 385 | 386 | r2$show('inline', include_assets = TRUE) 387 | 388 | ``` 389 | 390 | 391 | 392 | ## polychart - tooltips { .columns-2 .smaller } 393 | 394 | ```{r warning=FALSE, message=FALSE, echo=TRUE, eval=FALSE} 395 | 396 | r3 <- rPlot(x = "tax", y = "happy", 397 | data = mydf, type = "point", 398 | color = "continent", 399 | size = "size", 400 | tooltip="#!function(item){ 401 | return ('Country: ' +item.country+ 402 | ' Tax: ' +item.tax+ 403 | '% Happiness: ' +item.happy+ 404 | '
Pop: ' +item.population+ 405 | ' mio.') }!#") 406 | 407 | ``` 408 | 409 | Passing javascript is non-trivial. 410 | 411 | ```{r results = 'asis', commment = NA, message = FALSE, echo = FALSE, warning=FALSE} 412 | mydf <- happiness 413 | mydf$size <- sqrt(mydf$population)/8 414 | 415 | r3 <- rPlot(x = "tax", y = "happy", 416 | data = mydf, type = "point", 417 | color = "continent", 418 | size = "size", 419 | tooltip="#!function(item){ 420 | return ('Country: ' +item.country+ 421 | ' Tax: ' +item.tax+ 422 | '% Happiness: ' +item.happy+ 423 | '
Pop: ' +item.population+ 424 | ' mio.') }!#") 425 | 426 | r3$addParams(width = 400, height = 500) 427 | 428 | 429 | r3$show('inline', include_assets = TRUE) 430 | 431 | ``` 432 | 433 | 434 | 435 | ## [Highcharts](http://www.highcharts.com) 436 | 437 | ![HighCharter](img/highcharter.png) 438 | 439 | ## [highcharter]((http://jkunst.com/highcharter/index.html)) (highcharter package) {.columns-2 .smaller } 440 | 441 | ```{r} 442 | knit_print.htmlwidget <- function(x, ..., options = NULL){ 443 | options(pandoc.stack.size = "2048m") 444 | wdgtclass <- setdiff(class(x), "htmlwidget")[1] 445 | wdgtrndnm <- paste0(sample(letters, size = 7), collapse = "") 446 | wdgtfname <- sprintf("wdgt_%s_%s.html", wdgtclass, wdgtrndnm) 447 | htmlwidgets::saveWidget(x, file = wdgtfname, selfcontained = TRUE, background = "transparent") 448 | iframetxt <- sprintf("", wdgtfname) 449 | knitr::asis_output(iframetxt) 450 | } 451 | 452 | ``` 453 | 454 | Mature charts, stocks (time series), maps. Good API. 455 | 456 | - Start with empty chart and add components. 457 | - (Mostly) no default arguments 458 | 459 | ```{r echo=TRUE,eval=FALSE} 460 | library(highcharter) 461 | hc <- highchart() %>% 462 | hc_chart(type = "column") %>% 463 | hc_title(text = "Denmark") %>% 464 | hc_xAxis(categories = 2011:2016) %>% 465 | hc_add_series(data = c(3806, 6184, 466 | 7557, 14792, 467 | 21315, 3016), 468 | name = "Asylum seekers") %>% 469 | hc_add_series(name = "Syria", 470 | data = c(429, 822, 471 | 1710, 7087, 472 | 8608, 777), 473 | type = "spline") 474 | hc 475 | ``` 476 | 477 |


478 | 479 | ```{r echo=FALSE, eval=TRUE} 480 | library(highcharter) 481 | hc <- highchart() %>% 482 | hc_chart(type = "column") %>% 483 | hc_title(text = "Denmark") %>% 484 | hc_xAxis(categories = 2011:2016) %>% 485 | hc_add_series(data = c(3806, 6184, 486 | 7557, 14792, 487 | 21315, 3016), 488 | name = "Asylum seekers") %>% 489 | hc_add_series(name = "Syria", 490 | data = c(429, 822, 491 | 1710, 7087, 492 | 8608, 777), 493 | type = "spline") 494 | 495 | hc 496 | ``` 497 | 498 | ## highcharter - adding data { .smaller } 499 | 500 | Data are added using one of the following functions 501 | 502 | | Name | Function | 503 | |---+----------| 504 | | hc_add_series | Add single series (named: `data`, `name`) | 505 | | hc_add_series_list | Add *list* of named series | 506 | | hc_add_series_df | Add data.frame. Name variables accordingly => plot type | 507 | | hc_add_series_ts | Add and plot ts object. Extra argument: `name` | 508 | | hc_add_series_scatter | Create and plot scatter from two vectors. Extra arguments (size, color, label) | 509 | | hc_add_series_boxplot | Add and plot boxplots | 510 | | hc_add_series_map | Add geojson map | 511 | 512 | Chart types: line (default), column, boxplot, bubble, arearange, heatmap, funnel, pie, ... 513 | 514 | Also: the `hchart` function (a la `plot`) 515 | 516 | 517 | ## Highcharter function overview { .smaller } 518 | 519 | | Function | Example | 520 | |---+-------------| 521 | | Title, subtitle | hc_title(text = "Temperature"), hc_subtitle(text = "Somewhere warm") | 522 | | Axis | hc_xAxis(categories = month) | 523 | | | hc_yAxis(title = list(text = "Temperature"), labels = list(format = "{value} C")) | 524 | | Theme | hc_add_theme(hc_theme_sandsignika()) | 525 | | Zoom | hc_chart(zoomType = "xy") | 526 | | Export | hc_exporting(enabled = TRUE) | 527 | | Tooltip | hc_tooltip(useHTML = TRUE, headerFormat="<table>", | 528 | | | pointFormat = "<tr><th>x-val</th><td>{point.x}</td></tr>" | 529 | | | footerFormat = "</table>") | 530 | | Legend | hc_legend(enabled=FALSE) | 531 | | Credits | hc_credits(enabled = TRUE, text = "Source: Wikipedia", href = "https://wikipedia.com", style = list(fontSize = "12px")) | 532 | 533 | 534 | 535 | ## Highcharter - adding information { .smaller } 536 | 537 | 538 | ```{r echo=TRUE, eval=FALSE} 539 | happiness$size <- sqrt(happiness$population)/8 540 | hap <- happiness # Shorten name 541 | happy2 <- highchart() %>% 542 | hc_title(text = "Taxes and happiness") %>% 543 | hc_subtitle(text = "Source: Wikipedia") %>% 544 | hc_xAxis(title = list(text = "Taxation (%)")) %>% 545 | hc_yAxis(title = list(text = "Happiness")) %>% 546 | hc_chart(zoomType = "xy") %>% hc_exporting(enabled = TRUE) %>% 547 | hc_add_series_scatter(hap$tax, hap$happy, 548 | hap$size, hap$continent, hap$country, 549 | dataLabels = list( enabled = TRUE, 550 | format = "{point.label}")) %>% 551 | hc_tooltip(useHTML = TRUE, 552 | headerFormat = "", 553 | pointFormat = paste("", 554 | "", 555 | "", 556 | "", 557 | "", 558 | ""), 559 | footerFormat = "
{point.label}
Tax{point.x} %
Score{point.y}
Pop{point.z}
Cont.{point.valuecolor} hp
Religion{point.extrainfo} hp
") 560 | happy2 561 | ``` 562 | 563 | 564 | 565 | ## Highcharter - adding information 566 | 567 | 568 | ```{r} 569 | library(dplyr) 570 | library(viridis) 571 | happiness$size <- sqrt(happiness$population)/8 572 | hap <- happiness # Shorten name 573 | 574 | # Extra tooltip 575 | colorvar <- hap$continent 576 | cols <- viridis(1000)[round(ecdf(colorvar)(colorvar)*1000)] 577 | cols <- substr(cols, 0, 7) 578 | dt <- hap %>% mutate(x=tax, y=happy, z=size, color=cols, label=country) 579 | ds <- list.parse3(dt) 580 | 581 | happy2 <- highchart() %>% 582 | hc_title(text = "Taxes and happiness") %>% 583 | hc_subtitle(text = "Source: Wikipedia") %>% 584 | hc_xAxis(title = list(text = "Taxation (%)")) %>% 585 | hc_yAxis(title = list(text = "Happiness")) %>% 586 | hc_chart(zoomType = "xy") %>% 587 | hc_exporting(enabled = TRUE) %>% 588 | hc_add_series(data=ds, name=FALSE, type="bubble", showInLegend=FALSE, 589 | dataLabels = list(enabled = TRUE, format = "{point.label}")) %>% 590 | hc_tooltip(useHTML = TRUE, 591 | headerFormat = "", 592 | pointFormat = paste("", 593 | "", 594 | "", 595 | "", 596 | "", 597 | ""), 598 | footerFormat = "
{point.label}
Tax{point.x} %
Score{point.y}
Pop{point.z}
Cont.{point.continent}
Religion{point.religion}
") 599 | happy2 600 | ``` 601 | 602 | 603 | ## Exercise 604 | 605 | Take the `airquality` dataset. Plot series of temperature and wind speed for June using for example `highcharter` or `polychart`. 606 | 607 | ```{r eval=FALSE, echo=TRUE} 608 | data(airquality) 609 | aq <- subset(airquality, Month==6) 610 | head(aq) 611 | 612 | library(highcharter) 613 | hc <- highchart() %>% 614 | hc_chart(type = "column") %>% 615 | hc_title(text = "Denmark") %>% 616 | hc_xAxis(categories = aq$Day) %>% 617 | hc_add_series(data = aq$Temp, 618 | name = "Temperature") %>% 619 | ... 620 | ``` 621 | 622 | 623 | ## One solution 624 | 625 | ```{r} 626 | library(highcharter) 627 | data(airquality) 628 | aq <- subset(airquality, Month==6) 629 | hc <- highchart() %>% 630 | hc_chart(type = "column") %>% 631 | hc_title(text = "Denmark") %>% 632 | hc_xAxis(categories = 1:30) %>% 633 | hc_add_series(data = aq$Temp, 634 | name = "Temperature") %>% 635 | hc_add_series(name = "Wind speed", 636 | data = aq$Wind, 637 | type = "spline") 638 | 639 | hc 640 | ``` 641 | 642 | 643 | 644 | ## [dygraphs](http://dygraphs.com/index.html) 645 | 646 | ![dygraphs](img/dygraphs.png) 647 | 648 | 649 | ## dygraphs { .columns-2 .smaller } 650 | 651 | Same build-up as highcharter. Most of the information passed in `dygraph` and `dyOptions`. 652 | 653 | `xts` extended time series 654 | 655 | 656 | ```{r echo=TRUE, eval=FALSE} 657 | library(dygraphs) 658 | library(MESS) 659 | library(xts) 660 | data(greenland) 661 | rownames(greenland) <- 662 | paste0(greenland$year, "-07-15") 663 | greenland$year <- NULL 664 | temp <- as.xts(greenland) 665 | dygraph(temp, 666 | main="Av. Summer temp") %>% 667 | dyRangeSelector(dateWindow = 668 | c("1960-01-01", "2011-01-01")) 669 | ``` 670 | 671 | Series can be added with `dySeries`. 672 | 673 |


674 | 675 | ```{r echo=FALSE, eval=TRUE} 676 | library(dygraphs) 677 | library(MESS) 678 | library(xts) 679 | data(greenland) 680 | rownames(greenland) <-paste(greenland$year, 681 | "-07-15", sep="") 682 | greenland$year <- NULL 683 | temp <- as.xts(greenland) 684 | dygraph(temp, 685 | main="Average Summer temp") %>% 686 | dyRangeSelector(dateWindow = 687 | c("1960-01-01", "2011-01-01")) 688 | ``` 689 | 690 | 691 | 692 | ## dygraphs functions { .smaller } 693 | 694 | | Function | Example | 695 | |------+----------------| 696 | | Title | dygraph(data, main = "My Title") | 697 | | Axis | dyAxis("x", drawGrid = TRUE, label="My X axis") | 698 | | Zoom/panning | dyRangeSelector() | 699 | | Highlights | dyHighlight(highlightSeriesOpts = list(strokeWidth = 3)) | 700 | 701 | | dyOptions/dySeries | Example | 702 | |-------+-------------------| 703 | | Step Plot | dyOptions(stepPlot = TRUE) | 704 | | Colour | dyOptions(colors="blue") | 705 | | Fill | dyOptions(fillGraph = TRUE, fillAlpha = 0.4) | 706 | | L/V/U | A 3-vector name has special meaning (lower, value, upper). `dySeries(c("L", "V", "U"))` 707 | 708 | Also: `dyShading`, `dyEvent`, ... 709 | 710 | 711 | ## dygraphs 2 { .columns-2 .smaller } 712 | 713 | Danish Monthly births/deaths. Multiple series. 714 | 715 | ```{r echo=TRUE, eval=FALSE} 716 | library(MESS) 717 | library(dygraphs) 718 | data(bdstat) 719 | births <- ts(bdstat$births[1:(12*112)], 720 | frequency=12, 721 | start=c(1901, 1)) 722 | deaths <- ts(bdstat$dead[1:(12*112)], 723 | frequency=12, 724 | start=c(1901, 1)) 725 | DKdata <- cbind(births, deaths) 726 | dygraph(DKdata, 727 | main="Births/Deaths") %>% 728 | dyAxis("x", drawGrid = FALSE) %>% 729 | dySeries("births", drawPoints=TRUE, 730 | color = "blue") %>% 731 | dySeries("deaths", stepPlot = TRUE, 732 | fillGraph = TRUE, 733 | color = "red") %>% 734 | dyHighlight(highlightSeriesOpts = 735 | list(strokeWidth = 3)) 736 | ``` 737 | 738 |



739 | 740 | 741 | 742 | ```{r echo=FALSE} 743 | library(MESS) 744 | library(dygraphs) 745 | data(bdstat) 746 | births <- ts(bdstat$births[1:(12*112)], frequency=12, start=c(1901, 1)) 747 | deaths <- ts(bdstat$dead[1:(12*112)], frequency=12, start=c(1901, 1)) 748 | DKdata <- cbind(births, deaths) 749 | dkb <- HoltWinters(births) 750 | predicted <- predict(dkb, n.ahead = 50*12, prediction.interval = TRUE) 751 | dygraph(DKdata, main = "Births/Deaths (DK)") %>% 752 | dyAxis("x", drawGrid = FALSE) %>% 753 | dySeries("births", drawPoints = TRUE, color = "blue") %>% 754 | dySeries("deaths", stepPlot = TRUE, fillGraph = TRUE, color = "red") %>% 755 | dyHighlight(highlightSeriesOpts = list(strokeWidth = 3)) 756 | ``` 757 | 758 | 759 | 760 | ## dygraphs 3 { .columns-2 .smaller } 761 | 762 | Danish Monthly births/deaths. Multiple series. Prediciton 763 | 764 | ```{r echo=TRUE,eval=FALSE} 765 | dkb <- HoltWinters(births) 766 | p <- predict(dkb, n.ahead = 50*12, 767 | prediction.interval=TRUE) 768 | all <- cbind(births, p) 769 | 770 | dygraph(all, main = "Births (DK)") %>% 771 | dySeries("births", drawPoints = TRUE, 772 | color = "blue", 773 | label="births") %>% 774 | dySeries(c("p.lwr","p.fit","p.upr"), 775 | color = "red") 776 | ``` 777 | 778 |








779 | 780 | ```{r echo=FALSE, eval=TRUE} 781 | dkb <- HoltWinters(births) 782 | p <- predict(dkb, n.ahead = 50*12, 783 | prediction.interval = TRUE) 784 | all <- cbind(births, p) 785 | dygraph(all, main = "Births (DK)") %>% 786 | dySeries("births", drawPoints = TRUE, 787 | color = "blue", label="asd") %>% 788 | dySeries(c("p.lwr", "p.fit", "p.upr"), 789 | color = "red") 790 | ``` 791 | 792 | 793 | 794 | 795 | ## [leaflet](http://leafletjs.com/) 796 | 797 | ![](img/leaflet.png) 798 | 799 | 800 | ## The [leaflet](https://rstudio.github.io/leaflet/) package 801 | 802 | Beautiful maps crated by adding layers on top of maps. 803 | 804 | ```{r} 805 | library(leaflet) 806 | 807 | m <- leaflet() %>% 808 | addTiles() %>% # Default OpenStreetMap map tiles 809 | addMarkers(lat=37.431106, lng=-122.164672, popup="useR 2016") 810 | m 811 | ``` 812 | 813 | ## **leaflet example** 814 | 815 | ```{r echo=TRUE, eval=FALSE} 816 | library(leaflet) 817 | 818 | m <- leaflet() %>% 819 | addTiles() %>% # Default OpenStreetMap map tiles 820 | addMarkers(lat=37.431106, lng=-122.164672, popup="useR 2016") 821 | m 822 | ``` 823 | 824 | 825 | 826 | ## **leaflet function overview** 827 | 828 | Main functions 829 | 830 | | Function | Example | 831 | |--------+----------| 832 | | Default map | addTiles() | 833 | | Alternative maps | addProviderTiles("CartoDB.DarkMatter", options = providerTileOptions(opacity = 0.35)) Stackable! | 834 | | Markers | addMarkers(~long, ~lat, popup = ~as.character(mag)) | 835 | | Pop-ups | addPopups(lng=-122.164672, lat=37.431106, "<a href='http://www.user2016.org'> Hi </a>", options = popupOptions(closeButton = FALSE)) | 836 | | Custom icons | makeIcon() | 837 | 838 | 839 | ## **Earthquakes** 840 | 841 | ```{r eval=FALSE, echo=TRUE, message=FALSE} 842 | library(leaflet) 843 | library(MESS) 844 | 845 | pal <- colorNumeric("RdYlBu", 846 | domain = NULL) 847 | data(earthquakes) 848 | m <- leaflet(subset(earthquakes, mag>3)) %>% 849 | addProviderTiles("CartoDB.DarkMatter") %>% 850 | addCircleMarkers( 851 | radius = ~ mag*3, 852 | color = ~ pal(depth), 853 | stroke = FALSE, fillOpacity = 0.4 854 | ) 855 | m 856 | ``` 857 | 858 | ## **Earthquakes** 859 | 860 | ```{r eval=TRUE, echo=FALSE, message=FALSE} 861 | library(leaflet) 862 | library(MESS) 863 | 864 | pal <- colorNumeric("RdYlBu", 865 | domain = NULL) 866 | data(earthquakes) 867 | m <- leaflet(subset(earthquakes, mag>3)) %>% 868 | addProviderTiles("CartoDB.DarkMatter") %>% # Add default OpenStreetMap map tiles 869 | addCircleMarkers( 870 | radius = ~ mag*4, 871 | color = ~ pal(depth), 872 | stroke = FALSE, fillOpacity = 0.5 873 | ) 874 | m 875 | ``` 876 | 877 | 878 | ## **Exercise** 879 | 880 | Create your own icon and pop-up on this map. 881 | 882 | ```{r eval=FALSE, echo=TRUE} 883 | library(leaflet) 884 | m <- leaflet() %>% 885 | addTiles() %>% # Default OpenStreetMap map tiles 886 | addMarkers(lng=-122.164672, lat=37.431106, popup="useR 2016") 887 | m 888 | ``` 889 | 890 | Add the R icon to the map: https://www.r-project.org/logo/Rlogo.png 891 | (Use `icon` instead of `popup` in `addMarkers`). Create simple icon: 892 | 893 | ```{r echo=TRUE} 894 | myIcon <- makeIcon( 895 | iconUrl = "http://leafletjs.com/docs/images/leaf-green.png", 896 | iconWidth = 38, iconHeight = 95, 897 | iconAnchorX = 22, iconAnchorY = 94 898 | ) 899 | ``` 900 | 901 | 902 | ## **Publishing interactive graphics** 903 | 904 | Note: html/js output. Need javascript machinery to run (ie., html with js code embedded or online link). 905 | 906 | ```{r eval=FALSE, echo=TRUE} 907 | library(htmlwidgets) 908 | saveWidget(widget, file, selfcontained = TRUE, background="white") 909 | ``` 910 | 911 | ### Including in R markdown 912 | 913 | `htmlwidget` widgets behave nicely in R markdown. 914 | 915 | ### Otherwise 916 | 917 | `as.iframe` to appear. 918 | 919 | 920 | 921 | # Javascript-based libraries (ggplotly and ggiraph) 922 | 923 | 924 | ## ggplotly and ggiraph 925 | 926 | Use ggplot2 (and grammar of graphics) to render interactive graphics. 927 | 928 | - ggplotly use the [plot.ly]() service 929 | - ggiraph uses it's own htmlwidget extensions. 930 | 931 | 932 | ## [Plotly](https://plot.ly/) - ggplotly 933 | 934 | ![plotly](img/plotly.png) 935 | 936 | 937 | ## The [plotly](https://plot.ly/ggplot2/) package 938 | 939 | Use legend to toggle traces, zoom, shift and click to pan. 940 | Super simple: `p <- ggplot() ; ggplotly(p)` 941 | 942 | ```{r message=FALSE} 943 | library(plotly) 944 | 945 | x <- rnorm(100) 946 | y <- + .7*x + rnorm(100) 947 | f1 <- as.factor(c(rep("A",50),rep("B",50))) 948 | f2 <- as.factor(rep(c(rep("C",25),rep("D",25)),2)) 949 | df <- data.frame(cbind(x,y)) 950 | df$f1 <- f1 951 | df$f2 <- f2 952 | 953 | g <- ggplot(df,aes(x=x,y=y)) + 954 | geom_point() + 955 | facet_grid(f1~f2) + 956 | stat_smooth(method="lm") 957 | 958 | ggplotly(g) 959 | ``` 960 | 961 | 962 | ## Revisiting the happiness data 963 | ```{r warning=FALSE, message=FALSE, echo=TRUE, eval=FALSE} 964 | library(ggplot2) 965 | library(plotly) 966 | 967 | p <- ggplot(happiness, 968 | aes(x=tax, y=happy, color=continent, size=population, 969 | text = paste("country:", country))) + 970 | geom_point( alpha = I(0.8)) + 971 | scale_size_area(max_size = 30) + # Size of largest points 972 | geom_smooth(method="lm", se= F, size = 1, 973 | aes(linetype = continent, group = continent)) 974 | ggplotly(p) 975 | ``` 976 | 977 | ## Revisiting the happiness data 978 | ```{r warning=FALSE, message=FALSE} 979 | p <- ggplot(happiness, aes(x=tax, y=happy, color=continent, size=population, text = paste("country:", country))) + geom_point( alpha = I(0.8)) + scale_size_area(max_size = 30) + geom_smooth(method="lm", se= F, size = 1, aes(linetype = continent, group = continent)) 980 | ggplotly(p) 981 | ``` 982 | 983 | 984 | ## Publishing ggplotly graphics 985 | 986 | 987 | ### Works directly in R markdown / knitr 988 | 989 | Just works (automatically embedded) 990 | 991 | ### Post on plot.ly account 992 | 993 | Embed the graph as an iframe 994 | 995 | ```{r eval=FALSE, echo=TRUE} 996 | signup("username", "email", save=TRUE) 997 | plotly_POST(p, "My Chart") 998 | ``` 999 | 1000 | 1001 | 1002 | 1003 | ## The [ggiraph](https://github.com/davidgohel/ggiraph) package 1004 | 1005 | Extends `ggplot2` with new `geom` functions. 1006 | 1007 | - `geom_point_interactive`, `geom_polygon_interactive`, `geom_map_interactive`, `geom_path_interactive`, `geom_rect_interactive`, `geom_segment_interactive`, `geom_text_interactive` 1008 | 1009 | Three arguments let you add interactivity: 1010 | 1011 | - `tooltip`: mouse-over tooltips to be displayed when mouse is over elements. 1012 | - `onclick`: javascript function to be executed when elements are clicked. 1013 | - `data_id`: id to be associated with elements. 1014 | 1015 | 1016 | ## ggiraph example - happiness 1017 | 1018 | ```{r echo=TRUE, eval=FALSE} 1019 | library(ggiraph) 1020 | 1021 | happiness$tooltip <- paste0("
Welcome to
", 1022 | happiness$country, 1023 | "
") 1024 | 1025 | p <- ggplot(happiness, 1026 | aes(x=tax, y=happy, color=continent, 1027 | size=population, tooltip=tooltip)) + 1028 | geom_point_interactive(alpha=I(.8)) + 1029 | scale_size_area(max_size = 30) 1030 | 1031 | ggiraph(code = {print(p)}, height = "350px") 1032 | ``` 1033 | 1034 | ## ggiraph example - happiness 1035 | 1036 | ```{r warning=FALSE, message=FALSE} 1037 | library(ggiraph) 1038 | 1039 | happiness$tooltip <- paste0("
Welcome to
", 1040 | happiness$country, 1041 | "
") 1042 | 1043 | p <- ggplot(happiness, 1044 | aes(x=tax, y=happy, color=continent, 1045 | size=population, tooltip=tooltip)) + 1046 | geom_point_interactive(alpha=I(.8)) + 1047 | scale_size_area(max_size = 30) 1048 | 1049 | ggiraph(code = {print(p)}, width="600px", height = "300px") 1050 | 1051 | ``` 1052 | 1053 | 1054 | ## ggiraph and dataid and onclick events { .smaller } 1055 | 1056 | ```{r echo=TRUE, eval=FALSE} 1057 | library(ggiraph) 1058 | 1059 | happiness$tooltip <- paste0("
Welcome to
", happiness$country, "
") 1060 | 1061 | happiness$onclick <- sprintf( 1062 | "window.open(\"%s%s\")", 1063 | "http://en.wikipedia.org/wiki/", 1064 | as.character(happiness$country) 1065 | ) 1066 | 1067 | happiness$data_id <- happiness$country 1068 | 1069 | p3 <- ggplot(happiness, 1070 | aes(x=tax, y=happy, color=continent, 1071 | size=population, tooltip=tooltip, 1072 | onclick=onclick, data_id=data_id)) + 1073 | geom_point_interactive(alpha=I(.8)) + 1074 | scale_size_area(max_size = 30) 1075 | 1076 | ggiraph(code = print(p3), 1077 | hover_css = "fill-opacity:.3;cursor:pointer;", # data_id 1078 | width="600px", height = "300px" 1079 | ) 1080 | ``` 1081 | 1082 | 1083 | ## ggiraph and dataid and onclick events 1084 | 1085 | ```{r message=FALSE, warning=FALSE} 1086 | library(ggiraph) 1087 | 1088 | happiness$tooltip <- paste0("
Welcome to
", happiness$country, "
") 1089 | 1090 | happiness$onclick <- sprintf( 1091 | "window.open(\"%s%s\")", 1092 | "http://en.wikipedia.org/wiki/", 1093 | as.character(happiness$country) 1094 | ) 1095 | 1096 | happiness$data_id <- happiness$country 1097 | 1098 | 1099 | p2 <- ggplot(happiness, 1100 | aes(x=tax, y=happy, color=continent, 1101 | size=population, tooltip=tooltip, onclick=onclick, data_id=data_id)) + 1102 | geom_point_interactive(alpha=I(.8)) + 1103 | scale_size_area(max_size = 30) 1104 | 1105 | ggiraph(code = print(p2), 1106 | hover_css = "fill-opacity:.3;cursor:pointer;", 1107 | width="600px", height = "300px") 1108 | ``` 1109 | 1110 | 1111 | 1112 | ## Exercise { .columns-2 } 1113 | 1114 | Use **ggplotly**/ggiraph to create an interactive plot of development in average Danish life expectancy for males and females. 1115 | 1116 | 1117 | ```{r echo=TRUE} 1118 | library(MESS) 1119 | data(lifeexpect) 1120 | head(lifeexpect) 1121 | ``` 1122 | 1123 |
1124 | 1125 | Could start with 1126 | 1127 | ```{r echo=TRUE, eval=FALSE, out.width = 400} 1128 | library(MESS) 1129 | data(lifeexpect) 1130 | library(plotly) 1131 | p <- ggplot(lifeexpect, 1132 | aes(x=myear, y=male)) ... 1133 | ``` 1134 | 1135 | 1136 | # Shiny 1137 | 1138 | ## Shiny { .smaller } 1139 | 1140 | Use standard R. Rather simple and beautiful. Requires server, or running locally in R. 1141 | 1142 | Two files 1143 | ``` 1144 | Directory 1145 | | 1146 | +-- ui.R 1147 | +-- server.R 1148 | ``` 1149 | 1150 | Or single file, `app.R`, with 1151 | ```{r, eval=FALSE, echo=TRUE} 1152 | server <- function(input, output) { ... } 1153 | ui <- fluidPage( ...) # Fluid UI 1154 | 1155 | shinyApp(ui = ui, server = server) 1156 | ``` 1157 | 1158 | 1159 | Run using 1160 | ```{r echo=TRUE, eval=FALSE} 1161 | library(shiny) 1162 | runApp("/path/to/directory") # Local 1163 | runGitHub('ekstroem/ShinySampleMean') # From GitHub 1164 | ``` 1165 | 1166 | 1167 | ## Example 1168 | 1169 | ```{r eval=FALSE,echo=TRUE} 1170 | library(shiny) 1171 | runGitHub('ekstroem/ShinyLeastSquares') 1172 | ``` 1173 | 1174 | ## Shiny User Interface 1175 | 1176 | "Standard" [design layout](http://shiny.rstudio.com/articles/layout-guide.html) with sidebar for input and main window for output. 1177 | 1178 | ```{r eval=FALSE, echo=TRUE} 1179 | library(shiny) 1180 | 1181 | shinyUI(pageWithSidebar( 1182 | 1183 | titlePanel("My title"), # Application title 1184 | 1185 | sidebarLayout( # Layout for this page 1186 | sidebarPanel( # Well a side bar panel 1187 | selectInput() # Input type 1188 | ), 1189 | mainPanel( 1190 | plotOutput() # Types of output 1191 | ) # ... and main panel 1192 | ) 1193 | )) 1194 | ``` 1195 | 1196 | ## Shiny server interface 1197 | 1198 | Communication through `input` and `output` lists. 1199 | 1200 | ```{r eval=FALSE, echo=TRUE} 1201 | library(shiny) 1202 | 1203 | # Define server 1204 | shinyServer(function(input, output) { 1205 | 1206 | output$something <- renderFunction( 1207 | v1 <- input$variable1 # Get input 1208 | ... 1209 | ) 1210 | }) 1211 | ``` 1212 | 1213 | ## User interface functions { .columns-2 .smaller } 1214 | 1215 | ### Inputs 1216 | 1217 | - `checkboxInput` - Check box 1218 | - `dateInput` - Calendar to aid date selection 1219 | - `dateRangeInput` - Pair of calendars for selecting a date range 1220 | - `fileInput` - File upload control wizard 1221 | - `numericInput` - Field to enter numbers 1222 | - `radioButtons` - Set of radio buttons 1223 | - `selectInput` - Box with choices to select from 1224 | - `sliderInput` - Slider bar 1225 | - `textInput` - Text area 1226 | 1227 | ### Outputs 1228 | 1229 | - `htmlOutput` - raw HTML 1230 | - `imageOutput` - image 1231 | - `plotOutput` - plot 1232 | - `tableOutput` - table 1233 | - `textOutput` - text 1234 | - `verbatimTextOutput` - text 1235 | 1236 | ## Server side functions { .smaller } 1237 | 1238 | Input functions are strings 1239 | 1240 | * `renderImage` - images (saved as a link to a source file) 1241 | * `renderPlot` - plots 1242 | * `renderPrint` - any printed output 1243 | * `renderTable` - data frame, matrix, other table like structures 1244 | * `renderText` - Raw text 1245 | 1246 | Each `render*` function takes a single argument: an R expression surrounded by braces, {}. 1247 | 1248 | ## Example - view data frame 1249 | 1250 | ```{r eval=FALSE, echo=TRUE} 1251 | runGitHub("ekstroem/useRapp") 1252 | ``` 1253 | 1254 | ## Exercise 1255 | 1256 | Try to run the code from previous example. Add a slider to change the point size in the graph. 1257 | 1258 | 1. Look at the code 1259 | 2. Add `sliderInput` (arguments: label, text, start value, min value, max value) 1260 | 3. Change server function to accommodate the new input -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | IntGraph.html: IntGraph.Rmd 2 | Rscript -e 'rmarkdown::render("IntGraph.Rmd")' 3 | HOCKING-handout.pdf: HOCKING-handout.tex 4 | rm -rf *.aux *.bbl 5 | pdflatex HOCKING-handout 6 | pdflatex HOCKING-handout 7 | intreg.html: intreg.Rmd 8 | Rscript -e 'rmarkdown::render("intreg.Rmd")' 9 | introduction-vocabulary.html: introduction-vocabulary.Rmd 10 | Rscript -e 'rmarkdown::render("introduction-vocabulary.Rmd")' 11 | syllabus.pdf: syllabus.tex 12 | pdflatex syllabus 13 | tutorial-prop.pdf: tutorial-prop.tex 14 | pdflatex tutorial-prop 15 | README.pdf: README.tex 16 | pdflatex README 17 | pdflatex README 18 | -------------------------------------------------------------------------------- /README-old.org: -------------------------------------------------------------------------------- 1 | Proposal for an tutorial overview of interactive graphics packages 2 | 3 | Fill in [[file:tutorial-prop.org][template]] and send it to useR-2014@R-project.org before January 4 | 10, 2016. 5 | 6 | Below is old materials that we may want to copy to the template. 7 | 8 | ** Goals, why the tutorial is important 9 | 10 | There are two main goals for this tutorial: 11 | - Summarize of the differences and relative strengths of the different 12 | packages which are now available for making interactive graphics 13 | using R. 14 | - Bring the developers of these packages together in one place, to 15 | discuss future directions for interactive graphics in R. 16 | 17 | ** Detailed outline 18 | 19 | *First hour: simple graphics.* generate single-layer, single-panel 20 | interactive web graphics with only 1 line of R code (rCharts, 21 | googleVis). Interactivity is mostly limited to tooltips i.e. a little 22 | popup window that shows more information about a data point when you 23 | move your mouse over it. 24 | 25 | *Second hour: brushing.* One or several rows of 1 data.frame can be 26 | brushed interactively using the mouse, and the brushed data are 27 | highlighted in several linked plots (RIGHT, iplots, cranvas). 28 | 29 | *Third hour: show/hide data subsets.* Several multi-layer plots show 30 | different columns of a data set, and different rows can be shown over 31 | time (animation) or in response to mouse clicks (interactivity). We 32 | will focus on a detailed description about how to generate [[http://sugiyama-www.cs.titech.ac.jp/~toby/animint/WorldBank/viz.html][this 33 | GapMinder-style multipanel, multilayer, interactive animation]] using 34 | packages animation, animint, and shiny+ggvis. 35 | - 10 minutes: [[https://github.com/tdhock/interactive-tutorial/tree/master/animation][overview of the differences between the animation, 36 | animint, shiny, and ggvis packages]]. 37 | - 15 minutes: animation. 38 | - 15 minutes: animint. 39 | - 15 minutes: shiny+ggvis. 40 | 41 | ** Background knowledge required, potential attendees 42 | 43 | Since we plan to present state-of-the-art interactive graphics, people 44 | should know how to use R data structures (lists, data.frames) and the 45 | ggplot2 package. 46 | 47 | Even though many examples will be interactive web graphics, we will 48 | assume only knowledge of R, not HTML/JavaScript. 49 | 50 | There are two classes of potential attendees: 51 | - UseRs who are not very familiar with interactive graphics should 52 | benefit the most, since we will give a high-level overview of many 53 | different packages. 54 | - DevelopeRs of interactive packages are encouraged to come, to 55 | discuss the current state-of-the-art and future directions. 56 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | The official description from useR is 2 | http://user2016.org/tutorials/13.html 3 | 4 | - Part 1: [[http://tdhock.github.io/interactive-tutorial/IntGraph.html][Claus Thorn Ekstrom's slides]], [[https://github.com/tdhock/interactive-tutorial/blob/gh-pages/IntGraph.Rmd][source]]. 5 | - Part 2: Toby Dylan Hocking, animation and direct manipulation. 6 | - [[file:HOCKING-handout.pdf][1-page summary handout]], [[file:HOCKING-handout.tex][source]]. 7 | - Please install required packages via 8 | =source("http://tdhock.github.io/interactive-tutorial/packages.R")= 9 | and if that worked then =example(animint)= should open some web 10 | browser windows containing animints. 11 | - Thanks to [[https://github.com/hadley][Hadley Wickham]], the ggplot2 dev team, and my animint 12 | GSOC 2013-2016 students [[https://github.com/srvanderplas][Susan VanderPlas]], [[https://github.com/cpsievert][Carson Sievert]], [[https://github.com/caijun][Tony 13 | Tsai]], [[https://github.com/kferris10][Kevin Ferris]], [[https://github.com/faizan-khan-iit][Faizan Khan]]. Without their work none of this 14 | would be possible! 15 | - [[http://cbio.ensmp.fr/~thocking/interactive-tutorial/introduction-vocabulary.html][Introduction and vocabulary]] (5 min), [[https://github.com/tdhock/interactive-tutorial/blob/gh-pages/introduction-vocabulary.Rmd][source]]. 16 | - [[https://rcdata.nau.edu/genomic-ml/animint2-manual/Ch02-ggplot2.html][Basics of ggplot2 and animint]] (25 min). 17 | - [[https://rcdata.nau.edu/genomic-ml/animint2-manual/Ch03-showSelected.html][aes(showSelected)]] (25 min). 18 | - [[https://rcdata.nau.edu/genomic-ml/animint2-manual/Ch04-clickSelects.html][aes(clickSelects)]] (25 min). 19 | - [[file:HOCKING-exercises.R][Exercises]] ([[file:HOCKING-solutions.R][solutions]]). 20 | 21 | ** ALEA seminar Nov 2024 22 | 23 | Titre : animint2 dans R pour les graphiques intéractifs 24 | 25 | Conférencier : Toby Dylan Hocking, Professeur Agrégé, UdeS Département d'Informatique (http://tdhock.github.io/) 26 | 27 | Résumé : Dans la visualisation de données, les graphiques interactifs permettent de cliquer sur des éléments d'un graphique, pour ensuite changer ce qui est affiché dans un autre graphique. Ils sont utiles pour l'enseignement et la recherche, mais ils sont souvent difficiles à créer. Ici, je propose le package R animint2 pour la création rapide des graphiques interactifs, en utilisant la méthode "grammaire de graphiques" qui a été popularisé par ggplot2 pour les graphiques non interactifs. animint2 est un logiciel mature, développé depuis 2013, disponible sur CRAN, avec beaucoup de documentation. Dans cette présentation je vais expliquer comment vous pouvez utiliser animint2 pour créer et partager les graphiques interactifs. 28 | 29 | Diapos : https://docs.google.com/presentation/d/1QDwo9x4OM7UKAXffJrny6nSfeytFR0kO5NB-NQEspcE 30 | 31 | Article : https://doi.org/10.1080/10618600.2018.1513367 32 | 33 | Paquetage R : https://github.com/animint/animint2 34 | 35 | Documentation : https://rcdata.nau.edu/genomic-ml/animint2-manual/Ch02-ggplot2.html 36 | 37 | Exemples : https://animint.github.io/gallery/ 38 | 39 | Installation : =install.packages("animint2")= sous R version >= 3.5.0 40 | 41 | ** SHERC RIC workshop Spring 2022 42 | 43 | Title: Animated, Interactive Data Visualization: animint2 R package 44 | 45 | Abstract: Data visualization is useful for understanding patterns in large data sets and models. 46 | In constrast with static data visualization which produces a single image rendered as a PDF/PNG/etc image file, interactive data visualization can show many images of a data set, by rendering to a web page which can be clicked in order to show/hide different details of the data set. 47 | Interactive data visualization is useful for exploratory data analysis, for research, and for teaching. 48 | This tutorial will explain how to create animated and interactive data visualizations using the animint2 R package. 49 | It will cover chapters 2-4 of the animint2 Manual, https://rcdata.nau.edu/genomic-ml/animint2-manual/Ch02-ggplot2.html 50 | Participants in this workshop should have R installed on their computer so they can follow along with the exercises. 51 | Some prior knowledge of R and the ggplot2 package would be useful. 52 | We will begin by explaining the basics of ggplots (grammar of graphics plots), including plot sketching, geoms, and aesthetic mappings from data variables to visual properties. 53 | Next we will show how the animint() function can be used to render a list of ggplots on a web page. 54 | Finally we will explain the showSelected and clickSelected keywords, which can be used to add interactivity to ggplots. 55 | At the end of this workshop, participants should understand the basics of static and interactive data visualization using the grammar of graphics. 56 | 57 | *** Intro examples 58 | 59 | - [[https://github.com/tdhock/animint/wiki/Gallery][Animint Gallery containing links to example data visualizations and source code]]. 60 | - Click on legends to hide/show data subsets of interest, [[https://bl.ocks.org/tdhock/raw/8d188b04ca9aa629a3700a8055bf27dd/][Evaluation of binary classification algorithms, highly imbalanced Table Mountain Pine data]], [[https://github.com/tdhock/species-variable-selection/blob/master/figure-batchtools-expired.R][source]]. 61 | - Click on [[http://bl.ocks.org/tdhock/raw/43ac9c6be9188dcb02a7/][loss/BIC plot]] to select data and changepoint model, [[https://github.com/tdhock/animint/blob/master/inst/examples/intreg.R][source]]. 62 | - Animation over years and click selects countries, [[https://rcdata.nau.edu/genomic-ml/WorldBank-facets/][World Bank data visualization]], [[https://github.com/tdhock/animint2/blob/master/inst/examples/WorldBank-facets.R][source]]. 63 | - Animation over iterations of gradient descent and click selects data and step size, [[http://ml.nau.edu/viz/2022-02-02-gradient-descent-regression/][Gradient descent for linear regression]], [[https://github.com/tdhock/cs570-spring-2022/blob/master/figure-gradient-descent-regression.R][source]]. 64 | 65 | *** Hello world 66 | 67 | #+BEGIN_SRC R 68 | install.packages("animint2") 69 | example("animint", package="animint2") 70 | ## if it does not render try installing servr: 71 | install.packages("servr") 72 | #+END_SRC 73 | 74 | - [[https://github.com/tdhock/animint2/wiki/FAQ#web-browser-on-local-indexhtml-file-is-blank][FAQ]] about blank web browser page. 75 | 76 | 77 | -------------------------------------------------------------------------------- /README.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[T1]{fontenc} 4 | \usepackage{fullpage} 5 | \usepackage{graphicx} 6 | \usepackage{grffile} 7 | \usepackage{longtable} 8 | \usepackage{wrapfig} 9 | \usepackage{rotating} 10 | \usepackage[normalem]{ulem} 11 | \usepackage{amsmath} 12 | \usepackage{textcomp} 13 | \usepackage{amssymb} 14 | \usepackage{capt-of} 15 | \usepackage{hyperref} 16 | \author{Toby Dylan Hocking} 17 | \date{\today} 18 | \title{Understanding and producing interactive graphics} 19 | \hypersetup{ 20 | pdfauthor={Toby Dylan Hocking}, 21 | pdftitle={}, 22 | pdfkeywords={}, 23 | pdfsubject={}, 24 | pdfcreator={Emacs 24.3.1 (Org mode 8.3.2)}, 25 | pdflang={English}} 26 | \begin{document} 27 | 28 | %\tableofcontents 29 | 30 | %% \section{{\bfseries\sffamily TODO} } 31 | %% \label{sec:orgheadline1} 32 | 33 | %% send this to useR-2016@R-project.org before January 10, 2016. 34 | 35 | \section{Tutorial Title} 36 | \label{sec:orgheadline2} 37 | 38 | Understanding and creating interactive graphics 39 | 40 | \section{Instructors} 41 | \label{sec:orgheadline3} 42 | 43 | \begin{center} 44 | \begin{tabular}{llll} 45 | Name & Institution & Address & Email\\ 46 | \hline 47 | Toby Dylan Hocking & McGill & Montreal, Canada & toby.hocking@mail.mcgill.ca\\ 48 | Claus Thorn Ekstrøm & Univ. Copenhagen & Copenhagen, Denmark & ekstrom@sund.ku.dk\\ 49 | \end{tabular} 50 | \end{center} 51 | 52 | \section{Short Instructor Biography} 53 | \label{sec:orgheadline4} 54 | 55 | Toby Dylan Hocking has designed and implemented several R graphics 56 | packages. He is the designer and primary maintainer of directlabels 57 | (Best Student Poster Prize at useR 2011) and animint (presented in an 58 | \href{https://www.amstat.org/meetings/jsm/2015/onlineprogram/AbstractDetails.cfm?abstractid=314184\%0A}{invited 59 | session at Joint Statistical Meetings 2015}). He is also the 60 | original designer of the ggplot conversion feature of the plotly 61 | package. 62 | 63 | Claus Thorn Ekstrøm is the creator and contributor to a number of R 64 | packages (MESS, MethComp, SuperRanker) and is the author of "The R 65 | Primer" book. He has previously given 66 | \href{http://biostatistics.dk/presentations/DynGraph.html}(tutorials 67 | on Dynamic graphics in R) and the role of interactive graphics in 68 | teaching, and won the C. Oswald George prize for his article "Teaching 69 | ‘Instant Experience’ with Graphical Model Validation Techniques" in 70 | 2014. 71 | 72 | \section{Brief Description of Tutorial} 73 | \label{sec:orgheadline5} 74 | 75 | An interactive graphic invites the viewer to become an active partner 76 | in the analysis and allows for immediate feedback on how the data and 77 | results may change when inputs are modified. Interactive graphics can 78 | be extremely useful for exploratory data analysis, for teaching, and 79 | for reporting. 80 | 81 | Because there are so many different kinds of interactive graphics, 82 | there has been an explosion in R packages that can produce them 83 | (e.g. animint, shiny, rCharts, rMaps, ggvis, htmlwidgets). A beginner 84 | with little knowledge of interactive graphics can thus be easily 85 | confused by (1) understanding what kinds of graphics are useful for 86 | what kinds of data, and (2) finding an R package that can produce the 87 | desired type of graphic. This tutorial solves these two problems by 88 | (1) introducing a vocabulary of keywords for understanding the 89 | different kinds of graphics, and (2) explaining what R packages can be 90 | used for each kind of graphic. 91 | 92 | \section{Goals} 93 | \label{sec:orgheadline6} 94 | 95 | \begin{enumerate} 96 | \item Explain and emphasize the role that interactive graphics have in 97 | reporting, scientific journals, and in teaching. 98 | \item By showing several examples, explain different categories of 99 | graphics: animated, multi-panel, and multi-layer, interactive 100 | (direct vs indirect manipulation). 101 | \item Explain how existing R packages can be used to create these 102 | different types of graphics. 103 | \item Explain the strengths and weaknesses of the existing R packages, to 104 | highlight directions for future work. 105 | \end{enumerate} 106 | 107 | \section{Detailed Outline} 108 | \label{sec:orgheadline10} 109 | 110 | \subsection{A vocabulary for understanding interactive graphics, 30 minutes} 111 | \label{sec:orgheadline7} 112 | 113 | In this section we will give a high-level introduction about 114 | interactive graphics, without going into details about R code for 115 | specific packages. 116 | 117 | Motivation: interactive graphics in exploratory data analysis, 118 | reporting results and teaching. 119 | 120 | Vocabulary for describing interactive graphics: 121 | \begin{description} 122 | \item[{interactive}] user interaction changes what is displayed. Useful 123 | when there are many similar plots for different data subsets, but 124 | you \textbf{don't} want to see them all at the same time. 125 | \begin{description} 126 | \item[{direct manipulation}] interacting with plot elements (lines, 127 | points, etc). 128 | \item[{indirect manipulation}] interacting with keyboard, mouse clicks 129 | on widgets (buttons, menus, etc). 130 | \end{description} 131 | \item[{animated}] An animated graphic automatically advances over time, 132 | like a video. Animated graphics are most useful when data sets 133 | have a time dimension. The only interaction possible is moving 134 | forward and backward in time. 135 | \item[{multi-layer}] A multi-layer graphic uses several geometric elements 136 | to show several data sets and/or variables. Multi-layer plots are 137 | useful for showing relationships between data sets and/or 138 | variables. 139 | \item[{multi-panel}] A multi-panel graphic shows different things in 140 | different panels (sub-plots) which each have their own axes 141 | (perhaps different from each other). Useful when there are many 142 | similar plots for different data subsets, and you \textbf{do} want to 143 | see them at the same time. Also useful for showing different 144 | plots with aligned axes. 145 | \end{description} 146 | Compare and contrast: 147 | \begin{description} 148 | \item[{interactive vs animated}] only interaction possible in an animated 149 | graphic is moving forward and backward in time (animated graphics 150 | are thus a subset of interactive graphics). 151 | \item[{interactive vs multi-panel}] both useful for many similar plots 152 | with different data subsets. Do you want to see all the subsets 153 | at the same time? (yes=multi-panel, no=interactive) 154 | \end{description} 155 | 156 | \subsection{Quiz questions} 157 | \label{sec:orgheadline8} 158 | 159 | The previous section introduced a vocabulary for describing 160 | interactive graphics. In the following section, after showing a new 161 | graphic, we will ask the audience to take 1 minute to discuss with 162 | their neighbour about which vocabulary words can be used to describe 163 | that graphic. 164 | 165 | \subsection{Creating interactive graphics using R packages} 166 | \label{sec:orgheadline9} 167 | 168 | In this section we will show specific R code examples from the various 169 | packages. 170 | 171 | \begin{description} 172 | \item[{High-level interactive plotting packages, 30 minutes}] \mbox{ } 173 | 174 | \begin{itemize} 175 | \item Simple approaches like rotating plots (rgl package) and simple user 176 | interaction (wallyplot from MESS package). 177 | \item Interactive bar plots (rCharts, several different JavaScript 178 | interfaces, interfacing with JavaScript libraries to change axes 179 | and legends) 180 | \item Interactive scatter plots showing happiness and tax rate (rCharts, 181 | and clickme packages, several different JavaScript interfaces, add 182 | dropdown effects and improve tooltips) 183 | \item interactive maps and choropleths (the rMaps packages) 184 | \item Discussion of frustrations that new users unfamiliar with 185 | JavaScript may encounter when interfacing with JavaScript libraries 186 | \end{itemize} 187 | \item[{Interactive graphics with shiny and plotly, 30 minutes}] \mbox{ } 188 | \begin{itemize} 189 | \item Teaching least squares estimation (shiny) 190 | \item Teaching power calculations (shiny) 191 | \item Reproducing some of the previous graphics on happiness and tax 192 | rate in plotly (ggplot2, and ggplotly, adding tooltips/hover 193 | effects, and dropdown) 194 | \item Graphics on prediction accuracy for Danish population predictions 195 | (plotly, adding sliders) 196 | \end{itemize} 197 | \item[{Multi-layer graphics, ggplot2 package, 15 minutes}] \mbox{ } 198 | \begin{itemize} 199 | \item A map that shows a circle for every city, and a line for borders of 200 | each country. 201 | \item A plot of a linear model that shows data as circles, a regression 202 | line, and model residuals as line segments. 203 | \end{itemize} 204 | \item[{Multi-panel graphics, facets in ggplot2, 15 minutes}] useful in two 205 | different situations: 206 | \begin{description} 207 | \item[{Same plot for different data subsets}] a linear model fit to each 208 | of several data subsets. 209 | \item[{Different plots with aligned axes}] World Bank data viz with one 210 | time series panel, and one scatterplot panel. 211 | \end{description} 212 | \item[{Animated graphics, animation package, 15 minutes}] \mbox{ } 213 | \begin{itemize} 214 | \item Gradient descent (time=iterations). 215 | \item Two-panel World Bank data viz (time=years). 216 | \end{itemize} 217 | \item[{Interactive + animated + multi-panel + multi-layer, 45 minutes}] a 218 | few packages are able to produce complex graphics which can be 219 | described by several vocabulary words. 220 | \begin{description} 221 | \item[{shiny + ggplot2}] World Bank data viz, interacting with widgets 222 | changes selected year, countries, regions. 223 | \item[{shiny + ggvis}] same kind of graphic with World Bank data. 224 | \item[{animint}] World Bank data viz, direct manipulation changes 225 | selected year, countries, regions. 226 | \end{description} 227 | \end{description} 228 | 229 | \section{Justification} 230 | \label{sec:orgheadline11} 231 | 232 | The role of graphics is expanding and is moving away from simple 233 | static representations found in scientific journals to more 234 | interactive representations where the user is directly involved in 235 | exploring different facets of the data. In that sense, the reader 236 | indirectly takes on the role of the analyst, and R is the ideal tool 237 | to produce integrated, interactive graphics and for interfacing with 238 | some of the external graphics libraries that exist. 239 | 240 | The various implementations for interactive graphics found in R 241 | packages are often highly specialized in the same way as high-level 242 | plots, and each package typically has a completely different 243 | syntax. This tutorial will 244 | \begin{itemize} 245 | \item introduce a vocabulary for categorizing interactive graphics, 246 | \item present practical examples of how to produce interactive graphics 247 | using existing R packages, 248 | \item describe how to overcome frustrations typical of new users to 249 | interactive graphics, and 250 | \item highlight advantages and room for improvement in existing 251 | packages. 252 | \end{itemize} 253 | 254 | %\textbf{TDH should we delete this paragraph? It seems repetitive with the previous paragaph.} When the tutorial is over the attendees should 1) 255 | %have an overview of the packages for producing interactive 256 | %graphics, 2) have seen and tried examples so they are able to create 257 | %interactive graphics using some of the packages presented, and 3) have 258 | %seen the broad scope of variation among packages that seek to produce 259 | %the same type of graphics. 260 | 261 | \section{Background Knowledge} 262 | \label{sec:orgheadline12} 263 | 264 | Since we plan to present state-of-the-art interactive graphics, people 265 | should know how to use R data structures (lists, data.frames) and the 266 | ggplot2 package. 267 | 268 | Even though many examples will be interactive web graphics, we will 269 | assume only knowledge of R, not HTML/JavaScript. 270 | 271 | There are two classes of potential attendees: 272 | \begin{itemize} 273 | \item UseRs who are not very familiar with interactive graphics should 274 | benefit the most, since we will give a high-level overview of many 275 | different packages. 276 | \item DevelopeRs of interactive packages are encouraged to come, to 277 | discuss the current state-of-the-art and future directions. 278 | \end{itemize} 279 | 280 | \section{Expected Number of Attendees} 281 | \label{sec:orgheadline13} 282 | 283 | We're not sure how to estimate this, but typically interactive 284 | graphics are a popular topic so it would be best to have a decent 285 | sized lecture hall (50-150 people). 286 | \end{document} 287 | -------------------------------------------------------------------------------- /animation/README.org: -------------------------------------------------------------------------------- 1 | Comparison of R packages that can produce interactive animations 2 | 3 | All 4 methods below have these points in common: 4 | 5 | - Interact with the plot to show/hide subsets of data. 6 | - Animation. 7 | - Multi-layer: several different geoms can be combined on the same plot (e.g. points and lines). 8 | - The user only needs to write R code (not JavaScript). 9 | - Plot rendered in a web browser using HTML and JavaScript. 10 | 11 | | main idea | years | interaction | plotting | plot rendered as | click on | server? | interaction variables | programming | user LOC | user needs to learn | 12 | |--------------------+-------+-------------+----------+---------------------------+-----------------------+---------+-----------------------+-------------+----------+---------------------------------------------| 13 | | plots in sequence | 2007- | [[https://github.com/yihui/animation][animation]] | [[https://github.com/hadley/ggplot2][ggplot2]] | PNG | play/stop buttons | no | 1 = time | imperative | 40 | saveHTML() | 14 | | R server + ggplots | 2012- | [[http://www.rstudio.com/shiny/][shiny]] | [[https://github.com/hadley/ggplot2][ggplot2]] | PNG | sliders, etc. | yes | several | reactive | 60 | shinyUI(), sliderInput(), renderPlot() | 15 | | R server + vega | 2013- | [[http://www.rstudio.com/shiny/][shiny]] | [[https://github.com/rstudio/ggvis][ggvis]] | vega json (svg or canvas) | sliders, etc. | yes | several | reactive | 70 | props(), mark_point(), dscale(), reactive() | 16 | | ggplots -> D3 | 2013- | [[https://github.com/tdhock/animint][animint]] | [[https://github.com/hadley/ggplot2][ggplot2]] | json/csv/svg | the plot (data/geoms) | no | several | declarative | 20 | clickSelects, showSelected, gg2animint() | 17 | 18 | Raster/bitmap image formats 19 | - Portable Network Graphics (PNG). 20 | - canvas is an HTML element which can be used with JavaScript to render a 2D raster image on a web page. 21 | 22 | Vector image formats 23 | - Scalable Vector Graphics (svg). 24 | 25 | Text data formats 26 | - JavaScript Object Notation (json). 27 | - vega is a visualization grammar (a special case of json). 28 | - Comma-separated values (csv) is for data tables. 29 | 30 | Code formats (programming languages) 31 | - JavaScript is for controlling web pages. 32 | - Data-Driven Documents (D3) is a JavaScript library. 33 | 34 | ** animation 35 | 36 | If you want to interact with only one variable (time), then animation 37 | is the best, since it offers a wide variety of export formats (web 38 | page, MOV, animated GIF). To view an example, 39 | =source("animation.R")= in the WorldBank subdirectory. 40 | 41 | ** animint 42 | 43 | If you want to interact with several variables (not just time), then 44 | animint is the best. However, the only kind of interaction that can be 45 | expressed using animint is showing and hiding subsets of data, based 46 | on the selected value of each interaction variable. To view an 47 | example, =source("animint.R")= in the WorldBank subdirectory. 48 | 49 | ** shiny + ggplot2 or ggvis 50 | 51 | If you want other kinds of interactions, or you want to do 52 | calculations on the server, then shiny is the best. Do 53 | =shiny::runApp("shiny")= for ggplot2, and =shiny::runApp("ggvis")= for 54 | ggvis. Due to some backwards-incompatible changes, you may need to run 55 | =git checkout 3e0b8d379d15d51d29a4a7ba799741065abe3db2= to get a 56 | version of ggvis that works with this example. 57 | 58 | ** Future work 59 | 60 | A translator that takes a list of ggplots with showSelected and 61 | clickSelects aesthetics, and outputs a shiny app. 62 | -------------------------------------------------------------------------------- /animation/WorldBank/animation.R: -------------------------------------------------------------------------------- 1 | library(animation) 2 | library(grid) 3 | library(ggplot2) 4 | data(WorldBank, package="animint") 5 | fertility.range <- range(WorldBank$fertility.rate, na.rm=TRUE) 6 | life.range <- range(WorldBank$life.expectancy, na.rm=TRUE) 7 | years <- split(WorldBank, WorldBank$year) 8 | ani.options(ani.width=800,ani.height=800) 9 | saveHTML({ 10 | for(year in names(years)){ 11 | grid.newpage() 12 | wb <- years[[year]] 13 | selectedCountry <- "Japan" 14 | l <- grid.layout(nrow=2) 15 | pushViewport(viewport(layout=l)) 16 | YearLabel <- CountryLabel <- subset(wb, country == selectedCountry) 17 | YearLabel$fertility.rate <- 5 18 | YearLabel$life.expectancy <- 80 19 | TimeSeries <- ggplot()+ 20 | geom_vline(aes(xintercept=year), data=YearLabel)+ 21 | geom_line(aes(year, life.expectancy, group=country, colour=region, 22 | alpha=ifelse(country==selectedCountry, 1, 1/10)), 23 | data=WorldBank, size=1.5)+ 24 | scale_alpha_identity() 25 | print(TimeSeries, vp=viewport(layout.pos.col=1,layout.pos.row=1)) 26 | scatter <- ggplot(,aes(fertility.rate, life.expectancy))+ 27 | geom_point(aes(colour=region, size=population), data=wb, alpha=1/2)+ 28 | geom_text(aes(label=sprintf("Year = %d",year)), data=YearLabel)+ 29 | geom_text(aes(label=country), data=CountryLabel)+ 30 | continuous_scale("size","area",palette=function(x){ 31 | scales:::rescale(sqrt(abs(x)), c(2,20), c(0,1)) 32 | }, breaks=10^(4:9), limits=range(WorldBank$population, na.rm=TRUE))+ 33 | xlim(fertility.range)+ylim(life.range) #manually specify limits! 34 | if(any(!is.na(wb$fertility.rate))){ 35 | print(scatter, vp=viewport(layout.pos.col=1,layout.pos.row=2)) 36 | } 37 | } 38 | }) 39 | -------------------------------------------------------------------------------- /animation/WorldBank/animint.R: -------------------------------------------------------------------------------- 1 | library(animint) 2 | data(WorldBank) 3 | viz <- 4 | list(ts=ggplot()+ 5 | make_tallrect(WorldBank, "year")+ 6 | geom_line(aes(year, life.expectancy, group=country, colour=region, 7 | clickSelects=country), 8 | data=WorldBank, size=3, alpha=3/5), 9 | time=list(variable="year",ms=3000), 10 | duration=list(year=1000), 11 | scatter=ggplot()+ 12 | geom_point(aes(fertility.rate, life.expectancy, clickSelects=country, 13 | showSelected=year, colour=region, size=population), 14 | data=WorldBank)+ 15 | geom_text(aes(fertility.rate, life.expectancy, label=country, 16 | showSelected=country, showSelected2=year), 17 | data=WorldBank)+ 18 | make_text(WorldBank, 5, 80, "year")+ 19 | continuous_scale("size","area",palette=function(x){ 20 | scales:::rescale(sqrt(abs(x)), c(2,20), c(0,1)) 21 | },breaks=10^(4:9), limits=range(WorldBank$pop, na.rm=TRUE))) 22 | gg2animint(viz) 23 | -------------------------------------------------------------------------------- /animation/WorldBank/ggvis/server.r: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(animint) 3 | library(ggvis) 4 | 5 | data(WorldBank, package="animint") 6 | Worldbank <- subset(WorldBank, !is.na(life.expectancy) & !is.na(population) & !is.na(fertility.rate) & !is.na(year)) 7 | years <- split(Worldbank, Worldbank$year) 8 | countries <- split(Worldbank, Worldbank$country) 9 | fertility.range <- range(Worldbank$fertility.rate, na.rm=TRUE) 10 | life.range <- range(Worldbank$life.expectancy, na.rm=TRUE) 11 | pop.breaks <- seq(5e8, 1e9, by=1e8) 12 | pop.range <- range(Worldbank$population, na.rm=TRUE) 13 | regions <- levels(Worldbank$region) 14 | library(RColorBrewer) 15 | region.colors <- brewer.pal(length(regions), "Set1") 16 | shinyServer(function(input, output, session) { 17 | this.year <- reactive({ 18 | current.year <- as.character(input$year) 19 | dat <- years[[current.year]] 20 | selected <- input$country == dat$country 21 | dat$hilite <- ifelse(selected, "yes", "no") 22 | dat$width <- ifelse(selected, 5, 0) 23 | dat 24 | }) 25 | scatter <- ggvis(this.year, 26 | props(x= ~fertility.rate, y= ~life.expectancy, 27 | size= ~population, stroke= ~region, 28 | ##strokeWidth= ~width, 29 | fill= ~hilite)) + 30 | layer_point() + 31 | dscale("stroke", "nominal", range=region.colors, name="stroke") + 32 | dscale("fill", "nominal", name="fill", range=c("white", "black")) + 33 | dscale("size", "numeric", name="size") + 34 | dscale("x", "numeric", domain=fertility.range) + #manual limits! 35 | dscale("y", "numeric", domain=life.range) + 36 | guide_axis("x", title="Fertility Rate") + 37 | guide_axis("y", title="Life Expectancy") + 38 | guide_legend(size = "size", title="Population") + 39 | guide_legend(fill = "stroke", stroke="stroke", orient="left", title="Region") + 40 | guide_legend(stroke = "fill", orient="left", title="", values=c("", ""), 41 | properties=list( 42 | legend=props(size=0, stroke="transparent", fill="transparent", 43 | strokeOpacity=0, fillOpacity=0, strokeWidth='0px'), 44 | symbols=props(size=0, stroke="transparent", fill="transparent", 45 | strokeOpacity=0, fillOpacity=0, strokeWidth='0px'))) + 46 | opts(width=450, height=400) 47 | 48 | scatter$legends[which(sapply(scatter$legends, function(i) i$title==""))][[1]][["properties"]][["legend"]]$y <- 50 49 | r_gv <- reactive(scatter) 50 | observe_ggvis(r_gv, "scatter", session, "svg") 51 | this.country <- reactive({ 52 | countries[[input$country]] 53 | }) 54 | this.year.vline <- reactive({ 55 | current.year <- as.character(input$year) 56 | dat <- years[[current.year]][1:2,] 57 | dat$life.expectancy <- life.range 58 | subset(dat, !is.na(life.expectancy) & !is.na(region) & !is.na(year)) 59 | }) 60 | ts <- ggvis(props(x= ~year, y= ~life.expectancy), 61 | layer_path(props(stroke:="black", opacity := 2/10), 62 | data=subset(Worldbank, !is.na(life.expectancy))), 63 | layer_path(data=this.country, props(stroke=~region, strokeWidth :=2, opacity:=1)), 64 | layer_path(data=this.year.vline)) + 65 | guide_axis("x", title="Year", format="04d") + 66 | guide_axis("y", title="Life Expectancy") + 67 | guide_legend(fill = "stroke", stroke="stroke",orient="left", title="", values=c("", ""), 68 | properties=list( 69 | legend=props(size=0, stroke="transparent", fill="transparent", 70 | strokeOpacity=0, fillOpacity=0, strokeWidth='0px'), 71 | symbols=props(size=0, stroke="transparent", fill="transparent", 72 | strokeOpacity=0, fillOpacity=0, strokeWidth='0px'))) + 73 | opts(width=425, height=400) 74 | r_gv2 <- reactive(ts) 75 | observe_ggvis(r_gv2, "ts", session, "svg") 76 | }) 77 | -------------------------------------------------------------------------------- /animation/WorldBank/ggvis/test.r: -------------------------------------------------------------------------------- 1 | library(ggvis) 2 | data(WorldBank, package="animint") 3 | years <- split(WorldBank, WorldBank$year) 4 | fertility.range <- range(WorldBank$fertility.rate, na.rm=TRUE) 5 | life.range <- range(WorldBank$life.expectancy, na.rm=TRUE) 6 | pop.breaks <- seq(5e8, 1e9, by=1e8) 7 | pop.range <- range(WorldBank$population, na.rm=TRUE) 8 | regions <- levels(WorldBank$region) 9 | current.year <- 5 10 | 11 | dat <- years[[current.year]] 12 | ddat <- reactive({ 13 | invalidateLater(2000, NULL) 14 | current.year <<- current.year + 1 15 | dat <<- years[[current.year]] 16 | dat 17 | }) 18 | ggvis(ddat, 19 | props(x = ~fertility.rate, y = ~life.expectancy, 20 | size = ~population), 21 | mark_symbol(), 22 | dscale("x", "numeric", domain=fertility.range), 23 | dscale("y", "numeric", domain=life.range)) 24 | -------------------------------------------------------------------------------- /animation/WorldBank/ggvis/ui.r: -------------------------------------------------------------------------------- 1 | data(WorldBank, package="animint") 2 | years <- unique(WorldBank$year) 3 | countries <- sort(unique(WorldBank$country)) 4 | countryList <- structure(as.list(countries),names=countries) 5 | shinyUI(fluidPage( 6 | titlePanel("ggvis Interactive Graphics", tags$head(tags$style(type="text/css", "#g47 { display: none;} #g25 { display: none;} #g69 { display: none;} .ggvis-control { display: none;}")) 7 | ), 8 | fluidRow( 9 | column(2, sliderInput("year", "Year", min = 1960, max = 2011, 10 | value=1960, step = 1, format="#", 11 | animate=animationOptions(interval=2000, loop=TRUE)), 12 | selectInput("country", "Country", countryList, selected="Japan")), 13 | column(4, ggvis_output("ts")), 14 | column(6, ggvis_output("scatter")) 15 | ) 16 | )) 17 | -------------------------------------------------------------------------------- /animation/WorldBank/shiny/server.r: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | data(WorldBank, package="animint") 3 | years <- split(WorldBank, WorldBank$year) 4 | fertility.range <- range(WorldBank$fertility.rate, na.rm=TRUE) 5 | life.range <- range(WorldBank$life.expectancy, na.rm=TRUE) 6 | shinyServer(function(input, output, session) { 7 | output$scatter <- renderPlot({ 8 | this.year <- years[[as.character(input$year)]] 9 | this.year$hilite <- ifelse(this.year$country == input$country, "yes", "no") 10 | this.country <- subset(this.year, country==input$country) 11 | gg <- ggplot()+ 12 | geom_point(aes(fertility.rate, life.expectancy, 13 | colour=region, size=population, 14 | alpha=hilite), 15 | data=this.year)+ 16 | scale_alpha_manual(values=c(yes=1,no=1/2), guide=FALSE)+ 17 | continuous_scale("size","area",palette=function(x){ 18 | scales:::rescale(sqrt(abs(x)), c(2,20), c(0,1)) 19 | }, breaks=10^(4:9), limits=range(WorldBank$pop, na.rm=TRUE))+ 20 | xlim(fertility.range)+ylim(life.range)#Manually specify limits! 21 | if(!is.na(this.country$fert)){ 22 | gg <- gg+ 23 | geom_text(aes(fertility.rate, life.expectancy, label=country), 24 | data=this.country) 25 | } 26 | print(gg) 27 | }) 28 | output$ts <- renderPlot({ 29 | this.year <- years[[as.character(input$year)]] 30 | WorldBank$hilite <- ifelse(WorldBank$country == input$country, "yes", "no") 31 | gg <- ggplot()+ 32 | geom_vline(aes(xintercept=year), data=this.year[1,])+ 33 | scale_alpha_manual(values=c(yes=1,no=1/10), guide=FALSE)+ 34 | geom_line(aes(year, life.expectancy, group=country, colour=region, 35 | alpha=hilite), data=WorldBank)+ 36 | ylim(life.range) 37 | print(gg) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /animation/WorldBank/shiny/ui.r: -------------------------------------------------------------------------------- 1 | data(WorldBank, package="animint") 2 | years <- unique(WorldBank$year) 3 | countries <- sort(unique(WorldBank$country)) 4 | countryList <- structure(as.list(countries),names=countries) 5 | shinyUI(pageWithSidebar( 6 | div(), 7 | sidebarPanel( 8 | sliderInput("year", "Year", min = min(years), max = max(years), 9 | value=1970, step = 1, format="#", 10 | animate=animationOptions(interval=2000, loop=TRUE)), 11 | selectInput("country", "Country", countryList, selected="Japan") 12 | ), 13 | mainPanel( 14 | plotOutput("scatter"), 15 | plotOutput("ts") 16 | ) 17 | )) 18 | -------------------------------------------------------------------------------- /animation/WorldBank/shinyDX/global.r: -------------------------------------------------------------------------------- 1 | data(WorldBank, package="animint") 2 | WorldBank <- data.frame(WorldBank)#so all colnames start with a letter. 3 | for(num.var in c("longitude", "latitude")){ 4 | WorldBank[[num.var]] <- as.numeric(as.character(WorldBank[[num.var]])) 5 | } 6 | -------------------------------------------------------------------------------- /animation/WorldBank/shinyDX/server.r: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | years <- split(WorldBank, WorldBank$year) 3 | ranges <- list() 4 | breaks <- list() 5 | for(col.name in names(WorldBank)){ 6 | vec <- WorldBank[[col.name]] 7 | if(is.numeric(vec)){ 8 | ranges[[col.name]] <- rr <- range(vec, na.rm=TRUE) 9 | r <- round(rr) 10 | breaks[[col.name]] <- seq(r[1], r[2], l=5) 11 | } 12 | } 13 | shinyServer(function(input, output, session) { 14 | ggupdate <- function(gg, aes.var, input.var=aes.var){ 15 | var.name <- input[[input.var]] 16 | var.range <- ranges[[var.name]] 17 | if(!is.null(var.range)){#Manually specify limits! 18 | limfun <- get(sprintf("%slim",aes.var)) 19 | gg <- gg+limfun(var.range) 20 | } 21 | gg 22 | } 23 | output$scatter <- renderPlot({ 24 | this.year <- years[[as.character(input$year)]] 25 | this.year$hilite <- ifelse(this.year$country == input$country, "yes", "no") 26 | this.country <- subset(this.year, country==input$country) 27 | a <- aes_string(x=input$x, y=input$y, size=input$size, color=input$color, 28 | alpha="hilite") 29 | gg <- ggplot()+ 30 | geom_point(a, data=this.year)+ 31 | scale_alpha_manual(values=c(yes=1,no=1/2), guide=FALSE) 32 | size.range <- ranges[[input$size]] 33 | if(!is.null(size.range)){ 34 | gg <- gg+continuous_scale("size","area",palette=function(x){ 35 | scales:::rescale(sqrt(abs(x)), c(2,10), c(0,1)) 36 | },breaks=breaks[[input$size]], limits=size.range) 37 | } 38 | for(xy in c("x", "y")){ 39 | gg <- ggupdate(gg, xy) 40 | } 41 | ok <- !is.na(this.country[,c(input$x, input$y)]) 42 | if(all(ok)){ 43 | a <- aes_string(x=input$x, y=input$y, label=input$label) 44 | gg <- gg+geom_text(a, data=this.country) 45 | } 46 | print(gg) 47 | }) 48 | output$ts <- renderPlot({ 49 | this.year <- years[[as.character(input$year)]] 50 | WorldBank$hilite <- ifelse(WorldBank$country == input$country, "yes", "no") 51 | a <- aes_string(x="year", y=input$tsy, color=input$color, 52 | group="country", alpha="hilite") 53 | gg <- ggplot()+ 54 | geom_vline(aes(xintercept=year), data=this.year[1,])+ 55 | scale_alpha_manual(values=c(yes=1,no=1/10), guide=FALSE)+ 56 | geom_line(a, data=WorldBank) 57 | gg <- ggupdate(gg, "y", "tsy") 58 | print(gg) 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /animation/WorldBank/shinyDX/ui.r: -------------------------------------------------------------------------------- 1 | years <- unique(WorldBank$year) 2 | countries <- sort(unique(WorldBank$country)) 3 | countryList <- structure(as.list(countries),names=countries) 4 | vars <- names(WorldBank) 5 | shinyUI(pageWithSidebar( 6 | div(), 7 | sidebarPanel( 8 | sliderInput("year", "Year", min = min(years), max = max(years), 9 | value=1970, step = 1, format="#", 10 | animate=animationOptions(interval=2000, loop=TRUE)), 11 | selectInput("country", "Country", countryList, selected="Japan"), 12 | selectInput("x", "Scatterplot x", 13 | vars, selected="fertility.rate"), 14 | selectInput("y", "Scatterplot y", 15 | vars, selected="life.expectancy"), 16 | selectInput("size", "Scatterplot size", 17 | vars, selected="population"), 18 | selectInput("label", "Scatterplot text label", 19 | vars, selected="country"), 20 | selectInput("color", "Scatterplot and time series color", 21 | vars, selected="region"), 22 | selectInput("tsy", "Time series y", vars, selected="life.expectancy") 23 | ), 24 | mainPanel( 25 | plotOutput("scatter"), 26 | plotOutput("ts") 27 | ) 28 | )) 29 | -------------------------------------------------------------------------------- /app2.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | 3 | ui <- fluidPage( 4 | titlePanel("My title"), 5 | sidebarLayout( 6 | sidebarPanel( 7 | selectInput("xvar", label = h3("Select x"), 8 | choices = list("A"=1, "B"=2, "C"=3), 9 | selected = 1)), 10 | mainPanel( 11 | # textOutput("text"), 12 | plotOutput("plot", height="600") 13 | )) 14 | ) 15 | 16 | 17 | server <- function(input, output) { 18 | output$plot <- renderPlot({ 19 | mytext <- input$xvar 20 | 21 | par(mar=c(4,4,0,0)+.1, cex=1.4) 22 | hist(rnorm(1000)) 23 | }) 24 | # output$text <- renderText( { paste0("Hello ", mytext) } ) 25 | } 26 | 27 | shinyServer(server) 28 | 29 | shinyApp(ui = ui, server = server) 30 | -------------------------------------------------------------------------------- /contacts.org: -------------------------------------------------------------------------------- 1 | Emails I have sent to ask for help on a useR 2014 tutorial 2 | 3 | | package | category | person | email | response | 4 | |-----------+-----------+----------------------+-------------------------------+----------| 5 | | googleVis | simple | Markus Gesmann | markus.gesmann@googlemail.com | | 6 | | rCharts | simple | Ramnath Vaidyanathan | ramnath.vaidya@gmail.com | | 7 | | RIGHT | brush | Junghoon Lee | flammy@gmail.com | ok | 8 | | ggvis | animation | ggvis list | google group | | 9 | -------------------------------------------------------------------------------- /img/HOCKING-lab-2015.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/HOCKING-lab-2015.jpg -------------------------------------------------------------------------------- /img/Logo_D3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/Logo_D3.png -------------------------------------------------------------------------------- /img/RJavaHtml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/RJavaHtml.png -------------------------------------------------------------------------------- /img/Rlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/Rlogo.png -------------------------------------------------------------------------------- /img/client.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/client.png -------------------------------------------------------------------------------- /img/clientserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/clientserver.png -------------------------------------------------------------------------------- /img/danstat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/danstat.png -------------------------------------------------------------------------------- /img/dygraphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/dygraphs.png -------------------------------------------------------------------------------- /img/ekstrom-2014.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/ekstrom-2014.jpg -------------------------------------------------------------------------------- /img/fedtsyre.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/fedtsyre.pdf -------------------------------------------------------------------------------- /img/fedtsyre.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/fedtsyre.png -------------------------------------------------------------------------------- /img/fedtsyrer1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/fedtsyrer1.pdf -------------------------------------------------------------------------------- /img/fedtsyrer1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/fedtsyrer1.png -------------------------------------------------------------------------------- /img/fedtsyrer2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/fedtsyrer2.pdf -------------------------------------------------------------------------------- /img/fedtsyrer2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/fedtsyrer2.png -------------------------------------------------------------------------------- /img/frustration20logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/frustration20logo.jpg -------------------------------------------------------------------------------- /img/highcharter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/highcharter.png -------------------------------------------------------------------------------- /img/html5-css3-js-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/html5-css3-js-logo.png -------------------------------------------------------------------------------- /img/kahoot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/kahoot.png -------------------------------------------------------------------------------- /img/leaflet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/leaflet.png -------------------------------------------------------------------------------- /img/metgraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/metgraph.png -------------------------------------------------------------------------------- /img/napoleon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/napoleon.jpg -------------------------------------------------------------------------------- /img/nature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/nature.png -------------------------------------------------------------------------------- /img/nvd3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/nvd3.jpg -------------------------------------------------------------------------------- /img/plotly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/plotly.png -------------------------------------------------------------------------------- /img/primer-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/primer-image.jpg -------------------------------------------------------------------------------- /img/primer-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/primer-image.png -------------------------------------------------------------------------------- /img/wally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/wally.png -------------------------------------------------------------------------------- /img/wordcloud_DKnewbornnames_2014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdhock/interactive-tutorial/e40355fc7f61f03636110c97adcac81ac8bc1302/img/wordcloud_DKnewbornnames_2014.png -------------------------------------------------------------------------------- /intreg.Rmd: -------------------------------------------------------------------------------- 1 | 2 | # Breakpoint detection in copy number data 3 | 4 | ```{r} 5 | data(intreg, package="animint") 6 | str(intreg) 7 | library(data.table) 8 | (signals.dt <- data.table(intreg$signals)) 9 | ``` 10 | 11 | ## Multi-panel and multi-layer data viz 12 | 13 | We can use facets to view each signal in a separate panel. 14 | 15 | ```{r} 16 | library(ggplot2) 17 | gg.signals <- ggplot()+ 18 | ggtitle("Copy number profiles")+ 19 | theme_bw()+ 20 | theme(panel.margin=grid::unit(0, "lines"))+ 21 | scale_x_continuous( 22 | "position on chromosome (mega base pairs)", 23 | breaks=c(100, 200))+ 24 | scale_y_continuous( 25 | "logratio (approximate DNA copy number)", 26 | breaks=c(-1, 0, 1))+ 27 | geom_point(aes(base/1e6, logratio), 28 | data=intreg$sig) 29 | gg.signals+facet_wrap("signal") 30 | gg.signals+facet_grid(signal ~ .) 31 | gg.signals+facet_grid(. ~ signal) 32 | gg.signals+facet_grid(. ~ signal, scales="free") 33 | gg.signals+facet_grid(. ~ signal, scales="free", space="free") 34 | ``` 35 | 36 | Quiz: what keywords apply to the graphics above? 37 | 38 | There are 20 segmentation models for each signal, which we can also 39 | view in separate panels. 40 | 41 | ```{r} 42 | breaks.top <- 1 43 | breaks.bottom <- -1 44 | label.top <- 1 45 | label.bottom <- -1.5 46 | gg.models <- gg.signals+ 47 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean), 48 | data=intreg$seg, 49 | color="green")+ 50 | geom_segment(aes(x=base/1e6, xend=base/1e6, 51 | y=breaks.top, yend=breaks.bottom), 52 | color="green", 53 | linetype="dashed", 54 | data=intreg$breaks) 55 | gg.models+facet_grid(signal ~ segments, scales="free", space="free") 56 | gg.models+facet_grid(segments ~ signal, scales="free", space="free") 57 | ``` 58 | 59 | Quiz: what keywords apply to the graphics above? 60 | 61 | ```{r} 62 | segments.dt <- data.table(intreg$segments) 63 | setkey(segments.dt, signal, first.base, last.base) 64 | signals.dt[, base.after := base+1L] 65 | setkey(signals.dt, signal, base, base.after) 66 | (signals.with.models <- foverlaps(signals.dt, segments.dt)) 67 | ``` 68 | 69 | The data table above has joined segments with overlapping data points. 70 | 71 | ```{r} 72 | model.selection <- signals.with.models[, list( 73 | total.squared.error=sum((logratio-mean)^2), 74 | data=.N), by=.(signal, segments)] 75 | model.selection[, log.data := log(data)] 76 | model.selection[, penalized.error := total.squared.error + log.data * segments] 77 | (one.signal.selection <- model.selection[signal=="4.2",][order(segments),]) 78 | model.selection.labels <- model.selection[segments==1,] 79 | ggplot()+ 80 | geom_text(aes(segments, total.squared.error, label=signal), 81 | data=model.selection.labels, 82 | hjust=1)+ 83 | geom_line(aes(segments, total.squared.error, group=signal), 84 | data=model.selection) 85 | ggplot()+ 86 | geom_text(aes(segments, penalized.error, label=signal), 87 | data=model.selection.labels, 88 | hjust=1)+ 89 | geom_line(aes(segments, penalized.error, group=signal), 90 | data=model.selection) 91 | addType <- function(dt, error.type){ 92 | data.table(dt, error.type=factor(error.type, c("total squared error", "penalized error"))) 93 | } 94 | selectionPlotStatic <- ggplot()+ 95 | theme_bw()+ 96 | theme(panel.margin=grid::unit(0, "cm"))+ 97 | facet_grid(error.type ~ ., scales="free")+ 98 | ylab("")+ 99 | geom_line(aes(segments, total.squared.error, group=signal), 100 | data=addType(model.selection, "total squared error"))+ 101 | geom_line(aes(segments, penalized.error, group=signal), 102 | data=addType(model.selection, "penalized error")) 103 | selectionPlotStatic 104 | ``` 105 | 106 | Quiz: what keywords apply to the graphics above? Can you add labels to 107 | the last ggplot? 108 | 109 | Note that as the number of segments increases, the total squared error 110 | always decreases, so attains its minimum at 20 segments. In contrast, 111 | the penalized error (BIC) does not always decrease, so attains its 112 | minimum at an intermediate number of segments. 113 | 114 | ```{r} 115 | model.labels <- signals.with.models[, list( 116 | min.base=min(base), 117 | max.base=max(base) 118 | ), by=.(signal, segments)] 119 | model.labels[, label.base := (min.base+max.base)/2] 120 | signal.labels <- model.labels[segments==1,] 121 | gg.models+ 122 | geom_text(aes(label.base/1e6, label.top, 123 | label=paste("signal", signal)), 124 | data=signal.labels)+ 125 | geom_text(aes(label.base/1e6, label.bottom, 126 | label=paste0(segments, " segment", ifelse(segments==1, "", "s"))), 127 | data=model.labels, 128 | color="green")+ 129 | facet_grid(segments ~ signal, scales="free", space="free") 130 | ``` 131 | 132 | ## Interactive data viz using animint 133 | 134 | ```{r} 135 | selectionPlotInteractive <- ggplot()+ 136 | ggtitle("Click to select signal and model")+ 137 | theme_bw()+ 138 | theme(panel.margin=grid::unit(0, "cm"))+ 139 | facet_grid(error.type ~ ., scales="free")+ 140 | ylab("")+ 141 | geom_tallrect(aes(xmin=segments-0.5, xmax=segments+0.5, clickSelects=segments), 142 | alpha=0.5, 143 | data=one.signal.selection)+ 144 | geom_line(aes(segments, total.squared.error, group=signal, 145 | clickSelects=signal), #NEW 146 | data=addType(model.selection, "total squared error"), 147 | alpha=0.6, 148 | size=4)+ 149 | geom_line(aes(segments, penalized.error, group=signal, 150 | clickSelects=signal), #NEW 151 | data=addType(model.selection, "penalized error"), 152 | alpha=0.6, 153 | size=4) 154 | selectionPlotInteractive 155 | ``` 156 | 157 | New things above: 158 | 159 | * `geom_tallrect` creates a rectangle that spans the entire vertical 160 | area (so you only need to specify `xmin` and `xmax` aesthetics). 161 | * `aes(clickSelects=var)` means that clicking changes the current 162 | value of the selection variable `var`. So clicking the 163 | `geom_tallrect` changes `segments`, and clicking a `geom_line` 164 | changes `signal`. 165 | 166 | ```{r} 167 | signalsPlot <- ggplot()+ 168 | ggtitle("Selected signal and segmentation model")+ 169 | theme_bw()+ 170 | theme_animint(width=1000)+ #new 171 | theme(panel.margin=grid::unit(0, "lines"))+ 172 | scale_x_continuous( 173 | "position on chromosome (mega base pairs)", 174 | breaks=c(100, 200))+ 175 | scale_y_continuous( 176 | "logratio (approximate DNA copy number)", 177 | breaks=c(-1, 0, 1))+ 178 | geom_point(aes(base/1e6, logratio, 179 | showSelected=signal), #NEW 180 | data=intreg$sig)+ 181 | geom_text(aes(label.base/1e6, label.top, 182 | label=paste("signal", signal), 183 | showSelected=signal), #NEW 184 | data=signal.labels)+ 185 | geom_text(aes(label.base/1e6, label.bottom, 186 | label=paste0(segments, " segment", ifelse(segments==1, "", "s")), 187 | showSelected=segments, #NEW 188 | showSelected2=signal), #NEW 189 | data=model.labels, 190 | color="green")+ 191 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean, 192 | showSelected=signal, 193 | showSelected2=segments), 194 | data=intreg$seg, 195 | color="green")+ 196 | geom_segment(aes(x=base/1e6, xend=base/1e6, 197 | y=breaks.top, yend=breaks.bottom, 198 | showSelected=signal, 199 | showSelected2=segments), 200 | color="green", 201 | linetype="dashed", 202 | data=intreg$breaks) 203 | signalsPlot 204 | signalsPlot+facet_grid(segments ~ signal, scales="free", space="free") 205 | ``` 206 | 207 | New things above: 208 | 209 | * Any geoms with `showSelected` aesthetics will subset their data 210 | before plotting, using the values of the specified selection 211 | variables. 212 | * Since ggplot2 ignores the `showSelected` aesthetics, it shows all 213 | data at once. 214 | 215 | ```{r} 216 | library(animint) 217 | viz <- list( 218 | selection=selectionPlotInteractive, 219 | signals=signalsPlot) 220 | structure(viz, class="animint") 221 | ``` 222 | 223 | Click the plot above to select signals and models. Note how that in 224 | most cases the penalized error does a pretty good job at selecting a 225 | plausible segmentation model. One exception is signal 4.2 for which 226 | the penalized error says we should select 2 segments. However it is 227 | pretty clear that 4 segments should be preferred for that signal. 228 | 229 | TODO: add plot for selecting penalty constant, highlight BIC and AIC. 230 | 231 | ```{r} 232 | library(animint) 233 | data(intreg) 234 | mmir.selection <- 235 | list(segments=ggplot()+ 236 | ggtitle("Select profile and number of segments")+ 237 | tallrects+ 238 | geom_text(aes(0, error, label=signal, clickSelects=signal), 239 | data=sig.labels, hjust=1)+ 240 | scale_x_continuous("segments", breaks=c(1, 5, 10, 20), 241 | limits=c(-2, 20))+ 242 | xlab("squared error")+ 243 | geom_line(aes(segments, error, 244 | group=signal, 245 | clickSelects=signal), 246 | data=model.selection, 247 | alpha=0.6, size=8), 248 | 249 | signal=ggplot()+ 250 | theme_animint(width=800)+ 251 | scale_x_continuous("position on chromosome (mega base pairs)", 252 | breaks=c(100,200))+ 253 | scale_fill_manual(values=breakpoint.colors,guide="none")+ 254 | geom_blank(aes(first.base/1e6, logratio+2/8), data=intreg$ann)+ 255 | ggtitle("Copy number profile and maximum likelihood segmentation")+ 256 | ylab("logratio")+ 257 | geom_point(aes(base/1e6, logratio, 258 | showSelected=signal), 259 | data=intreg$sig)+ 260 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean, 261 | showSelected=signal, 262 | showSelected2=segments), 263 | data=intreg$seg, colour=signal.colors[["estimate"]])+ 264 | geom_segment(aes(base/1e6, min(signals.dt$logratio), 265 | xend=base/1e6, yend=max(signals.dt$logratio), 266 | showSelected=signal, 267 | showSelected2=segments), 268 | colour=signal.colors[["estimate"]], 269 | linetype="dashed", 270 | data=intreg$breaks)+ 271 | geom_text(aes(base/1e6, logratio, label=paste("signal", signal), 272 | showSelected=signal), 273 | data=sig.names)+ 274 | geom_text(aes(base/1e6, logratio, 275 | label=sprintf("%d segment%s", segments, 276 | ifelse(segments==1, "", "s")), 277 | showSelected=signal, 278 | showSelected2=segments), 279 | data=seg.names, color=signal.colors[["estimate"]]), 280 | 281 | first=list(signal="4.2", segments=4)) 282 | animint2dir(mmir.selection, "intreg-selection") 283 | ``` 284 | 285 | more examples. 286 | 287 | ```{r} 288 | library(animint) 289 | 290 | ## Example: 4 plots, 2 selectors. 291 | data(intreg) 292 | signal.colors <- c(estimate="#0adb0a", latent="#0098ef") 293 | breakpoint.colors <- c("1breakpoint"="#ff7d7d", "0breakpoints"='#f6f4bf') 294 | model.linetypes <- c(margin="dotted",limit="dashed",regression="solid") 295 | intreg$annotations$logratio <- max(intreg$sig$log) 296 | ## To get the bottom 3 plots to line up properly, we need to plot some 297 | ## geom_blanks bigger than the x range, so we calculate that here. 298 | blank.items <- with(intreg,{ 299 | list(segments=list(data=selection,x="min.L",y="segments"), 300 | error=list(data=selection,x="max.L",y="cost"), 301 | regression=list(data=model,x=c("min.L","max.L"), 302 | y=c("min.feature","max.feature")), 303 | intervals=list(data=intervals,x=c("min.L","max.L"),y="feature")) 304 | }) 305 | Lrange <- c() 306 | for(N in names(blank.items)){ 307 | L <- blank.items[[N]] 308 | Lrange <- range(c(Lrange,unlist(L$data[,L$x])),finite=TRUE) 309 | blank.items[[N]]$yrange <- range(unlist(L$data[,L$y])) 310 | } 311 | Lrange[1] <- Lrange[1]-1 312 | Lrange[2] <- Lrange[2]+1 313 | for(N in names(blank.items)){ 314 | L <- blank.items[[N]] 315 | blank.items[[N]]$blank <- data.frame(x=Lrange, y=L$yrange) 316 | } 317 | 318 | mmir.plot <- 319 | list(signal=ggplot()+ 320 | theme_animint(height=300, width=800)+ 321 | scale_x_continuous("position on chromosome (mega base pairs)", 322 | breaks=c(100,200))+ 323 | geom_tallrect(aes(xmin=first.base/1e6, xmax=last.base/1e6, 324 | fill=annotation, 325 | showSelected=signal), 326 | data=intreg$ann)+ 327 | scale_fill_manual(values=breakpoint.colors,guide="none")+ 328 | geom_text(aes((first.base+last.base)/2e6, logratio+1/8, 329 | label=annotation, 330 | showSelected=signal), 331 | data=intreg$ann)+ 332 | geom_blank(aes(first.base/1e6, logratio+2/8), data=intreg$ann)+ 333 | geom_point(aes(base/1e6, logratio, 334 | showSelected=signal), 335 | data=intreg$sig)+ 336 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean, 337 | showSelected=signal, 338 | showSelected2=segments), 339 | data=intreg$seg, colour=signal.colors[["estimate"]])+ 340 | geom_vline(aes(xintercept=base/1e6, 341 | showSelected=signal, 342 | showSelected2=segments), 343 | colour=signal.colors[["estimate"]], 344 | linetype="dashed", 345 | data=intreg$breaks), 346 | regression=ggplot()+ 347 | theme_animint(height=150, width=800)+ 348 | geom_blank(aes(x,y), data=blank.items$regression$blank)+ 349 | geom_segment(aes(x=min.L, y=feature, xend=max.L, yend=feature, 350 | clickSelects=signal), 351 | size=5, 352 | data=intreg$int)+ 353 | geom_segment(aes(min.L, min.feature, xend=max.L, yend=max.feature, 354 | linetype=line), 355 | colour="red", 356 | size=3, 357 | data=intreg$model)+ 358 | scale_linetype_manual(values=model.linetypes), 359 | error=ggplot()+ 360 | theme_animint(height=100, width=800)+ 361 | geom_blank(aes(x,y), data=blank.items$error$blank)+ 362 | geom_segment(aes(min.L, cost, xend=max.L, yend=cost, 363 | showSelected=signal), data=intreg$selection), 364 | segments=ggplot()+ 365 | theme_animint(height=100, width=800)+ 366 | geom_blank(aes(x,y), data=blank.items$segments$blank)+ 367 | geom_segment(aes(min.L, segments, xend=max.L, yend=segments, 368 | showSelected=signal), data=intreg$selection)+ 369 | geom_tallrect(aes(xmin=min.L, xmax=max.L, 370 | showSelected=signal, 371 | clickSelects=segments), 372 | data=intreg$selection, 373 | alpha=1/2)) 374 | ## This is a normal ggplot of all the data, subsets of which can be 375 | ## shown by clicking the plots. 376 | sig.facets <- mmir.plot$sig+ 377 | facet_grid(segments~signal, scales="free", space="free_x")+ 378 | theme_bw()+ 379 | theme(panel.margin=grid::unit(0,"cm")) 380 | print(sig.facets) 381 | animint2dir(mmir.plot, "intreg-nofacets") 382 | 383 | ## The mmir.plot above is way too complicated, since it does not use 384 | ## facets. The simpler facetted version looks like this: 385 | mmir.facet <- 386 | list(signal=mmir.plot$signal, 387 | 388 | penalty=ggplot()+ 389 | geom_tallrect(aes(xmin=min.L, xmax=max.L, 390 | showSelected=signal, 391 | clickSelects=segments), 392 | data=data.frame(intreg$selection, what="segments"), 393 | alpha=1/2)+ 394 | ylab("")+ 395 | theme_bw()+ 396 | theme_animint(height=500, width=800)+ 397 | theme(panel.margin=grid::unit(0, "lines"))+ 398 | geom_segment(aes(min.L, feature, xend=max.L, yend=feature, 399 | clickSelects=signal), 400 | size=5, 401 | data=data.frame(intreg$int, what="regression"))+ 402 | geom_segment(aes(min.L, min.feature, xend=max.L, yend=max.feature, 403 | linetype=line), 404 | colour="red", 405 | size=3, 406 | data=data.frame(intreg$model, what="regression"))+ 407 | scale_linetype_manual(values=model.linetypes)+ 408 | geom_segment(aes(min.L, cost, xend=max.L, yend=cost, 409 | showSelected=signal), 410 | data=data.frame(intreg$selection, what="error"))+ 411 | geom_segment(aes(min.L, segments, xend=max.L, yend=segments, 412 | showSelected=signal), 413 | data=data.frame(intreg$selection, what="segments"))+ 414 | xlab("penalty value $L=f(x)$")+ # TODO: mathjax. 415 | facet_grid(what~.,scales="free"), 416 | 417 | title="Max-margin interval regression") 418 | animint2dir(mmir.facet, "intreg-facets") 419 | ## This plot has an additional facet for signal, which would not be 420 | ## present in the interactive plot, but is useful here to see all 421 | ## the data in regular ggplot2. 422 | too.many.facets <- mmir.facet$penalty+ 423 | facet_grid(what~signal, scales="free")+ 424 | theme_bw()+ 425 | theme(panel.margin=grid::unit(0, "cm")) 426 | print(too.many.facets) 427 | 428 | ## Regions with linetype indicating errors. 429 | breaks.by.signal <- split(intreg$breaks, intreg$breaks$signal) 430 | anns.by.signal <- split(intreg$ann, intreg$ann$signal) 431 | error.regions.list <- list() 432 | for(signal in names(breaks.by.signal)){ 433 | signal.breaks <- breaks.by.signal[[signal]] 434 | signal.anns <- anns.by.signal[[signal]] 435 | signal.anns$target.breaks <- 436 | ifelse(signal.anns$annotation=="1breakpoint", 1, 0) 437 | for(model.i in 1:20){ 438 | model.breaks <- subset(signal.breaks, segments==model.i) 439 | signal.anns$breaks <- NA 440 | for(region.i in 1:nrow(signal.anns)){ 441 | region <- signal.anns[region.i, ] 442 | after.start <- region$first.base < model.breaks$base 443 | before.end <- model.breaks$base < region$last.base 444 | signal.anns$breaks[region.i] <- sum(after.start & before.end) 445 | } 446 | signal.anns$error.type <- with(signal.anns, { 447 | ifelse(breaks < target.breaks, "false negative", 448 | ifelse(target.breaks < breaks, "false positive", "correct")) 449 | }) 450 | error.regions.list[[paste(model.i, signal)]] <- 451 | data.frame(segments=model.i, signal.anns) 452 | } 453 | } 454 | error.regions <- do.call(rbind, error.regions.list) 455 | 456 | reg <- subset(intreg$model, line=="regression") 457 | slope <- with(reg, (min.L-max.L)/(min.feature-max.feature)) 458 | intreg$intervals$pred.L <- 459 | slope * (intreg$intervals$feature - reg$min.feature) + reg$min.L 460 | intreg.errors <- 461 | list(signal=ggplot()+ 462 | theme_animint(height=300, width=800)+ 463 | scale_x_continuous("position on chromosome (mega base pairs)", 464 | breaks=c(100,200))+ 465 | ylab("noisy copy number logratio signal")+ 466 | geom_tallrect(aes(xmin=first.base/1e6, xmax=last.base/1e6, 467 | fill=annotation, 468 | linetype=error.type, 469 | showSelected2=segments, 470 | showSelected=signal), 471 | color="black", 472 | alpha=0.5, 473 | data=error.regions)+ 474 | scale_linetype_manual("error type", values=c(correct=0, 475 | "false negative"=3, 476 | "false positive"=1))+ 477 | guides(linetype=guide_legend(override.aes=list(fill="white")))+ 478 | scale_fill_manual(values=breakpoint.colors)+ 479 | geom_blank(aes(first.base/1e6, logratio+2/8), data=intreg$ann)+ 480 | geom_point(aes(base/1e6, logratio, 481 | showSelected=signal), 482 | data=intreg$sig)+ 483 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean, 484 | showSelected=signal, 485 | showSelected2=segments), 486 | data=intreg$seg, colour=signal.colors[["estimate"]])+ 487 | geom_vline(aes(xintercept=base/1e6, 488 | showSelected=signal, 489 | showSelected2=segments), 490 | colour=signal.colors[["estimate"]], 491 | linetype="dashed", 492 | data=intreg$breaks), 493 | penalty=ggplot()+ 494 | theme_bw()+ 495 | theme_animint(height=500, width=800)+ 496 | theme(panel.margin=grid::unit(0, "cm"))+ 497 | geom_tallrect(aes(xmin=min.L, xmax=max.L, 498 | showSelected=signal, 499 | clickSelects=segments), 500 | data=data.frame(intreg$selection 501 | ##,what="segments" 502 | ), 503 | alpha=1/2)+ 504 | ylab("")+ 505 | geom_vline(aes(xintercept=pred.L, showSelected=signal), 506 | color="violet", 507 | data=intreg$intervals)+ 508 | geom_segment(aes(min.L, feature, xend=max.L, yend=feature, 509 | clickSelects=signal), 510 | size=6, 511 | data=data.frame(intreg$intervals, what="regression"))+ 512 | geom_segment(aes(min.L, min.feature, xend=max.L, yend=max.feature, 513 | linetype=line), 514 | colour="violet", 515 | size=3, 516 | data=data.frame(intreg$model, what="regression"))+ 517 | ## geom_point(aes(pred.L, feature), 518 | ## size=5, 519 | ## data=data.frame(intreg$intervals, what="regression"))+ 520 | scale_linetype_manual(values=model.linetypes)+ 521 | geom_segment(aes(min.L, cost, xend=max.L, yend=cost, 522 | showSelected=signal), 523 | data=data.frame(intreg$selection, what="incorrect labels"))+ 524 | geom_segment(aes(min.L, segments, xend=max.L, yend=segments, 525 | showSelected=signal), 526 | data=data.frame(intreg$selection, what="segments"))+ 527 | xlab("penalty value log(lambda)")+ # TODO: mathjax. 528 | facet_grid(what~., scales="free"), 529 | title="Max-margin interval regression") 530 | animint2dir(intreg.errors, "intreg-errors") 531 | 532 | ##animint2gist(intreg.errors) 533 | 534 | ## No annotated regions! 535 | mmir.segs <- 536 | list(signal=ggplot()+ 537 | theme_animint(height=300, width=800)+ 538 | scale_x_continuous("position on chromosome (mega base pairs)", 539 | breaks=c(100,200))+ 540 | scale_fill_manual(values=breakpoint.colors,guide="none")+ 541 | geom_blank(aes(first.base/1e6, logratio+2/8), data=intreg$ann)+ 542 | ggtitle("Copy number profile and maximum likelihood segmentation")+ 543 | ylab("logratio")+ 544 | geom_point(aes(base/1e6, logratio, 545 | showSelected=signal), 546 | data=intreg$sig)+ 547 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean, 548 | showSelected=signal, 549 | showSelected2=segments), 550 | data=intreg$seg, colour=signal.colors[["estimate"]])+ 551 | geom_vline(aes(xintercept=base/1e6, 552 | showSelected=signal, 553 | showSelected2=segments), 554 | colour=signal.colors[["estimate"]], 555 | linetype="dashed", 556 | data=intreg$breaks), 557 | 558 | segments=ggplot()+ 559 | theme_animint(height=300, width=800)+ 560 | xlab("log(penalty)")+ 561 | ylab("optimal number of segments")+ 562 | ggtitle("Select profile and number of segments")+ 563 | geom_tallrect(aes(xmin=min.L, xmax=max.L, 564 | showSelected=signal, 565 | clickSelects=segments), 566 | data=intreg$selection, 567 | alpha=1/2)+ 568 | geom_segment(aes(min.L, segments, xend=max.L, yend=segments, 569 | clickSelects=signal), 570 | data=intreg$selection, alpha=0.6, size=5)) 571 | animint2dir(mmir.segs, "intreg-segs") 572 | 573 | library(reshape2) 574 | model.tall <- melt(model.selection, measure.vars=c("error", "penalized.error")) 575 | ## Plot error AND penalized error versus number of segments. 576 | mmir.buggy <- 577 | list(segments=ggplot()+ 578 | ggtitle("Select profile and number of segments")+ 579 | tallrects+ 580 | scale_x_continuous("segments", breaks=c(1, 5, 10, 20), 581 | limits=c(-2, 21))+ 582 | xlab("")+ 583 | facet_grid(variable ~ ., scales="free_y")+ 584 | geom_line(aes(segments, value, 585 | group=interaction(signal, variable), 586 | clickSelects=signal), 587 | data=model.tall, 588 | alpha=0.6, size=8), 589 | 590 | signal=ggplot()+ 591 | theme_animint(width=800)+ 592 | scale_x_continuous("position on chromosome (mega base pairs)", 593 | breaks=c(100,200))+ 594 | scale_fill_manual(values=breakpoint.colors,guide="none")+ 595 | geom_blank(aes(first.base/1e6, logratio+2/8), data=intreg$ann)+ 596 | ggtitle("Copy number profile and maximum likelihood segmentation")+ 597 | ylab("logratio")+ 598 | geom_point(aes(base/1e6, logratio, 599 | showSelected=signal), 600 | data=intreg$sig)+ 601 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean, 602 | showSelected=signal, 603 | showSelected2=segments), 604 | data=intreg$seg, colour=signal.colors[["estimate"]])+ 605 | geom_segment(aes(base/1e6, min(signals.dt$logratio), 606 | xend=base/1e6, yend=max(signals.dt$logratio), 607 | showSelected=signal, 608 | showSelected2=segments), 609 | colour=signal.colors[["estimate"]], 610 | linetype="dashed", 611 | data=intreg$breaks)+ 612 | geom_text(aes(base/1e6, logratio, label=paste("signal", signal), 613 | showSelected=signal), 614 | data=sig.names)+ 615 | geom_text(aes(base/1e6, logratio, 616 | label=sprintf("%d segment%s", segments, 617 | ifelse(segments==1, "", "s")), 618 | showSelected=signal, 619 | showSelected2=segments), 620 | data=seg.names, color=signal.colors[["estimate"]]), 621 | 622 | first=list(signal="4.2", segments=4)) 623 | animint2dir(mmir.buggy, "intreg-buggy") 624 | 625 | ## Plot error AND penalized error versus number of segments. 626 | penalized <- model.selection %>% 627 | group_by(signal) %>% 628 | filter(penalized.error < penalized.error[1]*2) 629 | mmir.BIC <- 630 | list(segments=ggplot()+ 631 | ggtitle("Select profile and number of segments")+ 632 | tallrects+ 633 | scale_x_continuous("segments", breaks=c(1, 5, 10, 20), 634 | limits=c(-2, 21))+ 635 | xlab("")+ 636 | facet_grid(variable ~ ., scales="free_y")+ 637 | geom_line(aes(segments, error, 638 | group=signal, 639 | clickSelects=signal), 640 | data=data.frame(model.selection, 641 | variable="un-penalized error"), 642 | alpha=0.6, size=8)+ 643 | geom_line(aes(segments, penalized.error, 644 | group=signal, 645 | clickSelects=signal), 646 | data=data.frame(penalized, variable="penalized error (BIC)"), 647 | alpha=0.6, size=8), 648 | 649 | signal=ggplot()+ 650 | theme_animint(width=800)+ 651 | scale_x_continuous("position on chromosome (mega base pairs)", 652 | breaks=c(100,200))+ 653 | scale_fill_manual(values=breakpoint.colors,guide="none")+ 654 | geom_blank(aes(first.base/1e6, logratio+2/8), data=intreg$ann)+ 655 | ggtitle("Copy number profile and maximum likelihood segmentation")+ 656 | ylab("logratio")+ 657 | geom_point(aes(base/1e6, logratio, 658 | showSelected=signal), 659 | data=intreg$sig)+ 660 | geom_segment(aes(first.base/1e6, mean, xend=last.base/1e6, yend=mean, 661 | showSelected=signal, 662 | showSelected2=segments), 663 | data=intreg$seg, colour=signal.colors[["estimate"]])+ 664 | geom_segment(aes(base/1e6, min(signals.dt$logratio), 665 | xend=base/1e6, yend=max(signals.dt$logratio), 666 | showSelected=signal, 667 | showSelected2=segments), 668 | colour=signal.colors[["estimate"]], 669 | linetype="dashed", 670 | data=intreg$breaks)+ 671 | geom_text(aes(base/1e6, logratio, label=paste("signal", signal), 672 | showSelected=signal), 673 | data=sig.names)+ 674 | geom_text(aes(base/1e6, logratio, 675 | label=sprintf("%d segment%s", segments, 676 | ifelse(segments==1, "", "s")), 677 | showSelected=signal, 678 | showSelected2=segments), 679 | data=seg.names, color=signal.colors[["estimate"]]), 680 | 681 | first=list(signal="4.2", segments=4)) 682 | animint2dir(mmir.BIC, "intreg-BIC") 683 | ``` 684 | -------------------------------------------------------------------------------- /introduction-vocabulary.Rmd: -------------------------------------------------------------------------------- 1 | # A vocabulary for characterizing interactive graphics 2 | 3 | This tutorial presents several R packages for making interactive 4 | graphics. To begin, please install the required packages: 5 | 6 | ```{r} 7 | source("http://tdhock.github.io/interactive-tutorial/packages.R") 8 | ``` 9 | 10 | If that worked then `example(animint)` should open some web browser 11 | windows containing animints. 12 | 13 | ## Definition of interactive graphics 14 | 15 | The R command line is interactive, so aren't all R graphics 16 | interactive? Yes, if you have access to the data and R source 17 | code. No, if you only have access to the graphic itself. 18 | 19 | This tutorial uses the following definition: in an **interactive** or 20 | **dynamic** graphic, the plot can be updated without changing the R 21 | code. In a **non-interactive** or **static** graphic, the R code must 22 | be changed to update the plot. 23 | 24 | For example, the following is a static graphic 25 | 26 | ```{r} 27 | lungDeaths <- cbind(mdeaths, fdeaths) 28 | matplot(lungDeaths, type="l") 29 | ``` 30 | 31 | because it can be zoomed only by changing the R code: 32 | 33 | ```{r} 34 | matplot(lungDeaths, type="l", xlim=c(20, 40)) 35 | ``` 36 | 37 | In contrast, the following interactive graphic can be zoomed by 38 | dragging the mouse on the plot (without changing the R code). 39 | 40 | ```{r} 41 | library(dygraphs) 42 | dygraph(lungDeaths) 43 | ``` 44 | 45 | ## Actions, effects, and complexity 46 | 47 | We will use the terms **Actions** and **Effects** to categorize 48 | different kinds of interactive graphics. In the graphic above, we see 49 | several examples of **direct manipulation actions** which produce the 50 | following effects: 51 | 52 | | Action | Effect | 53 | |--------|------------| 54 | | Hover mouse | Show x and y values | 55 | | Drag mouse | Zoom x or y axis | 56 | | Double click | Zoom out | 57 | 58 | We use the term **direct manipulation** to describe **actions** near 59 | the plotted data. This contrasts **indirect manipulation** on buttons 60 | or menus which are typically located outside of the plotting region. 61 | 62 | We will use some other terms to describe the **complexity** of a data 63 | visualization. The complexity terms answer the following questions: 64 | 65 | * How many layers? A single plot may have several layers or different 66 | geoms (points, lines, etc) that represent different parts of a 67 | complex data set. The data viz above is **single-layer** because it 68 | only displays one layer (lines). 69 | * How many panels? A single plot may have several panels, each with 70 | its own axis. The data viz above is **single-panel** since it has 71 | only one panel. 72 | * How many plots? A single data viz may have several linked plots, 73 | each with different axes and data. The data viz above is 74 | **single-plot** since it has only one plot. 75 | 76 | ## The shiny web server 77 | 78 | The `shiny` package provides a web server that can be used for many 79 | interactive graphics based on indirect manipulation actions. For 80 | example, **multi-panel**, **multi-layer**, **single-plot** data viz 81 | below uses **indirect manipulation** to show how the central limit 82 | theorem works for data of different distributions. 83 | 84 | ```{r, eval=FALSE} 85 | shiny::runGitHub('ShinySampleMean', 'ekstroem') 86 | ``` 87 | 88 | Another example with the same keywords to explain power calculations. 89 | 90 | ```{r, eval=FALSE} 91 | shiny::runGitHub('ShinyPower', 'ekstroem') 92 | ``` 93 | 94 | ## Multi-plot data visualization 95 | 96 | This is not in R, but [dc.js](http://dc-js.github.io/dc.js/) can be 97 | used to create **multi-plot**, **single-panel**, **single-layer** data 98 | visualizations with **direct manipulation actions**. Note the **smooth 99 | transitions** that can be used to emphasize continuity between data 100 | subsets. 101 | 102 | ## Animated data visualization 103 | 104 | The `animation`, `ggvis`+`shiny` and `animint` packages can be used to 105 | produce **animated** data visualizations which are updated over time 106 | like a video. The main differences are that 107 | 108 | * `animation` uses **indirect manipulation**, and only allows 109 | scrolling forward or backward in time. 110 | * `ggvis`+`shiny` also uses **indirect manipulation**, but allows 111 | interaction with any number of variables (not just the time 112 | variable). 113 | * `animint` uses both **direct and indirect manipulation**, and allows 114 | interaction with any number of variables. 115 | 116 | Exercise: what keywords apply to the following data visualizations? 117 | 118 | | Data | `animation` | `shiny`+`ggvis` | `animint` | 119 | |--------|------------|--|--| 120 | | World Bank | [viz+source](http://www.ggplot2-exts.org/gganimate.html) | [viz](https://cpsievert.shinyapps.io/worldBank-ggvis/) | [viz](http://cbio.ensmp.fr/~thocking/WorldBank-facets/) [source](https://github.com/tdhock/animint/blob/master/inst/examples/WorldBank-facets.R) | 121 | | Evolution | [viz](http://nicholsonppp.r-forge.r-project.org/2009-08-19/index.htm) | n/a | [viz](http://cbio.ensmp.fr/~thocking/animint-evolution-plots/) [source](https://github.com/tdhock/animint/blob/master/inst/examples/evolution.R) | 122 | 123 | ## Summary of vocabulary 124 | 125 | We have discussed the following terms. 126 | 127 | ### Actions 128 | 129 | * Direct manipulation (click, drag, hover) is useful for showing 130 | details of plotted data. 131 | * Indirect manipulation (menus, buttons) is useful for changing the 132 | data subset or plotting parameters. 133 | * Animation is useful for showing how data sets vary with a time 134 | variable. 135 | 136 | ### Effects 137 | 138 | * Zooming is useful to show details of data that is already plotted. 139 | * Showing/hiding data/labels/tooltips is useful to show details that 140 | are not already shown. 141 | * Smooth transitions are useful to emphasize continuity between data 142 | subsets. 143 | * Highlighting is useful to show the current selection. 144 | 145 | ### Complexity 146 | 147 | * Multi-layer graphics are useful when there are different data sets 148 | to compare on the same axes. 149 | * Multi-panel graphics are useful in two situations: 150 | - Same geom for different data subsets (mostly useful for non-interactive graphics). 151 | - Different geoms for with aligned axes (useful for interactive graphics). 152 | * Multi-plot graphics are useful for data sets where there are more 153 | than two quantitative variables. You can show an overview in one 154 | plot and details in another. 155 | 156 | -------------------------------------------------------------------------------- /packages-old.R: -------------------------------------------------------------------------------- 1 | old.lib <- file.path(Sys.getenv("HOME"), "lib-old") 2 | dir.create(old.lib, showWarnings=FALSE) 3 | .libPaths(old.lib) 4 | options(repos="http://cran.rstudio.com") 5 | ### Write down what package versions work with your R code, and 6 | ### attempt to download and load those packages. The first argument is 7 | ### the version of R that you used, e.g. "3.0.2" and then the rest of 8 | ### the arguments are package versions. For 9 | ### CRAN/Bioconductor/R-Forge/etc packages, write 10 | ### e.g. RColorBrewer="1.0.5" and if RColorBrewer is not installed 11 | ### then we use install.packages to get the most recent version, and 12 | ### warn if the installed version is not the indicated version. For 13 | ### GitHub packages, write "user/repo@commit" 14 | ### e.g. "tdhock/animint@f877163cd181f390de3ef9a38bb8bdd0396d08a4" and 15 | ### we use install_github to get it, if necessary. 16 | works_with_R <- function(Rvers,...){ 17 | pkg_ok_have <- function(pkg,ok,have){ 18 | stopifnot(is.character(ok)) 19 | if(!as.character(have) %in% ok){ 20 | warning("works with ",pkg," version ", 21 | paste(ok,collapse=" or "), 22 | ", have ",have) 23 | } 24 | } 25 | pkg_ok_have("R",Rvers,getRversion()) 26 | pkg.vers <- list(...) 27 | for(pkg.i in seq_along(pkg.vers)){ 28 | vers <- pkg.vers[[pkg.i]] 29 | pkg <- if(is.null(names(pkg.vers))){ 30 | "" 31 | }else{ 32 | names(pkg.vers)[[pkg.i]] 33 | } 34 | if(pkg == ""){# Then it is from GitHub. 35 | ## suppressWarnings is quieter than quiet. 36 | if(!suppressWarnings(require(requireGitHub))){ 37 | ## If requireGitHub is not available, then install it using 38 | ## devtools. 39 | if(!suppressWarnings(require(devtools))){ 40 | install.packages("devtools") 41 | require(devtools) 42 | } 43 | install_github("tdhock/requireGitHub") 44 | require(requireGitHub) 45 | } 46 | requireGitHub(vers) 47 | }else{# it is from a CRAN-like repos. 48 | if(!suppressWarnings(require(pkg, character.only=TRUE))){ 49 | install.packages(pkg) 50 | } 51 | pkg_ok_have(pkg, vers, packageVersion(pkg)) 52 | require(pkg, character.only=TRUE) 53 | } 54 | } 55 | } 56 | 57 | 58 | works_with_R( 59 | "3.2.3", 60 | ##rCharts="0.4.2", 61 | ## "ramnathv/rCharts@faf2043f90e149d8620a570c78449079c6dbb6fb", 62 | ## "ramnathv/rMaps@e08edfed5a1c1e02dcf04269f42120dd3224c952", 63 | ## dygraphs="0.8", 64 | ## igraph="0.7.1", 65 | ## shiny="0.13.0", 66 | ## "ekstroem/MESS@0a4218119fb9f6d2bd715ffb57b6cf2f24eee710", 67 | ## metricsgraphics="0.9.0", 68 | ##highcharter="1.0", 69 | ##"jbkunst/highcharter@a8c917e91ae64efa66087d8fe883e1b403e177be", 70 | "hadley/scales@2c3edf45de56d617444dc38e47e0404173817886", 71 | "tdhock/ggplot2@a8b06ddb680acdcdbd927773b1011c562134e4d2", 72 | "tdhock/animint@6b1c9e588b03f632cd39cdec9bbcfa730db9e889", 73 | ## DiagrammeR="1.0"## DO NOT UNCOMMENT! Okay okay ;) 74 | ) 75 | 76 | 77 | -------------------------------------------------------------------------------- /packages.R: -------------------------------------------------------------------------------- 1 | options(repos="http://cran.rstudio.com") 2 | ### Write down what package versions work with your R code, and 3 | ### attempt to download and load those packages. The first argument is 4 | ### the version of R that you used, e.g. "3.0.2" and then the rest of 5 | ### the arguments are package versions. For 6 | ### CRAN/Bioconductor/R-Forge/etc packages, write 7 | ### e.g. RColorBrewer="1.0.5" and if RColorBrewer is not installed 8 | ### then we use install.packages to get the most recent version, and 9 | ### warn if the installed version is not the indicated version. For 10 | ### GitHub packages, write "user/repo@commit" 11 | ### e.g. "tdhock/animint@f877163cd181f390de3ef9a38bb8bdd0396d08a4" and 12 | ### we use install_github to get it, if necessary. 13 | works_with_R <- function(Rvers,...){ 14 | pkg_ok_have <- function(pkg,ok,have){ 15 | stopifnot(is.character(ok)) 16 | if(!as.character(have) %in% ok){ 17 | warning("works with ",pkg," version ", 18 | paste(ok,collapse=" or "), 19 | ", have ",have) 20 | } 21 | } 22 | pkg_ok_have("R",Rvers,getRversion()) 23 | pkg.vers <- list(...) 24 | for(pkg.i in seq_along(pkg.vers)){ 25 | vers <- pkg.vers[[pkg.i]] 26 | pkg <- if(is.null(names(pkg.vers))){ 27 | "" 28 | }else{ 29 | names(pkg.vers)[[pkg.i]] 30 | } 31 | if(pkg == ""){# Then it is from GitHub. 32 | ## suppressWarnings is quieter than quiet. 33 | if(!suppressWarnings(require(requireGitHub))){ 34 | ## If requireGitHub is not available, then install it using 35 | ## devtools. 36 | if(!suppressWarnings(require(devtools))){ 37 | install.packages("devtools") 38 | require(devtools) 39 | } 40 | install_github("tdhock/requireGitHub") 41 | require(requireGitHub) 42 | } 43 | requireGitHub(vers) 44 | }else{# it is from a CRAN-like repos. 45 | if(!suppressWarnings(require(pkg, character.only=TRUE))){ 46 | install.packages(pkg) 47 | } 48 | pkg_ok_have(pkg, vers, packageVersion(pkg)) 49 | require(pkg, character.only=TRUE) 50 | } 51 | } 52 | } 53 | 54 | works_with_R( 55 | "3.2.2", 56 | ##rCharts="0.4.2", 57 | ## "ramnathv/rCharts@faf2043f90e149d8620a570c78449079c6dbb6fb", 58 | ## "ramnathv/rMaps@e08edfed5a1c1e02dcf04269f42120dd3224c952", 59 | ## dygraphs="0.8", 60 | ## igraph="0.7.1", 61 | ## shiny="0.13.0", 62 | ## "ekstroem/MESS@0a4218119fb9f6d2bd715ffb57b6cf2f24eee710", 63 | ## metricsgraphics="0.9.0", 64 | ##highcharter="1.0", 65 | ##"jbkunst/highcharter@a8c917e91ae64efa66087d8fe883e1b403e177be", 66 | ## "hadley/scales@2c3edf45de56d617444dc38e47e0404173817886", 67 | ## "tdhock/ggplot2@a8b06ddb680acdcdbd927773b1011c562134e4d2", 68 | ## "tdhock/animint@6b1c9e588b03f632cd39cdec9bbcfa730db9e889", 69 | "tdhock/animint@0cacb604609c6952e4fb1c43620f512782a4a472" 70 | ## DiagrammeR="1.0"## DO NOT UNCOMMENT! Okay okay ;) 71 | ) 72 | 73 | 74 | -------------------------------------------------------------------------------- /syllabus.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[T1]{fontenc} 4 | \usepackage{fullpage} 5 | \usepackage{graphicx} 6 | \usepackage{grffile} 7 | \usepackage{longtable} 8 | \usepackage{wrapfig} 9 | \usepackage{rotating} 10 | \usepackage[normalem]{ulem} 11 | \usepackage{amsmath} 12 | \usepackage{textcomp} 13 | \usepackage{amssymb} 14 | \usepackage{capt-of} 15 | \usepackage{hyperref} 16 | \author{Toby Dylan Hocking} 17 | \date{\today} 18 | 19 | \begin{document} 20 | 21 | \section*{``Understanding and creating interactive graphics,'' a tutorial for useR 2016} 22 | %\tableofcontents 23 | 24 | %% \section*{{\bfseries\sffamily TODO} } 25 | %% \label{sec:orgheadline1} 26 | 27 | %% send this to useR-2016@R-project.org before January 10, 2016. 28 | 29 | \label{sec:orgheadline3} 30 | 31 | \begin{center} 32 | \begin{tabular}{llll} 33 | Instructor & Institution & Address & Email\\ 34 | \hline 35 | Toby Dylan Hocking & McGill Univ. & Montreal, Canada & toby.hocking@mail.mcgill.ca\\ 36 | Claus Thorn Ekstrøm & Univ. Copenhagen & Copenhagen, Denmark & ekstrom@sund.ku.dk\\ 37 | \end{tabular} 38 | \end{center} 39 | 40 | \section*{Background} 41 | \label{sec:orgheadline5} 42 | 43 | An interactive graphic invites the viewer to become an active partner 44 | in the analysis and allows for immediate feedback on how the data and 45 | results may change when inputs are modified. Interactive graphics can 46 | be extremely useful for exploratory data analysis, for teaching, and 47 | for reporting. 48 | 49 | Because there are so many different kinds of interactive graphics, 50 | there has recently been an explosion in R packages that can produce 51 | them. A beginner with little knowledge of interactive graphics can 52 | thus be easily confused by (1) understanding what kinds of graphics 53 | are useful for what kinds of data, and (2) finding an R package that 54 | can produce the desired type of graphic. This tutorial solves these 55 | two problems by (1) introducing a vocabulary of keywords for 56 | understanding the different kinds of graphics, and (2) explaining what 57 | R packages can be used for each kind of graphic. 58 | 59 | \section*{Tutorial Overview} 60 | 61 | Attendees will gain hands-on experience with using R to create 62 | interactive graphics. We will discuss several example data sets and 63 | several R interactive graphics packages. Attendees will learn a 64 | vocabulary that helps to understand the strengths and weaknesses of 65 | the many different packages which are currently available. 66 | 67 | \section*{Detailed Outline} 68 | \label{sec:orgheadline10} 69 | \begin{itemize} 70 | \item Differences between interactive/dynamic and non-interactive/static graphics. 71 | \item A vocabulary for understanding interactive graphics in terms of 72 | complexity, possible actions, and effects. 73 | \begin{description} 74 | \item[Complexity] multi-panel, multi-layer, multi-plot. 75 | \item[Actions] animation, direct manipulation (clicking, hovering), indirect manipulation 76 | (menus, buttons). 77 | \item[Effects] zoom, highlight, show/hide (data, labels, tooltips), 78 | hyperlink. 79 | \end{description} 80 | \item High-level interactive plotting packages (rgl, MESS, rCharts, 81 | clickme, rMaps, htmlwidgets, dygraphs). 82 | \item Discussion of frustrations that 83 | new users unfamiliar with JavaScript may encounter when using these 84 | libraries. 85 | \item Interactive graphics with shiny, plotly, ggplot2. 86 | \item Multi-layer graphics with ggplot2. 87 | \item Multi-panel graphics with facets in ggplot2, useful in two 88 | different situations: 89 | \begin{itemize} 90 | \item same plot for different data subsets, and 91 | \item different plots with aligned axes. 92 | \end{itemize} 93 | \item Animated graphics using the animation package. 94 | \item Multi-panel, multi-layer, multi-plot, interactive graphics 95 | (animint, shiny, ggplot2, ggvis). 96 | \end{itemize} 97 | 98 | \section*{Background Knowledge} 99 | 100 | Knowledge of base, lattice, or ggplot2 101 | functions for creating static graphics will be helpful. No 102 | knowledge of JavaScript is necessary. 103 | 104 | \section*{Potential Attendees} 105 | \label{sec:orgheadline12} 106 | Our tutorial is appropriate for: 107 | \begin{description} 108 | \item[complete R newbies:] the vocabulary for understanding interactive 109 | graphics should be useful, even if you don't understand all of the R 110 | code that we present. 111 | \item[intermediate useRs:] you already know how to use basic R data 112 | structures like data.frame and list, and maybe static graphics 113 | packages like ggplot2. You will learn how to create interactive 114 | graphics. 115 | \item[interactive graphics package developeRs:] you have written an 116 | interactive graphics package. Please come to see us present some 117 | other packages, and to discuss the current state-of-the-art and 118 | future directions. 119 | \end{description} 120 | 121 | \section*{Requirements for interactive session} 122 | 123 | Attendees should run the following R code to install the packages 124 | which are required for our tutorial: 125 | 126 | \begin{verbatim} 127 | source("http://tdhock.github.io/interactive-tutorial/packages.R") 128 | \end{verbatim} 129 | 130 | \end{document} 131 | -------------------------------------------------------------------------------- /tutorial-prop.tex: -------------------------------------------------------------------------------- 1 | \documentclass[11pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[T1]{fontenc} 4 | \usepackage{fullpage} 5 | \usepackage{graphicx} 6 | \usepackage{grffile} 7 | \usepackage{longtable} 8 | \usepackage{wrapfig} 9 | \usepackage{rotating} 10 | \usepackage[normalem]{ulem} 11 | \usepackage{amsmath} 12 | \usepackage{textcomp} 13 | \usepackage{amssymb} 14 | \usepackage{capt-of} 15 | \usepackage{hyperref} 16 | \author{Toby Dylan Hocking} 17 | \date{\today} 18 | \title{Understanding and producing interactive graphics} 19 | \hypersetup{ 20 | pdfauthor={Toby Dylan Hocking}, 21 | pdftitle={}, 22 | pdfkeywords={}, 23 | pdfsubject={}, 24 | pdfcreator={Emacs 24.3.1 (Org mode 8.3.2)}, 25 | pdflang={English}} 26 | \begin{document} 27 | 28 | %\tableofcontents 29 | 30 | %% \section{{\bfseries\sffamily TODO} } 31 | %% \label{sec:orgheadline1} 32 | 33 | %% send this to useR-2016@R-project.org before January 10, 2016. 34 | 35 | \section{Tutorial Title} 36 | \label{sec:orgheadline2} 37 | 38 | Understanding and creating interactive graphics 39 | 40 | \section{Instructors} 41 | \label{sec:orgheadline3} 42 | 43 | \begin{center} 44 | \begin{tabular}{llll} 45 | Name & Institution & Address & Email\\ 46 | \hline 47 | Toby Dylan Hocking & McGill & Montreal, Canada & toby.hocking@mail.mcgill.ca\\ 48 | Claus Thorn Ekstrøm & Univ. Copenhagen & Copenhagen, Denmark & ekstrom@sund.ku.dk\\ 49 | \end{tabular} 50 | \end{center} 51 | 52 | \section{Short Instructor Biography} 53 | \label{sec:orgheadline4} 54 | 55 | Toby Dylan Hocking has designed and implemented several R graphics 56 | packages. He is the designer and primary maintainer of directlabels 57 | (Best Student Poster Prize at useR 2011) and animint (presented in an 58 | \href{https://www.amstat.org/meetings/jsm/2015/onlineprogram/AbstractDetails.cfm?abstractid=314184\%0A}{invited 59 | session at Joint Statistical Meetings 2015}). He is also the 60 | original designer of the ggplot conversion feature of the plotly 61 | package. 62 | 63 | Claus Thorn Ekstrøm is the creator and contributor to a number of R 64 | packages (MESS, MethComp, SuperRanker) and is the author of "The R 65 | Primer" book. He has previously given 66 | \href{http://biostatistics.dk/presentations/DynGraph.html}(tutorials 67 | on Dynamic graphics in R) and the role of interactive graphics in 68 | teaching, and won the C. Oswald George prize for his article "Teaching 69 | ‘Instant Experience’ with Graphical Model Validation Techniques" in 70 | 2014. 71 | 72 | \section{Brief Description of Tutorial} 73 | \label{sec:orgheadline5} 74 | 75 | An interactive graphic invites the viewer to become an active partner 76 | in the analysis and allows for immediate feedback on how the data and 77 | results may change when inputs are modified. Interactive graphics can 78 | be extremely useful for exploratory data analysis, for teaching, and 79 | for reporting. 80 | 81 | Because there are so many different kinds of interactive graphics, 82 | there has been an explosion in R packages that can produce them 83 | (e.g. animint, shiny, rCharts, rMaps, ggvis, htmlwidgets). A beginner 84 | with little knowledge of interactive graphics can thus be easily 85 | confused by (1) understanding what kinds of graphics are useful for 86 | what kinds of data, and (2) finding an R package that can produce the 87 | desired type of graphic. This tutorial solves these two problems by 88 | (1) introducing a vocabulary of keywords for understanding the 89 | different kinds of graphics, and (2) explaining what R packages can be 90 | used for each kind of graphic. 91 | 92 | \section{Goals} 93 | \label{sec:orgheadline6} 94 | 95 | \begin{enumerate} 96 | \item Explain and emphasize the role that interactive graphics have in 97 | reporting, scientific journals, and in teaching. 98 | \item By showing several examples, explain different categories of 99 | graphics: animated, multi-panel, and multi-layer, interactive 100 | (direct vs indirect manipulation). 101 | \item Explain how existing R packages can be used to create these 102 | different types of graphics. 103 | \item Explain the strengths and weaknesses of the existing R packages, to 104 | highlight directions for future work. 105 | \end{enumerate} 106 | 107 | \section{Detailed Outline} 108 | \label{sec:orgheadline10} 109 | 110 | \subsection{A vocabulary for understanding interactive graphics, 30 minutes} 111 | \label{sec:orgheadline7} 112 | 113 | In this section we will give a high-level introduction about 114 | interactive graphics, without going into details about R code for 115 | specific packages. 116 | 117 | Motivation: interactive graphics in exploratory data analysis, 118 | reporting results and teaching. 119 | 120 | Vocabulary for describing interactive graphics: 121 | \begin{description} 122 | \item[zoomable] reduce axes limits and hide data outside of limits. can 123 | do it with both static and interactive. 124 | \item[{interactive}] user can change what is displayed without 125 | changing the code. (aka dynamic) 126 | \begin{description} 127 | \item[{direct manipulation}] interacting with plot elements (lines, 128 | points, etc). 129 | \item[{indirect manipulation}] interacting with keyboard, mouse clicks 130 | on widgets (buttons, menus, etc). 131 | Useful when there are many similar plots for 132 | different data subsets, 133 | but you \textbf{don't} want to see them all at the same time. 134 | \end{description} 135 | \item[{animated}] An animated graphic automatically advances over time, 136 | like a video. Animated graphics are most useful when data sets 137 | have a time dimension. The only interaction possible is moving 138 | forward and backward in time. 139 | \item[{multi-layer}] A multi-layer graphic uses several geometric elements 140 | to show several data sets and/or variables. Multi-layer plots are 141 | useful for showing relationships between data sets and/or 142 | variables. 143 | \item[{multi-panel}] A multi-panel graphic shows different things in 144 | different panels (sub-plots) which each have their own axes 145 | (perhaps different from each other). Useful when there are many 146 | similar plots for different data subsets, and you \textbf{do} want to 147 | see them at the same time. Also useful for showing different 148 | plots with aligned axes. 149 | \end{description} 150 | Compare and contrast: 151 | \begin{description} 152 | \item[{interactive vs animated}] only interaction possible in an animated 153 | graphic is moving forward and backward in time (animated graphics 154 | are thus a subset of interactive graphics). 155 | \item[{interactive vs multi-panel}] both useful for many similar plots 156 | with different data subsets. Do you want to see all the subsets 157 | at the same time? (yes=multi-panel, no=interactive) 158 | \end{description} 159 | 160 | \subsection{Quiz questions} 161 | \label{sec:orgheadline8} 162 | 163 | The previous section introduced a vocabulary for describing 164 | interactive graphics. In the following section, after showing a new 165 | graphic, we will ask the audience to take 1 minute to discuss with 166 | their neighbour about which vocabulary words can be used to describe 167 | that graphic. 168 | 169 | \subsection{Creating interactive graphics using R packages} 170 | \label{sec:orgheadline9} 171 | 172 | In this section we will show specific R code examples from the various 173 | packages. 174 | 175 | \begin{description} 176 | \item[{High-level interactive plotting packages, 30 minutes}] \mbox{ } 177 | 178 | \begin{itemize} 179 | \item Simple approaches like rotating plots (rgl package) and simple user 180 | interaction (wallyplot from MESS package). 181 | \item Interactive bar plots (rCharts, several different JavaScript 182 | interfaces, interfacing with JavaScript libraries to change axes 183 | and legends) 184 | \item Interactive scatter plots showing happiness and tax rate (rCharts, 185 | and clickme packages, several different JavaScript interfaces, add 186 | dropdown effects and improve tooltips) 187 | \item interactive maps and choropleths (the rMaps packages) 188 | \item Discussion of frustrations that new users unfamiliar with 189 | JavaScript may encounter when interfacing with JavaScript libraries 190 | \end{itemize} 191 | \item[{Interactive graphics with shiny and plotly, 30 minutes}] \mbox{ } 192 | \begin{itemize} 193 | \item Teaching least squares estimation (shiny) 194 | \item Teaching power calculations (shiny) 195 | \item Reproducing some of the previous graphics on happiness and tax 196 | rate in plotly (ggplot2, and ggplotly, adding tooltips/hover 197 | effects, and dropdown) 198 | \item Graphics on prediction accuracy for Danish population predictions 199 | (plotly, adding sliders) 200 | \end{itemize} 201 | \item[{Multi-layer graphics, ggplot2 package, 15 minutes}] \mbox{ } 202 | \begin{itemize} 203 | \item A map that shows a circle for every city, and a line for borders of 204 | each country. 205 | \item A plot of a linear model that shows data as circles, a regression 206 | line, and model residuals as line segments. 207 | \end{itemize} 208 | \item[{Multi-panel graphics, facets in ggplot2, 15 minutes}] useful in two 209 | different situations: 210 | \begin{description} 211 | \item[{Same plot for different data subsets}] a linear model fit to each 212 | of several data subsets. 213 | \item[{Different plots with aligned axes}] World Bank data viz with one 214 | time series panel, and one scatterplot panel. 215 | \end{description} 216 | \item[{Animated graphics, animation package, 15 minutes}] \mbox{ } 217 | \begin{itemize} 218 | \item Gradient descent (time=iterations). 219 | \item Two-panel World Bank data viz (time=years). 220 | \end{itemize} 221 | \item[{Interactive + animated + multi-panel + multi-layer, 45 minutes}] a 222 | few packages are able to produce complex graphics which can be 223 | described by several vocabulary words. 224 | \begin{description} 225 | \item[{shiny + ggplot2}] World Bank data viz, interacting with widgets 226 | changes selected year, countries, regions. 227 | \item[{shiny + ggvis}] same kind of graphic with World Bank data. 228 | \item[{animint}] World Bank data viz, direct manipulation changes 229 | selected year, countries, regions. 230 | \end{description} 231 | \end{description} 232 | 233 | \section{Justification} 234 | \label{sec:orgheadline11} 235 | 236 | The role of graphics is expanding and is moving away from simple 237 | static representations found in scientific journals to more 238 | interactive representations where the user is directly involved in 239 | exploring different facets of the data. In that sense, the reader 240 | indirectly takes on the role of the analyst, and R is the ideal tool 241 | to produce integrated, interactive graphics and for interfacing with 242 | some of the external graphics libraries that exist. 243 | 244 | The various implementations for interactive graphics found in R 245 | packages are often highly specialized in the same way as high-level 246 | plots, and each package typically has a completely different 247 | syntax. This tutorial will 248 | \begin{itemize} 249 | \item introduce a vocabulary for categorizing interactive graphics, 250 | \item present practical examples of how to produce interactive graphics 251 | using existing R packages, 252 | \item describe how to overcome frustrations typical of new users to 253 | interactive graphics, and 254 | \item highlight advantages and room for improvement in existing 255 | packages. 256 | \end{itemize} 257 | 258 | %\textbf{TDH should we delete this paragraph? It seems repetitive with the previous paragaph.} When the tutorial is over the attendees should 1) 259 | %have an overview of the packages for producing interactive 260 | %graphics, 2) have seen and tried examples so they are able to create 261 | %interactive graphics using some of the packages presented, and 3) have 262 | %seen the broad scope of variation among packages that seek to produce 263 | %the same type of graphics. 264 | 265 | \section{Background Knowledge} 266 | \label{sec:orgheadline12} 267 | 268 | Since we plan to present state-of-the-art interactive graphics, people 269 | should know how to use R data structures (lists, data.frames) and the 270 | ggplot2 package. 271 | 272 | Even though many examples will be interactive web graphics, we will 273 | assume only knowledge of R, not HTML/JavaScript. 274 | 275 | There are two classes of potential attendees: 276 | \begin{itemize} 277 | \item UseRs who are not very familiar with interactive graphics should 278 | benefit the most, since we will give a high-level overview of many 279 | different packages. 280 | \item DevelopeRs of interactive packages are encouraged to come, to 281 | discuss the current state-of-the-art and future directions. 282 | \end{itemize} 283 | 284 | \section{Expected Number of Attendees} 285 | \label{sec:orgheadline13} 286 | 287 | We're not sure how to estimate this, but typically interactive 288 | graphics are a popular topic so it would be best to have a decent 289 | sized lecture hall (50-150 people). 290 | \end{document} 291 | -------------------------------------------------------------------------------- /useR2016pack.R: -------------------------------------------------------------------------------- 1 | ## 2 | ## 3 | ## Install script for useR 2016 tutorial on interactive graphics 4 | ## 5 | ## 6 | 7 | CRANpackages <- c("dplyr", "shiny", "plotly", "xts", "highcharter", "DiagrammeR", "dygraphs", 8 | "ggplot2", "htmlwidgets", "leaflet", "viridis") 9 | 10 | install.packages(CRANpackages) 11 | 12 | require(devtools) 13 | install_github('ramnathv/rCharts', force=TRUE) 14 | 15 | install_github('ekstroem/MESS', force=TRUE) 16 | 17 | 18 | --------------------------------------------------------------------------------