Code to create graphics for Anki -> R article on http://chrisk91.me
require(RSQLite) | |
require(DBI) | |
require(ggplot2) | |
require(jsonlite) | |
require(ggthemes) | |
save_plot <- function(plot, filename, widthpx = 800, heightpx = 500){ | |
dpi <- 120 | |
width <- widthpx / dpi | |
height <- heightpx / dpi | |
ggsave(filename, plot, width = width, height = height, units = "in", dpi = dpi) | |
} | |
connection <- dbConnect(SQLite(), dbname="collection.anki2") | |
result <- dbSendQuery(connection, "SELECT * from cards") | |
cardData <- dbFetch(result) | |
dbClearResult(result) | |
result <- dbSendQuery(connection, "SELECT * from col") | |
collectionData <- dbFetch(result) | |
dbClearResult(result) | |
result <- dbSendQuery(connection, "SELECT * from notes") | |
notesData <- dbFetch(result) | |
dbClearResult(result) | |
result <- dbSendQuery(connection, "SELECT * from revlog") | |
revisionData <- dbFetch(result) | |
dbClearResult(result) | |
dbDisconnect(connection) | |
collectionNames <- fromJSON(txt=collectionData$decks[1]) | |
getDeckName <- function(x) collectionNames[[x]]$name | |
cardData$deck <- factor(mapply(getDeckName, as.character(cardData$did))) #perform lookup of deck names | |
getDeckNameFromCid <- function(x){ | |
lookup <- as.character(cardData$deck[cardData$id == x]) | |
if(identical(lookup, character(0))) #due to deleted cards, some lookups might fail | |
{ | |
lookup <- "Removed card" | |
} | |
return(lookup) | |
} | |
revisionData$deck <- factor(mapply(getDeckNameFromCid, revisionData$cid)) | |
tmp <- ggplot(revisionData, aes(time / 1000)) + geom_histogram(binwidth = 10) + xlab("time spent reviewing a single card\n(seconds)") + scale_y_log10() + ggtitle("Review times") | |
save_plot(tmp + theme_minimal(), "histogram.png") | |
tmp <- ggplot(revisionData, aes(time / 1000, fill = deck)) + guides(fill=FALSE) + geom_histogram(binwidth = 10) + xlim(0, 400) + xlab("time spent reviewing a single card\n(seconds)") + scale_y_log10() + ggtitle("Review times") + facet_wrap(~ deck) | |
save_plot(tmp + theme_minimal() + ggthemes::scale_fill_gdocs(), "histogram_decks.png", widthpx = 800, heightpx = 800) | |
tmp <- ggplot(cardData, aes(ivl, fill = deck)) + guides(fill=FALSE) + geom_histogram(binwidth = 10) + facet_wrap(~ deck, scales = "free_y") + xlab("interval") | |
save_plot(tmp + theme_minimal() + ggthemes::scale_fill_gdocs(), "histogram_review_times.png", widthpx = 800, heightpx = 800) | |
plotWidth <- floor(sqrt(nrow(cardData))) # our final dimesnion should be a square | |
cardData$index <- (0 : (nrow(cardData) - 1)) # to calculate the position of each card, we need a running count | |
cardData$X <- cardData$index %% plotWidth # x position | |
cardData$Y <- cardData$index %/% plotWidth # y position | |
cardData$mature <- cardData$ivl > 21 # you can also use this, to show mature cards | |
tmp <- ggplot(cardData, aes(X, Y)) + geom_tile(aes(fill = ivl)) + scale_fill_gradient2(mid = "#dd6a27", high = "#12e824") | |
save_plot(tmp + theme_void() + guides(fill = FALSE), "review_heatmap.png", widthpx = 400, heightpx = 400) | |
# Lets filter out premade decks | |
cardDataFiltered <- cardData[!(cardData$deck %in% c("Sprachen::Französisch::5000 Most Common French Words", "Sprachen::Französisch::Verben mit Konjugationen")), ] | |
plotWidth <- floor(sqrt(nrow(cardDataFiltered))) # our final dimesnion should be a square | |
cardDataFiltered$index <- (0 : (nrow(cardDataFiltered) - 1)) # to calculate the position of each card, we need a running count | |
cardDataFiltered$X <- cardDataFiltered$index %% plotWidth # x position | |
cardDataFiltered$Y <- cardDataFiltered$index %/% plotWidth # y position | |
cardDataFiltered$mature <- cardDataFiltered$ivl > 21 # you can also use this, to show mature cards | |
tmp <- ggplot(cardDataFiltered, aes(X, Y)) + geom_tile(aes(fill = mature)) | |
save_plot(tmp + theme_void() + guides(fill = FALSE), "review_heatmap_filtered.png", widthpx = 400, heightpx = 400) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment