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 {