From 66aef160b34476d9771e7012045fd3d58c91fe57 Mon Sep 17 00:00:00 2001 From: Jian Li Date: Sat, 2 Mar 2019 10:10:11 -0800 Subject: [PATCH 1/5] Refactor chunk calculation --- anki/stats.py | 43 +++++++++++++------------------------------ 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/anki/stats.py b/anki/stats.py index d6aef9c88..731319c76 100644 --- a/anki/stats.py +++ b/anki/stats.py @@ -198,13 +198,17 @@ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) # Due and cumulative due ###################################################################### - def dueGraph(self): + def get_start_end_chunk(self): if self.type == 0: start, end, chunk = 0, 31, 1 elif self.type == 1: start, end, chunk = 0, 52, 7 elif self.type == 2: start, end, chunk = 0, None, 30 + return start, end, chunk + + def dueGraph(self): + start, end, chunk = self.get_start_end_chunk() d = self._due(start, end, chunk) yng = [] mtr = [] @@ -269,12 +273,7 @@ group by day order by day""" % (self._limit(), lim), ###################################################################### def introductionGraph(self): - if self.type == 0: - days = 30; chunk = 1 - elif self.type == 1: - days = 52; chunk = 7 - else: - days = None; chunk = 30 + start, days, chunk = self.get_start_end_chunk() return self._introductionGraph(self._added(days, chunk), days, _("Added")) @@ -309,12 +308,7 @@ group by day order by day""" % (self._limit(), lim), return txt def repsGraphs(self): - if self.type == 0: - days = 30; chunk = 1 - elif self.type == 1: - days = 52; chunk = 7 - else: - days = None; chunk = 30 + start, days, chunk = self.get_start_end_chunk() return self._repsGraphs(self._done(days, chunk), days, _("Review Count"), @@ -548,12 +542,8 @@ group by day order by day)""" % lim, return txt + self._lineTbl(i) def _ivls(self): - if self.type == 0: - chunk = 1; lim = " and grp <= 30" - elif self.type == 1: - chunk = 7; lim = " and grp <= 52" - else: - chunk = 30; lim = "" + start, end, chunk = self.get_start_end_chunk() + lim = "and grp <= %d" % end if end else "" data = [self.col.db.all(""" select ivl / :chunk as grp, count() from cards where did in %s and queue = 2 %s @@ -625,12 +615,7 @@ select count(), avg(ivl), max(ivl) from cards where did in %s and queue = 2""" % lim = self._revlogLimit() if lim: lims.append(lim) - if self.type == 0: - days = 30 - elif self.type == 1: - days = 365 - else: - days = None + days = self._periodDays() if days is not None: lims.append("id > %d" % ( (self.col.sched.dayCutoff-(days*86400))*1000)) @@ -937,12 +922,10 @@ $(function () { return period def _periodDays(self): - if self.type == 0: - return 30 - elif self.type == 1: - return 365 - else: + start, end, chunk = self.get_start_end_chunk() + if end is None: return None + return end * chunk def _avgDay(self, tot, num, unit): vals = [] From 64064410a30051ad04e7d90e2d9920fed4187d3d Mon Sep 17 00:00:00 2001 From: Jian Li Date: Sat, 2 Mar 2019 12:49:31 -0800 Subject: [PATCH 2/5] Change bin width (chunk) based on deck age --- anki/stats.py | 60 ++++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/anki/stats.py b/anki/stats.py index 731319c76..b69392fc9 100644 --- a/anki/stats.py +++ b/anki/stats.py @@ -198,13 +198,20 @@ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) # Due and cumulative due ###################################################################### - def get_start_end_chunk(self): + def get_start_end_chunk(self, by='review'): + start = 0 if self.type == 0: - start, end, chunk = 0, 31, 1 + end, chunk = 31, 1 elif self.type == 1: - start, end, chunk = 0, 52, 7 + end, chunk = 52, 7 elif self.type == 2: - start, end, chunk = 0, None, 30 + end = None + if self._deckAge(by) < 365: + chunk = 1 + elif self._deckAge(by) < 1000: + chunk = 7 + else: + chunk = 31 return start, end, chunk def dueGraph(self): @@ -233,7 +240,7 @@ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) xaxis = dict(tickDecimals=0, min=-0.5) if end is not None: xaxis['max'] = end-0.5 - txt += self._graph(id="due", data=data, + txt += self._graph(id="due", data=data, xunit=chunk, ylabel2=_("Cumulative Cards"), conf=dict( xaxis=xaxis, yaxes=[dict(min=0), dict( min=0, tickDecimals=0, position="right")])) @@ -274,13 +281,9 @@ group by day order by day""" % (self._limit(), lim), def introductionGraph(self): start, days, chunk = self.get_start_end_chunk() - return self._introductionGraph(self._added(days, chunk), - days, _("Added")) - - def _introductionGraph(self, data, days, title): + data = self._added(days, chunk) if not data: return "" - d = data conf = dict( xaxis=dict(tickDecimals=0, max=0.5), yaxes=[dict(min=0), dict(position="right",min=0)]) @@ -288,14 +291,14 @@ group by day order by day""" % (self._limit(), lim), conf['xaxis']['min'] = -days+0.5 def plot(id, data, ylabel, ylabel2): return self._graph( - id, data=data, conf=conf, ylabel=ylabel, ylabel2=ylabel2) + id, data=data, conf=conf, xunit=chunk, ylabel=ylabel, ylabel2=ylabel2) # graph - (repdata, repsum) = self._splitRepData(d, ((1, colLearn, ""),)) + (repdata, repsum) = self._splitRepData(data, ((1, colLearn, ""),)) txt = self._title( - title, _("The number of new cards you have added.")) + _("Added"), _("The number of new cards you have added.")) txt += plot("intro", repdata, ylabel=_("Cards"), ylabel2=_("Cumulative Cards")) # total and per day average - tot = sum([i[1] for i in d]) + tot = sum([i[1] for i in data]) period = self._periodDays() if not period: # base off date of earliest added card @@ -309,15 +312,9 @@ group by day order by day""" % (self._limit(), lim), def repsGraphs(self): start, days, chunk = self.get_start_end_chunk() - return self._repsGraphs(self._done(days, chunk), - days, - _("Review Count"), - _("Review Time")) - - def _repsGraphs(self, data, days, reptitle, timetitle): + data = self._done(days, chunk) if not data: return "" - d = data conf = dict( xaxis=dict(tickDecimals=0, max=0.5), yaxes=[dict(min=0), dict(position="right",min=0)]) @@ -325,23 +322,23 @@ group by day order by day""" % (self._limit(), lim), conf['xaxis']['min'] = -days+0.5 def plot(id, data, ylabel, ylabel2): return self._graph( - id, data=data, conf=conf, ylabel=ylabel, ylabel2=ylabel2) + id, data=data, conf=conf, xunit=chunk, ylabel=ylabel, ylabel2=ylabel2) # reps - (repdata, repsum) = self._splitRepData(d, ( + (repdata, repsum) = self._splitRepData(data, ( (3, colMature, _("Mature")), (2, colYoung, _("Young")), (4, colRelearn, _("Relearn")), (1, colLearn, _("Learn")), (5, colCram, _("Cram")))) txt1 = self._title( - reptitle, _("The number of questions you have answered.")) + _("Review Count"), _("The number of questions you have answered.")) txt1 += plot("reps", repdata, ylabel=_("Answers"), ylabel2=_( "Cumulative Answers")) (daysStud, fstDay) = self._daysStudied() rep, tot = self._ansInfo(repsum, daysStud, fstDay, _("reviews")) txt1 += rep # time - (timdata, timsum) = self._splitRepData(d, ( + (timdata, timsum) = self._splitRepData(data, ( (8, colMature, _("Mature")), (7, colYoung, _("Young")), (9, colRelearn, _("Relearn")), @@ -353,7 +350,7 @@ group by day order by day""" % (self._limit(), lim), else: t = _("Hours") convHours = True - txt2 = self._title(timetitle, _("The time taken to answer the questions.")) + txt2 = self._title(_("Review Time"), _("The time taken to answer the questions.")) txt2 += plot("time", timdata, ylabel=t, ylabel2=_("Cumulative %s") % t) rep, tot2 = self._ansInfo( timsum, daysStud, fstDay, _("minutes"), convHours, total=tot) @@ -513,7 +510,7 @@ group by day order by day)""" % lim, ###################################################################### def ivlGraph(self): - (ivls, all, avg, max_) = self._ivls() + (ivls, all, avg, max_), chunk = self._ivls() tot = 0 totd = [] if not ivls or not all: @@ -529,7 +526,7 @@ group by day order by day)""" % lim, ivlmax = max(5, ivls[-1][0]) txt = self._title(_("Intervals"), _("Delays until reviews are shown again.")) - txt += self._graph(id="ivl", ylabel2=_("Percentage"), data=[ + txt += self._graph(id="ivl", ylabel2=_("Percentage"), xunit=chunk, data=[ dict(data=ivls, color=colIvl), dict(data=totd, color=colCum, yaxis=2, bars={'show': False}, lines=dict(show=True), stack=False) @@ -551,7 +548,7 @@ group by grp order by grp""" % (self._limit(), lim), chunk=chunk)] return data + list(self.col.db.first(""" select count(), avg(ivl), max(ivl) from cards where did in %s and queue = 2""" % - self._limit())) + self._limit())), chunk # Eases ###################################################################### @@ -796,7 +793,7 @@ from cards where did in %s""" % self._limit()) ###################################################################### def _graph(self, id, data, conf=None, - type="bars", ylabel=_("Cards"), timeTicks=True, ylabel2=""): + type="bars", xunit=1, ylabel=_("Cards"), ylabel2=""): if conf is None: conf = {} # display settings @@ -810,8 +807,7 @@ from cards where did in %s""" % self._limit()) conf['yaxis']['labelWidth'] = 40 if 'xaxis' not in conf: conf['xaxis'] = {} - if timeTicks: - conf['timeTicks'] = (_("d"), _("w"), _("mo"))[self.type] + conf['timeTicks'] = {1: _("d"), 7: _("w"), 31: _("mo")}[xunit] # types width = self.width height = self.height From c4f9a35af4b07e50e7f3b50c9488d5bd2f739b40 Mon Sep 17 00:00:00 2001 From: Jian Li Date: Sun, 10 Mar 2019 17:30:14 -0700 Subject: [PATCH 3/5] Restrict bin count to 100 --- anki/stats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/anki/stats.py b/anki/stats.py index b69392fc9..f9bd7fce0 100644 --- a/anki/stats.py +++ b/anki/stats.py @@ -206,9 +206,9 @@ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) end, chunk = 52, 7 elif self.type == 2: end = None - if self._deckAge(by) < 365: + if self._deckAge(by) <= 100: chunk = 1 - elif self._deckAge(by) < 1000: + elif self._deckAge(by) <= 700: chunk = 7 else: chunk = 31 From 08e51f220fc36467c5b4748e3f6005049afd7443 Mon Sep 17 00:00:00 2001 From: Jian Li Date: Sun, 10 Mar 2019 18:20:08 -0700 Subject: [PATCH 4/5] Clean up code --- anki/stats.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/anki/stats.py b/anki/stats.py index f9bd7fce0..0430c6fb9 100644 --- a/anki/stats.py +++ b/anki/stats.py @@ -240,10 +240,13 @@ from revlog where id > ? """+lim, (self.col.sched.dayCutoff-86400)*1000) xaxis = dict(tickDecimals=0, min=-0.5) if end is not None: xaxis['max'] = end-0.5 - txt += self._graph(id="due", data=data, xunit=chunk, - ylabel2=_("Cumulative Cards"), conf=dict( - xaxis=xaxis, yaxes=[dict(min=0), dict( - min=0, tickDecimals=0, position="right")])) + txt += self._graph( + id="due", data=data, xunit=chunk, ylabel2=_("Cumulative Cards"), + conf=dict( + xaxis=xaxis, yaxes=[ + dict(min=0), dict(min=0, tickDecimals=0, position="right")] + ), + ) txt += self._dueInfo(tot, len(totd)*chunk) return txt @@ -286,14 +289,14 @@ group by day order by day""" % (self._limit(), lim), return "" conf = dict( xaxis=dict(tickDecimals=0, max=0.5), - yaxes=[dict(min=0), dict(position="right",min=0)]) + yaxes=[dict(min=0), dict(position="right", min=0)]) if days is not None: conf['xaxis']['min'] = -days+0.5 def plot(id, data, ylabel, ylabel2): return self._graph( id, data=data, conf=conf, xunit=chunk, ylabel=ylabel, ylabel2=ylabel2) # graph - (repdata, repsum) = self._splitRepData(data, ((1, colLearn, ""),)) + repdata, repsum = self._splitRepData(data, ((1, colLearn, ""),)) txt = self._title( _("Added"), _("The number of new cards you have added.")) txt += plot("intro", repdata, ylabel=_("Cards"), ylabel2=_("Cumulative Cards")) @@ -317,7 +320,7 @@ group by day order by day""" % (self._limit(), lim), return "" conf = dict( xaxis=dict(tickDecimals=0, max=0.5), - yaxes=[dict(min=0), dict(position="right",min=0)]) + yaxes=[dict(min=0), dict(position="right", min=0)]) if days is not None: conf['xaxis']['min'] = -days+0.5 def plot(id, data, ylabel, ylabel2): @@ -407,7 +410,6 @@ group by day order by day""" % (self._limit(), lim), for (n, col, lab) in spec: totcnt[n] = 0 totd[n] = [] - sum = [] for row in data: for (n, col, lab) in spec: if n not in sep: @@ -836,8 +838,6 @@ from cards where did in %s""" % self._limit()) opacity=0.5, color="#000" ))) - - #conf['legend'] = dict(show=False) return ( """ From 99693fb2777528f32fb08f2d23dce2df386b7000 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Mon, 11 Mar 2019 15:12:21 +1000 Subject: [PATCH 5/5] Update stats.py disable spurious pylint warning --- anki/stats.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/anki/stats.py b/anki/stats.py index 0430c6fb9..eb0fb9cc2 100644 --- a/anki/stats.py +++ b/anki/stats.py @@ -291,6 +291,7 @@ group by day order by day""" % (self._limit(), lim), xaxis=dict(tickDecimals=0, max=0.5), yaxes=[dict(min=0), dict(position="right", min=0)]) if days is not None: + # pylint: disable=invalid-unary-operand-type conf['xaxis']['min'] = -days+0.5 def plot(id, data, ylabel, ylabel2): return self._graph( @@ -322,6 +323,7 @@ group by day order by day""" % (self._limit(), lim), xaxis=dict(tickDecimals=0, max=0.5), yaxes=[dict(min=0), dict(position="right", min=0)]) if days is not None: + # pylint: disable=invalid-unary-operand-type conf['xaxis']['min'] = -days+0.5 def plot(id, data, ylabel, ylabel2): return self._graph(