+
+ Display Point Threshold:
+
+ The Display Point Threshold value determines the number of data points to downsample the plot to.
+ The higher this value is, the more accurate the data will be to actual and similarly, the lower the
+ this value is, the less accurate it will be to actual. To turn off downsampling and use all data points,
+ set the Display Point Threshold to 0. The number of data points will considerably change the
+ loading time of the plot, the lower the value the faster it will load.
+
+ It is recommended to only use a high value, or 0, if your date range is small or need extremely
+ accurate data representation.
+
+ )}
+ />
+
+ setThreshold(newVal)}
+ />
+
diff --git a/src/app-pages/project/batch-plotting/batch-plot-errors.jsx b/src/app-pages/project/batch-plotting/components/batch-plot-errors.jsx
similarity index 100%
rename from src/app-pages/project/batch-plotting/batch-plot-errors.jsx
rename to src/app-pages/project/batch-plotting/components/batch-plot-errors.jsx
diff --git a/src/app-pages/project/batch-plotting/configuration-panel.jsx b/src/app-pages/project/batch-plotting/components/configuration-panel.jsx
similarity index 96%
rename from src/app-pages/project/batch-plotting/configuration-panel.jsx
rename to src/app-pages/project/batch-plotting/components/configuration-panel.jsx
index 0590183c..45072bbb 100644
--- a/src/app-pages/project/batch-plotting/configuration-panel.jsx
+++ b/src/app-pages/project/batch-plotting/components/configuration-panel.jsx
@@ -1,8 +1,8 @@
import React, { useState, useEffect, useMemo } from 'react';
import { connect } from 'redux-bundler-react';
-import Button from '../../../app-components/button';
-import MultiSelect from '../../../app-components/multi-select';
+import Button from '../../../../app-components/button';
+import MultiSelect from '../../../../app-components/multi-select';
const formatOptions = timeseries => (
timeseries.map(ts => ({
diff --git a/src/app-pages/project/batch-plotting/data-configuration.jsx b/src/app-pages/project/batch-plotting/components/data-configuration.jsx
similarity index 92%
rename from src/app-pages/project/batch-plotting/data-configuration.jsx
rename to src/app-pages/project/batch-plotting/components/data-configuration.jsx
index 63a2eaee..d6f25b84 100644
--- a/src/app-pages/project/batch-plotting/data-configuration.jsx
+++ b/src/app-pages/project/batch-plotting/components/data-configuration.jsx
@@ -2,13 +2,13 @@ import React, { useEffect, useState } from 'react';
import { connect } from 'redux-bundler-react';
import { Delete, Edit } from '@mui/icons-material';
-import Button from '../../../app-components/button';
+import Button from '../../../../app-components/button';
import ConfigurationPanel from './configuration-panel';
-import DeleteButton from '../../../app-components/delete-confirm';
-import Select from '../../../app-components/select';
-import usePrevious from '../../../customHooks/usePrevious';
+import DeleteButton from '../../../../app-components/delete-confirm';
+import Select from '../../../../app-components/select';
+import usePrevious from '../../../../customHooks/usePrevious';
-import './batch-plotting.scss';
+import '../batch-plotting.scss';
const DataConfiguration = connect(
'selectBatchPlotConfigurationsItems',
@@ -31,7 +31,7 @@ const DataConfiguration = connect(
const configurations = batchPlotConfigurationsItems.map(config => ({
text: config.name,
value: config.id,
- }));
+ })).sort((a, b) => a.text.localeCompare(b.text));
const handleEditClick = () => {
const currentItem = batchPlotConfigurationsItemsObject[batchPlotConfigurationsActiveId];
diff --git a/src/app-pages/project/batch-plotting/print-button.jsx b/src/app-pages/project/batch-plotting/components/print-button.jsx
similarity index 92%
rename from src/app-pages/project/batch-plotting/print-button.jsx
rename to src/app-pages/project/batch-plotting/components/print-button.jsx
index a8162fd3..e21a2e5b 100644
--- a/src/app-pages/project/batch-plotting/print-button.jsx
+++ b/src/app-pages/project/batch-plotting/components/print-button.jsx
@@ -13,10 +13,10 @@ import { connect } from 'redux-bundler-react';
// Font,
// } from '@react-pdf/renderer';
-import Button from '../../../app-components/button';
-import Plotly from '../../../app-components/chart/minify-plotly';
-import latoBoldSource from '../../../css/google-fonts/fonts/Lato-Bold.ttf';
-import latoSource from '../../../css/google-fonts/fonts/Lato-Regular.ttf';
+import Button from '../../../../app-components/button';
+import Plotly from '../../../../app-components/chart/minify-plotly';
+import latoBoldSource from '../../../../css/google-fonts/fonts/Lato-Bold.ttf';
+import latoSource from '../../../../css/google-fonts/fonts/Lato-Regular.ttf';
// Font.register({ family: 'Lato', src: latoSource });
// Font.register({ family: 'Lato-Bold', src: latoBoldSource });
diff --git a/src/app-pages/project/batch-plotting/index.js b/src/app-pages/project/batch-plotting/index.js
index ae651fb3..2fcfd535 100644
--- a/src/app-pages/project/batch-plotting/index.js
+++ b/src/app-pages/project/batch-plotting/index.js
@@ -1 +1 @@
-export { default } from './batch-plotting';
\ No newline at end of file
+export { default } from './batch-plotting';
diff --git a/src/app-pages/project/batch-plotting/batch-plot-chart.jsx b/src/app-pages/project/batch-plotting/tab-content/batch-plot-chart.jsx
similarity index 79%
rename from src/app-pages/project/batch-plotting/batch-plot-chart.jsx
rename to src/app-pages/project/batch-plotting/tab-content/batch-plot-chart.jsx
index 72977ea7..ff71b4f3 100644
--- a/src/app-pages/project/batch-plotting/batch-plot-chart.jsx
+++ b/src/app-pages/project/batch-plotting/tab-content/batch-plot-chart.jsx
@@ -2,10 +2,10 @@ import React, { useEffect, useState } from 'react';
import { connect } from 'redux-bundler-react';
import { subDays } from 'date-fns';
-import Chart from '../../../app-components/chart/chart';
-import ChartErrors from './batch-plot-errors';
-import ChartSettings from './batch-plot-chart-settings';
-import { generateNewChartData } from './helper';
+import Chart from '../../../../app-components/chart/chart';
+import ChartErrors from '../components/batch-plot-errors';
+import ChartSettings from '../components/batch-plot-chart-settings';
+import { generateNewChartData } from '../helper';
const BatchPlotChart = connect(
'doPrintSetData',
@@ -30,6 +30,7 @@ const BatchPlotChart = connect(
const [measurements, setMeasurements] = useState([]);
const [chartData, setChartData] = useState([]);
const [dateRange, setDateRange] = useState([subDays(new Date(), 365), new Date()]);
+ const [threshold, setThreshold] = useState(3000);
const [withPrecipitation, setWithPrecipitation] = useState(false);
const [chartSettings, setChartSettings] = useState({ auto_range: false });
@@ -61,6 +62,11 @@ const BatchPlotChart = connect(
height: 600,
};
+ const savePlotSettings = (params) => {
+ timeseriesIds.forEach(id => doTimeseriesMeasurementsFetchById({ timeseriesId: id, dateRange, threshold }));
+ doBatchPlotConfigurationsSave(...params);
+ };
+
/** Load specific timeseries ids into state when new configurations are loaded */
useEffect(() => {
const config = batchPlotConfigurationsItemsObject[batchPlotConfigurationsActiveId];
@@ -75,8 +81,8 @@ const BatchPlotChart = connect(
/** Fetch the timeseries measurements in regards to date range */
useEffect(() => {
- timeseriesIds.forEach(id => doTimeseriesMeasurementsFetchById({ timeseriesId: id, dateRange }));
- }, [timeseriesIds, dateRange, doInstrumentTimeseriesSetActiveId]);
+ timeseriesIds.forEach(id => doTimeseriesMeasurementsFetchById({ timeseriesId: id, dateRange, threshold })); // @TODO - allow slider fo threshold
+ }, [timeseriesIds, doInstrumentTimeseriesSetActiveId]);
/** Extract specific measurements from the store that relate to our set timeseries */
useEffect(() => {
@@ -88,14 +94,11 @@ const BatchPlotChart = connect(
}, [timeseriesIds, timeseriesMeasurementsItems, setMeasurements]);
/** When we get new measurements, update chart data */
- useEffect(
- () => {
- const newData = generateNewChartData(measurements, instrumentTimeseriesItemsByRoute, chartSettings);
+ useEffect(() => {
+ const newData = generateNewChartData(measurements, instrumentTimeseriesItemsByRoute, chartSettings);
- setChartData(newData);
- },
- [measurements, instrumentTimeseriesItemsByRoute, withPrecipitation, chartSettings]
- );
+ setChartData(newData);
+ }, [measurements, instrumentTimeseriesItemsByRoute, withPrecipitation, chartSettings]);
/** When chart data changes, see if there is precip data to adjust plot */
useEffect(() => {
@@ -132,11 +135,13 @@ const BatchPlotChart = connect(
<>
>
diff --git a/src/app-pages/project/batch-plotting/tab-content/depth-chart.jsx b/src/app-pages/project/batch-plotting/tab-content/depth-chart.jsx
new file mode 100644
index 00000000..d6e21fda
--- /dev/null
+++ b/src/app-pages/project/batch-plotting/tab-content/depth-chart.jsx
@@ -0,0 +1,219 @@
+import React, { useEffect, useState } from 'react';
+import { connect } from 'redux-bundler-react';
+import { Slider } from '@mui/material';
+import { DateTime } from 'luxon';
+
+import Chart from '../../../../app-components/chart/chart';
+
+const colors = [
+ '#800000',
+ '#000075',
+ '#e6194B',
+ '#3cb44b',
+ '#911eb4',
+ '#fabed4',
+];
+
+const formatData = (data = [], indexes = []) => {
+ const inclinometerIds = Object.keys(data);
+ if (!inclinometerIds.length) return {};
+
+ const workingData = data[inclinometerIds[0]].inclinometers;
+
+ const depthIncrements = workingData.map((datum, i) => {
+ const { time, values } = datum;
+
+ const valueDisplacement = values.sort((a, b) => b.nDepth - a.nDepth);
+
+ return { time, valueDisplacement, colorIndex: i };
+ }).sort((a, b) => DateTime.fromISO(a.time).toMillis() - DateTime.fromISO(b.time).toMillis());
+
+ const relevantData = depthIncrements.slice(indexes[0], indexes[1] + 1);
+ const dataArray = [];
+
+ for (let i = 0; i < relevantData.length; i++) {
+ const { valueDisplacement, time, colorIndex } = relevantData[i];
+
+ dataArray.push(
+ valueDisplacement.reduce((accum, current, ind) => {
+ const { depth, aIncrement, bIncrement } = current;
+
+ if (ind === 0) {
+ accum.nDepth.push(depth);
+ accum.aIncrement.push(aIncrement);
+ accum.bIncrement.push(bIncrement);
+ accum.time = DateTime.fromISO(time).toFormat('MMM dd, yyyy hh:mm:ss');
+ accum.colorIndex = colorIndex;
+ } else {
+ accum.nDepth.push(depth);
+ accum.aIncrement.push(accum.aIncrement[ind - 1] + aIncrement);
+ accum.bIncrement.push(accum.bIncrement[ind - 1] + bIncrement);
+ accum.time = DateTime.fromISO(time).toFormat('MMM dd, yyyy hh:mm:ss');
+ accum.colorIndex = colorIndex;
+ }
+
+ return accum;
+ }, {
+ nDepth: [],
+ aIncrement: [],
+ bIncrement: [],
+ time: '',
+ colorIndex: '',
+ })
+ )
+ }
+
+ return { depthIncrements, dataArray, relevantData };
+};
+
+const build3dTraces = (dataArray, unit) => dataArray.map(data => (
+ {
+ x: data.aIncrement,
+ y: data.bIncrement,
+ z: data.nDepth,
+ mode: 'markers+lines',
+ marker: { size: 3, color: colors[data.colorIndex % colors.length] },
+ line: { width: 1 },
+ type: 'scatter3d',
+ name: `${data.time} Cumulative Displacement (in ${unit})`,
+ }
+
+ // If client wants A and B Displacement on the 3-D plot, add these back in and adjust function to a forEach using push logic.
+ // , {
+ // x: data.aIncrement,
+ // y: new Array(data.bIncrement.length).fill(0),
+ // z: data.nDepth,
+ // mode: 'markers+lines',
+ // marker: { size: 5, color: 'green' },
+ // type: 'scatter3d',
+ // name: `A Displacement (in ${unit})`,
+ // }, {
+ // x: new Array(data.aIncrement.length).fill(0),
+ // y: data.bIncrement,
+ // z: data.nDepth,
+ // mode: 'markers+lines',
+ // marker: { size: 5, color: 'orange' },
+ // type: 'scatter3d',
+ // name: `B Displacement (in ${unit})`
+ // }
+));
+
+const build2dTrace = (dataArray, key, unit) => dataArray.map(data => (
+ {
+ x: data[key],
+ y: data.nDepth,
+ mode: 'markers+lines',
+ marker: { size: 5, color: colors[data.colorIndex % colors.length] },
+ line: { width: 1 },
+ type: 'scatter',
+ name: `${key} Displacement (in ${unit})`,
+ hovertemplate: `
+ ${data.time}
+ Depth: %{y}
+ Displacement: %{x}
+
+ `,
+ }
+));
+
+const DepthChart = connect(
+ 'doFetchInclinometerMeasurementsByTimeseriesId',
+ 'selectCurrentInclinometerMeasurements',
+ ({
+ doFetchInclinometerMeasurementsByTimeseriesId,
+ currentInclinometerMeasurements,
+ inclinometerTimeseriesIds,
+ }) => {
+ const [sliderVal, setSliderVal] = useState([0, 0]);
+
+ useEffect(() => {
+ inclinometerTimeseriesIds.forEach(id => {
+ doFetchInclinometerMeasurementsByTimeseriesId(id);
+ });
+ }, [inclinometerTimeseriesIds, doFetchInclinometerMeasurementsByTimeseriesId]);
+
+ const inclinometerIds = Object.keys(currentInclinometerMeasurements || {});
+ const isMetric = false;
+ const unit = isMetric ? 'mm' : 'inches';
+ const { dataArray = [], depthIncrements = [] } = formatData(currentInclinometerMeasurements, sliderVal, isMetric);
+
+ const config = {
+ repsonsive: true,
+ displaylogo: false,
+ displayModeBar: true,
+ scrollZoom: true,
+ };
+
+ const layout3d = {
+ autosize: true,
+ height: 800,
+ scene: {
+ xaxis: { title: `A-Displacement (in ${unit})` },
+ yaxis: { title: `B-Displacement (in ${unit})` },
+ zaxis: { title: 'Depth', autorange: 'reversed' },
+ },
+ legend: {
+ 'orientation': 'h',
+ },
+ };
+
+ const layoutTall = (key) => ({
+ showlegend: false,
+ autosize: true,
+ height: 800,
+ yaxis: {
+ autorange: 'reversed',
+ title: `Depth in Feet`,
+ },
+ xaxis: {
+ title: `${key}-Displacement in ${unit}`,
+ },
+ });
+
+ const incrementData = build3dTraces(dataArray, unit);
+
+ return inclinometerIds.length ? (
+ <>
+