-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslide_status.Rmd
253 lines (216 loc) · 8.93 KB
/
slide_status.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
---
title: "Lecture Slide Status Overview"
author: "`r Sys.info()[['user']]`"
date: '`r format(Sys.time(), format = "%F %T", tz = "Europe/Berlin", usetz = TRUE)`'
output:
html_document:
toc: yes
toc_depth: 5
toc_float:
collapsed: true
self_contained: no
mathjax: null
editor_options:
chunk_output_type: console
---
```{css, echo=FALSE}
/*
Apply some custom CSS to add breathing room between sub-tables
and we don't bother creating a separate .css file for just this bit
*/
h3 {
/*text-align: center;*/
margin-top: 1.25em;
margin-bottom: 1.25em;
}
```
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
library(lese)
library(ggplot2)
included_lectures <- lectures()
if (!file.exists("slide_check_cache.rds")) {
stop(paste(
"slide_check_cache.rds does not exists.",
"Run `make` and get a coffee, or",
"Rscript -e 'source(here::here(\"helpers.R\")); check_all_slides()", sep = "\n "
))
}
all_slide_check <- readRDS("slide_check_cache.rds")
# Get lectures and reorder them
# Ignores lectures that exist locally but are not listed in included_lectures
lectures <- unique(all_slide_check$lecture)
lectures <- lectures[match(included_lectures, lectures, nomatch = 0)]
# Might as well subset table to only selected lectures
# This allows having a lecture locally for testing but not include them here yet.
all_slide_check <- all_slide_check[all_slide_check$lecture %in% included_lectures, ]
```
This document tabulates the state of the slides in `lecture*/slides/<topic>/` in terms of a) compilability and b) comparison with presumably "known good" versions of the slides located in `lecture_*/slides-pdf/`.
# Latest Commits
Displaying the latest commits of the lecture service repository and each of the currently included lectures (for debugging and race condition mitigation (kind of)).
```{r slide-checker-repo-status}
this_repo_status() |>
dplyr::mutate(
branch = sprintf("<a href='https://github.com/slds-lmu/lecture_service/tree/%s'>%s</a>", branch, branch)
) |>
dplyr::select(branch, last_commit_time, last_commit_by, last_commit_summary) |>
kableExtra::kbl(
col.names = c("Branch", "Last Commit", "By", "Message"),
escape = FALSE, caption = "Status of the lecture_service repo (time in UTC)"
) |>
kableExtra::kable_styling()
```
```{r lecture-repo-status}
lecture_status_local(lectures) |>
dplyr::arrange(dplyr::desc(last_commit_time)) |>
dplyr::mutate(
lecture_link = sprintf("<a href='https://%s.github.io/%s'>%s</a>", org, lecture, lecture),
branch = sprintf("<a href='https://github.com/%s/%s/tree/%s'>%s</a>", org, lecture, branch, branch)
) |>
dplyr::select(lecture_link, branch, last_commit_time, last_commit_by, last_commit_summary) |>
kableExtra::kbl(
col.names = c("Lecture", "Branch", "Last Commit", "By", "Message"),
escape = FALSE, caption = "Latest commits per lecture (times in UTC)"
) |>
kableExtra::kable_styling() |>
# Increase width of message column as it contains the most text (potentially)
kableExtra::column_spec(5, width = "40%")
```
If you're missing a lecture here, you might have to add them to or ensure they are downloaded correctly.
# Slide status
```{r slide-status-plot, eval = requireNamespace("ggplot2")}
#| fig.width: 10
#| fig.height: 6
#| out.width: "100%"
check_counts <- do.call(rbind, lapply(c("compile_check", "compare_check"), \(x) {
all_slide_check |>
dplyr::filter(lecture %in% .env$included_lectures) |>
dplyr::count(lecture, .data[[x]]) |>
dplyr::group_by(lecture) |>
dplyr::mutate(prop = n / sum(n), check = x) |>
dplyr::rename(result = dplyr::all_of(x)) |>
dplyr::mutate(
result = dplyr::case_when(
result ~ "Passed",
!result ~ "Failed",
.default = "N/A"
)
)
})) |>
dplyr::mutate(
lecture = stringr::str_remove(lecture, "^lecture_"),
lecture = factor(lecture, levels = stringr::str_remove(included_lectures, "^lecture_")),
check = stringr::str_remove(check, "_check$"),
)
check_counts |>
ggplot(aes(x = check, y = prop, fill = result)) +
facet_wrap(vars(lecture)) +
coord_flip() +
geom_col(alpha = 2/3) +
scale_y_continuous(labels = scales::percent) +
scale_fill_manual(
breaks = c("Passed", "Failed", "N/A"),
values = c(Passed = "#1B9E77", Failed = "#D95F02", "N/A" = "#7570B3")
) +
labs(
# title = "Lecture Check Overview",
y = "Proportion of Slides", x = NULL, fill = NULL
) +
theme_minimal(base_size = 16) +
theme(
legend.position = "bottom",
plot.title.position = "plot",
panel.grid.minor = element_blank(),
panel.grid.major.y = element_blank(),
axis.text.y = element_text(angle = 90, hjust = .5)
)
```
<details>
<summary>Click to expand explanation of table columns</summary>
```
lecture_advml/slides/gaussian-processes/slides-gp-bayes-lm.tex
\___________/ \________________/ \________________/
lecture topic <slide-name>
lecture_advml/slides-pdf/slides-gp-bayes-lm.pdf
\___________________/
pdf_static / "Reference PDF"
```
Tables are organized by lecture (first level) and lecture topics corresponding to folders in `slides/<topic>` (second level), with a table per topic.
Topics ignore certain folders like `attic` and `all`.
- **Slide**: The `<slide-name>` with a link to the compiled .tex file (if it compiles).
- **Compiles?**: Whether the .tex file compiles without error using `latexmk -pdf`.
This can depend on the availability of specific LaTeX dependencies, but assuming they are not the issue, this usually indicates syntax issues or things like `\includegraphics` calls using relative paths that work on Overleaf but not locally.
- **Comparison**: Checking the compiled `<slide-name>.tex` against `slides-pdf/<slide-name>.pdf` using `diff-pdf-visually`:
- ❌: The check failed surely, either due to differing page counts or because there is no reference PDF.
- ❓: The check indicates differences on at least one slide, but they may be minor and need manual checking.
- ✅: The check seems to be fine, the PDF files match.
- **Note**: A comment on the previous column listing the specific reason for a failing check.
Also enumerates the slide pages where differences are found, and links to a PDF containing a diff of the two files generated with `diff-pdf` (at a lower resolution than the originals).
</details>
```{r data-prep, include=FALSE}
check_table <- all_slide_check |>
# Transforms the logical columns, i.e. pdf_exists, pdf_static_exists, compile_check, ...
dplyr::mutate(dplyr::across(dplyr::where(is.logical), \(x) {
dplyr::case_when(
x ~ "\u2705", # Green check symbol
!x ~ "\u274c", # Red X symbol
is.na(x) ~ ""
)
})) |>
dplyr::mutate(
# Insert red question mark emoji instead of red X for easier visual parsing maybe
compare_check = ifelse(grepl("Dissimilar pages", compare_check_note), "\u2753", compare_check),
compare_check = ifelse(grepl("No reference", compare_check_note), "", compare_check)
) |>
# Make links out of a few columns
dplyr::mutate(
comparison_path = here::here("comparison", fs::path_file(pdf)),
check_note = ifelse(
compare_check %in% c("\u274c", "\u2753"),
sprintf("<a href='%s'>%s</a>", fs::path_rel(comparison_path), compare_check_note),
compare_check_note
),
compile_note = stringr::str_replace_all(compile_note, "`", "'") |>
stringr::str_replace_all(r"(\\)", r"(\\\\)"),
check_note = ifelse(compile_check == "\u274c", compile_note, check_note),
slide_name = ifelse(
fs::file_exists(pdf),
sprintf("<a href='%s'>%s</a>", fs::path_rel(pdf), slide_name),
slide_name
)
)
```
```{r slide-status-table, results='asis'}
# This is a markdown "asis" chunk that can output raw markdown or HTML and is treated as such by knitr
# Useful to manually assemble tables with sub-headings
for (current_lecture in lectures) {
tmp <- check_table |>
dplyr::filter(lecture == current_lecture)
cat(sprintf("\n## %s \n\n", current_lecture))
cat(sprintf("%i topics with a total of %i slides\n", length(unique(tmp$topic)), nrow(tmp)))
for (current_topic in sort(unique(tmp$topic))) {
tmp <- check_table |>
dplyr::filter(lecture == current_lecture, topic == current_topic)
cat(sprintf("\n### %s\n\n", current_topic))
tmp |>
dplyr::select(
slide_name,
compile_check, compare_check, check_note) |>
kableExtra::kbl(
format = "html", escape = FALSE,
align = c("l", "c", "c", "l"),
col.names = c("Slide", "Compiles?", "Comparison", "Note")
) |>
kableExtra::kable_styling(
full_width = TRUE,
fixed_thead = TRUE,
bootstrap_options = c("hover", "condensed", "responsive")
) |>
kableExtra::column_spec(1, width = "40%") |>
kableExtra::column_spec(2, width = "10%") |>
kableExtra::column_spec(3, width = "10%") |>
kableExtra::column_spec(4, width = "40%") |>
cat()
}
}
```