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 2020/03/22 14:35:07 UTC

[incubator-streampipes] branch dev updated: STREAMPIPES-58: Show measurement unit in single value visualizations

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/incubator-streampipes.git


The following commit(s) were added to refs/heads/dev by this push:
     new 6b5c69f  STREAMPIPES-58: Show measurement unit in single value visualizations
6b5c69f is described below

commit 6b5c69fcf32a0202b39cd1938b79b1bcb9f03f4a
Author: Dominik Riemer <ri...@fzi.de>
AuthorDate: Sun Mar 22 15:34:47 2020 +0100

    STREAMPIPES-58: Show measurement unit in single value visualizations
---
 .../backend/StreamPipesResourceConfig.java         | 52 ++++++++++-----------
 streampipes-measurement-units/pom.xml              | 11 +++++
 .../streampipes/units/test/TestUnitProvider.java   | 34 ++++++++++++++
 .../test/java/org/streampipes/units/test/Test.java | 54 ----------------------
 .../java/org/streampipes/units/test/Test2.java     | 49 --------------------
 .../rest/api/IMeasurementUnitResource.java         | 24 ++++++++++
 .../rest/impl/MeasurementUnitResource.java         | 41 ++++++++++++++++
 .../core-model/measurement-unit/MeasurementUnit.ts | 30 ++++++++++++
 .../widgets/area/area-widget.component.ts          |  5 +-
 .../widgets/base/base-ngx-charts-widget.ts         |  5 +-
 .../widgets/base/base-ngx-line-charts-widget.ts    |  5 +-
 .../components/widgets/base/base-widget.ts         |  2 +
 .../widgets/gauge/gauge-widget.component.ts        |  5 +-
 .../widgets/html/html-widget.component.ts          |  5 +-
 .../widgets/image/image-widget.component.ts        |  5 +-
 .../widgets/line/line-widget.component.ts          |  5 +-
 .../components/widgets/map/map-widget.component.ts |  5 +-
 .../components/widgets/number/number-config.ts     |  2 +-
 .../widgets/number/number-widget.component.css     | 13 ++++++
 .../widgets/number/number-widget.component.html    | 11 +++--
 .../widgets/number/number-widget.component.ts      | 22 +++++++--
 .../components/widgets/raw/raw-widget.component.ts |  5 +-
 .../components/widgets/table/table-config.ts       |  1 -
 .../widgets/table/table-widget.component.ts        |  5 +-
 .../trafficlight/traffic-light-widget.component.ts |  5 +-
 .../sdk/extractor/static-property-extractor.ts     |  5 ++
 ui/src/app/dashboard/services/dashboard.service.ts | 11 +++++
 27 files changed, 257 insertions(+), 160 deletions(-)

diff --git a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java
index 09e324e..b8bf526 100644
--- a/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java
+++ b/streampipes-backend/src/main/java/org/apache/streampipes/backend/StreamPipesResourceConfig.java
@@ -28,6 +28,7 @@ import org.apache.streampipes.rest.impl.Couchdb;
 import org.apache.streampipes.rest.impl.DataStream;
 import org.apache.streampipes.rest.impl.Deployment;
 import org.apache.streampipes.rest.impl.InternalPipelineTemplates;
+import org.apache.streampipes.rest.impl.MeasurementUnitResource;
 import org.apache.streampipes.rest.impl.Notification;
 import org.apache.streampipes.rest.impl.OntologyContext;
 import org.apache.streampipes.rest.impl.OntologyKnowledge;
