From 463791fecbfcd9379f5ce6de4c0b7c15edf79e18 Mon Sep 17 00:00:00 2001 From: Jenny Fung Date: Thu, 31 Aug 2017 13:06:09 -0400 Subject: [PATCH] Add percentile extra params --- src/app/app.module.ts | 5 +- src/app/charts/chart.component.html | 9 ++- src/app/charts/chart.component.ts | 12 +++- .../extra-params.constants.ts | 17 +++++- .../charts/extra-params-components/index.ts | 1 + .../percentile.component.html | 10 ++++ .../percentile.component.ts | 55 +++++++++++++++++++ .../threshold.component.ts | 4 +- .../percentile-indicator-query-opts.model.ts | 7 +++ src/app/services/indicator.service.ts | 12 +++- 10 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 src/app/charts/extra-params-components/percentile.component.html create mode 100644 src/app/charts/extra-params-components/percentile.component.ts create mode 100644 src/app/models/percentile-indicator-query-opts.model.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1e279249..f0de5d00 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -41,9 +41,11 @@ import { LoginComponent } from './login/login.component'; import { NavbarComponent } from './navbar/navbar.component'; import { PageNotFoundComponent } from './http-status/page-not-found/page-not-found.component'; import { SidebarComponent } from './sidebar/sidebar.component'; -import { ThresholdComponent } from './charts/extra-params-components/threshold.component'; import { WaveComponent } from './ng2-spin-kit/wave.component'; +import { ThresholdComponent, + PercentileComponent } from './charts/extra-params-components/'; + // App services import { ApiHttp } from './auth/api-http.service'; import { apiHttpProvider } from './auth/api-http.provider'; @@ -69,6 +71,7 @@ const locationStrategyProvider = { AppComponent, WaveComponent, ThresholdComponent, + PercentileComponent, ChartComponent, DashboardComponent, IndicatorListComponent, diff --git a/src/app/charts/chart.component.html b/src/app/charts/chart.component.html index 4d2797fc..42c8f6c4 100644 --- a/src/app/charts/chart.component.html +++ b/src/app/charts/chart.component.html @@ -7,9 +7,16 @@

