Better Anki forecasting for Review Heatmap with Anki Simulator
Review Heatmap is an addon for Anki that adds a heatmap showing past and future card review activity. It is handy to see at a glance whether there are any particularly heavy or light days coming up, and a colourful reward for regular reviews.
However, Review Heatmap bases its review forecasts only on cards' current intervals. For example, if I add a bunch of new cards today, I expect to see that I will have a heavy review load in 3 days when those cards are up for review, and regular periods thereafter. Review Heatmap cannot natively handle this projection.
Similarly, in the screenshot above, I have limited my maximum review interval to 30 days, so Review Heatmap does not display any information beyond 30 days.
Anki Simulator is an addon that can ‘simulate Anki progress over time … to estimate your future workload’. We can combine Anki Simulator with Review Heatmap to get the better forecasting that we desire.
Below is a simple Anki addon that extends Review Heatmap to make use of Anki Simulator:
DECK_ID = 1234567890123 # replace with the deck ID of the deck you need to forecast
from datetime import datetime, timedelta
import review_heatmap
from review_simulator import collection_simulator, review_simulator
class MWStandin:
pass
def mp_cardsDue(self, start=None, stop=None):
mw = MWStandin()
mw.col = self.col
col_sim = collection_simulator.CollectionSimulator(mw)
conf = self.col.decks.confForDid(DECK_ID)
learningSteps = conf["new"]["delays"]
lapseSteps = conf["lapse"]["delays"]
dateArray = col_sim.generate_for_deck(
DECK_ID,
365, # daysToSimulate
conf["new"]["perDay"], # newCardsPerDay
conf["new"]["initialFactor"] / 10.0, # startingEase
len(learningSteps),
len(lapseSteps),
True, # includeOverdueCards
True, # includeSuspendedNewCards
0, # newCardsToGenerate
)
sim = review_simulator.ReviewSimulator(
dateArray,
365, # daysToSimulate
conf["new"]["perDay"], # newCardsPerDay
conf["rev"]["ivlFct"], # intervalModifier
conf["rev"]["perDay"], # maxReviewsPerDay
learningSteps,
lapseSteps,
conf["new"]["ints"][0], # graduatingInterval
conf["lapse"]["mult"], # newLapseInterval
conf["rev"]["maxIvl"], # maxInterval
[100] * len(learningSteps), # percentagesCorrectForLearningSteps
[100] * len(lapseSteps), # percentagesCorrectForLapseSteps
100, # percentageGoodYoung
100, # percentageGoodMature
0, # Percentage hard is set to 0
0, # Percentage easy is set to 0
self.col.schedVer()
)
result = sim.simulate()
result_dt = []
for entry in result:
if entry['y']:
dt = datetime.strptime(entry['x'], '%Y-%m-%d')
dt += timedelta(days=1) # Appears to be necessary for some reason
result_dt.append([int(dt.timestamp()), -entry['y']]) # Review Heatmap expects negative numbers
return result_dt
review_heatmap.activity.ActivityReporter._cardsDue = mp_cardsDue
This can be placed within the Anki addons directory, for example, at ~/.local/share/Anki2/addons21/review_forecast/__init__.py
.
Anki Simulator by default uses the historical percentage of correct cards to forecast future load, thereby resulting in slightly different results each time it is run. The above code disables this by setting the percentage of correct cards to 100%, so the results are deterministic. This does mean, however, that the results will be slightly inaccurate, particularly if the actual correct percentage is significantly less than 100%.
With this modified code, Review Heatmap now projects future reviews out as far as we need!