@@ -77,55 +78,54 @@ public class StreamPipesResourceConfig extends ResourceConfig {
   public StreamPipesResourceConfig() {
     register(Authentication.class);
     register(Authentication.class);
+    register(ApplicationLink.class);
     register(AssetDashboard.class);
     register(AutoComplete.class);
-    register(PipelineElementCategory.class);
+    register(ConsulConfig.class);
+    register(ContainerProvidedOptions.class);
+    register(Couchdb.class);
+    register(DashboardWidget.class);
+    register(Dashboard.class);
+    register(DataLakeResourceV3.class);
+    register(DataLakeNoUserResourceV3.class);
+    register(DataStream.class);
     register(Deployment.class);
+    register(FileServingResource.class);
+    register(InternalPipelineTemplates.class);
+    register(MeasurementUnitResource.class);
     register(Notification.class);
     register(OntologyContext.class);
     register(OntologyKnowledge.class);
     register(OntologyMeasurementUnit.class);
     register(OntologyPipelineElement.class);
-    register(PipelineWithUserResource.class);
-    register(PipelineNoUserResource.class);
-    register(PipelineElementImportNoUser.class);
+    register(PipelineCache.class);
     register(PipelineCategory.class);
+    register(PipelineElementAsset.class);
+    register(PipelineElementCategory.class);
+    register(PipelineElementFile.class);
+    register(PipelineElementImportNoUser.class);
     register(PipelineElementImport.class);
+    register(PipelineElementRuntimeInfo.class);
+    register(PipelineNoUserResource.class);
+    register(PipelineTemplate.class);
+    register(PipelineWithUserResource.class);
+    register(RdfEndpoint.class);
     register(SemanticEventConsumer.class);
     register(SemanticEventProcessingAgent.class);
     register(SemanticEventProducer.class);
     register(Setup.class);
-    register(VirtualSensor.class);
-    register(Visualization.class);
-    register(RdfEndpoint.class);
-    register(ApplicationLink.class);
-    register(User.class);
-    register(ConsulConfig.class);
-    register(DataStream.class);
-    register(ContainerProvidedOptions.class);
     register(StreamPipesLogs.class);
-    register(PipelineTemplate.class);
-    register(Couchdb.class);
-    register(InternalPipelineTemplates.class);
-    register(PipelineElementRuntimeInfo.class);
+    register(User.class);
     register(Version.class);
-    register(PipelineElementAsset.class);
-    register(DataLakeResourceV3.class);
-    register(DataLakeNoUserResourceV3.class);
-    register(PipelineElementFile.class);
-    register(FileServingResource.class);
-    register(DashboardWidget.class);
-    register(Dashboard.class);
+    register(VirtualSensor.class);
+    register(Visualization.class);
     register(VisualizablePipeline.class);
-    register(PipelineCache.class);
-
 
     // Serializers
     register(GsonWithIdProvider.class);
     register(GsonWithoutIdProvider.class);
     register(GsonClientModelProvider.class);
     register(JsonLdProvider.class);
-
     register(MultiPartFeature.class);
   }
 
diff --git a/streampipes-measurement-units/pom.xml b/streampipes-measurement-units/pom.xml
index ff7f94e..cfa8297 100644
--- a/streampipes-measurement-units/pom.xml
+++ b/streampipes-measurement-units/pom.xml
@@ -43,5 +43,16 @@
 			<groupId>org.eclipse.rdf4j</groupId>
 			<artifactId>rdf4j-rio-rdfxml</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.eclipse.rdf4j</groupId>
+			<artifactId>rdf4j-rio-turtle</artifactId>
+		</dependency>
+
+		<!--Test dependencies-->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 </project>
\ No newline at end of file
diff --git a/streampipes-measurement-units/src/test/java/org/apache/streampipes/units/test/TestUnitProvider.java b/streampipes-measurement-units/src/test/java/org/apache/streampipes/units/test/TestUnitProvider.java
new file mode 100644
index 0000000..878082e
--- /dev/null
+++ b/streampipes-measurement-units/src/test/java/org/apache/streampipes/units/test/TestUnitProvider.java
@@ -0,0 +1,34 @@
+/*
+ *   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.
+ */
+
+package org.apache.streampipes.units.test;
+
+import static org.junit.Assert.assertEquals;
+
+import com.github.jqudt.Unit;
+import org.apache.streampipes.units.UnitProvider;
+import org.junit.Test;
+
+public class TestUnitProvider {
+
+	@Test
+	public void testUnitProvider() {
+		Unit unit = UnitProvider.INSTANCE.getUnit("http://qudt.org/vocab/unit#KilometerPerHour");
+		assertEquals("Kilometer per Hour", unit.getLabel());
+		assertEquals("km/hr", unit.getAbbreviation());
+	}
+}
diff --git a/streampipes-measurement-units/src/test/java/org/streampipes/units/test/Test.java b/streampipes-measurement-units/src/test/java/org/streampipes/units/test/Test.java
deleted file mode 100644
index 862ba59..0000000
--- a/streampipes-measurement-units/src/test/java/org/streampipes/units/test/Test.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.
- *
- */
-
-package org.apache.streampipes.units.test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-import com.github.jqudt.Quantity;
-import com.github.jqudt.Unit;
-import com.github.jqudt.onto.UnitFactory;
-import com.github.jqudt.onto.units.TemperatureUnit;
-
-import org.apache.streampipes.units.UnitCollector;
-
-public class Test {
-
-	public static void main(String[] args ) throws IllegalArgumentException, IllegalAccessException {
-		Quantity temp = new Quantity(20, TemperatureUnit.CELSIUS);
-		System.out.println(temp + " = " +  temp.convertTo(TemperatureUnit.KELVIN));
-		
-		
-		List<String> units = UnitFactory.getInstance().getURIs("http://qudt.org/schema/qudt#ThermodynamicsUnit");
-		units.forEach(u -> System.out.println("\"" +u.replace("http://qudt.org/schema/qudt#", "") +"\","));
-//		
-//		Unit unit = UnitFactory.getInstance().getUnit("http://qudt.org/vocab/unit#BaseUnit");
-//		System.out.println(uniSet<E>etLabel());
-		
-		Set<Unit> us = new UnitCollector().getAvailableUnits();
-		System.out.println(us.size());
-		//us.forEach(u -> System.out.println(u.getLabel()));
-		
-		List<Unit> all = new ArrayList<>();
-		all.addAll(us);
-		//all.get(3).
-		
-	}
-}
diff --git a/streampipes-measurement-units/src/test/java/org/streampipes/units/test/Test2.java b/streampipes-measurement-units/src/test/java/org/streampipes/units/test/Test2.java
deleted file mode 100644
index 1fd5e69..0000000
--- a/streampipes-measurement-units/src/test/java/org/streampipes/units/test/Test2.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.
- *
- */
-
-package org.apache.streampipes.units.test;
-
-import com.github.jqudt.Quantity;
-import com.github.jqudt.Unit;
-import org.apache.streampipes.units.UnitProvider;
-
-import java.util.List;
-
-public class Test2 {
-
-    public static void main(String[] args ) throws IllegalArgumentException, IllegalAccessException {
-        List<Unit> availableUnits = UnitProvider.INSTANCE.getAvailableUnits();
-
-        Unit unit = UnitProvider.INSTANCE.getUnit("http://qudt.org/vocab/unit#DegreeCelsius");
-Unit outUnit = UnitProvider.INSTANCE.getUnit("http://qudt.org/vocab/unit#DegreeFahrenheit");
-
-        double value = 32.0;
-
-        Quantity obs = new Quantity(value, unit);
-        double newValue = obs.convertTo(outUnit).getValue();
-        System.out.println(newValue);
-
-        //System.out.println(unit.getResource().equals(unit2.getResource()));
-
-        //UnitProvider.INSTANCE.getUnitByLabel("Kelvin");
-        //UnitProvider.INSTANCE.getUnitByLabel("Degree Celsius12");
-
-
-    }
-
-}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IMeasurementUnitResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IMeasurementUnitResource.java
new file mode 100644
index 0000000..6db83c3
--- /dev/null
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/api/IMeasurementUnitResource.java
@@ -0,0 +1,24 @@
+/*
+ *   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.
+ */
+package org.apache.streampipes.rest.api;
+
+import javax.ws.rs.core.Response;
+
+public interface IMeasurementUnitResource {
+
+  Response getMeasurementUnitInfo(String measurementResourceUri);
+}
diff --git a/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/MeasurementUnitResource.java b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/MeasurementUnitResource.java
new file mode 100644
index 0000000..8f6707c
--- /dev/null
+++ b/streampipes-rest/src/main/java/org/apache/streampipes/rest/impl/MeasurementUnitResource.java
@@ -0,0 +1,41 @@
+/*
+ *   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.
+ */
+package org.apache.streampipes.rest.impl;
+
+import org.apache.streampipes.rest.api.IMeasurementUnitResource;
+import org.apache.streampipes.rest.shared.annotation.GsonWithIds;
+import org.apache.streampipes.units.UnitProvider;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/v2/users/{username}/measurement-units")
+public class MeasurementUnitResource extends AbstractRestInterface implements IMeasurementUnitResource {
+
+  @GET
+  @Path("/{measurementResourceUri}")
+  @Produces(MediaType.APPLICATION_JSON)
+  @GsonWithIds
+  @Override
+  public Response getMeasurementUnitInfo(@PathParam("measurementResourceUri") String measurementResourceUri) {
+    return ok(UnitProvider.INSTANCE.getUnit(measurementResourceUri));
+  }
+}
diff --git a/ui/src/app/core-model/measurement-unit/MeasurementUnit.ts b/ui/src/app/core-model/measurement-unit/MeasurementUnit.ts
new file mode 100644
index 0000000..5d25a5e
--- /dev/null
+++ b/ui/src/app/core-model/measurement-unit/MeasurementUnit.ts
@@ -0,0 +1,30 @@
+/*
+ *   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.
+ */
+
+export interface MeasurementUnit {
+    resource: string;
+    label: string;
+    abbreviation: string;
+    symbol: string;
+    type: string;
+    multiplier: MeasurementUnitMultiplier;
+}
+
+export interface MeasurementUnitMultiplier {
+    offset: number;
+    multiplier: number;
+}
\ No newline at end of file
diff --git a/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts b/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts
index aaa6db0..7deb068 100644
--- a/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/area/area-widget.component.ts
@@ -20,6 +20,7 @@ import {Component, OnDestroy, OnInit} from "@angular/core";
 import {BaseNgxLineChartsStreamPipesWidget} from "../base/base-ngx-line-charts-widget";
 import {RxStompService} from "@stomp/ng2-stompjs";
 import {ResizeService} from "../../../services/resize.service";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'area-widget',
@@ -28,8 +29,8 @@ import {ResizeService} from "../../../services/resize.service";
 })
 export class AreaWidgetComponent extends BaseNgxLineChartsStreamPipesWidget implements OnInit, OnDestroy {
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/base/base-ngx-charts-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-ngx-charts-widget.ts
index 883576d..7ab1578 100644
--- a/ui/src/app/dashboard/components/widgets/base/base-ngx-charts-widget.ts
+++ b/ui/src/app/dashboard/components/widgets/base/base-ngx-charts-widget.ts
@@ -21,6 +21,7 @@ import {RxStompService} from "@stomp/ng2-stompjs";
 import {ResizeService} from "../../../services/resize.service";
 import {GridsterInfo} from "../../../models/gridster-info.model";
 import {GridsterItemComponent} from "angular-gridster2";
+import {DashboardService} from "../../../services/dashboard.service";
 
 export abstract class BaseNgxChartsStreamPipesWidget extends BaseStreamPipesWidget {
 
@@ -29,8 +30,8 @@ export abstract class BaseNgxChartsStreamPipesWidget extends BaseStreamPipesWidg
 
     colorScheme: any;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService, true);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService, true);
     }
 
     ngOnInit() {
diff --git a/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts
index 03d0172..beb8153 100644
--- a/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts
+++ b/ui/src/app/dashboard/components/widgets/base/base-ngx-line-charts-widget.ts
@@ -21,6 +21,7 @@ import {ResizeService} from "../../../services/resize.service";
 import {BaseNgxChartsStreamPipesWidget} from "./base-ngx-charts-widget";
 import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
 import {LineConfig} from "../line/line-config";
+import {DashboardService} from "../../../services/dashboard.service";
 
 export abstract class BaseNgxLineChartsStreamPipesWidget extends BaseNgxChartsStreamPipesWidget {
 
@@ -31,8 +32,8 @@ export abstract class BaseNgxLineChartsStreamPipesWidget extends BaseNgxChartsSt
     minYAxisRange: number;
     maxYAxisRange: number;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/base/base-widget.ts b/ui/src/app/dashboard/components/widgets/base/base-widget.ts
index 7b2e057..51b15c7 100644
--- a/ui/src/app/dashboard/components/widgets/base/base-widget.ts
+++ b/ui/src/app/dashboard/components/widgets/base/base-widget.ts
@@ -28,6 +28,7 @@ import {WidgetConfigBuilder} from "../../../registry/widget-config-builder";
 import {VisualizablePipeline} from "../../../../core-model/dashboard/VisualizablePipeline";
 import {ResizeService} from "../../../services/resize.service";
 import {GridsterInfo} from "../../../models/gridster-info.model";
+import {DashboardService} from "../../../services/dashboard.service";
 
 export abstract class BaseStreamPipesWidget implements OnChanges {
 
@@ -57,6 +58,7 @@ export abstract class BaseStreamPipesWidget implements OnChanges {
 
 
     protected constructor(private rxStompService: RxStompService,
+                          protected dashboardService: DashboardService,
                           protected resizeService: ResizeService,
                           protected adjustPadding: boolean) {
     }
diff --git a/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts b/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts
index 09a4121..f224350 100644
--- a/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/gauge/gauge-widget.component.ts
@@ -22,6 +22,7 @@ import {RxStompService} from "@stomp/ng2-stompjs";
 import {ResizeService} from "../../../services/resize.service";
 import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
 import {GaugeConfig} from "./gauge-config";
+import {DashboardService} from "../../../services/dashboard.service";
 
 
 @Component({
@@ -37,8 +38,8 @@ export class GaugeWidgetComponent extends BaseNgxChartsStreamPipesWidget impleme
 
     selectedProperty: string;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService, private el: ElementRef) {
-        super(rxStompService, resizeService);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService, private el: ElementRef) {
+        super(rxStompService, dashboardService, resizeService);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts b/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts
index 8a1a133..b8925c4 100644
--- a/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/html/html-widget.component.ts
@@ -21,6 +21,7 @@ import {BaseStreamPipesWidget} from "../base/base-widget";
 import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
 import {ResizeService} from "../../../services/resize.service";
 import {HtmlConfig} from "./html-config";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'html-widget',
@@ -35,8 +36,8 @@ export class HtmlWidgetComponent extends BaseStreamPipesWidget implements OnInit
 
     selectedHtmlField: string;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService, false);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService, false);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts b/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts
index 6725eea..00d5b6f 100644
--- a/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/image/image-widget.component.ts
@@ -22,6 +22,7 @@ import {RxStompService} from "@stomp/ng2-stompjs";
 import {ResizeService} from "../../../services/resize.service";
 import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
 import {GaugeConfig} from "../gauge/gauge-config";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'image-widget',
@@ -34,8 +35,8 @@ export class ImageWidgetComponent extends BaseNgxChartsStreamPipesWidget impleme
     title: string;
     selectedProperty: string;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/line/line-widget.component.ts b/ui/src/app/dashboard/components/widgets/line/line-widget.component.ts
index d007165..610691e 100644
--- a/ui/src/app/dashboard/components/widgets/line/line-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/line/line-widget.component.ts
@@ -20,6 +20,7 @@ import {Component, OnDestroy, OnInit} from "@angular/core";
 import {RxStompService} from "@stomp/ng2-stompjs";
 import {ResizeService} from "../../../services/resize.service";
 import {BaseNgxLineChartsStreamPipesWidget} from "../base/base-ngx-line-charts-widget";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'line-widget',
@@ -28,8 +29,8 @@ import {BaseNgxLineChartsStreamPipesWidget} from "../base/base-ngx-line-charts-w
 })
 export class LineWidgetComponent extends BaseNgxLineChartsStreamPipesWidget implements OnInit, OnDestroy {
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts b/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts
index 61da91c..a579bc2 100644
--- a/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/map/map-widget.component.ts
@@ -22,6 +22,7 @@ import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-ex
 import {MapConfig} from "./map-config";
 import {latLng, marker, Marker, tileLayer, Map, LatLngExpression, LatLng, icon, Content} from "leaflet";
 import {ResizeService} from "../../../services/resize.service";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'map-widget',
@@ -52,8 +53,8 @@ export class MapWidgetComponent extends BaseStreamPipesWidget implements OnInit,
         center: latLng(46.879966, -121.726909)
     };
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService, false);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService, false);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/number/number-config.ts b/ui/src/app/dashboard/components/widgets/number/number-config.ts
index 0f439f4..5a29d69 100644
--- a/ui/src/app/dashboard/components/widgets/number/number-config.ts
+++ b/ui/src/app/dashboard/components/widgets/number/number-config.ts
@@ -35,7 +35,7 @@ export class NumberConfig extends WidgetConfig {
             .withDescription("Displays a single number or text value")
             .requiredSchema(SchemaRequirementsBuilder
                 .create()
-                .requiredPropertyWithUnaryMapping(NumberConfig.NUMBER_MAPPING_KEY, "Select property", "", EpRequirements.numberReq())
+                .requiredPropertyWithUnaryMapping(NumberConfig.NUMBER_MAPPING_KEY, "Select property", "", EpRequirements.anyProperty())
                 .build())
             .build();
     }
