add working (not yet perfect) graphs, all have same range and toggle for graphs not there yet

This commit is contained in:
Sina Blattmann 2023-04-26 13:54:57 +02:00
parent 6fc414a2c0
commit 9fa0fd1f22
3 changed files with 116 additions and 68 deletions

View File

@ -1,65 +1,10 @@
import React, { useState } from "react"; import React from "react";
import ScalarGraph from "./ScalarGraph"; import ScalarGraph from "./ScalarGraph";
import DataCache, { FetchResult } from "../../../dataCache/dataCache";
import { TimeSpan, UnixTime } from "../../../dataCache/time";
import { S3Access } from "../../../dataCache/S3/S3Access";
import { map, debounceTime } from "rxjs/operators";
import { RecordSeries } from "../../../dataCache/data";
import { parseCsv } from "../../../util/graph.util";
const Log = () => { const Log = () => {
const [timeSeries, setTimeSeries] = useState<RecordSeries>([]);
const s3Access = new S3Access(
"saliomameiringen",
"sos-ch-dk-2",
"exo.io",
"EXO18e7ae9e53fae71ee55cf35b",
"3Cyonq8gMQ0a3elTH2vP7Yv-czcCj8iE2lBcPB9XhSc",
""
);
const fetchData = (
timestamp: UnixTime
): Promise<FetchResult<Record<string, number>>> => {
const s3Path = `${timestamp.ticks}.csv`;
return s3Access
.get(s3Path)
.then(async (r) => {
if (r.status === 404) {
return Promise.resolve(FetchResult.notAvailable);
} else if (r.status === 200) {
const text = await r.text();
return parseCsv(text);
} else {
console.error("unexpected status code");
return Promise.resolve(FetchResult.notAvailable);
}
})
.catch((e) => {
console.log(e);
return Promise.resolve(FetchResult.tryLater);
});
};
const cache = new DataCache(fetchData, TimeSpan.fromSeconds(2));
const sampleTimes = UnixTime.fromTicks(1682085650)
.earlier(TimeSpan.fromMinutes(1))
.rangeBefore(TimeSpan.fromMinutes(1))
.sample(TimeSpan.fromSeconds(2));
cache.getSeries(sampleTimes);
const update = cache.gotData.pipe(
debounceTime(2000),
map((_) => setTimeSeries(cache.getSeries(sampleTimes)))
);
update.subscribe();
return ( return (
<> <>
<ScalarGraph data={timeSeries} /> <ScalarGraph />
</> </>
); );
}; };

View File

