You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@streampipes.apache.org by ri...@apache.org on 2024/03/18 14:15:10 UTC

(streampipes) branch dev updated: feat(#2568): Make time series axes configurable (#2569)

This is an automated email from the ASF dual-hosted git repository.

riemer pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 9e4e0c0284 feat(#2568): Make time series axes configurable (#2569)
9e4e0c0284 is described below

commit 9e4e0c028485c3e4fd5a7401044688e8622c2854
Author: Dominik Riemer <do...@gmail.com>
AuthorDate: Mon Mar 18 15:15:04 2024 +0100

    feat(#2568): Make time series axes configurable (#2569)
    
    * feat(#2568): Make time series axes configurable
    
    * Rename auto scale variable
---
 .../data-explorer-dashboard-panel.component.css    |   2 +-
 .../time-series-chart-widget-config.component.html |  20 +++
 .../time-series-chart-widget-config.component.ts   |  12 +-
 .../model/time-series-chart-widget.model.ts        |   7 +-
 .../sp-timeseries-renderer.service.ts              |  10 +-
 .../select-axis-options.component.html             |  59 +++++++
 .../select-axis-options.component.scss}            |  14 +-
 .../select-axis-options.component.ts}              |  57 +++----
 .../select-color-properties.component.html         | 138 +---------------
 .../select-color-properties.component.scss         |   5 -
 .../select-color-properties.component.ts           |  47 +-----
 .../time-series-item-config.component.html}        | 158 +++++++++----------
 .../time-series-item-config.component.scss}        |  22 +--
 .../time-series-item-config.component.ts}          |  90 +++++------
 ui/src/app/data-explorer/data-explorer.module.ts   |   4 +
 .../echarts-dataset-generator.service.ts           |   1 -
 .../models/dataview-dashboard.model.ts             |   6 +
 .../registry/data-explorer-widget-registry.ts      | 175 +++++++++++----------
 18 files changed, 359 insertions(+), 468 deletions(-)

diff --git a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css
index 83f153f3cc..c1e524bb89 100644
--- a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css
+++ b/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css
@@ -49,7 +49,7 @@
 }
 
 .designer-panel {
-    width: 400px;
+    width: 450px;
     border: 1px solid var(--color-tab-border);
 }
 
diff --git a/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.html b/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.html
index 36051643f4..62a6b9b4b4 100644
--- a/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.html
+++ b/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.html
@@ -34,6 +34,26 @@
     >
     </sp-select-color-properties>
 
+    <sp-configuration-box title="Axes" marginTop="5px">
+        <sp-select-axis-options
+            (viewRefreshEmitter)="triggerViewRefresh()"
+            title="left axis"
+            [axisConfig]="
+                currentlyConfiguredWidget.visualizationConfig.leftAxis
+            "
+        >
+        </sp-select-axis-options>
+
+        <sp-select-axis-options
+            (viewRefreshEmitter)="triggerViewRefresh()"
+            title="right axis"
+            [axisConfig]="
+                currentlyConfiguredWidget.visualizationConfig.rightAxis
+            "
+        >
+        </sp-select-axis-options>
+    </sp-configuration-box>
+
     <sp-configuration-box title="Tooltip">
         <mat-checkbox
             [(ngModel)]="
diff --git a/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts b/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts
index 5e63c35d47..97d526a83c 100644
--- a/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts
+++ b/ui/src/app/data-explorer/components/widgets/time-series-chart/config/time-series-chart-widget-config.component.ts
@@ -79,7 +79,7 @@ export class TimeSeriesChartWidgetConfigComponent extends BaseWidgetConfig<
 
         const lenBefore = Object.keys(currentAxis).length;
 
