├── .gitignore ├── HtmlWidgetExamples.Rproj ├── README.md ├── _site.yml ├── data.rds ├── ex_dt_sparkline.R └── ex_dt_sparkline.Rmd /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | libs/ 6 | .Rhistory 7 | *.pydevproject 8 | .project 9 | .metadata 10 | bin/ 11 | tmp/ 12 | *.tmp 13 | *.bak 14 | *.swp 15 | *~.nib 16 | local.properties 17 | .classpath 18 | .settings/ 19 | .loadpath 20 | 21 | # External tool builders 22 | .externalToolBuilders/ 23 | 24 | # Locally stored "Eclipse launch configurations" 25 | *.launch 26 | 27 | # CDT-specific 28 | .cproject 29 | 30 | # PDT-specific 31 | .buildpath 32 | 33 | 34 | ################# 35 | ## Visual Studio 36 | ################# 37 | 38 | ## Ignore Visual Studio temporary files, build results, and 39 | ## files generated by popular Visual Studio add-ons. 40 | 41 | # User-specific files 42 | *.suo 43 | *.user 44 | *.sln.docstates 45 | 46 | # Build results 47 | 48 | [Dd]ebug/ 49 | [Rr]elease/ 50 | x64/ 51 | build/ 52 | [Bb]in/ 53 | [Oo]bj/ 54 | 55 | # MSTest test Results 56 | [Tt]est[Rr]esult*/ 57 | [Bb]uild[Ll]og.* 58 | 59 | *_i.c 60 | *_p.c 61 | *.ilk 62 | *.meta 63 | *.obj 64 | *.pch 65 | *.pdb 66 | *.pgc 67 | *.pgd 68 | *.rsp 69 | *.sbr 70 | *.tlb 71 | *.tli 72 | *.tlh 73 | *.tmp 74 | *.tmp_proj 75 | *.log 76 | *.vspscc 77 | *.vssscc 78 | .builds 79 | *.pidb 80 | *.log 81 | *.scc 82 | 83 | # Visual C++ cache files 84 | ipch/ 85 | *.aps 86 | *.ncb 87 | *.opensdf 88 | *.sdf 89 | *.cachefile 90 | 91 | # Visual Studio profiler 92 | *.psess 93 | *.vsp 94 | *.vspx 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | 103 | # TeamCity is a build add-in 104 | _TeamCity* 105 | 106 | # DotCover is a Code Coverage Tool 107 | *.dotCover 108 | 109 | # NCrunch 110 | *.ncrunch* 111 | .*crunch*.local.xml 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.Publish.xml 131 | *.pubxml 132 | *.publishproj 133 | 134 | # NuGet Packages Directory 135 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 136 | #packages/ 137 | 138 | # Windows Azure Build Output 139 | csx 140 | *.build.csdef 141 | 142 | # Windows Store app package directory 143 | AppPackages/ 144 | 145 | # Others 146 | sql/ 147 | *.Cache 148 | ClientBin/ 149 | [Ss]tyle[Cc]op.* 150 | ~$* 151 | *~ 152 | *.dbmdl 153 | *.[Pp]ublish.xml 154 | *.pfx 155 | *.publishsettings 156 | 157 | # RIA/Silverlight projects 158 | Generated_Code/ 159 | 160 | # Backup & report files from converting an old project file to a newer 161 | # Visual Studio version. Backup files are not needed, because we have git ;-) 162 | _UpgradeReport_Files/ 163 | Backup*/ 164 | UpgradeLog*.XML 165 | UpgradeLog*.htm 166 | 167 | # SQL Server files 168 | App_Data/*.mdf 169 | App_Data/*.ldf 170 | 171 | ############# 172 | ## Windows detritus 173 | ############# 174 | 175 | # Windows image file caches 176 | Thumbs.db 177 | ehthumbs.db 178 | 179 | # Folder config file 180 | Desktop.ini 181 | 182 | # Recycle Bin used on file shares 183 | $RECYCLE.BIN/ 184 | 185 | # Mac crap 186 | .DS_Store 187 | 188 | 189 | ############# 190 | ## Python 191 | ############# 192 | 193 | *.py[cod] 194 | 195 | # Packages 196 | *.egg 197 | *.egg-info 198 | dist/ 199 | build/ 200 | eggs/ 201 | parts/ 202 | var/ 203 | sdist/ 204 | develop-eggs/ 205 | .installed.cfg 206 | 207 | # Installer logs 208 | pip-log.txt 209 | 210 | # Unit test / coverage reports 211 | .coverage 212 | .tox 213 | 214 | #Translations 215 | *.mo 216 | 217 | #Mr Developer 218 | .mr.developer.cfg 219 | .Rproj.user 220 | -------------------------------------------------------------------------------- /HtmlWidgetExamples.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | StripTrailingWhitespace: Yes 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HtmlWidgetExamples 2 | Examples using R packages which use htmlwidgets 3 | -------------------------------------------------------------------------------- /_site.yml: -------------------------------------------------------------------------------- 1 | navbar: 2 | title: "R htmlwidgets examples" 3 | left: 4 | - text: "DT & Sparklines" 5 | href: index.html 6 | right: 7 | - icon: fa-github fa-lg 8 | href: https://github.com/leonawicz/HtmlWidgetExamples 9 | -------------------------------------------------------------------------------- /data.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonawicz/HtmlWidgetExamples/72ff77840f96da3ed7c102e6f5dc842275331fdf/data.rds -------------------------------------------------------------------------------- /ex_dt_sparkline.R: -------------------------------------------------------------------------------- 1 | # @knitr setup 2 | library(dplyr) 3 | library(tidyr) 4 | library(DT) 5 | library(sparkline) 6 | 7 | # @knitr table 8 | dat <- readRDS("data.rds") 9 | datatable(dat, rownames = FALSE) 10 | 11 | # @knitr defs 12 | js <- "function(data, type, full){ return '' + data + '' }" 13 | colDefs1 <- list(list(targets = c(1:12), render = JS(js))) 14 | colDefs2 <- list(list(targets = c(1:6), render = JS(js))) 15 | 16 | # @knitr callbacks 17 | r <- range(filter(dat, Var == "Temperature")$Val) 18 | bar_string <- "type: 'bar', barColor: 'orange', negBarColor: 'purple', highlightColor: 'black'" 19 | cb_bar <- JS(paste0("function (oSettings, json) { $('.spark:not(:has(canvas))').sparkline('html', { ", bar_string, " }); }"), collapse = "") 20 | 21 | x <- "function (oSettings, json) { $('.spark:not(:has(canvas))').sparkline('html', { " 22 | line_string <- "type: 'line', lineColor: 'black', fillColor: '#ccc', highlightLineColor: 'orange', highlightSpotColor: 'orange'" 23 | cb_line <- JS(paste0(x, line_string, ", chartRangeMin: ", r[1], ", chartRangeMax: ", r[2], " }); }"), collapse = "") 24 | 25 | box_string <- "type: 'box', lineColor: 'black', whiskerColor: 'black', outlierFillColor: 'black', outlierLineColor: 'black', medianColor: 'black', boxFillColor: 'orange', boxLineColor: 'black'" 26 | cb_box1 <- JS(paste0(x, box_string," }); }"), collapse = "") 27 | cb_box2 <- JS(paste0(x, box_string, ", chartRangeMin: ", r[1], ", chartRangeMax: ", r[2], " }); }"), collapse = "") 28 | 29 | # @knitr sparklines 30 | dat_p <- filter(dat, Var == "Precipitation" & Decade == "2000s" & Month == "Aug")$Val 31 | dat_p 32 | 33 | # @knitr sparkline_dt_prep 34 | dat_t <- filter(dat, Var == "Temperature") %>% 35 | group_by(Decade, Month) %>% summarise(Temperature = paste(Val, collapse = ",")) 36 | dat_t1 <- spread(dat_t, Month, Temperature) 37 | dat_t2 <- spread(dat_t, Decade, Temperature) 38 | 39 | # @knitr table_DxM_line 40 | d1 <- datatable(dat_t1, rownames = FALSE, options = list(columnDefs = colDefs1, fnDrawCallback = cb_line)) 41 | d1$dependencies <- append(d1$dependencies, htmlwidgets:::getDependency("sparkline")) 42 | d1 43 | 44 | # @knitr table_MxD_bar 45 | d2 <- datatable(dat_t2, rownames = FALSE, options = list(columnDefs = colDefs2, fnDrawCallback = cb_bar)) 46 | d2$dependencies <- append(d2$dependencies, htmlwidgets:::getDependency("sparkline")) 47 | d2 48 | 49 | # @knitr table_MxD_box1 50 | d3 <- datatable(dat_t2, rownames = FALSE, options = list(columnDefs = colDefs2, fnDrawCallback = cb_box1)) 51 | d3$dependencies <- append(d3$dependencies, htmlwidgets:::getDependency("sparkline")) 52 | d3 53 | 54 | # @knitr table_MxD_box2 55 | d4 <- datatable(dat_t2, rownames = FALSE, options = list(columnDefs = colDefs2, fnDrawCallback = cb_box2)) 56 | d4$dependencies <- append(d4$dependencies, htmlwidgets:::getDependency("sparkline")) 57 | d4 58 | 59 | # @knitr final_prep 60 | dat_t3 <- filter(dat, Var == "Temperature" & Month == "Aug") %>% 61 | group_by(Location, Month, Var, Decade) %>% 62 | summarise(Mean = round(mean(Val), 1), SD = round(sd(Val), 2), Min = min(Val), Max = max(Val), Samples = paste(Val, collapse = ",")) %>% 63 | mutate(Series = Samples) 64 | 65 | js <- "function(data, type, full){ return '' + data + '' }" 66 | cd <- list(list(targets = 8, render = JS(js)), list(targets = 9, render = JS(js))) 67 | cb <- JS(paste0("function (oSettings, json) { 68 | $('.sparkSeries:not(:has(canvas))').sparkline('html', { ", line_string, " }); 69 | $('.sparkSamples:not(:has(canvas))').sparkline('html', { ", box_string, " }); 70 | }"), collapse = "") 71 | 72 | # @knitr table_final 73 | d5 <- datatable(dat_t3, rownames = FALSE, options = list(columnDefs = cd, fnDrawCallback = cb)) 74 | d5$dependencies <- append(d5$dependencies, htmlwidgets:::getDependency("sparkline")) 75 | d5 76 | -------------------------------------------------------------------------------- /ex_dt_sparkline.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: Combining data tables and sparklines 3 | output: 4 | html_document: 5 | toc: false 6 | theme: cosmo 7 | highlight: zenburn 8 | --- 9 | 10 | ```{r knitr_setup, echo=FALSE} 11 | knitr::opts_chunk$set(cache=FALSE, echo=TRUE, eval=TRUE, tidy=TRUE, message=FALSE, warning=FALSE) 12 | knitr::read_chunk("ex_dt_sparkline.R") 13 | rinline <- function(code_string) sprintf('``` `r %s` ```', bquote(.(code_string))) 14 | ``` 15 | 16 | ## 17 | ## 18 | ## Examples using Edmonton, Alberta climate data 19 | 20 | In the examples below, I use a 1950 - 2009 subset of SNAP's 2-km resolution downscaled CRU 3.2 temperature and precipitation data for Edmonton, Alberta 21 | to demonstrate the use of the [DT](http://rstudio.github.io/DT/) package for data tables and the [sparkline](https://github.com/htmlwidgets/sparkline) package for inline graphs as well as integration of inline graphs into data tables. 22 | These packages make use of the [htmlwidgets](http://www.htmlwidgets.org/index.html) package and are interfaces to the jQuery plugins [dataTables](https://datatables.net/) and [sparkline](http://omnipotent.net/jquery.sparkline/#s-about). 23 | 24 | First, load data and required packages. I store the temperature range over all months and years for later use. 25 | 26 | ```{r setup} 27 | ``` 28 | 29 | ## 30 | ## 31 | ### DT data tables 32 | 33 | Here is the full data table generated with `DT`. There are various feature options for data table html widgets in the browser using `DT`. See this [introduction](http://rstudio.github.io/DT/) for details. 34 | 35 | ```{r table} 36 | ``` 37 | 38 | ## 39 | ## 40 | ### Sparkline inline graphs 41 | 42 | ```{r sparklines} 43 | ``` 44 | 45 | ## 46 | 47 | Next, display some inline graphs. Here I use August precipitation totals from Edmonton each year from 2000 - 2009, stored in `dat.p`. 48 | Inline graphs can be shown with calls in your `R` Markdown document in the form, e.g., `r rinline("sparkline(rnorm(10))")`. 49 | Different plots can be made by passing a `type` argument. 50 | Options include but are not limited to line graphs `r sparkline(dat_p)`, bar graphs `r sparkline(dat_p, type='bar')`, and box plots `r sparkline(dat_p, type='box')`. 51 | 52 | ## 53 | ## 54 | ### Sparklines inside data tables 55 | 56 | To make things more interesting, I integrate sparklines into data tables. This requires providing column definitions and callback functions when making the tables. 57 | Here I provide two similar column definitions, the only difference being which columns to target (counting from zero because this refers to javascript, not `R`). 58 | These definitions add the `spark` class to the targeted columns. 59 | 60 | ```{r defs} 61 | ``` 62 | 63 | ## 64 | 65 | I also define several callback functions, again all very similar. The only differences are minor tweaks to what I want the sparklines to look like. 66 | I make four data tables with sparklines, using lines, bars, and two with box plots. 67 | For some tables I use the range values from earlier to set a single y-axis common to each graph and for the others I allow each plot to have unique axis limits. 68 | 69 | ```{r callbacks} 70 | ``` 71 | 72 | ## 73 | 74 | Notice that the call to `summarise` below does collapse the data over years (grouped by decades and months), but nothing is lost because the values are concatenated into single character strings. 75 | `dcast` is used to return the table to wide format for a more convenient display. 76 | 77 | ```{r sparkline_dt_prep} 78 | ``` 79 | 80 | ## 81 | ## 82 | #### Example tables 83 | 84 | Plot temperature line graphs with a decades by months layout. 85 | This table shows sparklines which all share a common y-axis. It is not easy to read given the data. 86 | Sparklines are most often used inline among text, though inline in a table is really no different and can in fact only make them easier to juxtapose and compare. 87 | Nevertheless, they work best when the interest is in obtaining a sense for variability in a signal at a glance. 88 | By their nature they will not work as well for making comparisons between sparklines. 89 | 90 | ```{r table_DxM_line} 91 | ``` 92 | 93 | ## 94 | 95 | Plot bar graphs using a months by decades layout. In this case I allow individual sparklines to have unique y-axis limits. 96 | They are much easier to read, but in this case the focus is more clearly not on comparing across months or decades. 97 | 98 | ```{r table_MxD_bar} 99 | ``` 100 | 101 | ## 102 | 103 | Plot box plots using a months by decades layout. The two versions below differ in their axis settings. 104 | The first allows unique chart ranges like the previous bar graph. The second fixes all sparklines to a single range. 105 | 106 | ```{r table_MxD_box1} 107 | ``` 108 | 109 | ```{r table_MxD_box2} 110 | ``` 111 | 112 | ## 113 | ## 114 | #### A more useful table 115 | 116 | Generally I would not use a table as a complete substitute for a plot. In cases where I can, it is because the data set is simple enough that a traditional text table will suffice. 117 | If adding sparklines to a table, my preference is to use them to enhance a particular column or two, which otherwise remains a standard data table, rather than turn it into a "many-paneled plot". 118 | 119 | The above examples are for illustration. The table below seems like a good mix of data tables and sparklines. 120 | This time I also grouped by location, month, and climate variable even though they are constants in this data subset. This retains them in the final data table for display purposes. 121 | I think it gives a better picture of what the table would look like with more columns which are not all narrow-width and numeric-valued. 122 | 123 | In the column definitions and the callback function, note the use of `.sparkSeries` and `.sparkSamples` to differentiate which type of sparklines are placed in each of the two columns. 124 | The box plot shows the distribution of values over a decade whereas the time series line gives a sense of whether any trend is present. 125 | Although it is a simple example and each individual plot is based on only ten values, 126 | it reveals how each inline graph type draws the eye to different properties of the data and both are a nice compliment to the original data table. 127 | 128 | ```{r final_prep} 129 | ``` 130 | 131 | ## 132 | 133 | This strikes a nice balance. On the one hand, I could add additional columns to the table such as the median and quartiles, 134 | but I don't need to add these columns because I can hover over the box plot and see those values in the tooltip. I can also see information about outliers. 135 | This alleviates the need for additional columns. I cannot look at trends easily, or at all, in a summary table. 136 | I can only do this if I use a full table and summarize nothing. For this reason the time series plots are also helpful. 137 | 138 | On the other hand, I could remove all my value columns, but I definitely do not want to. 139 | Technically speaking, I can get the medians from the samples column using the box plots, which are close enough to the means, and the min and max values from the series column inline graphs. 140 | Neither plot type specifically provides the standard deviation, but perhaps seeing the distribution in a box plot is "better" in some instances anyhow, like if the data were highly skewed. 141 | Ultimately, I do not want to be required to hover over all these little plots to essentially decrypt my table. 142 | I want to look at a table and see numbers without any intermediary mental decoding. 143 | 144 | ```{r table_final} 145 | ``` 146 | 147 | This is why I see the integration of sparklines inside data tables as complimentary to other information in a table, but not generally as a full replacement where the table becomes a series of pictures, 148 | requiring human interaction with all the individual table cells in order to obtain certain types of information. 149 | 150 | To make a simile, the numeric data columns are like open doorways to an aggregation of the data. 151 | The box plots are more like closed doors. You have to fuss with them as a user to obtain similar information. 152 | The time series graphs are more like locked doors in this context. You can figure out the mean from them, but doing so is ridiculous. 153 | However, the box plots and time series lines are each open doors to disaggregated information from the original data set, where the summary statistics in the numeric columns are more like closed doors. 154 | More complete distributional information and data at a more disaggregated scale can seamlessly be piped through into the summary table where it would normally never be visible. 155 | 156 | The right balance allows for the most information to be immediately accessible. Some information, like a specific statistic, is best shown as a clearly visible number. 157 | Other information like the distribution of a random variable, a trend line, an expression of variability around a trend through time, or some other functional form, can be most quickly interpreted from a visual description. 158 | --------------------------------------------------------------------------------