diff --git a/ui/src/app/dashboard/components/widgets/number/number-widget.component.css b/ui/src/app/dashboard/components/widgets/number/number-widget.component.css
index eaf8444..1e3bf58 100644
--- a/ui/src/app/dashboard/components/widgets/number/number-widget.component.css
+++ b/ui/src/app/dashboard/components/widgets/number/number-widget.component.css
@@ -31,6 +31,19 @@
     font-weight:bold;
 }
 
+.measurementUnitItem {
+    font-size: 20px;
+    display:flex;
+    justify-content: center;
+}
+
 .title-panel {
     font-size:20px;
+}
+
+.value-panel {
+    display:flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
 }
\ No newline at end of file
diff --git a/ui/src/app/dashboard/components/widgets/number/number-widget.component.html b/ui/src/app/dashboard/components/widgets/number/number-widget.component.html
index 0550f87..515775d 100644
--- a/ui/src/app/dashboard/components/widgets/number/number-widget.component.html
+++ b/ui/src/app/dashboard/components/widgets/number/number-widget.component.html
@@ -20,8 +20,13 @@
     <div class="title-panel" *ngIf="hasTitlePanelSettings">
         {{selectedTitle}}
     </div>
-    <div class="numberItem">
-        <div *ngIf="isNumber(item)">{{item}}</div>
-        <div *ngIf="!isNumber(item)">{{item}}</div>
+    <div class="value-panel">
+        <div class="numberItem">
+            <div *ngIf="isNumber(item)">{{item}}</div>
+            <div *ngIf="!isNumber(item)">{{item}}</div>
+        </div>
+        <div class="measurementUnitItem" *ngIf="measurementUnitAbbrev">
+            {{measurementUnitAbbrev}}
+        </div>
     </div>
 </div>
