Skip to content

Commit fe605db

Browse files
committed
Bump default half window to 4
1 parent bfc1bcb commit fe605db

4 files changed

Lines changed: 28 additions & 18 deletions

File tree

app/components/Package/WeeklyDownloadStats.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { VueUiSparkline } from 'vue-data-ui/vue-ui-sparkline'
33
import { useCssVariables } from '~/composables/useColors'
44
import type { WeeklyDataPoint } from '~/types/chart'
55
import { applyDataCorrection } from '~/utils/chart-data-correction'
6-
import { OKLCH_NEUTRAL_FALLBACK, lightenOklch } from '~/utils/colors'
76
import { applyHampelCorrection } from '~/utils/download-anomalies'
7+
import { OKLCH_NEUTRAL_FALLBACK, lightenOklch } from '~/utils/colors'
88
import type { RepoRef } from '#shared/utils/git-providers'
99
import type { VueUiSparklineConfig, VueUiSparklineDatasetItem } from 'vue-data-ui'
1010
import { onKeyDown } from '@vueuse/core'

app/composables/useSettings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ const DEFAULT_SETTINGS: AppSettings = {
7171
averageWindow: 0,
7272
smoothingTau: 1,
7373
anomaliesFixed: true,
74-
hampelWindow: 3,
74+
hampelWindow: 4,
7575
hampelThreshold: 3,
7676
predictionPoints: 4,
7777
},

app/utils/download-anomalies.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { EvolutionData } from '~/types/chart'
1111
* package equally, with no manual curation.
1212
*/
1313

14-
const DEFAULT_HALF_WINDOW = 3
14+
const DEFAULT_HALF_WINDOW = 4
1515
const DEFAULT_THRESHOLD = 3
1616

1717
function median(values: number[]): number {

test/unit/app/utils/download-anomalies.spec.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ function makeWeeklyPoint(weekStart: string, value: number): WeeklyDataPoint {
1616
describe('applyHampelCorrection', () => {
1717
it('flags and corrects a spike in the middle of steady data', () => {
1818
const data: WeeklyDataPoint[] = [
19+
makeWeeklyPoint('2022-10-24', 100),
20+
makeWeeklyPoint('2022-10-31', 100),
1921
makeWeeklyPoint('2022-11-07', 100),
2022
makeWeeklyPoint('2022-11-14', 100),
21-
makeWeeklyPoint('2022-11-21', 100),
22-
makeWeeklyPoint('2022-11-28', 1000), // spike
23+
makeWeeklyPoint('2022-11-21', 1000), // spike (index 4)
24+
makeWeeklyPoint('2022-11-28', 100),
2325
makeWeeklyPoint('2022-12-05', 100),
2426
makeWeeklyPoint('2022-12-12', 100),
2527
makeWeeklyPoint('2022-12-19', 100),
@@ -28,18 +30,20 @@ describe('applyHampelCorrection', () => {
2830
const result = applyHampelCorrection(data) as WeeklyDataPoint[]
2931

3032
// The spike should be corrected
31-
expect(result[3]!.hasAnomaly).toBe(true)
32-
expect(result[3]!.value).toBe(100) // replaced with median
33+
expect(result[4]!.hasAnomaly).toBe(true)
34+
expect(result[4]!.value).toBe(100) // replaced with median
3335

3436
// Non-spike points should be unchanged
3537
expect(result[0]!.value).toBe(100)
3638
expect(result[0]!.hasAnomaly).toBeUndefined()
37-
expect(result[1]!.value).toBe(100)
38-
expect(result[6]!.value).toBe(100)
39+
expect(result[3]!.value).toBe(100)
40+
expect(result[8]!.value).toBe(100)
3941
})
4042

4143
it('does not flag gradual growth as anomalies', () => {
4244
const data: WeeklyDataPoint[] = [
45+
makeWeeklyPoint('2022-10-24', 80),
46+
makeWeeklyPoint('2022-10-31', 90),
4347
makeWeeklyPoint('2022-11-07', 100),
4448
makeWeeklyPoint('2022-11-14', 110),
4549
makeWeeklyPoint('2022-11-21', 120),
@@ -70,6 +74,8 @@ describe('applyHampelCorrection', () => {
7074
it('does not flatten a "great start" (sudden real growth at the end)', () => {
7175
// A package going from zero to real adoption — this is NOT a spike.
7276
const data: WeeklyDataPoint[] = [
77+
makeWeeklyPoint('2022-10-24', 0),
78+
makeWeeklyPoint('2022-10-31', 0),
7379
makeWeeklyPoint('2022-11-07', 0),
7480
makeWeeklyPoint('2022-11-14', 0),
7581
makeWeeklyPoint('2022-11-21', 0),
@@ -82,41 +88,45 @@ describe('applyHampelCorrection', () => {
8288
const result = applyHampelCorrection(data) as WeeklyDataPoint[]
8389

8490
// The 20000 should NOT be erased — it's real growth, not an anomaly.
85-
expect(result[6]!.value).toBe(20000)
86-
expect(result[6]!.hasAnomaly).toBeUndefined()
91+
expect(result[8]!.value).toBe(20000)
92+
expect(result[8]!.hasAnomaly).toBeUndefined()
8793
})
8894

8995
it('does not flatten low-volume real activity', () => {
9096
// Sparse package with occasional real downloads
9197
const data: WeeklyDataPoint[] = [
98+
makeWeeklyPoint('2022-10-24', 0),
99+
makeWeeklyPoint('2022-10-31', 0),
92100
makeWeeklyPoint('2022-11-07', 0),
93101
makeWeeklyPoint('2022-11-14', 0),
94-
makeWeeklyPoint('2022-11-21', 0),
95-
makeWeeklyPoint('2022-11-28', 1),
102+
makeWeeklyPoint('2022-11-21', 1),
96103
makeWeeklyPoint('2022-12-05', 0),
97104
makeWeeklyPoint('2022-12-12', 0),
98105
makeWeeklyPoint('2022-12-19', 0),
106+
makeWeeklyPoint('2022-12-26', 0),
99107
]
100108

101109
const result = applyHampelCorrection(data) as WeeklyDataPoint[]
102110

103111
// A single download is not an anomaly
104-
expect(result[3]!.value).toBe(1)
105-
expect(result[3]!.hasAnomaly).toBeUndefined()
112+
expect(result[4]!.value).toBe(1)
113+
expect(result[4]!.hasAnomaly).toBeUndefined()
106114
})
107115

108116
it('does not mutate the original data', () => {
109117
const data: WeeklyDataPoint[] = [
118+
makeWeeklyPoint('2022-10-24', 100),
119+
makeWeeklyPoint('2022-10-31', 100),
110120
makeWeeklyPoint('2022-11-07', 100),
111121
makeWeeklyPoint('2022-11-14', 100),
112-
makeWeeklyPoint('2022-11-21', 100),
113-
makeWeeklyPoint('2022-11-28', 1000),
122+
makeWeeklyPoint('2022-11-21', 1000),
123+
makeWeeklyPoint('2022-11-28', 100),
114124
makeWeeklyPoint('2022-12-05', 100),
115125
makeWeeklyPoint('2022-12-12', 100),
116126
makeWeeklyPoint('2022-12-19', 100),
117127
]
118128

119129
applyHampelCorrection(data)
120-
expect(data[3]!.value).toBe(1000) // original unchanged
130+
expect(data[4]!.value).toBe(1000) // original unchanged
121131
})
122132
})

0 commit comments

Comments
 (0)