-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy path3-21-htmlwidgets-basics.Rmd
179 lines (144 loc) Β· 8.64 KB
/
3-21-htmlwidgets-basics.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# Basics of Building Widgets {#widgets-basics}
Having explored existing packages that build on top of the htmlwidgets\index{htmlwidgets} package gives some idea of the end product, but much of how it works and where to start probably remains somewhat mysterious.
```{r include=FALSE}
source("utils.R")
```
## Read and Study {#widgets-basics-study}
Once you have found an impressive library that you would like to use from R, the very first step when building a widget is to study the JavaScript library you want to integrate thoroughly.
1. Start where the documentation tells you to start, often a "hello world" example, or a get-started section. This will already give you a good sense of how this library functions, the expected data format, and more.
2. Second, it's good to head to the "installation" part of the documentation to know more about the library's dependencies\index{dependency}, see whether it is modularised or available in a single bundle, etc.
3. Look at examples in great depth. One cue to know if the library will be more or less complex to integrate with R is whether the various snippets of code that generate the examples are similar or drastically different: commonalities make for easier abstractions and ultimately simpler R code and packages. Some libraries will ultimately be more straightforward to integrate than others.
4. At this stage you should have some idea of what it will take to bring the library to R, and though you likely are vaguely familiar with the functions and methods that comprise the library you must look at the "API," or proper "documentation" of the API to grasp precisely what is available.
5. Finally, before starting the R work, it is advised to properly experience using the library as it was intended: with JavaScript and HTML. This will further give a sense of which parts of the API are great and which not so much. This is useful to know because you will get to improve or mirror this API in R when you develop the widget for it.
This is likely a section you will want to come back to at the end of this part as you browse for libraries to integrate into your workflow.
## Candidate Libraries {#widgets-basics-candidates}
Before going down the rabbit hole, let us explore the types of libraries you will work with; htmlwidgets' main clients so to speak. Below we look at some such popular libraries and briefly analyse how they work and what they have in common. This will significantly help readers conceptualise what trying to achieve in this chapter.
### Plotly.js {#widgets-basics-candidates-plotly}
[Plotly.js](https://plotly.com/javascript/) is probably one of the more popular out there; it provides over 40 fully customisable chart types, many of which are very sophisticated. That is indeed the JavaScript library used by the R package of the same name: plotly.
Looking at the code presented in the "Get Started" guide reveals just how convenient the library is. In Figure \@ref(fig:candidate-plotly) we import plotly, of course, then have a `<div>` where the visualisation will be placed. Then, using `Plotly.newPlot`, create the actual visualisation by passing it first the element previously mentioned and a JSON\index{JSON} of options that describe the chart.
```html
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<!-- Import library -->
<script src="plotly-latest.min.js"></script>
</head>
<body>
<!-- div to hold visualisation -->
<div id="chart" style="width:600px;height:400px;"></div>
<!-- Script to create visualisation -->
<script>
el = document.getElementById('chart');
Plotly.newPlot(el, [{
x: [1, 2, 3, 4, 5],
y: [1, 2, 4, 8, 16] }]
);
</script>
</body>
</html>
```
```{r candidate-plotly, fig.pos="H", echo=FALSE, fig.cap='Plotly example'}
knitr::include_graphics("images/candidate-plotly.png")
```
Now let's look at how another popular library does it.
### Highchart.js {#widgets-basics-candidates-highcharts}
[Highcharts](https://www.highcharts.com/) is another library that allows creating gorgeous visualisation\index{visualisation}, maps, and more; it's also very popular, albeit not being entirely free.
```html
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<!-- Import library -->
<script src="highcharts.js"></script>
</head>
<body>
<!-- div to hold visualisation -->
<div id="chart" style="width:100%;height:400px;"></div>
<!-- Script to create visualisation -->
<script>
var myChart = Highcharts.chart('chart', {
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
series: [{
name: 'Jane',
data: [1, 0, 4]
}, {
name: 'John',
data: [5, 7, 3]
}]
});
</script>
</body>
</html>
```
```{r candidate-highcharts, fig.pos="H", echo=FALSE, fig.cap='Highcharts example'}
knitr::include_graphics("images/candidate-highcharts.png")
```
Figure \@ref(fig:candidate-highcharts) is very similar to what plotly.js requires: import libraries, create a `<div>` where to put the visualisation\index{visualisation}. Then, to create the chart, run a function which also takes the id of the div where to place said chart and a JSON of options defining the actual chart, including the data.
### Chart.js {#widgets-basics-candidates-chart.js}
[Chart.js](https://www.chartjs.org/) is yet another library with which to draw standard charts; it is popular for its permissive license and convenient API.
```html
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<!-- Import library -->
<script src="Chart.min.js"></script>
</head>
<body>
<!-- canvas to hold visualisation -->
<canvas id="chart"></canvas>
<!-- Script to create visualisation -->
<script>
var el = document.getElementById('chart').getContext('2d');
var myChart = new Chart(el, {
type: 'bar',
data: {
labels: [
'Red', 'Blue', 'Yellow', 'Green',
'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3]
}]
}
});
</script>
</body>
</html>
```
```{r candidate-chartjs, fig.pos="H", echo=FALSE, fig.cap='Chart.js example'}
knitr::include_graphics("images/candidate-chartjs.png")
```
In Figure \@ref(fig:candidate-chartjs), we again observe a very similar structure as with previous libraries. The library is imported; instead of a `div` chart.js uses a `canvas`, the visualisation\index{visualisation} is also created from a single function which takes the canvas as first argument and a JSON of options as second.
Hopefully, this reveals the repeating structure such libraries tend to follow as well as demonstrate how little JavaScript code is involved. It also hints at what should be reproduced, to some extent at least, using R.
## How It Works {#widgets-basics-inner-workings}
Imagine there is no such package as htmlwidgets\index{htmlwidgets} to help create interactive visualisations from R: how would one attempt to go about it?
As observed, an interactive visualisation using JavaScript will be contained within an HTML\index{HTML} document. Therefore it would probably have to be created first. Secondly, the visualisation that is yet to be created likely relies on external libraries; these would need to be imported in the document. The document should also include an HTML\index{HTML} element (e.g.: `<div>`) to host said visualisation\index{visualisation}. Then data would have to be serialised\index{serialise} in R and embedded into the document, where it should be read by JavaScript code that uses it to create the visualisation. Finally, all should be managed to work seamlessly across R markdown\index{R markdown}, Shiny\index{Shiny}, and other environments.
This gives the basic diagram shown in Figure \@ref(fig:widget-inner-diagram); it will be broken down further in the next chapter as the first widget is built.
```{r widget-inner-diagram, fig.pos="H", echo=FALSE, fig.cap='htmlwidgets inner-workings visualised'}
d <- DiagrammeR::grViz("
digraph {
graph [rankdir = LR]
subgraph cluster_0 {
node [shape=box]
'HTML element'
'JSON'
'JavaScript'
'Dependencies'
label='HTML'
color=gold
}
subgraph cluster_1 {
node [shape=box]
'Data'
'Chart options'
label = 'R environment'
color=royalBlue
}
'Data' -> 'JSON'
'Chart options' -> 'JSON' [label='serialise' constraint=false]
'JSON' -> 'JavaScript'
'JavaScript' -> 'HTML element'
'Dependencies' -> 'JavaScript'
}
", width="100%", height=250)
include_widget(d, "03-htmlwidget-viz.png")
```
Thankfully the htmlwidgets package is there to handle most of this. Nonetheless, it is essential to understand that these operations are undertaken (to some degree) by htmlwidgets.