-
Notifications
You must be signed in to change notification settings - Fork 15
/
interactive.qmd
175 lines (135 loc) · 5.65 KB
/
interactive.qmd
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
---
title: "Interactivity: Quarto & Observable JS"
date-modified: 'today'
date-format: long
license: CC BY-NC
bibliography: references.bib
format:
html:
df-print: paged
toc: true
echo: false
warning: false
messages: false
code-summary: "Show the code"
code-tools: true
---
```{r}
library(tidyverse)
library(haven)
satisfaction_df <- read_sav("data/student_satisfaction_test-data_from_qualtrics.sav") |>
janitor::clean_names() |>
mutate(across(is.labelled, \(x) as_factor(x), .names = "{.col}_label")) |>
select(response_id, ends_with("_label")) |>
pivot_longer(-response_id, names_to = "my_question", values_to = "response") |>
mutate(rnumber = as.numeric(response))
trade_df <- read_csv("data/data.csv")
trade_df <- trade_df |>
filter(str_detect(business, "(Motor|beverage|Electronics)")) |>
mutate(sales = as.integer(sales))
```
```{r}
ojs_define(trade_df_ojs = trade_df)
ojs_define(my_df_tall_ojs = satisfaction_df)
```
This is a very basic example of displaying an interactive visualization using ObservableJS. Use the drop-down box to test how the plots and tables are reactive to user input.
```{ojs}
//| panel: input
//| layout-ncol: 1
viewof questions =
Inputs.select(
["q1_label", "q2_label", "q3_label", "q4_label", "q5_label",
"q6_label", "q7_label", "q8_label", "q9_label", "q10_label",
"q12_label", "q13_label", "q14_label", "q15_nps_group_label"],
{value: "q3_label", label: "Select a question"})
// viewof questions = Inputs.select(d3.group(my_survey, d => d.my_question))
```
::: panel-tabset
## Plot
```{ojs}
//| code-fold: true
//| echo: fenced
my_survey_filtered_too = my_survey
.filter(aq.escape(d => d.my_question == questions))
.groupby('my_question', 'response', 'rnumber')
.count()
.orderby('my_question', 'rnumber')
Plot.plot({
marginRight: 140,
y: {
axis: null,
domain: d3.sort(my_survey_filtered_too, d => -d.rnumber).map(d => d.response).reverse()
},
x: {
grid: true
},
marks: [
Plot.barX(my_survey_filtered_too, {y: "response", x: "count"}),
Plot.text(my_survey_filtered_too, {
x: "count",
y: "response",
text: "response",
textAnchor: "start",
dx: 6
})
]
})
```
## Data
```{ojs}
my_survey_filtered_too.view()
```
:::
::: {.callout-tip collapse="true"}
## Workflow: How'd we do that?
The above example uses `{r}` code-chunks and the `{haven}` package to import labeled Qualtrics data. The SPSS data file is a .*sav* file with raw data, variable and value labels ingested via `read_sav`, wrangled with `{dplyr}`, and then visualized with client-side interactive ObservableJS `{ojs}` code-chunks. Using the RStudio IDE and Quarto, it's easy to combine R and Observable code so that we can render this interactive page. (See the `</> Code` icon at the top of this page.)
Learn more below...
:::
## Transpose to arquero
Behind the scenes, when rendering this report, I use `{r}` code-chunks to import and wrangle the data. I'm importing and wrangling my data with a quarto-friendly code language. Then I *transpose* my data frame into an OJS object.
```{ojs}
//| echo: fenced
my_data = aq.from(transpose(trade_df_ojs))
my_survey = aq.from(transpose(my_df_tall_ojs))
```
## Simplified example
### basic
The next code-chunk shows a very simple example of ObservableJS `{Plot}` code for visualization. This example *is not interactive* but it demonstrates the remarkable similarity to `{ggplot2}` syntax.
plot
```{ojs}
//| echo: fenced
Plot.plot({
marks: [
Plot.ruleY([0]),
Plot.lineY(my_data_wrangled, {
x: "date",
y: "sales",
stroke: "business"
}),
]
})
```
::: callout-note
## ↥ Look up!
Notice the crispness and clarity of the simple non-interactive plot above. [Observable Plot](https://observablehq.com/@observablehq/plot) shows well on the web!
:::
## Arquero data wrangling
::: gray
**Derive date**
Aside from the `{dplyr}` wrangling that I did in the background of this code notebook, I still needed to parse the date fields. Arquero to the rescue.
**Arquero**! Now what is that? *Observable JavaScript* is its own coding language and we can minimize the learning curve by keeping our data wrangling within our favorite coding language R. This way we can focus on using the [{Plot}](#0) grammar and syntax that is very similar to `{ggplot2}` -- see the above example. However, [Observable JS](#0) is a complete and rich language of its own. So, just like [{`shiny`}](#0), we want to learn just enough to get the job done. That said, there is a case where a little more data wrangling is optimal. This is where [`{arquero}`](#0) comes in. Arquero is used for data wrangling and is easy to learn because it was inspired by `{dplyr}`. *Show the code* for the first plot on this page and you'll see the similarity to `{dplyr}`.
Below we can coerce a data-type for the `my_data$date` vector by transforming a *character* data-type to a *date* data-type using Arquero's `.derive()` function. Arquero's `.derive()` function is similar to `dplyr::mutate()`
:::
```{ojs}
//| echo: fenced
my_data_wrangled = my_data
.derive({ date: d => op.parse_date(d.date) })
```
On this page, we use both `{r}` and `{ojs}` code chunks within one Quarto notebook. This shows how to present useful interactivity in a multilingual coding context.
```{ojs}
import { aq, op } from '@uwdata/arquero'
// aq = import('https://esm.run/arquero')
// op = import('https://esm.run/arquero')
```
## Examples and documentation
See a [very cool demo at the Quarto-Observable](https://quarto.org/docs/interactive/#observable-js) introduction page. Learn more about this exciting option at the [*Quarto-Observable JS Guide*](https://quarto.org/docs/interactive/ojs/).