Public
Edited
Dec 24, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// how many of each type do i know at least as well as foo
Insert cell
passedAtFormatted = _(assignmentsPassedPerDay).toPairs().map(([date_and_type, count]) => {
const [date, type] = date_and_type.split(",")
return { date: new Date(date), type: `${type} guru`, count} }
).sortBy('type')
.value()

Insert cell
burnedAtFormatted = _(assignments)
.filter((r) => r.burned_at)
.groupBy((r) => [new Date(r.burned_at).toDateString(), r.subject_type])
.mapValues('length')
.toPairs().map(([date_and_type, count]) => {
const [date, type] = date_and_type.split(",")
return { date: new Date(date), type: `${type} burned`, count} }
).sortBy('type')
.value()

Insert cell
Insert cell
Insert cell
reviewStats = await fetchPaged('https://api.wanikani.com/v2/review_statistics', 'review_statistics')
Insert cell
reviewsByDay = _.groupBy(reviewStats, (r) => new Date(r.created_at).toDateString())


Insert cell
Insert cell
levelProgressions = await fetchPaged('https://api.wanikani.com/v2/level_progressions', 'levelProgression')
// left behind from fork but may be useful to add to chart
Insert cell
assignments = fetchPaged('https://api.wanikani.com/v2/assignments', 'assignments')
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
progress_plots = ["kana_vocabulary", "kanji", "radical", "vocabulary"].map(target_subject_type => {
return Plot.plot({
marks: [
Plot.rectY(srs_progress_by_type.filter(p => p.subject == target_subject_type),
{x: "subject", y: "count", fill: "srs_stage"}),
// Plot.tip(_(srs_progress_by_type).reverse().filter(p => p.subject == target_subject_type),
// {x: "subject", y: "count", fill: "srs_stage"})
// TODO from here: make the plots nicer, and figure out why the tip is in reverse order - also probably add a color scale.
],
x: {
label: "Type",
},
y: {
grid: true,
label: target_subject_type
},
height: 1200,
color: {
legend: true
}
})
})
Insert cell
srs_progress_by_type = _(assignments)
.groupBy((r) => [r.subject_type, r.srs_stage])
.mapValues('length')
.toPairs()
.map(([subject_comma_stage, count]) => {
const [subject, srs_stage] = subject_comma_stage.split(",")
return { subject, srs_stage, count }
})
.sortBy('subject', 'srs_stage')
.reverse()
.value()
Insert cell
srs_at_least_level_type_type = aggregateAtLeast(srs_progress_by_type)


Insert cell
// Function to aggregate data on an "at least" basis - ChatGPT
aggregateAtLeast = (data) => {
// Group data by subject
const groupedBySubject = _.groupBy(data, 'subject');

return _.map(groupedBySubject, (entries, subject) => {
// Sort entries by SRS stage in descending order
const sortedEntries = _.orderBy(entries, entry => parseInt(entry.srs_stage), 'desc');

// Accumulate counts
return sortedEntries.reduce((acc, entry, index) => {
if (index === 0) {
acc.push(entry);
} else {
acc.push({
subject: entry.subject,
srs_stage: entry.srs_stage,
count: entry.count + acc[index - 1].count
});
}
return acc;
}, []);
}).flat();
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more