-        numericPlusBooleanFields.map((field, index) => {
+        numericPlusBooleanFields.forEach((field, index) => {
             const name = field.fullDbName + field.sourceIndex;
             if (!(name in currentColors)) {
                 currentColors[name] = this.presetColors[lenBefore + index];
@@ -146,6 +146,16 @@ export class TimeSeriesChartWidgetConfigComponent extends BaseWidgetConfig<
                 },
             );
         config.showSpike ??= true;
+        config.leftAxis ??= {
+            autoScaleActive: true,
+            axisMin: 0,
+            axisMax: 100,
+        };
+        config.rightAxis ??= {
+            autoScaleActive: true,
+            axisMin: 0,
+            axisMax: 100,
+        };
     }
 
     private getConfigOrDefault(
diff --git a/ui/src/app/data-explorer/components/widgets/time-series-chart/model/time-series-chart-widget.model.ts b/ui/src/app/data-explorer/components/widgets/time-series-chart/model/time-series-chart-widget.model.ts
index f65e113743..4cc95bc86f 100644
--- a/ui/src/app/data-explorer/components/widgets/time-series-chart/model/time-series-chart-widget.model.ts
+++ b/ui/src/app/data-explorer/components/widgets/time-series-chart/model/time-series-chart-widget.model.ts
@@ -22,7 +22,10 @@ import {
     DataExplorerWidgetModel,
     EventPropertyUnion,
 } from '@streampipes/platform-services';
-import { DataExplorerVisConfig } from '../../../../models/dataview-dashboard.model';
+import {
+    AxisConfig,
+    DataExplorerVisConfig,
+} from '../../../../models/dataview-dashboard.model';
 
 export interface TimeSeriesChartVisConfig extends DataExplorerVisConfig {
     selectedTimeSeriesChartProperties: DataExplorerField[];
@@ -36,6 +39,8 @@ export interface TimeSeriesChartVisConfig extends DataExplorerVisConfig {
     displayName: { [id: string]: string };
     displayType: { [id: string]: string };
     chosenAxis: { [id: string]: string };
+    leftAxis: AxisConfig;
+    rightAxis: AxisConfig;
     showSpike: boolean;
 }
 
diff --git a/ui/src/app/data-explorer/components/widgets/time-series-chart/sp-timeseries-renderer.service.ts b/ui/src/app/data-explorer/components/widgets/time-series-chart/sp-timeseries-renderer.service.ts
index 0f70e119eb..6ab5fc00b6 100644
--- a/ui/src/app/data-explorer/components/widgets/time-series-chart/sp-timeseries-renderer.service.ts
+++ b/ui/src/app/data-explorer/components/widgets/time-series-chart/sp-timeseries-renderer.service.ts
@@ -39,7 +39,6 @@ export class SpTimeseriesRendererService extends SpBaseEchartsRenderer<TimeSerie
         _widgetSize: WidgetSize,
     ): void {
         this.addAxisOptions(widgetConfig, options);
-
         const finalSeries: SeriesOption[] = [];
 
         widgetConfig.visualizationConfig.selectedTimeSeriesChartProperties.forEach(
@@ -232,6 +231,7 @@ export class SpTimeseriesRendererService extends SpBaseEchartsRenderer<TimeSerie
             0,
             config.baseAppearanceConfig as WidgetBaseAppearanceConfig,
         );
+
         const yAxisOptions: YAXisOption[] = [];
 
         const uniqueAxes = new Set(
@@ -239,12 +239,20 @@ export class SpTimeseriesRendererService extends SpBaseEchartsRenderer<TimeSerie
                 a.localeCompare(b),
             ),
         );
+        let axisIndex = 0;
 
         uniqueAxes.forEach(axis => {
+            const settings =
+                axisIndex === 0
+                    ? config.visualizationConfig.leftAxis
+                    : config.visualizationConfig.rightAxis;
             yAxisOptions.push({
                 type: 'value',
                 position: axis as CartesianAxisPosition,
+                min: settings.autoScaleActive ? undefined : settings.axisMin,
+                max: settings.autoScaleActive ? undefined : settings.axisMax,
             });
+            axisIndex++;
         });
 
         Object.assign(options, {
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.html b/ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.html
new file mode 100644
index 0000000000..da26fd557f
--- /dev/null
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.html
@@ -0,0 +1,59 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div class="mb-10" fxLayout="column">
+    <mat-checkbox
+        [(ngModel)]="axisConfig.autoScaleActive"
+        (change)="viewRefreshEmitter.emit()"
+        >Auto-scale {{ title }}
+    </mat-checkbox>
+    <div
+        fxFlex
+        fxLayoutAlign="start center"
+        *ngIf="!axisConfig.autoScaleActive"
+        class="ml-10 mb-10"
+    >
+        <small>Min</small>
+        <span fxFlex></span>
+        <mat-form-field appearance="outline" color="accent" fxFlex="30">
+            <input
+                matInput
+                type="number"
+                [(ngModel)]="axisConfig.axisMin"
+                (ngModelChange)="viewRefreshEmitter.emit()"
+            />
+        </mat-form-field>
+    </div>
+    <div
+        fxFlex
+        fxLayoutAlign="start center"
+        *ngIf="!axisConfig.autoScaleActive"
+        class="ml-10 mb-10"
+    >
+        <small>Max</small>
+        <span fxFlex></span>
+        <mat-form-field appearance="outline" color="accent" fxFlex="30">
+            <input
+                matInput
+                type="number"
+                [(ngModel)]="axisConfig.axisMax"
+                (ngModelChange)="viewRefreshEmitter.emit()"
+            />
+        </mat-form-field>
+    </div>
+</div>
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss b/ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.scss
similarity index 80%
copy from ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss
copy to ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.scss
index 993720434e..efc38fc2b0 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.scss
@@ -16,18 +16,6 @@
  *
  */
 
-.marginColorFieldMore {
+.ml-10 {
     margin-left: 10px;
-    margin-right: 1px;
-}
-
-.color-field {
-    width: 20px;
-    height: 20px;
-}
-
-.field-selection-box {
-    border: 1px solid var(--color-bg-3);
-    padding: 5px;
-    margin: 5px;
 }
diff --git a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css b/ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.ts
similarity index 50%
copy from ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css
copy to ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.ts
index 83f153f3cc..cbf08a50f8 100644
--- a/ui/src/app/data-explorer/components/panel/data-explorer-dashboard-panel.component.css
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-axis-options/select-axis-options.component.ts
@@ -16,43 +16,22 @@
  *
  */
 
-.fixed-height {
-    height: 50px;
-}
-
-.data-explorer-options {
-    padding: 0px;
-}
-
-.data-explorer-options-item {
-    display: inline;
-    margin-right: 10px;
-}
-
-.m-20 {
-    margin: 20px;
-}
-
-.h-100 {
-    height: 100%;
-}
-
-.dashboard-grid {
-    display: flex;
-    flex-direction: column;
-    flex: 1 1 100%;
-}
-
-.designer-panel-container {
-    width: 100%;
-    height: 100%;
-}
-
-.designer-panel {
-    width: 400px;
-    border: 1px solid var(--color-tab-border);
-}
-
-.edit-menu-btn {
-    margin-right: 5px;
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { DataExplorerField } from '@streampipes/platform-services';
+import { TimeSeriesChartWidgetModel } from '../../time-series-chart/model/time-series-chart-widget.model';
+import { WidgetConfigurationService } from '../../../../services/widget-configuration.service';
+import { AxisConfig } from '../../../../models/dataview-dashboard.model';
+
+@Component({
+    selector: 'sp-select-axis-options',
+    templateUrl: './select-axis-options.component.html',
+    styleUrls: ['./select-axis-options.component.scss'],
+})
+export class SpSelectAxisOptionsComponent {
+    @Input() title: string;
+    @Input() axisConfig: AxisConfig;
+
+    @Output() viewRefreshEmitter: EventEmitter<void> = new EventEmitter<void>();
+
+    constructor() {}
 }
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html
index b2172a6d77..4fd4af8416 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html
@@ -16,7 +16,7 @@
   ~
   -->
 
-<sp-configuration-box title="Fields" marginTop="5px" class="mr-10">
+<sp-configuration-box title="Fields" marginTop="5px">
     <div header>
         <button
             mat-button
@@ -43,135 +43,13 @@
         fxLayout="column"
         class="field-selection-box"
     >
-        <mat-checkbox
-            color="accent"
-            [checked]="isSelected(field)"
-            (change)="toggleFieldSelection(field)"
-        >
-            <b>{{ field.runtimeName }}</b>
-            {{
-                '(' +
-                    (field.aggregation ? field.aggregation + ', ' : '') +
-                    field.measure +
-                    ' #' +
-                    (field.sourceIndex + 1).toString() +
-                    ')'
-            }}
-        </mat-checkbox>
-        <div
-            fxLayout="row"
-            fxFlex="90"
-            fxLayoutAlign="start center"
-            *ngIf="isSelected(field)"
-            fxLayoutGap="5px"
+        <sp-time-series-item-config
+            [selectedProperties]="selectedProperties"
+            [currentlyConfiguredWidget]="currentlyConfiguredWidget"
+            [field]="field"
+            (viewRefreshEmitter)="triggerViewRefresh()"
+            (configChangeEmitter)="triggerSelectedProperties($event)"
         >
-            <div fxFlex="30px" fxLayoutAlign="start center">
-                <input
-                    class="color-field"
-                    [(colorPicker)]="
-                        currentlyConfiguredWidget.visualizationConfig
-                            .chosenColor[
-                            field.fullDbName + field.sourceIndex.toString()
-                        ]
-                    "
-                    [style.background]="
-                        currentlyConfiguredWidget.visualizationConfig
-                            .chosenColor[
-                            field.fullDbName + field.sourceIndex.toString()
-                        ]
-                    "
-                    required
-                    [cpPosition]="'bottom'"
-                    [cpPresetColors]="presetColors"
-                    (colorPickerSelect)="triggerViewRefresh()"
-                    autocomplete="off"
-                />
-            </div>
-            <div fxFlex="190px">
-                <mat-form-field
-                    appearance="outline"
-                    color="accent"
-                    class="w-100"
-                >
-                    <input
-                        [(ngModel)]="
-                            currentlyConfiguredWidget.visualizationConfig
-                                .displayName[
-                                field.fullDbName + field.sourceIndex.toString()
-                            ]
-                        "
-                        matInput
-                        (input)="onFilterChange($event.target.value, field)"
-                    />
-                </mat-form-field>
-            </div>
-            <div fxFlex="30" fxLayoutAlign="end center">
-                <mat-form-field
-                    appearance="outline"
-                    color="accent"
-                    class="w-100"
-                >
-                    <mat-select
-                        [(value)]="
-                            currentlyConfiguredWidget.visualizationConfig
-                                .displayType[
-                                field.fullDbName + field.sourceIndex.toString()
-                            ]
-                        "
-                        (selectionChange)="triggerViewRefresh()"
-                    >
-                        <mat-option [value]="'lines'">Line</mat-option>
-                        <mat-option [value]="'normal_markers'"
-                            >Scatter</mat-option
-                        >
-                        <mat-option [value]="'lines+markers'"
-                            >Scattered Line
-                        </mat-option>
-                        <mat-option [value]="'bar'">Bar</mat-option>
-                        <mat-option [value]="'symbol_markers'"
-                            >Symbol</mat-option
-                        >
-                    </mat-select>
-                </mat-form-field>
-            </div>
-        </div>
-    </div>
-</sp-configuration-box>
-<sp-configuration-box title="Axis" marginTop="5px">
-    <div
-        style="margin-left: 1px; margin-right: 1px"
-        *ngFor="let field of availableProperties"
-        fxLayout="column"
-        class="field-scroll-panel mb-10"
-    >
-        <div fxFlex fxLayoutAlign="start center" *ngIf="isSelected(field)">
-            <small>{{
-                field.runtimeName +
-                    ' (' +
-                    (field.aggregation ? field.aggregation + ', ' : '') +
-                    field.measure +
-                    ')'
-            }}</small>
-            <span fxFlex></span>
-            <mat-form-field
-                appearance="outline"
-                color="accent"
-                fxFlex="30"
-                class="marginColorFieldMore"
-            >
-                <mat-select
-                    [(value)]="
-                        currentlyConfiguredWidget.visualizationConfig
-                            .chosenAxis[
-                            field.fullDbName + field.sourceIndex.toString()
-                        ]
-                    "
-                    (selectionChange)="triggerViewRefresh()"
-                >
-                    <mat-option [value]="'left'">Left</mat-option>
-                    <mat-option [value]="'right'">Right</mat-option>
-                </mat-select>
-            </mat-form-field>
-        </div>
+        </sp-time-series-item-config>
     </div>
 </sp-configuration-box>
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss
index 993720434e..48bef7bebf 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss
@@ -21,11 +21,6 @@
     margin-right: 1px;
 }
 
-.color-field {
-    width: 20px;
-    height: 20px;
-}
-
 .field-selection-box {
     border: 1px solid var(--color-bg-3);
     padding: 5px;
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
index b2421b4d54..e2468b2ee7 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
@@ -38,23 +38,14 @@ export class SelectColorPropertiesComponent implements OnInit {
         protected widgetConfigurationService: WidgetConfigurationService,
     ) {}
 
-    presetColors: string[] = [
-        '#39B54A',
-        '#1B1464',
-        '#f44336',
-        '#4CAF50',
-        '#FFEB3B',
-        '#FFFFFF',
-        '#000000',
-    ];
-
     ngOnInit(): void {
         if (!this.selectedProperties) {
             this.selectedProperties = [];
         }
     }
 
-    triggerSelectedProperties() {
+    triggerSelectedProperties(selectedProperties: DataExplorerField[]) {
+        this.selectedProperties = selectedProperties;
         this.changeSelectedProperties.emit(this.selectedProperties);
     }
 
@@ -68,32 +59,7 @@ export class SelectColorPropertiesComponent implements OnInit {
 
     selectFields(selected: boolean) {
         this.selectedProperties = selected ? this.availableProperties : [];
-        this.triggerSelectedProperties();
-    }
-
-    isSelected(field: DataExplorerField): boolean {
-        return (
-            this.selectedProperties.find(
-                sp =>
-                    sp.fullDbName === field.fullDbName &&
-                    sp.sourceIndex === field.sourceIndex,
-            ) !== undefined
-        );
-    }
-
-    toggleFieldSelection(field: DataExplorerField) {
-        if (this.isSelected(field)) {
-            this.selectedProperties = this.selectedProperties.filter(
-                sp =>
-                    !(
-                        sp.fullDbName === field.fullDbName &&
-                        sp.sourceIndex === field.sourceIndex
-                    ),
-            );
-        } else {
-            this.selectedProperties.push(field);
-        }
-        this.triggerSelectedProperties();
+        this.triggerSelectedProperties(this.selectedProperties);
     }
 
     triggerViewRefresh() {
@@ -103,11 +69,4 @@ export class SelectColorPropertiesComponent implements OnInit {
             refreshView: true,
         });
     }
-
-    onFilterChange(searchValue: string, field: DataExplorerField): void {
-        this.currentlyConfiguredWidget.visualizationConfig.displayName[
-            field.fullDbName + field.sourceIndex.toString()
-        ] = searchValue;
-        this.triggerViewRefresh();
-    }
 }
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.html
similarity index 58%
copy from ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html
copy to ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.html
index b2172a6d77..31b8ea956e 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.html
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.html
@@ -16,33 +16,8 @@
   ~
   -->
 
-<sp-configuration-box title="Fields" marginTop="5px" class="mr-10">
-    <div header>
-        <button
-            mat-button
-            mat-raised-button
-            color="accent"
-            class="small-button"
-            style="margin-right: 10px"
-            (click)="selectAllFields()"
-        >
-            Select all
-        </button>
-        <button
-            mat-button
-            mat-raised-button
-            class="small-button mat-basic"
-            style="margin-right: 10px"
-            (click)="deselectAllFields()"
-        >
-            Deselect all
-        </button>
-    </div>
-    <div
-        *ngFor="let field of availableProperties"
-        fxLayout="column"
-        class="field-selection-box"
-    >
+<div fxLayout="column">
+    <div fxLayout="row" fxLayoutAlign="start center">
         <mat-checkbox
             color="accent"
             [checked]="isSelected(field)"
@@ -53,19 +28,41 @@
                 '(' +
                     (field.aggregation ? field.aggregation + ', ' : '') +
                     field.measure +
-                    ' #' +
-                    (field.sourceIndex + 1).toString() +
                     ')'
             }}
         </mat-checkbox>
-        <div
-            fxLayout="row"
-            fxFlex="90"
-            fxLayoutAlign="start center"
-            *ngIf="isSelected(field)"
-            fxLayoutGap="5px"
+        <span fxFlex></span>
+        <span
+            class="color-indicator"
+            [ngStyle]="{
+                background:
+                    currentlyConfiguredWidget.visualizationConfig.chosenColor[
+                        field.fullDbName + field.sourceIndex.toString()
+                    ]
+            }"
+        ></span>
+        <button
+            mat-icon-button
+            color="accent"
+            matTooltip="Field settings"
+            (click)="toggleExpand()"
+            [disabled]="!isSelected(field)"
         >
-            <div fxFlex="30px" fxLayoutAlign="start center">
+            <i class="material-icons">{{
+                expanded ? 'expand_less' : 'expand_more'
+            }}</i>
+        </button>
+    </div>
+    <div
+        fxLayout="column"
+        fxFlex="100"
+        *ngIf="isSelected(field) && expanded"
+        fxLayoutGap="5px"
+        class="ml-10"
+    >
+        <div fxLayout="row" fxFlex="100">
+            <div fxFlex="30"><small>Color</small></div>
+            <div fxFlex="70" fxLayoutAlign="start center">
                 <input
                     class="color-field"
                     [(colorPicker)]="
@@ -83,11 +80,16 @@
                     required
                     [cpPosition]="'bottom'"
                     [cpPresetColors]="presetColors"
-                    (colorPickerSelect)="triggerViewRefresh()"
+                    (colorPickerSelect)="viewRefreshEmitter.emit()"
                     autocomplete="off"
                 />
             </div>
-            <div fxFlex="190px">
+        </div>
+        <div fxLayout="row" fxFlex="100">
+            <div fxFlex="30" fxLayoutAlign="start center">
+                <small>Label</small>
+            </div>
+            <div fxFlex="70" fxLayoutAlign="start center">
                 <mat-form-field
                     appearance="outline"
                     color="accent"
@@ -105,7 +107,13 @@
                     />
                 </mat-form-field>
             </div>
-            <div fxFlex="30" fxLayoutAlign="end center">
+        </div>
+
+        <div fxLayout="row" fxFlex="100">
+            <div fxFlex="30" fxLayoutAlign="start center">
+                <small>Type</small>
+            </div>
+            <div fxFlex="70" fxLayoutAlign="start center">
                 <mat-form-field
                     appearance="outline"
                     color="accent"
@@ -118,60 +126,48 @@
                                 field.fullDbName + field.sourceIndex.toString()
                             ]
                         "
-                        (selectionChange)="triggerViewRefresh()"
+                        (selectionChange)="viewRefreshEmitter.emit()"
                     >
                         <mat-option [value]="'lines'">Line</mat-option>
                         <mat-option [value]="'normal_markers'"
-                            >Scatter</mat-option
-                        >
+                            >Scatter
+                        </mat-option>
                         <mat-option [value]="'lines+markers'"
                             >Scattered Line
                         </mat-option>
                         <mat-option [value]="'bar'">Bar</mat-option>
                         <mat-option [value]="'symbol_markers'"
-                            >Symbol</mat-option
-                        >
+                            >Symbol
+                        </mat-option>
                     </mat-select>
                 </mat-form-field>
             </div>
         </div>
-    </div>
-</sp-configuration-box>
-<sp-configuration-box title="Axis" marginTop="5px">
-    <div
-        style="margin-left: 1px; margin-right: 1px"
-        *ngFor="let field of availableProperties"
-        fxLayout="column"
-        class="field-scroll-panel mb-10"
-    >
-        <div fxFlex fxLayoutAlign="start center" *ngIf="isSelected(field)">
-            <small>{{
-                field.runtimeName +
-                    ' (' +
-                    (field.aggregation ? field.aggregation + ', ' : '') +
-                    field.measure +
-                    ')'
-            }}</small>
-            <span fxFlex></span>
-            <mat-form-field
-                appearance="outline"
-                color="accent"
-                fxFlex="30"
-                class="marginColorFieldMore"
-            >
-                <mat-select
-                    [(value)]="
-                        currentlyConfiguredWidget.visualizationConfig
-                            .chosenAxis[
-                            field.fullDbName + field.sourceIndex.toString()
-                        ]
-                    "
-                    (selectionChange)="triggerViewRefresh()"
+
+        <div fxLayout="row" fxFlex="100">
+            <div fxFlex="30" fxLayoutAlign="start center">
+                <small>Axis</small>
+            </div>
+            <div fxFlex="70" fxLayoutAlign="start center">
+                <mat-form-field
+                    appearance="outline"
+                    color="accent"
+                    class="w-100"
                 >
-                    <mat-option [value]="'left'">Left</mat-option>
-                    <mat-option [value]="'right'">Right</mat-option>
-                </mat-select>
-            </mat-form-field>
+                    <mat-select
+                        [(value)]="
+                            currentlyConfiguredWidget.visualizationConfig
+                                .chosenAxis[
+                                field.fullDbName + field.sourceIndex.toString()
+                            ]
+                        "
+                        (selectionChange)="viewRefreshEmitter.emit()"
+                    >
+                        <mat-option [value]="'left'">Left</mat-option>
+                        <mat-option [value]="'right'">Right</mat-option>
+                    </mat-select>
+                </mat-form-field>
+            </div>
         </div>
     </div>
-</sp-configuration-box>
+</div>
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.scss
similarity index 83%
copy from ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss
copy to ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.scss
index 993720434e..6deadf1192 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.scss
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements.  See the NOTICE file distributed with
  * this work for additional information regarding copyright ownership.
@@ -16,18 +16,18 @@
  *
  */
 
-.marginColorFieldMore {
-    margin-left: 10px;
-    margin-right: 1px;
-}
-
 .color-field {
-    width: 20px;
+    width: 100%;
     height: 20px;
 }
 
-.field-selection-box {
-    border: 1px solid var(--color-bg-3);
-    padding: 5px;
-    margin: 5px;
+.color-indicator {
+    border-radius: 50%;
+    width: 10px;
+    height: 10px;
+    margin-right: 5px;
+}
+
+.ml-10 {
+    margin-left: 10px;
 }
diff --git a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.ts
similarity index 54%
copy from ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
copy to ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.ts
index b2421b4d54..8cc198c5be 100644
--- a/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/select-color-properties.component.ts
+++ b/ui/src/app/data-explorer/components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component.ts
@@ -16,27 +16,32 @@
  *
  */
 
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
-import { WidgetConfigurationService } from '../../../../services/widget-configuration.service';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
 import { DataExplorerField } from '@streampipes/platform-services';
-import { TimeSeriesChartWidgetModel } from '../../time-series-chart/model/time-series-chart-widget.model';
+import { TimeSeriesChartWidgetModel } from '../../../time-series-chart/model/time-series-chart-widget.model';
 
 @Component({
-    selector: 'sp-select-color-properties',
-    templateUrl: './select-color-properties.component.html',
-    styleUrls: ['./select-color-properties.component.scss'],
+    selector: 'sp-time-series-item-config',
+    templateUrl: './time-series-item-config.component.html',
+    styleUrls: ['./time-series-item-config.component.scss'],
 })
-export class SelectColorPropertiesComponent implements OnInit {
-    @Output() changeSelectedProperties: EventEmitter<DataExplorerField[]> =
-        new EventEmitter();
+export class SpTimeseriesItemConfigComponent {
+    @Input()
+    field: DataExplorerField;
 
-    @Input() availableProperties: DataExplorerField[];
-    @Input() selectedProperties: DataExplorerField[];
-    @Input() currentlyConfiguredWidget: TimeSeriesChartWidgetModel;
+    @Input()
+    currentlyConfiguredWidget: TimeSeriesChartWidgetModel;
 
-    constructor(
-        protected widgetConfigurationService: WidgetConfigurationService,
-    ) {}
+    @Input()
+    selectedProperties: DataExplorerField[];
+
+    @Output()
+    viewRefreshEmitter: EventEmitter<void> = new EventEmitter<void>();
+
+    @Output()
+    configChangeEmitter: EventEmitter<DataExplorerField[]> = new EventEmitter<
+        DataExplorerField[]
+    >();
 
     presetColors: string[] = [
         '#39B54A',
@@ -48,38 +53,7 @@ export class SelectColorPropertiesComponent implements OnInit {
         '#000000',
     ];
 
-    ngOnInit(): void {
-        if (!this.selectedProperties) {
-            this.selectedProperties = [];
-        }
-    }
-
-    triggerSelectedProperties() {
-        this.changeSelectedProperties.emit(this.selectedProperties);
-    }
-
-    selectAllFields() {
-        this.selectFields(true);
-    }
-
-    deselectAllFields() {
-        this.selectFields(false);
-    }
-
-    selectFields(selected: boolean) {
-        this.selectedProperties = selected ? this.availableProperties : [];
-        this.triggerSelectedProperties();
-    }
-
-    isSelected(field: DataExplorerField): boolean {
-        return (
-            this.selectedProperties.find(
-                sp =>
-                    sp.fullDbName === field.fullDbName &&
-                    sp.sourceIndex === field.sourceIndex,
-            ) !== undefined
-        );
-    }
+    expanded: boolean = false;
 
     toggleFieldSelection(field: DataExplorerField) {
         if (this.isSelected(field)) {
@@ -93,21 +67,27 @@ export class SelectColorPropertiesComponent implements OnInit {
         } else {
             this.selectedProperties.push(field);
         }
-        this.triggerSelectedProperties();
+        this.configChangeEmitter.emit(this.selectedProperties);
+    }
+
+    isSelected(field: DataExplorerField): boolean {
+        return (
+            this.selectedProperties.find(
+                sp =>
+                    sp.fullDbName === field.fullDbName &&
+                    sp.sourceIndex === field.sourceIndex,
+            ) !== undefined
+        );
     }
 
-    triggerViewRefresh() {
-        this.widgetConfigurationService.notify({
-            widgetId: this.currentlyConfiguredWidget._id,
-            refreshData: false,
-            refreshView: true,
-        });
+    toggleExpand(): void {
+        this.expanded = !this.expanded;
     }
 
     onFilterChange(searchValue: string, field: DataExplorerField): void {
         this.currentlyConfiguredWidget.visualizationConfig.displayName[
             field.fullDbName + field.sourceIndex.toString()
         ] = searchValue;
-        this.triggerViewRefresh();
+        this.viewRefreshEmitter.emit();
     }
 }
diff --git a/ui/src/app/data-explorer/data-explorer.module.ts b/ui/src/app/data-explorer/data-explorer.module.ts
index 4f19079e8d..090270e95d 100644
--- a/ui/src/app/data-explorer/data-explorer.module.ts
+++ b/ui/src/app/data-explorer/data-explorer.module.ts
@@ -87,6 +87,8 @@ import { SpPieChartWidgetConfigComponent } from './components/widgets/pie/config
 import { SpInvalidConfigurationComponent } from './components/widgets/utils/invalid-configuration/invalid-configuration.component';
 import { SpConfigurationBoxComponent } from './components/widgets/utils/layout/configuration-box.component';
 import { SpVisualizationConfigOuterComponent } from './components/widgets/utils/visualization-config-outer/visualization-config-outer.component';
+import { SpSelectAxisOptionsComponent } from './components/widgets/utils/select-axis-options/select-axis-options.component';
+import { SpTimeseriesItemConfigComponent } from './components/widgets/utils/select-color-properties/time-series-item-config/time-series-item-config.component';
 
 @NgModule({
     imports: [
@@ -182,6 +184,8 @@ import { SpVisualizationConfigOuterComponent } from './components/widgets/utils/
         SpInvalidConfigurationComponent,
         SpConfigurationBoxComponent,
         SpVisualizationConfigOuterComponent,
+        SpSelectAxisOptionsComponent,
+        SpTimeseriesItemConfigComponent,
     ],
     providers: [SemanticTypeUtilsService],
     exports: [],
diff --git a/ui/src/app/data-explorer/echarts-renderer/echarts-dataset-generator.service.ts b/ui/src/app/data-explorer/echarts-renderer/echarts-dataset-generator.service.ts
index f41825170e..22debf01ee 100644
--- a/ui/src/app/data-explorer/echarts-renderer/echarts-dataset-generator.service.ts
+++ b/ui/src/app/data-explorer/echarts-renderer/echarts-dataset-generator.service.ts
@@ -127,7 +127,6 @@ export class EchartsDatasetGeneratorService<T extends DataExplorerWidgetModel> {
     ): number {
         return (
             currentDatasetIndex +
-            1 + // raw dataset for each query result
             preparedDataset.initialTransformDatasets.length +
             preparedDataset.groupedDatasets.length +
             1
diff --git a/ui/src/app/data-explorer/models/dataview-dashboard.model.ts b/ui/src/app/data-explorer/models/dataview-dashboard.model.ts
index a935798c0a..ad94850e3a 100644
--- a/ui/src/app/data-explorer/models/dataview-dashboard.model.ts
+++ b/ui/src/app/data-explorer/models/dataview-dashboard.model.ts
@@ -104,6 +104,12 @@ export interface FieldProvider {
     nonNumericFields: DataExplorerField[];
 }
 
+export interface AxisConfig {
+    autoScaleActive: boolean;
+    axisMin: number;
+    axisMax: number;
+}
+
 export interface DataExplorerVisConfig {
     forType?: number | string;
     configurationValid: boolean;
diff --git a/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts b/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts
index d53ddfabf1..4f3661d456 100644
--- a/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts
+++ b/ui/src/app/data-explorer/registry/data-explorer-widget-registry.ts
@@ -50,90 +50,7 @@ import { SpTimeseriesRendererService } from '../components/widgets/time-series-c
 
 @Injectable({ providedIn: 'root' })
 export class DataExplorerWidgetRegistry {
-    widgetTypes: IWidget<any>[] = [
-        {
-            id: 'table',
-            label: 'Table',
-            widgetConfigurationComponent: TableWidgetConfigComponent,
-            widgetComponent: TableWidgetComponent,
-        },
-        {
-            id: 'map',
-            label: 'Map',
-            widgetConfigurationComponent: MapWidgetConfigComponent,
-            widgetComponent: MapWidgetComponent,
-        },
-        {
-            id: 'heatmap',
-            label: 'Time-Series Heatmap',
-            widgetConfigurationComponent: HeatmapWidgetConfigComponent,
-            widgetComponent: SpEchartsWidgetComponent<HeatmapWidgetModel>,
-            chartRenderer: this.heatmapRenderer,
-        },
-        {
-            id: 'time-series-chart',
-            label: 'Time Series Chart',
-            widgetConfigurationComponent: TimeSeriesChartWidgetConfigComponent,
-            widgetComponent:
-                SpEchartsWidgetComponent<TimeSeriesChartWidgetModel>,
-            chartRenderer: this.timeseriesRenderer,
-        },
-        {
-            id: 'image',
-            label: 'Image',
-            widgetConfigurationComponent: ImageWidgetConfigComponent,
-            widgetComponent: ImageWidgetComponent,
-        },
-        {
-            id: 'indicator-chart',
-            label: 'Indicator',
-            widgetConfigurationComponent: IndicatorWidgetConfigComponent,
-            widgetComponent:
-                SpEchartsWidgetComponent<IndicatorChartWidgetModel>,
-            chartRenderer: this.indicatorRenderer,
-        },
-        {
-            id: 'scatter-chart',
-            label: 'Scatter',
-            widgetConfigurationComponent: CorrelationWidgetConfigComponent,
-            widgetComponent:
-                SpEchartsWidgetComponent<CorrelationChartWidgetModel>,
-            chartRenderer: this.scatterRenderer,
-            alias: 'correlation-chart',
-        },
-        {
-            id: 'histogram-chart',
-            label: 'Histogram',
-            widgetConfigurationComponent: SpHistogramChartWidgetConfigComponent,
-            widgetComponent:
-                SpEchartsWidgetComponent<HistogramChartWidgetModel>,
-            chartRenderer: this.histogramRenderer,
-            alias: 'distribution-chart',
-        },
-        {
-            id: 'pie-chart',
-            label: 'Pie',
-            widgetConfigurationComponent: SpPieChartWidgetConfigComponent,
-            widgetComponent: SpEchartsWidgetComponent<PieChartWidgetModel>,
-            chartRenderer: this.pieRenderer,
-        },
-        {
-            id: 'value-heatmap-chart',
-            label: 'Value Distribution Heatmap',
-            widgetConfigurationComponent: SpValueHeatmapWidgetConfigComponent,
-            widgetComponent:
-                SpEchartsWidgetComponent<ValueHeatmapChartWidgetModel>,
-            chartRenderer: this.valueHeatmapRenderer,
-        },
-        {
-            id: 'density-chart',
-            label: '2D Density Contour',
-            widgetConfigurationComponent: CorrelationWidgetConfigComponent,
-            widgetComponent:
-                SpEchartsWidgetComponent<CorrelationChartWidgetModel>,
-            chartRenderer: this.densityRenderer,
-        },
-    ];
+    widgetTypes: IWidget<any>[] = [];
 
     constructor(
         private heatmapRenderer: SpHeatmapRendererService,
@@ -144,7 +61,95 @@ export class DataExplorerWidgetRegistry {
         private densityRenderer: SpDensityRendererService,
         private indicatorRenderer: SpIndicatorRendererService,
         private timeseriesRenderer: SpTimeseriesRendererService,
-    ) {}
+    ) {
+        this.widgetTypes = [
+            {
+                id: 'table',
+                label: 'Table',
+                widgetConfigurationComponent: TableWidgetConfigComponent,
+                widgetComponent: TableWidgetComponent,
+            },
+            {
+                id: 'map',
+                label: 'Map',
+                widgetConfigurationComponent: MapWidgetConfigComponent,
+                widgetComponent: MapWidgetComponent,
+            },
+            {
+                id: 'heatmap',
+                label: 'Time-Series Heatmap',
+                widgetConfigurationComponent: HeatmapWidgetConfigComponent,
+                widgetComponent: SpEchartsWidgetComponent<HeatmapWidgetModel>,
+                chartRenderer: this.heatmapRenderer,
+            },
+            {
+                id: 'time-series-chart',
+                label: 'Time Series Chart',
+                widgetConfigurationComponent:
+                    TimeSeriesChartWidgetConfigComponent,
+                widgetComponent:
+                    SpEchartsWidgetComponent<TimeSeriesChartWidgetModel>,
+                chartRenderer: this.timeseriesRenderer,
+            },
+            {
+                id: 'image',
+                label: 'Image',
+                widgetConfigurationComponent: ImageWidgetConfigComponent,
+                widgetComponent: ImageWidgetComponent,
+            },
+            {
+                id: 'indicator-chart',
+                label: 'Indicator',
+                widgetConfigurationComponent: IndicatorWidgetConfigComponent,
+                widgetComponent:
+                    SpEchartsWidgetComponent<IndicatorChartWidgetModel>,
+                chartRenderer: this.indicatorRenderer,
+            },
+            {
+                id: 'scatter-chart',
+                label: 'Scatter',
+                widgetConfigurationComponent: CorrelationWidgetConfigComponent,
+                widgetComponent:
+                    SpEchartsWidgetComponent<CorrelationChartWidgetModel>,
+                chartRenderer: this.scatterRenderer,
+                alias: 'correlation-chart',
+            },
+            {
+                id: 'histogram-chart',
+                label: 'Histogram',
+                widgetConfigurationComponent:
+                    SpHistogramChartWidgetConfigComponent,
+                widgetComponent:
+                    SpEchartsWidgetComponent<HistogramChartWidgetModel>,
+                chartRenderer: this.histogramRenderer,
+                alias: 'distribution-chart',
+            },
+            {
+                id: 'pie-chart',
+                label: 'Pie',
+                widgetConfigurationComponent: SpPieChartWidgetConfigComponent,
+                widgetComponent: SpEchartsWidgetComponent<PieChartWidgetModel>,
+                chartRenderer: this.pieRenderer,
+            },
+            {
+                id: 'value-heatmap-chart',
+                label: 'Value Distribution Heatmap',
+                widgetConfigurationComponent:
+                    SpValueHeatmapWidgetConfigComponent,
+                widgetComponent:
+                    SpEchartsWidgetComponent<ValueHeatmapChartWidgetModel>,
+                chartRenderer: this.valueHeatmapRenderer,
+            },
+            {
+                id: 'density-chart',
+                label: '2D Density Contour',
+                widgetConfigurationComponent: CorrelationWidgetConfigComponent,
+                widgetComponent:
+                    SpEchartsWidgetComponent<CorrelationChartWidgetModel>,
+                chartRenderer: this.densityRenderer,
+            },
+        ];
+    }
 
     getAvailableWidgetTemplates(): IWidget<any>[] {
         return this.widgetTypes.sort((a, b) => a.label.localeCompare(b.label));