add working (not yet perfect) graphs, all have same range and toggle for graphs not there yet
This commit is contained in:
parent
6fc414a2c0
commit
9fa0fd1f22
|
@ -1,65 +1,10 @@
|
|||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
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 [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 (
|
||||
<>
|
||||
<ScalarGraph data={timeSeries} />
|
||||
<ScalarGraph />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,26 +1,112 @@
|
|||
import Plot from "react-plotly.js";
|
||||
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 {
|
||||
data: RecordSeries;
|
||||
const ScalarGraph = () => {
|
||||
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 coordinateTimeSeries = transformToGraphData(props.data);
|
||||
const coordinateTimeSeries = transformToGraphData(timeSeries);
|
||||
return Object.keys(coordinateTimeSeries).map((path) => {
|
||||
const data = coordinateTimeSeries[path] ?? { x: [], y: [] };
|
||||
return (
|
||||
<Plot
|
||||
data={[
|
||||
{
|
||||
...coordinateTimeSeries[path],
|
||||
...data,
|
||||
type: "scatter",
|
||||
mode: "lines+markers",
|
||||
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={{
|
||||
modeBarButtonsToRemove: [
|
||||
"lasso2d",
|
||||
|
@ -29,8 +115,24 @@ const ScalarGraph = (props: I_ScalarGraphProps) => {
|
|||
"autoScale2d",
|
||||
],
|
||||
}}
|
||||
onUpdate={(figure) => {
|
||||
//console.log(figure);
|
||||
onRelayout={(params) => {
|
||||
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);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -31,7 +31,7 @@ export const transformToGraphData = (timeStampData: RecordSeries) => {
|
|||
return {
|
||||
...pathAcc,
|
||||
[currPath]: {
|
||||
x: [curr.time.ticks],
|
||||
x: [new Date(curr.time.ticks * 1000)],
|
||||
y: [curr.value ? curr.value[currPath] : 0],
|
||||
},
|
||||
};
|
||||
|
@ -40,6 +40,7 @@ export const transformToGraphData = (timeStampData: RecordSeries) => {
|
|||
},
|
||||
{} as GraphData
|
||||
);
|
||||
console.log("acc", acc, timeStampObj);
|
||||
return mergeDeep(acc, timeStampObj);
|
||||
}
|
||||
return acc;
|
||||
|
|
Loading…
Reference in New Issue