diff --git a/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts b/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts
index 28e1373..f466066 100644
--- a/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/number/number-widget.component.ts
@@ -22,6 +22,9 @@ import {BaseStreamPipesWidget} from "../base/base-widget";
 import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
 import {NumberConfig} from "./number-config";
 import {ResizeService} from "../../../services/resize.service";
+import {EventProperty} from "../../../../connect/schema-editor/model/EventProperty";
+import {EventPropertyPrimitive} from "../../../../connect/schema-editor/model/EventPropertyPrimitive";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'number-widget',
@@ -30,12 +33,13 @@ import {ResizeService} from "../../../services/resize.service";
 })
 export class NumberWidgetComponent extends BaseStreamPipesWidget implements OnInit, OnDestroy {
 
-    item: any;
+    item: any = "-";
 
     selectedProperty: string;
+    measurementUnitAbbrev: string;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService, false);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService, false);
     }
 
     ngOnInit(): void {
@@ -48,6 +52,12 @@ export class NumberWidgetComponent extends BaseStreamPipesWidget implements OnIn
 
     extractConfig(extractor: StaticPropertyExtractor) {
         this.selectedProperty = extractor.mappingPropertyValue(NumberConfig.NUMBER_MAPPING_KEY);
+        let eventProperty: EventPropertyPrimitive = extractor.getEventPropertyByName(this.selectedProperty) as EventPropertyPrimitive;
+        if (eventProperty.measurementUnit) {
+            this.dashboardService.getMeasurementUnitInfo(eventProperty.measurementUnit).subscribe(unit => {
+                this.measurementUnitAbbrev = unit.abbreviation;
+            })
+        }
     }
 
     isNumber(item: any): boolean {
@@ -55,7 +65,11 @@ export class NumberWidgetComponent extends BaseStreamPipesWidget implements OnIn
     }
 
     protected onEvent(event: any) {
-        this.item = event[this.selectedProperty];
+        let value = event[this.selectedProperty];
+        if (!isNaN(value)) {
+            value = value.toFixed(2);
+        }
+        this.item = value;
     }
 
     protected onSizeChanged(width: number, height: number) {
diff --git a/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts b/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts
index d288d51..6539238 100644
--- a/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/raw/raw-widget.component.ts
@@ -20,6 +20,7 @@ import {RxStompService} from "@stomp/ng2-stompjs";
 import {BaseStreamPipesWidget} from "../base/base-widget";
 import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
 import {ResizeService} from "../../../services/resize.service";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'raw-widget',
@@ -32,8 +33,8 @@ export class RawWidgetComponent extends BaseStreamPipesWidget implements OnInit,
     width: number;
     height: number;
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService, false);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService, false);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/table/table-config.ts b/ui/src/app/dashboard/components/widgets/table/table-config.ts
index e7be6c5..284ba1e 100644
--- a/ui/src/app/dashboard/components/widgets/table/table-config.ts
+++ b/ui/src/app/dashboard/components/widgets/table/table-config.ts
@@ -39,7 +39,6 @@ export class TableConfig extends WidgetConfig {
                 .create()
                 .requiredPropertyWithNaryMapping(TableConfig.SELECTED_PROPERTIES_KEYS, "Select properties", "", EpRequirements.anyProperty())
                 .build())
