You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by eb...@apache.org on 2020/07/02 12:54:37 UTC
[incubator-streampipes] branch dev updated: Add selection of
non-numeric properties (string columns) to linechart widget
This is an automated email from the ASF dual-hosted git repository.
ebi pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-streampipes.git
The following commit(s) were added to refs/heads/dev by this push:
new dc96e56 Add selection of non-numeric properties (string columns) to linechart widget
new ba6119f Merge branch 'dev' of github.com:apache/incubator-streampipes into dev
dc96e56 is described below
commit dc96e56f2505b57538963e42f33b0aa621f6c30a
Author: Daniel Ebi <eb...@fzi.de>
AuthorDate: Thu Jul 2 14:56:47 2020 +0200
Add selection of non-numeric properties (string columns) to linechart widget
---
.../rest/impl/datalake/DataLakeManagementV3.java | 4 +-
.../rest/impl/datalake/DataLakeResourceV3.java | 7 +-
.../datalake/datalake-rest.service.ts | 4 +-
.../widgets/base/base-data-explorer-widget.ts | 10 ++
.../line-chart/line-chart-widget.component.html | 11 ++
.../line-chart/line-chart-widget.component.ts | 129 ++++++++++++---------
.../select-properties.component.html | 4 +-
.../select-properties.component.ts | 6 +
8 files changed, 113 insertions(+), 62 deletions(-)
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java
index 7417b92..5041b32 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeManagementV3.java
@@ -577,7 +577,7 @@ public class DataLakeManagementV3 {
return route;
}
- public void updateLabels(String index, long startdate, long enddate, String label) {
+ public void updateLabels(String index, String labelColumn, long startdate, long enddate, String label) {
DataResult queryResult = getEvents(index, startdate, enddate);
Map<String, String> headerWithTypes = getHeadersWithTypes(index);
List<String> headers = queryResult.getHeaders();
@@ -592,7 +592,7 @@ public class DataLakeManagementV3 {
for (int i = 1; i < row.size(); i++) {
String selected_header = headers.get(i);
- if (!selected_header.equals("sp_internal_label")) {
+ if (!selected_header.equals(labelColumn)) {
if (headerWithTypes.get(selected_header).equals("integer")) {
p.addField(selected_header, Math.round((double) row.get(i)));
} else if (headerWithTypes.get(selected_header).equals("string")) {
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java
index 285a65d..d2a64c8 100644
--- a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/datalake/DataLakeResourceV3.java
@@ -228,14 +228,15 @@ public class DataLakeResourceV3 extends AbstractRestInterface {
@POST
@Produces(MediaType.TEXT_PLAIN)
- @Path("/data/{index}/{startdate}/{enddate}/labeling")
+ @Path("/data/{index}/{startdate}/{enddate}/labeling/{column}")
public Response labelData(@Context UriInfo info,
@PathParam("index") String index,
@PathParam("startdate") long startdate,
- @PathParam("enddate") long enddate) {
+ @PathParam("enddate") long enddate,
+ @PathParam("column") String column) {
String label = info.getQueryParameters().getFirst("label");
- this.dataLakeManagement.updateLabels(index, startdate, enddate, label);
+ this.dataLakeManagement.updateLabels(index, column, startdate, enddate, label);
return Response.ok("Successfully updated database.", MediaType.TEXT_PLAIN).build();
}
diff --git a/ui/src/app/core-services/datalake/datalake-rest.service.ts b/ui/src/app/core-services/datalake/datalake-rest.service.ts
index aaa553c..c816e45 100644
--- a/ui/src/app/core-services/datalake/datalake-rest.service.ts
+++ b/ui/src/app/core-services/datalake/datalake-rest.service.ts
@@ -123,9 +123,9 @@ export class DatalakeRestService {
return this.http.post(this.dataLakeUrlV3 + '/data/image/' + imageRoute + '/coco', data);
}
- saveLabelsInDatabase(index, startDate, endDate, label) {
+ saveLabelsInDatabase(index, labelColumn, startDate, endDate, label) {
const request = new HttpRequest('POST', this.dataLakeUrlV3 + '/data/' + index + '/' + startDate + '/' +
- endDate + '/labeling?label=' + label, {}, {
+ endDate + '/labeling/' + labelColumn + '?label=' + label, {}, {
reportProgress: true,
responseType: 'text'
});
diff --git a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.ts b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.ts
index 4536410..3eddc5a 100644
--- a/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.ts
+++ b/ui/src/app/data-explorer/components/widgets/base/base-data-explorer-widget.ts
@@ -109,6 +109,16 @@ export abstract class BaseDataExplorerWidget implements OnChanges {
return result;
}
+ getNonNumericProperties(eventSchema: EventSchema) {
+ const result: EventProperty[] = [];
+ eventSchema.eventProperties.forEach(p => {
+ if (p.domainProperty !== 'http://schema.org/DateTime' && !this.isNumber(p)) {
+ result.push(p);
+ }
+ });
+
+ return result;
+ }
getTimestampProperty(eventSchema: EventSchema) {
const propertyKeys: string[] = [];
diff --git a/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.html b/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.html
index 8befba4..09b594e 100644
--- a/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.html
+++ b/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.html
@@ -21,12 +21,23 @@
<div fxFlex="100" layout="row" fxLayoutAlign="end center" style="margin-left: 0px;margin-right: 0px;">
<sp-select-properties
+ label="Select Columns"
+ multiple = true
style="margin-right: 10px;"
(changeSelectedProperties)="setSelectedColumn($event)"
[availableProperties]="availableColumns"
[selectedProperties]="selectedColumns">
</sp-select-properties>
+ <sp-select-properties
+ label="Select Label Column"
+ multiple = false
+ style="margin-right: 10px;"
+ (changeSelectedProperties)="setSelectedLabelColumn($event)"
+ [availableProperties]="availableNonNumericColumns"
+ [selectedProperties]="selectedNonNumericColumn">
+ </sp-select-properties>
+
<mat-slide-toggle [(ngModel)]="advancedSettingsActive">Advanced</mat-slide-toggle>
diff --git a/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.ts b/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.ts
index 8e97619..c348bf9 100644
--- a/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.ts
+++ b/ui/src/app/data-explorer/components/widgets/line-chart/line-chart-widget.component.ts
@@ -36,13 +36,19 @@ import { BaseDataExplorerWidget } from '../base/base-data-explorer-widget';
export class LineChartWidgetComponent extends BaseDataExplorerWidget implements OnInit {
data: any[] = undefined;
+ labels: any[] = undefined;
availableColumns: EventProperty[] = [];
+ availableNonNumericColumns: EventProperty[] = [];
selectedColumns: EventProperty[] = [];
+ selectedNonNumericColumn: EventProperty = undefined;
dimensionProperties: EventProperty[] = [];
+
yKeys: string[] = [];
xKey: string;
+ private nonNumericKey: string = undefined;
advancedSettingsActive = false;
+ showNonNumericData = false;
selectedStartX = undefined;
selectedEndX = undefined;
@@ -55,6 +61,7 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
groupValue = 'None';
showCountValue = false;
+
constructor(public dialog: MatDialog, public plotlyService: PlotlyService, public colorService: ColorService,
public renderer: Renderer2, protected dataLakeRestService: DatalakeRestService) {
super(dataLakeRestService, dialog);
@@ -137,38 +144,38 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
this.availableColumns = this.getNumericProperty(this.dataExplorerWidget.dataLakeMeasure.eventSchema);
this.dimensionProperties = this.getDimensionProperties(this.dataExplorerWidget.dataLakeMeasure.eventSchema);
+ this.availableNonNumericColumns = this.getNonNumericProperties(this.dataExplorerWidget.dataLakeMeasure.eventSchema);
// Reduce selected columns when more then 6
this.selectedColumns = this.availableColumns.length > 6 ? this.availableColumns.slice(0, 5) : this.availableColumns;
-
+ if (this.availableNonNumericColumns.length > 0) {
+ this.selectedNonNumericColumn = this.availableNonNumericColumns[0];
+ }
this.xKey = this.getTimestampProperty(this.dataExplorerWidget.dataLakeMeasure.eventSchema).runtimeName;
this.yKeys = this.getRuntimeNames(this.selectedColumns);
+ this.nonNumericKey = this.selectedNonNumericColumn.runtimeName;
this.updateData();
}
updateData() {
+ this.graph.layout.shapes = [];
if (!this.advancedSettingsActive) {
this.setShownComponents(false, false, true);
this.dataLakeRestService.getDataAutoAggergation(
this.dataExplorerWidget.dataLakeMeasure.measureName, this.viewDateRange.startDate.getTime(), this.viewDateRange.endDate.getTime())
.subscribe((res: DataResult) => {
-
if (res.total === 0) {
this.setShownComponents(true, false, false);
} else {
res.measureName = this.dataExplorerWidget.dataLakeMeasure.measureName;
const tmp = this.transformData(res, this.xKey);
this.data = this.displayData(tmp, this.yKeys);
+ this.labels = this.loadLabels(tmp, this.nonNumericKey);
+ this.addLabelsToGraph(this.data, this.labels);
this.data['measureName'] = tmp.measureName;
- this.data['labels'] = tmp.labels;
-
- if (this.data['labels'] !== undefined && this.data['labels'].length > 0) {
- this.addInitialColouredShapesToGraph();
- }
this.setShownComponents(false, true, false);
}
-
}
);
} else {
@@ -179,32 +186,25 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
this.dataExplorerWidget.dataLakeMeasure.measureName, this.viewDateRange.startDate.getTime(), this.viewDateRange.endDate.getTime()
, this.aggregationTimeUnit, this.aggregationValue)
.subscribe((res: DataResult) => {
-
- if (res.total === 0) {
- this.setShownComponents(true, false, false);
- } else {
- res.measureName = this.dataExplorerWidget.dataLakeMeasure.measureName;
- const tmp = this.transformData(res, this.xKey);
- this.data = this.displayData(tmp, this.yKeys);
- this.data['measureName'] = tmp.measureName;
- this.data['labels'] = tmp.labels;
-
- if (this.data['labels'] !== undefined && this.data['labels'].length > 0) {
- this.addInitialColouredShapesToGraph();
+ if (res.total === 0) {
+ this.setShownComponents(true, false, false);
+ } else {
+ res.measureName = this.dataExplorerWidget.dataLakeMeasure.measureName;
+ const tmp = this.transformData(res, this.xKey);
+ this.data = this.displayData(tmp, this.yKeys);
+ this.labels = this.loadLabels(tmp, this.nonNumericKey);
+ this.addLabelsToGraph(this.data, this.labels);
+ this.data['measureName'] = tmp.measureName;
+
+ this.setShownComponents(false, true, false);
}
-
- this.setShownComponents(false, true, false);
}
-
- }
);
} else {
-
this.dataLakeRestService.getGroupedData(
this.dataExplorerWidget.dataLakeMeasure.measureName, this.viewDateRange.startDate.getTime(), this.viewDateRange.endDate.getTime(),
this.aggregationTimeUnit, this.aggregationValue, this.groupValue)
.subscribe((res: GroupedDataResult) => {
-
if (res.total === 0) {
this.setShownComponents(true, false, false);
} else {
@@ -227,7 +227,6 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
}
}
-
displayData(transformedData: DataResult, yKeys: string[]) {
if (this.yKeys.length > 0) {
const tmp = [];
@@ -235,16 +234,6 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
transformedData.rows.forEach(serie => {
if (serie.name === key) {
tmp.push(serie);
-
- // adding customdata property in order to store labels in graph
- if (transformedData.labels !== undefined && transformedData.labels.length !== 0) {
- serie['customdata'] = transformedData.labels;
- } else {
- serie['customdata'] = Array(serie['x'].length).fill('');
- }
- // adding custom hovertemplate in order to display labels in graph
- serie['hovertemplate'] = 'y: %{y}<br>' + 'x: %{x}<br>' + 'label: %{customdata}';
-
}
});
});
@@ -256,6 +245,33 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
}
}
+ loadLabels(transformedData: DataResult, labelKey: string) {
+ let labels = undefined;
+ if (labelKey !== undefined) {
+ transformedData.rows.forEach(serie => {
+ if (serie.name === labelKey) {
+ labels = serie.y;
+ }
+ });
+ }
+ return labels;
+ }
+
+ addLabelsToGraph(data, labels) {
+ data.forEach(serie => {
+ // adding customdata property in order to store labels in graph
+ if (labels !== undefined && labels.length !== 0) {
+ serie['customdata'] = labels;
+ this.addInitialColouredShapesToGraph();
+ } else {
+ serie['customdata'] = Array(serie['x'].length).fill('');
+ }
+ // adding custom hovertemplate in order to display labels in graph
+ serie['hovertemplate'] = 'y: %{y}<br>' + 'x: %{x}<br>' + this.nonNumericKey + ': %{customdata}';
+ });
+ this.data = data;
+ }
+
displayGroupedData(transformedData: GroupedDataResult, yKeys: string[]) {
// if (this.yKeys.length > 0) {
@@ -292,48 +308,49 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
// }
}
-
transformData(data: DataResult, xKey: string): DataResult {
const tmp: any[] = [];
const dataKeys = [];
- const label_column = [];
+ const label_columns = [];
data.rows.forEach(row => {
data.headers.forEach((headerName, index) => {
if (!dataKeys.includes(index) && typeof row[index] === 'number') {
dataKeys.push(index);
- } else if (!label_column.includes(index) && typeof row[index] == 'string' && data.headers[index] == 'sp_internal_label') {
- label_column.push(index);
+ } else if (!label_columns.includes(index) && typeof row[index] === 'string') {
+ label_columns.push(index);
}
});
});
const indexXkey = data.headers.findIndex(headerName => headerName === this.xKey);
- const labels = [];
dataKeys.forEach(key => {
const headerName = data.headers[key];
tmp[key] = {
type: 'scatter', mode: 'lines', name: headerName, connectgaps: false, x: [], y: []};
});
+
+ label_columns.forEach(key => {
+ const headerName = data.headers[key];
+ tmp[key] = {
+ name: headerName, x: [], y: []};
+ });
+
data.rows.forEach(row => {
data.headers.forEach((headerName, index) => {
- if (dataKeys.includes(index)) {
+ if (dataKeys.includes(index) || label_columns.includes(index)) {
tmp[index].x.push(new Date(row[indexXkey]));
if ((row[index]) !== undefined) {
tmp[index].y.push(row[index]);
} else {
tmp[index].y.push(null);
}
- } else if (label_column.length > 0 && label_column.includes(index)) {
- labels.push(row[index]);
}
});
});
data.rows = tmp;
- data.labels = labels;
-
return data;
}
@@ -352,6 +369,12 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
this.updateData();
}
+ setSelectedLabelColumn(selectedLabelColumn: EventProperty) {
+ this.selectedNonNumericColumn = selectedLabelColumn;
+ this.nonNumericKey = selectedLabelColumn.runtimeName;
+ this.updateData();
+ }
+
handleDefaultModeBarButtonClicks($event) {
if (!('xaxis.autorange' in $event) && !('hovermode' in $event)) {
if ($event.dragmode !== 'select') {
@@ -430,7 +453,7 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
series['customdata'][point] = result;
}
}
- this.data['labels'] = this.data[0]['customdata'];
+ this.labels = this.data[0]['customdata'];
// saving labels persistently
this.saveLabelsInDatabase(result, this.selectedStartX, this.selectedEndX);
@@ -531,7 +554,7 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
private saveLabelsInDatabase(label, start_X, end_X) {
const startdate = new Date(start_X).getTime() - 1;
const enddate = new Date(end_X).getTime() + 1;
- this.dataLakeRestService.saveLabelsInDatabase(this.data['measureName'], startdate, enddate, label).subscribe(
+ this.dataLakeRestService.saveLabelsInDatabase(this.data['measureName'], this.nonNumericKey, startdate, enddate, label).subscribe(
res => {
// console.log('Successfully wrote label ' + currentLabel + ' into database.');
}
@@ -539,10 +562,10 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
}
private addInitialColouredShapesToGraph() {
- let selectedLabel;
+ let selectedLabel = '';
let indices = [];
- for (let label = 0; label <= this.data['labels'].length; label++) {
- if (selectedLabel !== this.data['labels'][label] && indices.length > 0) {
+ for (let label = 0; label <= this.labels.length; label++) {
+ if (selectedLabel !== this.labels[label] && indices.length > 0) {
const startdate = new Date(this.data[0]['x'][indices[0]]).getTime();
const enddate = new Date(this.data[0]['x'][indices[indices.length - 1]]).getTime();
const color = this.colorService.getColor(selectedLabel);
@@ -555,7 +578,7 @@ export class LineChartWidgetComponent extends BaseDataExplorerWidget implements
} else {
indices.push(label);
}
- selectedLabel = this.data['labels'][label];
+ selectedLabel = this.labels[label];
}
}
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.html b/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.html
index 14c0ef0..8d346f4 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.html
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.html
@@ -17,8 +17,8 @@
-->
<mat-form-field appearance="outline" class="sp_form_field_wrapper">
- <mat-label>Select Columns</mat-label>
- <mat-select [ngModel]="this.selectedProperties" (selectionChange)="triggerSelectedProperties($event.value)" multiple>
+ <mat-label>{{this.label}}</mat-label>
+ <mat-select [ngModel]="this.selectedProperties" (selectionChange)="triggerSelectedProperties($event.value)" [multiple]="multiple">
<mat-option *ngFor="let column of availableProperties" [value]="column" style="background-color: #FFFFFF">
{{column.runtimeName}}
</mat-option>
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.ts b/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.ts
index 7336589..e254599 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.ts
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-properties/select-properties.component.ts
@@ -35,6 +35,12 @@ export class SelectPropertiesComponent implements OnInit {
@Input()
selectedProperties: EventProperty[];
+ @Input()
+ label: string;
+
+ @Input()
+ multiple: boolean
+
constructor() { }
ngOnInit(): void {