Skip to content

Commit

Permalink
Add cumulative
Browse files Browse the repository at this point in the history
  • Loading branch information
webjunkie committed Aug 7, 2024
1 parent 50c3a78 commit bdf780a
Show file tree
Hide file tree
Showing 12 changed files with 68 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ export const retentionFilterToQuery = (filters: Partial<RetentionFilterType>): R
targetEntity: sanitizeRetentionEntity(filters.target_entity),
period: filters.period,
showMean: filters.show_mean,
cumulative: filters.cumulative,
})
// TODO: query.aggregation_group_type_index
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,14 @@ export const queryNodeToFilter = (query: InsightQueryNode): Partial<FilterType>
camelCasedRetentionProps.target_entity = queryCopy.retentionFilter?.targetEntity
camelCasedRetentionProps.total_intervals = queryCopy.retentionFilter?.totalIntervals
camelCasedRetentionProps.show_mean = queryCopy.retentionFilter?.showMean
camelCasedRetentionProps.cumulative = queryCopy.retentionFilter?.cumulative
delete queryCopy.retentionFilter?.retentionReference
delete queryCopy.retentionFilter?.retentionType
delete queryCopy.retentionFilter?.returningEntity
delete queryCopy.retentionFilter?.targetEntity
delete queryCopy.retentionFilter?.totalIntervals
delete queryCopy.retentionFilter?.showMean
delete queryCopy.retentionFilter?.cumulative
} else if (isPathsQuery(queryCopy)) {
camelCasedPathsProps.edge_limit = queryCopy.pathsFilter?.edgeLimit
camelCasedPathsProps.paths_hogql_expression = queryCopy.pathsFilter?.pathsHogQLExpression
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ScalePicker } from 'scenes/insights/EditorFilters/ScalePicker'
import { ShowLegendFilter } from 'scenes/insights/EditorFilters/ShowLegendFilter'
import { ValueOnSeriesFilter } from 'scenes/insights/EditorFilters/ValueOnSeriesFilter'
import { InsightDateFilter } from 'scenes/insights/filters/InsightDateFilter'
import { CumulativeRetentionCheckbox } from 'scenes/insights/filters/RetentionCumulativeCheckbox'

Check failure on line 20 in frontend/src/queries/nodes/InsightViz/InsightDisplayConfig.tsx

View workflow job for this annotation

GitHub Actions / Code quality checks

Cannot find module 'scenes/insights/filters/RetentionCumulativeCheckbox' or its corresponding type declarations.
import { RetentionMeanCheckbox } from 'scenes/insights/filters/RetentionMeanCheckbox'
import { RetentionReferencePicker } from 'scenes/insights/filters/RetentionReferencePicker'
import { insightLogic } from 'scenes/insights/insightLogic'
Expand Down Expand Up @@ -146,6 +147,7 @@ export function InsightDisplayConfig(): JSX.Element {
<RetentionDatePicker />
<RetentionReferencePicker />
<RetentionMeanCheckbox />
<CumulativeRetentionCheckbox />
</ConfigFilter>
)}