-            .requiredTextParameter(TableConfig.TITLE_KEY, "Title", "The title")
             .build();
     }
 
diff --git a/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts b/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts
index 17185f2..102a766 100644
--- a/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/table/table-widget.component.ts
@@ -24,6 +24,7 @@ import {MatTableDataSource} from "@angular/material/table";
 import {TableConfig} from "./table-config";
 import {SemanticTypeUtilsService} from "../../../../core-services/semantic-type/semantic-type-utils.service";
 import {ResizeService} from "../../../services/resize.service";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'table-widget',
@@ -38,8 +39,8 @@ export class TableWidgetComponent extends BaseStreamPipesWidget implements OnIni
     dataSource = new MatTableDataSource();
     semanticTypes: { [key: string]: string; } = {};
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService, private semanticTypeUtils: SemanticTypeUtilsService) {
-        super(rxStompService, resizeService, false);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService, private semanticTypeUtils: SemanticTypeUtilsService) {
+        super(rxStompService, dashboardService, resizeService, false);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts b/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts
index 17083e7..df164a0 100644
--- a/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts
+++ b/ui/src/app/dashboard/components/widgets/trafficlight/traffic-light-widget.component.ts
@@ -21,6 +21,7 @@ import {BaseStreamPipesWidget} from "../base/base-widget";
 import {StaticPropertyExtractor} from "../../../sdk/extractor/static-property-extractor";
 import {ResizeService} from "../../../services/resize.service";
 import {TrafficLightConfig} from "./traffic-light-config";
+import {DashboardService} from "../../../services/dashboard.service";
 
 @Component({
     selector: 'traffic-light-widget',
@@ -46,8 +47,8 @@ export class TrafficLightWidgetComponent extends BaseStreamPipesWidget implement
 
     activeClass = 'red';
 
-    constructor(rxStompService: RxStompService, resizeService: ResizeService) {
-        super(rxStompService, resizeService, false);
+    constructor(rxStompService: RxStompService, dashboardService: DashboardService, resizeService: ResizeService) {
+        super(rxStompService, dashboardService, resizeService, false);
     }
 
     ngOnInit(): void {
diff --git a/ui/src/app/dashboard/sdk/extractor/static-property-extractor.ts b/ui/src/app/dashboard/sdk/extractor/static-property-extractor.ts
index 00af63c..ef52c75 100644
--- a/ui/src/app/dashboard/sdk/extractor/static-property-extractor.ts
+++ b/ui/src/app/dashboard/sdk/extractor/static-property-extractor.ts
@@ -23,6 +23,7 @@ import {FreeTextStaticProperty} from "../../../connect/model/FreeTextStaticPrope
 import {ColorPickerStaticProperty} from "../../../connect/model/ColorPickerStaticProperty";
 import {MappingPropertyNary} from "../../../connect/model/MappingPropertyNary";
 import {OneOfStaticProperty} from "../../../connect/model/OneOfStaticProperty";
+import {EventProperty} from "../../../connect/schema-editor/model/EventProperty";
 
 export class StaticPropertyExtractor {
 
@@ -83,6 +84,10 @@ export class StaticPropertyExtractor {
         return this.staticProperties.find(sp => (sp.internalName == internalId));
     }
 
+    getEventPropertyByName(runtimeName: string): EventProperty {
+        return this.inputSchema.eventProperties.find(ep => ep.runtimeName === runtimeName);
+    }
+
 
     removePrefix(propertyValue: string) {
         return propertyValue.split("::").length > 1 ? propertyValue.split("::")[1] : propertyValue;
diff --git a/ui/src/app/dashboard/services/dashboard.service.ts b/ui/src/app/dashboard/services/dashboard.service.ts
index a4f1d63..e9f6200 100644
--- a/ui/src/app/dashboard/services/dashboard.service.ts
+++ b/ui/src/app/dashboard/services/dashboard.service.ts
@@ -25,6 +25,7 @@ import {Dashboard} from "../models/dashboard.model";
 import {TsonLdSerializerService} from "../../platform-services/tsonld-serializer.service";
 import {DashboardWidget} from "../../core-model/dashboard/DashboardWidget";
 import {VisualizablePipeline} from "../../core-model/dashboard/VisualizablePipeline";
+import {MeasurementUnit} from "../../core-model/measurement-unit/MeasurementUnit";
 
 @Injectable()
 export class DashboardService {
@@ -83,6 +84,12 @@ export class DashboardService {
         })
     }
 
+    getMeasurementUnitInfo(measurementUnitResource: string): Observable<MeasurementUnit> {
+        return this.http.get(this.measurementUnitsUrl  + "/" + encodeURIComponent(measurementUnitResource)).map(data => {
+            return data as MeasurementUnit
+        });
+    }
+
     updateDashboard(dashboard: Dashboard): Observable<Dashboard> {
         return this.http.put(this.dashboardUrl + "/" +dashboard._id, dashboard).map(data => {
             return data as Dashboard;
@@ -101,6 +108,10 @@ export class DashboardService {
         return '/streampipes-backend';
     }
 
+    private get measurementUnitsUrl() {
+        return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/measurement-units'
+    }
+
     private get dashboardUrl() {
         return this.baseUrl + '/api/v2/users/' + this.authStatusService.email + '/ld/dashboards'
     }