From a81220f2f0fdde486fc09162e84ecf2e814b30da Mon Sep 17 00:00:00 2001 From: Sina Blattmann Date: Fri, 30 Jun 2023 09:02:55 +0200 Subject: [PATCH] fix interpolate bug, fix graph bugs, remove modebar buttons --- typescript/Frontend/package-lock.json | 24 +++- typescript/Frontend/package.json | 3 +- .../Installations/Log/ScalarGraph.tsx | 16 ++- .../Installations/Log/TopologyBox.tsx | 135 +++++++++--------- .../Installations/Log/TopologyFlow.tsx | 4 +- .../Frontend/src/dataCache/dataCache.ts | 26 ++-- typescript/Frontend/src/util/graph.util.tsx | 56 ++++++-- 7 files changed, 163 insertions(+), 101 deletions(-) diff --git a/typescript/Frontend/package-lock.json b/typescript/Frontend/package-lock.json index d36bf3040..5b160b6da 100644 --- a/typescript/Frontend/package-lock.json +++ b/typescript/Frontend/package-lock.json @@ -57,7 +57,8 @@ "@formatjs/cli": "^6.0.3", "@types/react-plotly.js": "^2.6.0", "@types/react-window": "^1.8.5", - "eslint-plugin-formatjs": "^4.10.1" + "eslint-plugin-formatjs": "^4.10.1", + "prettier": "^2.8.8" } }, "node_modules/@adobe/css-tools": { @@ -19743,6 +19744,21 @@ "node": ">=0.10.0" } }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -39706,6 +39722,12 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha512-PhmXi5XmoyKw1Un4E+opM2KcsJInDvKyuOumcjjw3waw86ZNjHwVUOOWLc4bCzLdcKNaWBH9e99sbWzDQsVaYg==" }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", diff --git a/typescript/Frontend/package.json b/typescript/Frontend/package.json index 900de2c7a..e9719afc3 100644 --- a/typescript/Frontend/package.json +++ b/typescript/Frontend/package.json @@ -85,6 +85,7 @@ "@formatjs/cli": "^6.0.3", "@types/react-plotly.js": "^2.6.0", "@types/react-window": "^1.8.5", - "eslint-plugin-formatjs": "^4.10.1" + "eslint-plugin-formatjs": "^4.10.1", + "prettier": "^2.8.8" } } diff --git a/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx b/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx index 334688921..89a559628 100644 --- a/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx +++ b/typescript/Frontend/src/components/Installations/Log/ScalarGraph.tsx @@ -16,7 +16,7 @@ import { S3Access } from "../../../dataCache/S3/S3Access"; import DataCache, { FetchResult } from "../../../dataCache/dataCache"; import { LogContext } from "../../Context/LogContextProvider"; import { isDefined } from "../../../dataCache/utils/maybe"; -import { Data, Layout, PlotRelayoutEvent } from "plotly.js"; +import { Data, Icons, Layout, PlotRelayoutEvent, relayout } from "plotly.js"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { FormattedMessage } from "react-intl"; import DateRangePicker from "./DateRangePicker"; @@ -45,6 +45,7 @@ export const fetchData = ( return Promise.resolve(FetchResult.notAvailable); } else if (r.status === 200) { const text = await r.text(); + console.log("parsecsv", text, parseCsv(text)); return parseCsv(text); } else { console.error("unexpected status code"); @@ -153,6 +154,7 @@ const ScalarGraph = () => { const handleRelayout = useCallback( (params: PlotRelayoutEvent) => { + console.log("relayout"); const xaxisRange0 = params["xaxis.range[0]"]; const xaxisRange1 = params["xaxis.range[1]"]; if (xaxisRange0 && xaxisRange1) { @@ -169,11 +171,8 @@ const ScalarGraph = () => { if (checkedToggles.length > 0) { const coordinateTimeSeries = transformToGraphData(timeSeries); const visibleGraphs = Object.keys(coordinateTimeSeries).filter((path) => { - console.log('checkedToggles',coordinateTimeSeries, checkedToggles) - return checkedToggles.find((toggle) => toggle === path) - } - ); - console.log('visibleGraphs', visibleGraphs) + return checkedToggles.find((toggle) => toggle === path); + }); if (visibleGraphs.length > 0) { return (
@@ -186,6 +185,8 @@ const ScalarGraph = () => { {visibleGraphs.map((path) => { const isScalar = isNumeric(coordinateTimeSeries[path].y[0]); + console.log("graphdata", timeSeries, coordinateTimeSeries); + const data = isScalar ? [ { @@ -203,7 +204,6 @@ const ScalarGraph = () => { barnorm: "percent", } : {}; - console.log("graphdata", coordinateTimeSeries); return ( { "select2d", "pan2d", "autoScale2d", + "resetScale2d", + "zoom2d", ], }} onRelayout={handleRelayout} diff --git a/typescript/Frontend/src/components/Installations/Log/TopologyBox.tsx b/typescript/Frontend/src/components/Installations/Log/TopologyBox.tsx index 3eb85a039..9f6a87ac2 100644 --- a/typescript/Frontend/src/components/Installations/Log/TopologyBox.tsx +++ b/typescript/Frontend/src/components/Installations/Log/TopologyBox.tsx @@ -1,79 +1,86 @@ -import {Box} from "@mui/material"; -import {getBoxColor} from "../../../util/graph.util"; +import { Box } from "@mui/material"; +import { getBoxColor } from "../../../util/graph.util"; + +export interface BoxDataValue { + unit: string; + value: string | number; +} export type BoxData = { - label: string; - values: (string | number)[]; - unit: string; + label: string; + values: BoxDataValue[]; }; export type TopologyBoxProps = { - title?: string; - data?: BoxData; + title?: string; + data?: BoxData; }; const isInt = (value: number) => { - return value % 1 === 0; + return value % 1 === 0; }; export const BOX_SIZE = 85; const TopologyBox = (props: TopologyBoxProps) => { - const {titleColor, boxColor} = getBoxColor(props.title); - return ( - -

- {props.title} -

-
- {props.data && ( - <> - {props.data.values.map((value, index) => { - return ( -

{`${ - props.data && props.data.values.length === 3 - ? "L" + (index + 1) + " " - : "" - }${ - !isInt(Number(value)) ? Number(value).toPrecision(4) : value - }${props.data?.unit}`}

- ); - })} - - )} -
-
- ); + const { titleColor, boxColor } = getBoxColor(props.title); + return ( + +

+ {props.title} +

+
+ {props.data && ( + <> + {props.data.values.map((boxData, index) => { + console.log("boxData", boxData); + return ( +

{`${ + props.data && props.data.values.length === 3 + ? "L" + (index + 1) + " " + : "" + }${ + !isInt(Number(boxData.value)) + ? Number(boxData.value).toPrecision(4) + : boxData.value + }${boxData.unit}`}

+ ); + })} + + )} +
+
+ ); }; export default TopologyBox; diff --git a/typescript/Frontend/src/components/Installations/Log/TopologyFlow.tsx b/typescript/Frontend/src/components/Installations/Log/TopologyFlow.tsx index 4f3912382..cc077eee4 100644 --- a/typescript/Frontend/src/components/Installations/Log/TopologyFlow.tsx +++ b/typescript/Frontend/src/components/Installations/Log/TopologyFlow.tsx @@ -43,9 +43,9 @@ const TopologyFlow = (props: TopologyFlowProps) => { }} > {values - ?.filter((value) => (value as number) !== 0) + ?.filter((boxData) => (boxData.value as number) !== 0) .map( - (value) => `${Math.round(value as number)} ${props.data?.unit}` + (boxData) => `${Math.round(boxData.value as number)} ${boxData.unit}` )}

> { const n = after.index - t; const pn = p + n; - let interpolated: Partial> = {}; + let interpolated: Record = {}; //What about string nodes? like Alarms for (const k of Object.keys(dataBefore)) { - const beforeData = dataBefore[k].value; - const afterData = Number(dataAfter[k].value); - let foo = interpolated[k]; - if (foo) { - foo.value = isNumber(beforeData) - ? (beforeData * n + afterData * p) / pn - : n < p - ? afterData - : beforeData; + const valueBefore = dataBefore[k].value; + const valueAfter = dataAfter[k]?.value as Maybe; + + let value: number | string; + + if (isUndefined(valueAfter)) { + value = valueBefore; + } else if (isNumber(valueBefore) && isNumber(valueAfter)) { + value = (valueBefore * n + valueAfter * p) / pn; + } else { + value = n < p ? valueAfter : valueBefore; } + + interpolated[k] = { value, unit: dataBefore[k].unit }; } return interpolated as T; diff --git a/typescript/Frontend/src/util/graph.util.tsx b/typescript/Frontend/src/util/graph.util.tsx index 9df5afb52..2c081982d 100644 --- a/typescript/Frontend/src/util/graph.util.tsx +++ b/typescript/Frontend/src/util/graph.util.tsx @@ -1,11 +1,12 @@ import { Datum, TypedArray } from "plotly.js"; -import { - TreeElement, -} from "../components/Installations/Log/CheckboxTree"; +import { TreeElement } from "../components/Installations/Log/CheckboxTree"; import { TimeRange, UnixTime } from "../dataCache/time"; import { DataPoint, DataRecord } from "../dataCache/data"; import { isDefined } from "../dataCache/utils/maybe"; -import { BoxData } from "../components/Installations/Log/TopologyBox"; +import { + BoxData, + BoxDataValue, +} from "../components/Installations/Log/TopologyBox"; export interface GraphCoordinates { x: Datum[] | Datum[][] | TypedArray; @@ -30,6 +31,7 @@ export const createTimes = ( ); return roundedRange.sample(oneSpan); }; + export interface GraphData { [path: string]: GraphCoordinates; } @@ -95,6 +97,7 @@ interface BoxColor { titleColor: string; boxColor: string; } + export const getBoxColor = (boxTitle?: string): BoxColor => { switch (boxTitle) { case "Grid": @@ -138,18 +141,33 @@ export const extractTopologyValues = ( const timeSeriesValue = timeSeriesData.value; if (isDefined(timeSeriesValue)) { return Object.keys(topologyPaths).reduce((acc, topologyKey) => { - let topologyValues: (string | number)[]; + let topologyValues: BoxDataValue[]; const values = topologyPaths[topologyKey as keyof TopologyValues].map( (topologyPath) => timeSeriesValue[topologyPath] ); switch (topologyKey as keyof TopologyValues) { case "gridToAcInConnection": topologyValues = [ - values.reduce((acc, curr) => Number(acc) + Number(curr.value), 0), + values.reduce( + (acc, curr) => { + return { + value: Number(acc.value) + Number(curr.value), + unit: acc.unit, + }; + }, + { value: 0, unit: values[0].unit } + ), ]; break; default: - topologyValues = values.map((element) => element.value); + topologyValues = values + .filter((element) => element) + .map((element) => { + if (element) { + return { value: element.value, unit: element.unit }; + } + return { value: 0, unit: "" }; + }); } return { ...acc, @@ -158,7 +176,6 @@ export const extractTopologyValues = ( label: topologyPaths[topologyKey as keyof TopologyValues][0] .split("/") .pop(), - unit: values[0].unit, } as BoxData, }; }, {} as TopologyValues); @@ -171,16 +188,22 @@ export const getHighestConnectionValue = (values: TopologyValues) => .filter((value) => value.includes("Connection")) .reduce((acc, curr) => { const value = Math.abs( - values[curr as keyof TopologyValues].values[0] as number + values[curr as keyof TopologyValues].values[0].value as number ); return value > acc ? value : acc; }, 0); export const getAmount = ( highestConnectionValue: number, - values: (string | number)[] + values: BoxDataValue[] ) => { - return Math.abs(values[0] as number) / highestConnectionValue; + console.log( + "getamount", + Math.abs(values[0].value as number) / highestConnectionValue, + Math.abs(values[0].value as number), + highestConnectionValue + ); + return Math.abs(values[0].value as number) / highestConnectionValue; }; export interface CsvEntry { @@ -189,23 +212,26 @@ export interface CsvEntry { } export const parseCsv = (text: string): DataRecord => { + console.log("parseText", text); const y = text .split(/\r?\n/) .filter((split) => split.length > 0) .map((l) => { return l.split(";"); }); - const x = y + return y .map((fields) => { - if (fields[0] === "/AcDc/Warnings") - console.log("warnings", fields[1], isNaN(+fields[1])); + if (fields[0].includes("LoadOnAcIsland")) { + console.log("fields", fields, { + [fields[0]]: { value: parseFloat(fields[1]), unit: fields[2] }, + }); + } if (isNaN(Number(fields[1])) || fields[1] === "") { return { [fields[0]]: { value: fields[1], unit: fields[2] } }; } return { [fields[0]]: { value: parseFloat(fields[1]), unit: fields[2] } }; }) .reduce((acc, current) => ({ ...acc, ...current }), {} as DataRecord); - return x; }; export const insertTreeElements = (