Reveal code
= "High School Aces"
title = "vivid"
palette = true
showLegend = ({
verticalAxis title: "Number of A+ scores"
})
This is an R + OJS (Observable-flavored JavaScript) Quarto version of this Observable notebook.
You must go through that notebook first before going through this. I will not be explaining too much about Plotteus, just how to wrangle data in R to get it to work with Plotteus.
Plotteus is a JS datavis library to help craft interactive stories. It kind of works best in a scrollytelling setting, but it can be used outside of said setting quite well.
We’ll work through how to get R data frame data to Plotteus so you can tell stories with it in Quarto docs. I’ve folded most of the code blocks for readability.
The following code block sets up some common labels and settings we’ll use throughout the three OJS charting blocks. Reveal it to see what’s set.
= "High School Aces"
title = "vivid"
palette = true
showLegend = ({
verticalAxis title: "Number of A+ scores"
})
This is the intial data frame of the students (you saw this as an ugly JS array within the code block of the chart in the pure Observable version):
data.frame(
student = c("Alicja", "Borys", "Celina", "Dorian", "Ewa", "Filip", "Greg"),
subject = rep("Math", 7),
num_scores = c(3L, 4L, 7L, 6L, 5L, 2L, 1L)
-> students
)
students
student subject num_scores
1 Alicja Math 3
2 Borys Math 4
3 Celina Math 7
4 Dorian Math 6
5 Ewa Math 5
6 Filip Math 2
7 Greg Math 1
We’re going to get it into the shape you saw in the Observable notebook (an excerpt from that is below). I like to wrangle the data into a JSON string and then just parse that on the OJS side. I have the most control over what its shape will be that way.
We actually make two data frames: the original and one sorted by the number of “A+” grades. We could just wrangle that in JS-land, but we’re using R for a reason: we are better at data ops in R.
Each block outputs the JSON that will be parsed.
|>
students ::rename(
dplyrkey = subject,
value = num_scores
|>
) ::group_by(
dplyr
student|>
) ::nest(
tidyrdata = c(key, value)
|>
) ::ungroup() |>
dplyr::rename(key = student) |>
dplyr::toJSON() -> students_json
jsonlite
students_json
[{"key":"Alicja","data":[{"key":"Math","value":3}]},{"key":"Borys","data":[{"key":"Math","value":4}]},{"key":"Celina","data":[{"key":"Math","value":7}]},{"key":"Dorian","data":[{"key":"Math","value":6}]},{"key":"Ewa","data":[{"key":"Math","value":5}]},{"key":"Filip","data":[{"key":"Math","value":2}]},{"key":"Greg","data":[{"key":"Math","value":1}]}]
|>
students ::arrange(
dplyrdesc(num_scores)
|>
) ::rename(
dplyrkey = subject,
value = num_scores
|>
) ::group_by(
dplyr
student|>
) ::nest(
tidyrdata = c(key, value)
|>
) ::rename(key = student) |>
dplyr::ungroup() |>
dplyr::toJSON() -> students_sorted_json
jsonlite
students_sorted_json
[{"key":"Celina","data":[{"key":"Math","value":7}]},{"key":"Dorian","data":[{"key":"Math","value":6}]},{"key":"Ewa","data":[{"key":"Math","value":5}]},{"key":"Borys","data":[{"key":"Math","value":4}]},{"key":"Alicja","data":[{"key":"Math","value":3}]},{"key":"Filip","data":[{"key":"Math","value":2}]},{"key":"Greg","data":[{"key":"Math","value":1}]}]
Now we make those text strings available to the OJS runtime:
ojs_define(students_json = students_json)
ojs_define(students_sorted_json = students_sorted_json)
And, we parse the text into proper objects.
= JSON.parse(students_json)
students = JSON.parse(students_sorted_json) students_sorted
This is the format Plotteus expects, and you can see it matches what we built.
[
{key: "Alicja",
data: [{ key: "Math", value: 3 }]
,
}
{key: "Borys",
data: [{ key: "Math", value: 4 }]
} ]
This is the first plot (please use the “Code Tools” at the top of the document top see the OJS code that makes the chart):
We will have another data frame for the second example since the transition in part two has two subjects. This is what the JS Object looks like:
[
{key: "Greg",
data: [
key: "Math", value: 1 },
{ key: "Chemistry", value: 6 }
{
],
}
{key: "Filip",
data: [
key: "Math", value: 2 },
{ key: "Chemistry", value: 4 }
{
]
} ]
And this is the R code that makes the new data frame and JSON we’ll send to OJS:
read.csv(
text = '"student","subject","num_scores"
"Alicja","Chemistry",4
"Alicja","Math",4
"Borys","Chemistry",1
"Borys","Math",5
"Celina","Math",7
"Dorian","Chemistry",4
"Dorian","Math",6
"Ewa","Chemistry",2
"Ewa","Math",3
"Filip","Chemistry",4
"Filip","Math",2
"Greg","Chemistry",6
"Greg","Math",1
"Celina","Chemistry",2',
header = TRUE
|>
) ::mutate(
dplyrstudent = forcats::fct_reorder(student, num_scores, sum)
|>
) ::arrange(
dplyr
student,
subject-> two_subjects
)
|>
two_subjects ::rename(
dplyrkey = subject,
value = num_scores
|>
) ::group_by(
dplyr
student|>
) ::nest(
tidyrdata = c(key, value)
|>
) ::ungroup() |>
dplyr::rename(key = student) |>
dplyr::toJSON() -> students2_json
jsonlite
ojs_define(students2_json = students2_json)
And, we make this second one available to OJS as well:
= JSON.parse(students2_json) students2
This is the second example chart. Again, please use the “Code Tools” up top to view the chart OJS source:
We’ll just do one more, the one that makes the horrible pie charts. It does show how cool and flexible the Plotteus transition framework is, though. First, we filter the second data frame down to just three students and pass it to OJS:
|>
two_subjects ::filter(
dplyr%in% c("Alicja", "Celina", "Dorian")
student |>
) ::rename(
dplyrkey = subject,
value = num_scores
|>
) ::group_by(
dplyr
student|>
) ::nest(
tidyrdata = c(key, value)
|>
) ::ungroup() |>
dplyr::rename(key = student) |>
dplyr::toJSON() -> just_three_json
jsonlite
ojs_define(just_three_json = just_three_json)
= JSON.parse(just_three_json) just_three
And, now we render the final chart:
There is invisible setup code below. Please use the “Code Tools” to view it, and read the Observable notebook version for more information.