Feat/add future projection to forgetting curve with today marker (#3732)

* Feat/Add future projection to forgetting curve with today marker

* format

* remove the vertical line
This commit is contained in:
Jarrett Ye 2025-01-18 12:54:53 +08:00 committed by GitHub
parent 899cb89990
commit ac2b44859e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -90,7 +90,7 @@ export function prepareData(revlog: RevlogEntry[], maxDays: number) {
return;
}
const totalDaysElapsed = (reviewTime - lastReviewTime) / (24 * 60 * 60);
const totalDaysElapsed = (reviewTime - lastReviewTime) / 86400;
let elapsedDays = 0;
while (elapsedDays < totalDaysElapsed - step) {
elapsedDays += step;
@ -121,7 +121,7 @@ export function prepareData(revlog: RevlogEntry[], maxDays: number) {
}
const now = Date.now() / 1000;
const totalDaysSinceLastReview = (now - lastReviewTime) / (24 * 60 * 60);
const totalDaysSinceLastReview = (now - lastReviewTime) / 86400;
let elapsedDays = 0;
while (elapsedDays < totalDaysSinceLastReview - step) {
elapsedDays += step;
@ -144,6 +144,20 @@ export function prepareData(revlog: RevlogEntry[], maxDays: number) {
stability: lastStability,
});
const previewDays = maxDays - totalDaysSinceLastReview;
let previewDaysElapsed = 0;
while (previewDaysElapsed < previewDays) {
previewDaysElapsed += step;
const retrievability = forgettingCurve(lastStability, elapsedDays + previewDaysElapsed);
data.push({
date: new Date((now + previewDaysElapsed * 86400) * 1000),
daysSinceFirstLearn: data[data.length - 1].daysSinceFirstLearn + step,
elapsedDaysSinceLastReview: totalDaysSinceLastReview + previewDaysElapsed,
retrievability: retrievability * 100,
stability: lastStability,
});
}
const filteredData = filterDataByTimeRange(data, maxDays);
return filteredData;
}
@ -152,9 +166,14 @@ export function calculateMaxDays(filteredRevlog: RevlogEntry[], timeRange: TimeR
if (filteredRevlog.length === 0) {
return 0;
}
const daysSinceFirstLearn = (Date.now() / 1000 - Number(filteredRevlog[filteredRevlog.length - 1].time))
/ (24 * 60 * 60);
return Math.min(daysSinceFirstLearn, MAX_DAYS[timeRange]);
const today = new Date();
const daysSinceFirstLearn = (today.getTime() / 1000 - Number(filteredRevlog[filteredRevlog.length - 1].time))
/ 86400;
const totalDaysSinceLastReview = (today.getTime() / 1000 - Number(filteredRevlog[0].time))
/ 86400;
const lastScheduledDays = filteredRevlog[0].interval / 86400;
const previewDays = Math.max(lastScheduledDays * 1.5 - totalDaysSinceLastReview, lastScheduledDays * 0.5);
return Math.min(daysSinceFirstLearn + previewDays, MAX_DAYS[timeRange]);
}
export function renderForgettingCurve(
@ -181,7 +200,7 @@ export function renderForgettingCurve(
setDataAvailable(svg, true);
}
svg.select(".forgetting-curve-line").remove();
svg.selectAll(".forgetting-curve-line").remove();
svg.select(".hover-columns").remove();
const xMin = min(data, d => d.date);
@ -242,14 +261,30 @@ export function renderForgettingCurve(
.attr("offset", d => d.offset)
.attr("stop-color", d => d.color);
// Split data into past and future
const today = new Date();
const pastData = data.filter(d => d.date <= today);
const futureData = data.filter(d => d.date >= today);
// Draw solid line for past data
svg.append("path")
.datum(data)
.datum(pastData)
.attr("class", "forgetting-curve-line")
.attr("fill", "none")
.attr("stroke", "url(#line-gradient)")
.attr("stroke-width", 1.5)
.attr("d", lineGenerator);
// Draw dashed line for future data
svg.append("path")
.datum(futureData)
.attr("class", "forgetting-curve-line")
.attr("fill", "none")
.attr("stroke", "url(#line-gradient)")
.attr("stroke-width", 1.5)
.attr("stroke-dasharray", "4 4")
.attr("d", lineGenerator);
svg.select(".desired-retention-line").remove();
if (desiredRetentionY > yMin) {
svg.append("line")