Add wordcounts plot script
This commit is contained in:
@@ -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)}}
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
Reference in New Issue
Block a user