@ -1,26 +1,112 @@
import Plot from "react-plotly.js"; import Plot from "react-plotly.js";
import { RecordSeries } from "../../../dataCache/data"; import { RecordSeries } from "../../../dataCache/data";
import { transformToGraphData } from "../../../util/graph.util"; import { parseCsv, transformToGraphData } from "../../../util/graph.util";
import { TimeSpan, UnixTime } from "../../../dataCache/time";
import { useEffect, useMemo, useState } from "react";
import { BehaviorSubject, startWith, throttleTime, withLatestFrom } from "rxjs";
import { S3Access } from "../../../dataCache/S3/S3Access";
import DataCache, { FetchResult } from "../../../dataCache/dataCache";
interface I_ScalarGraphProps { const ScalarGraph = () => {
data: RecordSeries; const timeRange = UnixTime.fromTicks(1682085650)
} .rangeBefore(TimeSpan.fromDays(1))
.sample(TimeSpan.fromMinutes(30));
const [timeSeries, setTimeSeries] = useState<RecordSeries>([]);
const [uiRevision, setUiRevision] = useState(Math.random());
const [range, setRange] = useState([
timeRange[0].toDate(),
timeRange[timeRange.length - 1].toDate(),
]);
const [toggles, setToggles] = useState<Object | null>(null);
const times$ = useMemo(() => new BehaviorSubject(timeRange), []);
const s3Access = new S3Access(
"saliomameiringen",
"sos-ch-dk-2",
"exo.io",
"EXO18e7ae9e53fae71ee55cf35b",
"3Cyonq8gMQ0a3elTH2vP7Yv-czcCj8iE2lBcPB9XhSc",
""
);
useEffect(() => {
const subscription = cache.gotData
.pipe(
startWith(0),
throttleTime(200, undefined, { leading: true, trailing: true }),
withLatestFrom(times$)
)
.subscribe(([_, times]) => {
const timeSeries = cache.getSeries(times);
console.log("GOT DATA", _, times, timeSeries);
setTimeSeries(timeSeries);
if (toggles === null) setToggles(timeSeries);
});
return () => subscription.unsubscribe();
}, []);
const roundToNearest30 = (date: Date) => {
const minutes = 30;
const ms = 1000 * 60 * minutes;
return new Date(Math.round(date.getTime() / ms) * ms);
};
const fetchData = (
timestamp: UnixTime
): Promise<FetchResult<Record<string, number>>> => {
const s3Path = `${timestamp.ticks}.csv`;
return s3Access
.get(s3Path)
.then(async (r) => {
if (r.status === 404) {
return Promise.resolve(FetchResult.notAvailable);
} else if (r.status === 200) {
const text = await r.text();
return parseCsv(text);
} else {
console.error("unexpected status code");
return Promise.resolve(FetchResult.notAvailable);
}
})
.catch((e) => {
console.log(e);
return Promise.resolve(FetchResult.tryLater);
});
};
const cache = useMemo(
() => new DataCache(fetchData, TimeSpan.fromSeconds(2)),
[]
);
const ScalarGraph = (props: I_ScalarGraphProps) => {
const renderGraphs = () => { const renderGraphs = () => {
const coordinateTimeSeries = transformToGraphData(props.data); const coordinateTimeSeries = transformToGraphData(timeSeries);
return Object.keys(coordinateTimeSeries).map((path) => { return Object.keys(coordinateTimeSeries).map((path) => {
const data = coordinateTimeSeries[path] ?? { x: [], y: [] };
return ( return (
<Plot <Plot
data={[ data={[
{ {
...coordinateTimeSeries[path], ...data,
type: "scatter", type: "scatter",
mode: "lines+markers", mode: "lines+markers",
marker: { color: "red" }, marker: { color: "red" },
}, },
]} ]}
layout={{ width: 1000, height: 500, title: path }} layout={{
width: 1000,
height: 500,
title: path,
uirevision: uiRevision,
xaxis: {
autorange: false,
range: range,
type: "date",
},
}}
config={{ config={{
modeBarButtonsToRemove: [ modeBarButtonsToRemove: [
"lasso2d", "lasso2d",
@ -29,8 +115,24 @@ const ScalarGraph = (props: I_ScalarGraphProps) => {
"autoScale2d", "autoScale2d",
], ],
}} }}
onUpdate={(figure) => { onRelayout={(params) => {
//console.log(figure); console.log("PARAMS", params);
const xaxisRange0 = params["xaxis.range[0]"];
const xaxisRange1 = params["xaxis.range[1]"];
if (xaxisRange0 && xaxisRange1) {
const epoch0 =
roundToNearest30(new Date(xaxisRange0)).getTime() / 1000;
const epoch1 =
roundToNearest30(new Date(xaxisRange1)).getTime() / 1000;
setRange([new Date(xaxisRange0), new Date(xaxisRange1)]);
setUiRevision(Math.random());
const times = UnixTime.fromTicks(epoch1)
.rangeBefore(TimeSpan.fromSeconds(epoch1 - epoch0))
.sample(TimeSpan.fromMinutes(30));
cache.getSeries(times);
times$.next(times);
}
}} }}
/> />
); );

View File

@ -31,7 +31,7 @@ export const transformToGraphData = (timeStampData: RecordSeries) => {
return { return {
...pathAcc, ...pathAcc,
[currPath]: { [currPath]: {
x: [curr.time.ticks], x: [new Date(curr.time.ticks * 1000)],
y: [curr.value ? curr.value[currPath] : 0], y: [curr.value ? curr.value[currPath] : 0],
}, },
}; };
@ -40,6 +40,7 @@ export const transformToGraphData = (timeStampData: RecordSeries) => {
}, },
{} as GraphData {} as GraphData
); );
console.log("acc", acc, timeStampObj);
return mergeDeep(acc, timeStampObj); return mergeDeep(acc, timeStampObj);
} }
return acc; return acc;