Expand Down
3 changes: 3 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8090,6 +8090,9 @@
"RetentionFilter": {
"additionalProperties": false,
"properties": {
"cumulative": {
"type": "boolean"
},
"period": {
"$ref": "#/definitions/RetentionPeriod",
"default": "Day"
Expand Down
1 change: 1 addition & 0 deletions frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,7 @@ export type RetentionFilter = {
/** @default Day */
period?: RetentionFilterLegacy['period']
showMean?: RetentionFilterLegacy['show_mean']
cumulative?: RetentionFilterLegacy['cumulative']
}

export interface RetentionValue {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/scenes/insights/utils/compareInsightQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const cleanInsightQuery = (query: InsightQueryNode, ignoreVisualizationOnlyChang
toggledLifecycles: undefined,
showLabelsOnSeries: undefined,
showMean: undefined,
cumulative: undefined,
yAxisScaleType: undefined,
hiddenLegendIndexes: undefined,
hiddenLegendBreakdowns: undefined,
Expand Down
44 changes: 29 additions & 15 deletions frontend/src/scenes/retention/RetentionModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function RetentionModal(): JSX.Element | null {
const { results } = useValues(retentionLogic(insightProps))
const { people, peopleLoading, peopleLoadingMore } = useValues(retentionPeopleLogic(insightProps))
const { loadMorePeople } = useActions(retentionPeopleLogic(insightProps))
const { aggregationTargetLabel, selectedInterval, exploreUrl, actorsQuery } = useValues(
const { aggregationTargetLabel, selectedInterval, exploreUrl, actorsQuery, retentionFilter } = useValues(
retentionModalLogic(insightProps)
)
const { closeModal } = useActions(retentionModalLogic(insightProps))
Expand Down Expand Up @@ -111,20 +111,34 @@ export function RetentionModal(): JSX.Element | null {
<tbody>
<tr>
<th>{capitalizeFirstLetter(aggregationTargetLabel.singular)}</th>
{row.values?.map((data: any, index: number) => (
<th key={index}>
<div>{results[index].label}</div>
<div>
{data.count}
&nbsp;
{data.count > 0 && (
<span className="text-muted">
({percentage(data.count / row?.values[0]['count'])})
</span>
)}
</div>
</th>
))}
{row.values?.map((data: any, index: number) => {
// Calculate the cumulative count
let cumulativeCount = data.count
if (retentionFilter?.cumulative) {
for (let i = index + 1; i < row.values.length; i++) {
cumulativeCount += row.values[i].count
}
cumulativeCount = Math.min(cumulativeCount, row.values[0].count) // Ensure cumulative count doesn't exceed total count
}
// Calculate the percentage based on the cumulative count
const percentageValue =
row.values[0].count > 0 ? cumulativeCount / row.values[0].count : 0

return (
<th key={index}>
<div>{results[index].label}</div>
<div>
{cumulativeCount}
&nbsp;
{cumulativeCount > 0 && (
<span className="text-muted">
({percentage(percentageValue)})
</span>
)}
</div>
</th>
)
})}
</tr>
{people.result &&
people.result.map((personAppearances: RetentionTableAppearanceType) => (
Expand Down
16 changes: 13 additions & 3 deletions frontend/src/scenes/retention/retentionLineGraphLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const retentionLineGraphLogic = kea<retentionLineGraphLogicType>([
trendSeries: [
(s) => [s.results, s.retentionFilter],
(results, retentionFilter): RetentionTrendPayload[] => {
const { period, retentionReference } = retentionFilter || {}
const { period, retentionReference, cumulative } = retentionFilter || {}
// If the retention reference option is specified as previous,
// then translate retention rates to relative to previous,
// otherwise, just use what the result was originally.
Expand All @@ -45,12 +45,22 @@ export const retentionLineGraphLogic = kea<retentionLineGraphLogicType>([
// further and translate these numbers into percentage of the
// previous value so we get some idea for the rate of
// convergence.

return results.map((cohortRetention, datasetIndex) => {
const retentionPercentages = cohortRetention.values
let retentionPercentages = cohortRetention.values
.map((value) => value.count / cohortRetention.values[0].count)
// Make them display in the right scale
.map((value) => (isNaN(value) ? 0 : 100 * value))

if (cumulative) {
retentionPercentages = retentionPercentages.map((value, valueIndex, arr) => {
let cumulativeValue = value
for (let i = valueIndex + 1; i < arr.length; i++) {
cumulativeValue += arr[i]
}
return Math.min(cumulativeValue, 100)
})
}

// To calculate relative percentages, we take for instance Cohort 1 as percentages
// of the cohort size and create another series that has a 100 at prepended so we have
//
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/scenes/retention/retentionModalLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const retentionModalLogic = kea<retentionModalLogicType>([
connect((props: InsightLogicProps) => ({
values: [
insightVizDataLogic(props),
['querySource'],
['querySource', 'retentionFilter'],
groupsModel,
['aggregationLabel'],
featureFlagLogic,
Expand Down
17 changes: 13 additions & 4 deletions frontend/src/scenes/retention/retentionTableLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const retentionTableLogic = kea<retentionTableLogicType>([
tableRows: [
(s) => [s.results, s.maxIntervalsCount, s.retentionFilter, s.breakdownFilter, s.hideSizeColumn],
(results, maxIntervalsCount, retentionFilter, breakdownFilter, hideSizeColumn) => {
const { period } = retentionFilter || {}
const { period, cumulative } = retentionFilter || {}
const { breakdowns } = breakdownFilter || {}

return range(maxIntervalsCount).map((index: number) => {
Expand Down Expand Up @@ -99,12 +99,21 @@ export const retentionTableLogic = kea<retentionTableLogicType>([

const secondColumn = hideSizeColumn ? [] : [currentResult.values[0].count]

const otherColumns = currentResult.values.map((value) => {
const otherColumns = currentResult.values.map((value, valueIndex) => {
const totalCount = currentResult.values[0]['count']
const percentage = totalCount > 0 ? (value['count'] / totalCount) * 100 : 0
let count = value['count']

if (cumulative && valueIndex > 0) {
for (let i = valueIndex + 1; i < currentResult.values.length; i++) {
count += currentResult.values[i]['count']
}
count = Math.min(count, totalCount) // Ensure cumulative count doesn't exceed total count
}

const percentage = totalCount > 0 ? (count / totalCount) * 100 : 0

return {
count: value['count'],
count,
percentage,
}
})
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2268,6 +2268,7 @@ export interface RetentionFilterType extends FilterType {

//frontend only
show_mean?: boolean
cumulative?: boolean
}
export interface LifecycleFilterType extends FilterType {
/** @deprecated */
Expand Down
1 change: 1 addition & 0 deletions posthog/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -3083,6 +3083,7 @@ class RetentionFilter(BaseModel):
model_config = ConfigDict(
extra="forbid",
)
cumulative: Optional[bool] = None
period: Optional[RetentionPeriod] = RetentionPeriod.DAY
retentionReference: Optional[RetentionReference] = None
retentionType: Optional[RetentionType] = None
Expand Down

0 comments on commit bdf780a

Please sign in to comment.