├── .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 |
--------------------------------------------------------------------------------