+ (thresholdParamSelected)="onExtraParamsSelected($event)"> +
+ + +
diff --git a/src/app/charts/chart.component.ts b/src/app/charts/chart.component.ts index a83c99cc..88cffdf4 100644 --- a/src/app/charts/chart.component.ts +++ b/src/app/charts/chart.component.ts @@ -27,7 +27,8 @@ import { IndicatorService } from '../services/indicator.service'; import { DataExportService } from '../services/data-export.service'; import { ImageExportService } from '../services/image-export.service'; -import { isThresholdIndicator } from '../charts/extra-params-components/extra-params.constants'; +import { isThresholdIndicator, + isPercentileIndicator } from '../charts/extra-params-components/extra-params.constants'; import * as _ from 'lodash'; @@ -65,6 +66,7 @@ export class ChartComponent implements OnChanges, OnDestroy, AfterViewInit { private lastYear = 2100; public dateRange: number[] = [this.firstYear, this.lastYear]; public isThresholdIndicator = isThresholdIndicator; + public isPercentileIndicator = isPercentileIndicator; public sliderConfig: any = { behaviour: 'drag', connect: true, @@ -181,13 +183,19 @@ export class ChartComponent implements OnChanges, OnDestroy, AfterViewInit { this.imageExportService.downloadAsPNG(this.chart.indicator.name, fileName); } - public onThresholdSelected($event) { + public onExtraParamsSelected($event) { const thresholdParams = $event.data as ThresholdIndicatorQueryOpts; this.extraParams = thresholdParams; this.onExtraParamsChanged.emit(this.extraParams); this.updateChart(this.extraParams); } + public onPercentileSelected($event) { + const percentileParams = $event.data; + console.log(percentileParams); + this.updateChart(percentileParams); + } + curlCommandCopied(copiedPopup) { // show a confirmation tooltip, then hide it again after a second copiedPopup.show(); diff --git a/src/app/charts/extra-params-components/extra-params.constants.ts b/src/app/charts/extra-params-components/extra-params.constants.ts index b38d376d..6d6d5d2b 100644 --- a/src/app/charts/extra-params-components/extra-params.constants.ts +++ b/src/app/charts/extra-params-components/extra-params.constants.ts @@ -6,8 +6,14 @@ const thresholdIndicatorNames = [ 'precipitation_threshold' ]; +const percentileIndicatorNames = [ + 'percentile_high_temperature', + 'percentile_low_temperature', + 'percentile_precipitation' +]; + // TODO: concat additional extra parameter names to this array for #203, #204, and #205 -const extraParamsIndicatorNames = thresholdIndicatorNames; +const extraParamsIndicatorNames = [].concat(thresholdIndicatorNames, percentileIndicatorNames); export function isThresholdIndicator(indicatorName: string): boolean { for (const thresholdName of thresholdIndicatorNames) { @@ -26,3 +32,12 @@ export function hasExtraParams(indicatorName: string): boolean { } return false; } + +export function isPercentileIndicator(indicatorName: string): boolean { + for (const percentileName of percentileIndicatorNames) { + if (indicatorName === percentileName) { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/src/app/charts/extra-params-components/index.ts b/src/app/charts/extra-params-components/index.ts index e2d0f861..491507d7 100644 --- a/src/app/charts/extra-params-components/index.ts +++ b/src/app/charts/extra-params-components/index.ts @@ -1 +1,2 @@ export * from './threshold.component'; +export * from './percentile.component'; \ No newline at end of file diff --git a/src/app/charts/extra-params-components/percentile.component.html b/src/app/charts/extra-params-components/percentile.component.html new file mode 100644 index 00000000..797af1fe --- /dev/null +++ b/src/app/charts/extra-params-components/percentile.component.html @@ -0,0 +1,10 @@ +
+
+
+ Show {{indicator.label | lowercase}} at percentile + + of projections. +
+
+
diff --git a/src/app/charts/extra-params-components/percentile.component.ts b/src/app/charts/extra-params-components/percentile.component.ts new file mode 100644 index 00000000..8030cf6e --- /dev/null +++ b/src/app/charts/extra-params-components/percentile.component.ts @@ -0,0 +1,55 @@ +import { AfterViewInit, Component, EventEmitter, Input, Output, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; + +import { Indicator } from '../../models/indicator.model'; + +import * as _ from 'lodash'; + +/* + * Percentile params component + * Uni-field form to allow user to specify the percentile params + */ +@Component({ + selector: 'ccl-percentile-parameters', + templateUrl: './percentile.component.html' +}) +export class PercentileComponent implements AfterViewInit, OnInit { + + @Input() indicator: Indicator; + @Input() extraParams: any; + + percentileForm: FormGroup; + + // default form values + private defaultPercentile = 50; + + @Output() percentileParamSelected = new EventEmitter(); + + constructor(private formBuilder: FormBuilder) {} + + ngOnInit() { + // must create form on init instead of constructor to capture @Input values + this.createForm(); + } + + ngAfterViewInit() { + // Since valueChanges triggers initially before parent is ready, wait until + // parent is ready here and trigger it to draw chart with extra parameters. + this.percentileParamSelected.emit({data: { + 'percentile': this.percentileForm.controls.percentileCtl.value + }}); + } + + createForm() { + this.percentileForm = this.formBuilder.group({ + percentileCtl: [this.extraParams.percentile || this.defaultPercentile, Validators.required] + }); + + this.percentileForm.valueChanges.debounceTime(700).subscribe(form => { + this.percentileParamSelected.emit({data: { + 'event': event, + 'percentile': form.percentileCtl + }}); + }); + } +} diff --git a/src/app/charts/extra-params-components/threshold.component.ts b/src/app/charts/extra-params-components/threshold.component.ts index e017081d..6c11e0c4 100644 --- a/src/app/charts/extra-params-components/threshold.component.ts +++ b/src/app/charts/extra-params-components/threshold.component.ts @@ -6,8 +6,8 @@ import { Indicator } from '../../models/indicator.model'; import * as _ from 'lodash'; /* - * Chart component - * Container for each individual chart plus controls + * Threshold params component + * Multi-field form to allow user to specify threshold params */ @Component({ selector: 'ccl-threshold-parameters', diff --git a/src/app/models/percentile-indicator-query-opts.model.ts b/src/app/models/percentile-indicator-query-opts.model.ts new file mode 100644 index 00000000..b9a283bc --- /dev/null +++ b/src/app/models/percentile-indicator-query-opts.model.ts @@ -0,0 +1,7 @@ +import { IndicatorQueryOpts } from './indicator-query-opts.model'; + +export interface PercentileIndicatorQueryOpts extends IndicatorQueryOpts { + params: { + percentile: Number; + } +} diff --git a/src/app/services/indicator.service.ts b/src/app/services/indicator.service.ts index f36fe0c0..9c510f96 100644 --- a/src/app/services/indicator.service.ts +++ b/src/app/services/indicator.service.ts @@ -6,11 +6,12 @@ import 'rxjs/Rx'; import { Indicator } from '../models/indicator.model'; import { IndicatorQueryOpts } from '../models/indicator-query-opts.model'; +import { PercentileIndicatorQueryOpts } from '../models/percentile-indicator-query-opts.model'; import { ThresholdIndicatorQueryOpts } from '../models/threshold-indicator-query-opts.model'; import { ApiHttp } from '../auth/api-http.service'; import { apiHost } from '../constants'; -import { isThresholdIndicator } from '../charts/extra-params-components/extra-params.constants'; +import { isThresholdIndicator, isPercentileIndicator } from '../charts/extra-params-components/extra-params.constants'; /* * Indicator Service @@ -40,6 +41,15 @@ export class IndicatorService { searchParams.append('threshold_comparator', thresholdOpts.params.threshold_comparator); } + if (isPercentileIndicator(options.indicator.name)) { + const percentileOpts: PercentileIndicatorQueryOpts = options; + // abort request if chart is in flux (these parameters are required) + if (!percentileOpts.params.percentile) { + return Observable.of({url: ''}); + } + searchParams.append('percentile', percentileOpts.params.percentile.toString()); + } + if (options.params.years) { searchParams.append('years', options.params.years.join(',')); }