Add wordcounts plot script

This commit is contained in:
2026-09-12 14:05:28 +02:00
parent 86fab09dfe
commit f52ab00652
3 changed files with 195 additions and 0 deletions
+4
View File
@@ -16,3 +16,7 @@ format:
clean-format: clean-format:
rm thesis.fmt thesis.log thesis.tex.bbl thesis.tex.blg rm thesis.fmt thesis.log thesis.tex.bbl thesis.tex.blg
# Plot wordcounts.svg with ticks every n days (default: 7).
plot-wordcounts days="7":
Rscript plot_wordcounts.R {{quote(days)}}
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env Rscript
# Usage: Rscript plot_wordcounts.R [tick_days] [input.csv] [output.svg]
# By default, label every seven days, independently of the data points.
library(ggplot2)
args <- commandArgs(trailingOnly = TRUE)
if (length(args) > 3L) {
stop("Usage: Rscript plot_wordcounts.R [tick_days] [input.csv] [output.svg]")
}
tick_days <- if (length(args) >= 1L) {
as.numeric(args[1])
} else {
7
}
script_arg <- grep("^--file=", commandArgs(), value = TRUE)[1]
script_dir <- dirname(normalizePath(sub("^--file=", "", script_arg)))
input <- if (length(args) >= 2L) {
args[2]
} else {
file.path(script_dir, "wordcounts.csv")
}
output <- if (length(args) >= 3L) {
args[3]
} else {
file.path(script_dir, "wordcounts.svg")
}
counts <- read.csv(input, colClasses = "character")
timezone <- Sys.getenv("TZ", unset = "Europe/Berlin")
if (!nzchar(timezone)) {
timezone <- "Europe/Berlin"
}
normalized <- sub("([+-][0-9]{2}):([0-9]{2})$", "\\1\\2", counts$date)
counts$timestamp <- as.POSIXct(
normalized,
format = "%Y-%m-%dT%H:%M:%S%z",
tz = timezone
)
date_only <- grepl("^[0-9]{4}-[0-9]{2}-[0-9]{2}$", counts$date)
counts$timestamp[date_only] <- as.POSIXct(
counts$date[date_only],
format = "%Y-%m-%d",
tz = timezone
)
counts$wordcount <- as.numeric(counts$wordcount)
counts <- counts[order(counts$timestamp), ]
# Fixed time intervals
start <- as.POSIXct(
format(min(counts$timestamp), "%Y-%m-%d", tz = timezone),
tz = timezone
)
interval <- tick_days * 86400
span <- as.numeric(difftime(max(counts$timestamp), start, units = "secs"))
ticks <- start + seq(0, max(1, ceiling(span / interval))) * interval
plot <- ggplot(counts, aes(x = timestamp, y = wordcount)) +
scale_x_datetime(
breaks = ticks,
limits = range(ticks),
date_labels = "%Y-%m-%d",
timezone = timezone,
minor_breaks = NULL
) +
scale_y_continuous(labels = scales::label_comma()) +
labs(
title = "Thesis Word Count",
x = "Date",
y = "Words"
) +
theme_minimal(base_size = 12) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1),
panel.grid.minor = element_blank()
)
if (nrow(counts) > 1L) {
plot <- plot + geom_line(linewidth = 0.5)
}
ggsave(output, plot, width = 10, height = 5, dpi = 180, bg = "white")
message("Saved ", output)
+107
View File
@@ -0,0 +1,107 @@
date,wordcount
2026-06-23T12:00:00+02:00,496
2026-06-30T12:00:00+02:00,2210
2026-07-01T10:00:00+02:00,3745
2026-07-01T12:00:00+02:00,4587
2026-07-02T12:00:00+02:00,5058
2026-07-05T12:00:00+02:00,5783
2026-07-07T12:00:00+02:00,5538
2026-09-11T11:24:33+02:00,8603
2026-09-11T11:26:13+02:00,8603
2026-09-11T11:31:20+02:00,8596
2026-09-11T11:42:48+02:00,8727
2026-09-11T11:43:08+02:00,8727
2026-09-11T11:47:47+02:00,8746
2026-09-11T12:01:42+02:00,8812
2026-09-11T12:03:40+02:00,8860
2026-09-11T12:07:01+02:00,8887
2026-09-11T12:07:14+02:00,8888
2026-09-11T12:07:31+02:00,8884
2026-09-11T12:08:51+02:00,8892
2026-09-11T12:09:39+02:00,8894
2026-09-11T12:11:27+02:00,8913
2026-09-11T12:12:29+02:00,8924
2026-09-11T12:13:22+02:00,8920
2026-09-11T12:13:42+02:00,8927
2026-09-11T12:14:31+02:00,8927
2026-09-11T12:15:46+02:00,8946
2026-09-11T12:20:47+02:00,9070
2026-09-11T12:23:46+02:00,9099
2026-09-11T12:24:02+02:00,9102
2026-09-11T12:24:42+02:00,9109
2026-09-11T12:26:15+02:00,9109
2026-09-11T12:26:25+02:00,9109
2026-09-11T12:26:38+02:00,9109
2026-09-11T12:30:20+02:00,9137
2026-09-11T12:30:35+02:00,9137
2026-09-11T12:31:24+02:00,9115
2026-09-11T12:34:33+02:00,9124
2026-09-11T12:36:17+02:00,9129
2026-09-11T12:36:44+02:00,9113
2026-09-11T12:42:09+02:00,9167
2026-09-11T12:42:35+02:00,9167
2026-09-11T12:53:02+02:00,9235
2026-09-11T12:53:46+02:00,9234
2026-09-11T12:54:27+02:00,9235
2026-09-11T12:55:42+02:00,9235
2026-09-11T12:56:42+02:00,9250
2026-09-11T12:58:59+02:00,9379
2026-09-11T12:59:54+02:00,9389
2026-09-11T13:00:27+02:00,9389
2026-09-11T13:00:43+02:00,9389
2026-09-11T13:04:39+02:00,9427
2026-09-11T13:04:55+02:00,9485
2026-09-11T13:06:04+02:00,9488
2026-09-11T13:07:00+02:00,9496
2026-09-11T13:09:11+02:00,9494
2026-09-11T13:10:20+02:00,9504
2026-09-11T13:10:37+02:00,9509
2026-09-11T13:10:45+02:00,9508
2026-09-11T13:12:12+02:00,9510
2026-09-11T13:17:28+02:00,9639
2026-09-11T13:20:11+02:00,9686
2026-09-11T13:20:35+02:00,9686
2026-09-11T13:30:23+02:00,9704
2026-09-11T13:31:28+02:00,9713
2026-09-11T13:34:02+02:00,9740
2026-09-11T13:34:11+02:00,9738
2026-09-11T13:36:51+02:00,9771
2026-09-11T13:37:45+02:00,9768
2026-09-11T13:39:55+02:00,9778
2026-09-11T13:40:19+02:00,9779
2026-09-11T13:40:55+02:00,9779
2026-09-11T13:41:22+02:00,9779
2026-09-11T13:44:40+02:00,9800
2026-09-11T13:44:47+02:00,9801
2026-09-11T13:45:09+02:00,9801
2026-09-11T13:47:18+02:00,9801
2026-09-11T13:47:55+02:00,9801
2026-09-11T13:49:17+02:00,9769
2026-09-11T13:50:04+02:00,9906
2026-09-11T16:31:06+02:00,9952
2026-09-11T16:32:21+02:00,9967
2026-09-11T16:40:24+02:00,10123
2026-09-11T16:40:56+02:00,10123
2026-09-11T16:41:08+02:00,10127
2026-09-11T16:43:54+02:00,10166
2026-09-11T16:44:23+02:00,10170
2026-09-11T16:44:54+02:00,10170
2026-09-11T16:45:46+02:00,10170
2026-09-11T16:46:07+02:00,10170
2026-09-12T11:57:09+02:00,10170
2026-09-12T12:05:20+02:00,10170
2026-09-12T12:05:36+02:00,10169
2026-09-12T13:09:05+02:00,10172
2026-09-12T13:10:19+02:00,10188
2026-09-12T13:10:53+02:00,10197
2026-09-12T13:12:10+02:00,10201
2026-09-12T13:14:00+02:00,10242
2026-09-12T13:14:23+02:00,10228
2026-09-12T13:15:51+02:00,10227
2026-09-12T13:17:15+02:00,10230
2026-09-12T13:18:49+02:00,10224
2026-09-12T13:25:07+02:00,10225
2026-09-12T13:26:35+02:00,10236
2026-09-12T13:27:44+02:00,10236
2026-09-12T13:28:26+02:00,10237
2026-09-12T13:58:35+02:00,10237
1 date wordcount
2 2026-06-23T12:00:00+02:00 496
3 2026-06-30T12:00:00+02:00 2210
4 2026-07-01T10:00:00+02:00 3745
5 2026-07-01T12:00:00+02:00 4587
6 2026-07-02T12:00:00+02:00 5058
7 2026-07-05T12:00:00+02:00 5783
8 2026-07-07T12:00:00+02:00 5538
9 2026-09-11T11:24:33+02:00 8603
10 2026-09-11T11:26:13+02:00 8603
11 2026-09-11T11:31:20+02:00 8596
12 2026-09-11T11:42:48+02:00 8727
13 2026-09-11T11:43:08+02:00 8727
14 2026-09-11T11:47:47+02:00 8746
15 2026-09-11T12:01:42+02:00 8812
16 2026-09-11T12:03:40+02:00 8860
17 2026-09-11T12:07:01+02:00 8887
18 2026-09-11T12:07:14+02:00 8888
19 2026-09-11T12:07:31+02:00 8884
20 2026-09-11T12:08:51+02:00 8892
21 2026-09-11T12:09:39+02:00 8894
22 2026-09-11T12:11:27+02:00 8913
23 2026-09-11T12:12:29+02:00 8924
24 2026-09-11T12:13:22+02:00 8920
25 2026-09-11T12:13:42+02:00 8927
26 2026-09-11T12:14:31+02:00 8927
27 2026-09-11T12:15:46+02:00 8946
28 2026-09-11T12:20:47+02:00 9070
29 2026-09-11T12:23:46+02:00 9099
30 2026-09-11T12:24:02+02:00 9102
31 2026-09-11T12:24:42+02:00 9109
32 2026-09-11T12:26:15+02:00 9109
33 2026-09-11T12:26:25+02:00 9109
34 2026-09-11T12:26:38+02:00 9109
35 2026-09-11T12:30:20+02:00 9137
36 2026-09-11T12:30:35+02:00 9137
37 2026-09-11T12:31:24+02:00 9115
38 2026-09-11T12:34:33+02:00 9124
39 2026-09-11T12:36:17+02:00 9129
40 2026-09-11T12:36:44+02:00 9113
41 2026-09-11T12:42:09+02:00 9167
42 2026-09-11T12:42:35+02:00 9167
43 2026-09-11T12:53:02+02:00 9235
44 2026-09-11T12:53:46+02:00 9234
45 2026-09-11T12:54:27+02:00 9235
46 2026-09-11T12:55:42+02:00 9235
47 2026-09-11T12:56:42+02:00 9250
48 2026-09-11T12:58:59+02:00 9379
49 2026-09-11T12:59:54+02:00 9389
50 2026-09-11T13:00:27+02:00 9389
51 2026-09-11T13:00:43+02:00 9389
52 2026-09-11T13:04:39+02:00 9427
53 2026-09-11T13:04:55+02:00 9485
54 2026-09-11T13:06:04+02:00 9488
55 2026-09-11T13:07:00+02:00 9496
56 2026-09-11T13:09:11+02:00 9494
57 2026-09-11T13:10:20+02:00 9504
58 2026-09-11T13:10:37+02:00 9509
59 2026-09-11T13:10:45+02:00 9508
60 2026-09-11T13:12:12+02:00 9510
61 2026-09-11T13:17:28+02:00 9639
62 2026-09-11T13:20:11+02:00 9686
63 2026-09-11T13:20:35+02:00 9686
64 2026-09-11T13:30:23+02:00 9704
65 2026-09-11T13:31:28+02:00 9713
66 2026-09-11T13:34:02+02:00 9740
67 2026-09-11T13:34:11+02:00 9738
68 2026-09-11T13:36:51+02:00 9771
69 2026-09-11T13:37:45+02:00 9768
70 2026-09-11T13:39:55+02:00 9778
71 2026-09-11T13:40:19+02:00 9779
72 2026-09-11T13:40:55+02:00 9779
73 2026-09-11T13:41:22+02:00 9779
74 2026-09-11T13:44:40+02:00 9800
75 2026-09-11T13:44:47+02:00 9801
76 2026-09-11T13:45:09+02:00 9801
77 2026-09-11T13:47:18+02:00 9801
78 2026-09-11T13:47:55+02:00 9801
79 2026-09-11T13:49:17+02:00 9769
80 2026-09-11T13:50:04+02:00 9906
81 2026-09-11T16:31:06+02:00 9952
82 2026-09-11T16:32:21+02:00 9967
83 2026-09-11T16:40:24+02:00 10123
84 2026-09-11T16:40:56+02:00 10123
85 2026-09-11T16:41:08+02:00 10127
86 2026-09-11T16:43:54+02:00 10166
87 2026-09-11T16:44:23+02:00 10170
88 2026-09-11T16:44:54+02:00 10170
89 2026-09-11T16:45:46+02:00 10170
90 2026-09-11T16:46:07+02:00 10170
91 2026-09-12T11:57:09+02:00 10170
92 2026-09-12T12:05:20+02:00 10170
93 2026-09-12T12:05:36+02:00 10169
94 2026-09-12T13:09:05+02:00 10172
95 2026-09-12T13:10:19+02:00 10188
96 2026-09-12T13:10:53+02:00 10197
97 2026-09-12T13:12:10+02:00 10201
98 2026-09-12T13:14:00+02:00 10242
99 2026-09-12T13:14:23+02:00 10228
100 2026-09-12T13:15:51+02:00 10227
101 2026-09-12T13:17:15+02:00 10230
102 2026-09-12T13:18:49+02:00 10224
103 2026-09-12T13:25:07+02:00 10225
104 2026-09-12T13:26:35+02:00 10236
105 2026-09-12T13:27:44+02:00 10236
106 2026-09-12T13:28:26+02:00 10237
107 2026-09-12T13:58:35+02:00 10237