Skip to content

Instantly share code, notes, and snippets.

@tashian
Created August 11, 2015 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tashian/15325a1d27979f461836 to your computer and use it in GitHub Desktop.
Save tashian/15325a1d27979f461836 to your computer and use it in GitHub Desktop.
Retention chart generator for Keen.io
# KeenIO stuff
#
CsvStringify = require 'csv-stringify'
Keen = require './keen_client.js.coffee'
Q = require 'q'
_ = require 'underscore'
moment = require 'moment-timezone'
class Retention
constructor: (@keenClient, @steps, @period = 'weeks') ->
@periodsBack = 12
if @period == 'weeks'
@startOfThisPeriod = moment().day(0).startOf('day')
else
@period = 'days'
@startOfThisPeriod = moment().startOf('day')
firstRowLabels: ->
periodLabel = if @period == 'weeks' then 'Week' else 'Day'
firstRowLabels = [periodLabel, 'Cohort Size']
firstRowLabels = firstRowLabels.concat(
_(@periodsBack).times (n) ->
periodLabel + ' ' + (n+1)
)
startOfPeriod: (periodsAgo) ->
moment(@startOfThisPeriod).subtract(periodsAgo, @period).toDate()
cohortTimeframe: (cohortPeriod) ->
{
start: @startOfPeriod(cohortPeriod)
end: @startOfPeriod(cohortPeriod - 1)
}
retentionTimeframe: (cohortPeriod, currentPeriod) ->
{
start: @startOfPeriod(cohortPeriod - currentPeriod)
end: @startOfPeriod(cohortPeriod - currentPeriod - 1)
}
generate: ->
console.log 'Generating retention chart'
finished = Q.defer()
rowPromises = _(@periodsBack).times(@rowPromiseForPeriodAgo)
allPromises = Q.all(rowPromises)
allPromises.done((results) =>
csv = [@firstRowLabels()]
csv = csv.concat(results)
CsvStringify csv, (err, csv) ->
console.log(err) if err
finished.resolve(csv)
)
finished.promise
rowPromiseForPeriodAgo: (n) =>
rowPromise = Q.defer()
cohortPeriod = @periodsBack - n
Q.all(@getCohortRow(cohortPeriod)).done((results) =>
cohortSize = results[0].result[0]
rowValues = [moment(@startOfPeriod(cohortPeriod)).format('MMM D'), cohortSize]
rowPromise.resolve(
rowValues.concat(_.map(results, (el) ->
el.result[el.result.length - 1] / cohortSize
))
)
)
rowPromise.promise
getCohortRow: (cohortPeriod) ->
_.times(cohortPeriod, (currentPeriod) =>
@getCohortCell(cohortPeriod, currentPeriod)
)
getCohortCell: (cohortPeriod, currentPeriod) ->
@keenClient.scheduleWithPromise(@funnelQuery(cohortPeriod, currentPeriod))
funnelQuery: (cohortPeriod, currentPeriod) ->
currentSteps = JSON.parse(JSON.stringify(@steps))
[step0, ..., stepN] = currentSteps
step0.timeframe = @cohortTimeframe(cohortPeriod)
stepN.timeframe = @retentionTimeframe(cohortPeriod, currentPeriod)
new Keen.Query(
'funnel',
steps: currentSteps,
maxAge: 43200
)
module.exports = Retention
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment