Files
perfdb/pdb-js/src/app/plot.service.ts
2019-12-27 12:25:25 +01:00

200 lines
6.0 KiB
TypeScript

import { Injectable, OnInit } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class PlotService {
plotTypes: Array<PlotType>;
constructor(private http: HttpClient) {
this.plotTypes = new Array<PlotType>();
this.plotTypes.push(new PlotType("SCATTER","Scatter","scatter-chart2",true,DataType.Time,DataType.Duration));
this.plotTypes.push(new PlotType("HEATMAP", "Heatmap", "heatmap", false, DataType.Other, DataType.Other));
this.plotTypes.push(new PlotType("CONTOUR", "Contour", "contour-chart", false, DataType.Time, DataType.Duration));
this.plotTypes.push(new PlotType("CUM_DISTRIBUTION", "Cumulative Distribution", "cumulative-distribution-chart", true, DataType.Percent, DataType.Duration));
this.plotTypes.push(new PlotType("HISTOGRAM", "Histogram", "histogram", true, DataType.HistogramBin, DataType.HistogramCount));
this.plotTypes.push(new PlotType("RIDGELINES", "Ridgelines", "ridgelines", false, DataType.Other, DataType.Other));
this.plotTypes.push(new PlotType("QQ", "Quantile-Quantile", "quantile-quantile", false, DataType.Other, DataType.Other));
this.plotTypes.push(new PlotType("PARALLEL", "Parallel Requests", "parallel-requests-chart", true, DataType.Time, DataType.Count));
this.plotTypes.push(new PlotType("VIOLIN", "Violin", "violin-chart", false, DataType.Group, DataType.Duration));
this.plotTypes.push(new PlotType("STRIP", "Strip", "strip-chart", false, DataType.Group, DataType.Duration));
this.plotTypes.push(new PlotType("PIE", "Pie", "pie-chart", false, DataType.Other, DataType.Other));
this.plotTypes.push(new PlotType("BAR", "Bar", "bar-chart", false, DataType.Other, DataType.Other));
this.plotTypes.push(new PlotType("STEP_FIT", "Step Fit", "step-fit", false, DataType.Other, DataType.Other));
this.plotTypes.push(new PlotType("LAG", "Lag", "lag-plot", false, DataType.Other, DataType.Other));
this.plotTypes.push(new PlotType("ACF", "ACF", "acf-plot", false, DataType.Other, DataType.Other));
}
ngOnInit() {
}
getPlotTypes(): Array<PlotType> {
return this.plotTypes.filter(plotType => plotType.active);
}
getTagFields(): Observable<Array<string>> {
return this.http.get<Array<string>>('//'+window.location.hostname+':8080/fields');
}
autocomplete(query: string, caretIndex: number, resultMode: ResultMode): Observable<AutocompleteResult>
{
const options = {
params: new HttpParams()
.set('caretIndex', ""+caretIndex)
.set('query', query)
.set('resultMode', resultMode)
};
return this.http.get<AutocompleteResult>('//'+window.location.hostname+':8080/autocomplete', options);
}
sendPlotRequest(plotRequest: PlotRequest): Observable<PlotResponse>{
//console.log("send plot request: "+ JSON.stringify(plotRequest));
return this.http.post<PlotResponse>('//'+window.location.hostname+':8080/plots', plotRequest);
}
getFilterDefaults(): Observable<FilterDefaults>{
return this.http.get<FilterDefaults>('//'+window.location.hostname+':8080/filters/defaults')
}
splitQuery(query: string, splitBy:string) : Observable<Array<string>>{
const q = "("+query+") and "+splitBy+"=";
return this.autocomplete(q, q.length+1, ResultMode.FULL_VALUES).pipe(
map(
autocompleteResult => autocompleteResult.proposals.map(suggestion => suggestion.value)
)
);
}
}
export class PlotType {
id: string;
name: string;
icon: string
active: boolean;
xAxis: DataType;
yAxis: DataType;
constructor(id: string, name: string, icon: string, active: boolean, xAxis: DataType, yAxis: DataType) {
this.id = id;
this.name = name;
this.icon = icon;
this.active = active;
this.xAxis = xAxis;
this.yAxis = yAxis;
}
compatible(other: PlotType) : boolean {
const xEqual = this.xAxis === other.xAxis;
const yEqual = this.yAxis === other.yAxis;
const anyIsOther = this.xAxis === DataType.Other
|| this.yAxis === DataType.Other
|| other.xAxis === DataType.Other
|| other.yAxis === DataType.Other;
var result = xEqual || yEqual;
// if either dimension is Other, then this plot is not compatible with any other plot
result = result && !anyIsOther;
// is not the same
result = result && this.name != other.name;
return result;
}
}
export class TagField {
name: string;
constructor(name: string) {
this.name = name;
}
}
export enum DataType {
Time,
Duration,
Percent,
Count,
Group,
Metric,
HistogramBin,
HistogramCount,
Other
}
export class Suggestion {
value: string;
newQuery: string;
newCaretPosition: number;
}
export class AutocompleteResult{
proposals: Array<Suggestion>;
}
export class PlotRequest {
query : string;
height : number;
width : number;
thumbnailMaxWidth : number = 300;
thumbnailMaxHeight : number = 200;
groupBy : Array<string>;
limitBy : string;
axisScale : string;
limit : number;
dateRange : string;
aggregates : Array<string>;
yRangeMin : number;
yRangeMax : number;
yRangeUnit : string;
keyOutside : boolean = false;
generateThumbnail : boolean;
copy(): PlotRequest {
return JSON.parse(JSON.stringify(this));
}
}
export class PlotResponse {
imageUrl : string;
stats : PlotResponseStats;
thumbnailUrl : string;
}
export class PlotResponseStats {
maxValue : number;
values : number;
average : number ;
plottedValues : number;
dataSeriesStats : Array<DataSeriesStats>;
}
export class DataSeriesStats {
values : number;
maxValue : number;
average : number;
plottedValues : number;
}
export class FilterDefaults {
groupBy: Array<string>;
fields: Array<string>;
splitBy: string;
}
export enum ResultMode {
CUT_AT_DOT = "CUT_AT_DOT",
FULL_VALUES = "FULL_VALUES"
}