diff --git a/package.json b/package.json index 576ea3f..6fa31d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gnssmetrics", - "version": "1.0.4", + "version": "1.0.5", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.17.0", diff --git a/public/Examples/example-2D.csv b/public/Examples/example-2D.csv index 582084f..bad37da 100644 --- a/public/Examples/example-2D.csv +++ b/public/Examples/example-2D.csv @@ -98,4 +98,4 @@ Latitude,Longitude 51.1802495,-114.1319418 51.1801314,-114.1320491 51.1802924,-114.1320491 -51.1802924,-114.1320276 +51.1802924,-114.1320276 \ No newline at end of file diff --git a/public/Examples/example-3D.csv b/public/Examples/example-3D.csv index 932f6df..8ef48bc 100644 --- a/public/Examples/example-3D.csv +++ b/public/Examples/example-3D.csv @@ -1,101 +1,101 @@ Latitude,Longitude,Altitude -21.1803138,-114.1320062,1050 -21.1803246,-114.1320920,1050 -21.1803997,-114.1321993,1050 -21.1805069,-114.1321564,1050 -21.1801821,-114.1320062,1050 -21.1803246,-114.1319847,1050 -21.1803138,-114.1320276,1050 -21.1803782,-114.1320705,1050 -21.1807108,-114.1320705,1050 -21.1801636,-114.1321349,1050 -21.1804426,-114.1319847,1050 -21.1803460,-114.1320491,1050 -21.1803997,-114.1319203,1050 -21.1803889,-114.1320062,1050 -21.1803460,-114.1320062,1050 -21.1802924,-114.1319418,1050 -21.1804748,-114.1321993,1050 -21.1801529,-114.1320276,1050 -21.1802709,-114.1321778,1050 -21.1803246,-114.1320491,1050 -21.1803782,-114.1320062,1050 -21.1802602,-114.1320920,1050 -21.1803031,-114.1320276,1050 -21.1802280,-114.1320491,1050 -21.1802816,-114.1320062,1050 -21.1802924,-114.1319633,1050 -21.1803782,-114.1320920,1050 -21.1803567,-114.1321349,1050 -21.1805606,-114.1320062,1050 -21.1803567,-114.1321564,1050 -21.1804426,-114.1320920,1050 -21.1801314,-114.1320705,1050 -21.1802495,-114.1320062,1050 -21.1804104,-114.1320705,1050 -21.1803675,-114.1320705,1050 -21.1802280,-114.1320491,1050 -21.1803138,-114.1320062,1050 -21.1802280,-114.1321993,1050 -21.1804211,-114.1321778,1050 -21.1803675,-114.1322422,1050 -21.1801422,-114.1321564,1050 -21.1803138,-114.1323280,1050 -21.1801744,-114.1325212,1050 -21.1803246,-114.1321564,1050 -21.1804104,-114.1320062,1050 -21.1802816,-114.1319847,1050 -21.1803782,-114.1320276,1050 -21.1802816,-114.1320705,1050 -21.1802924,-114.1319203,1050 -21.1802280,-114.1320062,1050 -21.1803460,-114.1320491,1050 -21.1802495,-114.1320491,1050 -21.1803138,-114.1320920,1050 -21.1803997,-114.1320705,1050 -21.1804318,-114.1321564,1050 -21.1803889,-114.1320705,1050 -21.1804533,-114.1321135,1050 -21.1801958,-114.1320062,1050 -21.1802924,-114.1321778,1050 -21.1803567,-114.1321135,1050 -21.1803246,-114.1320062,1050 -21.1802602,-114.1320491,1050 -21.1803460,-114.1320062,1050 -21.1803889,-114.1320491,1050 -21.1802924,-114.1320705,1050 -21.1803460,-114.1320062,1050 -21.1802387,-114.1320491,1050 -21.1803675,-114.1320276,1050 -21.1802387,-114.1320705,1050 -21.1803675,-114.1320276,1050 -21.1803782,-114.1320062,1050 -21.1803031,-114.1320062,1050 -21.1803675,-114.1320491,1050 -21.1802495,-114.1320062,1050 -21.1802924,-114.1319203,1050 -21.1803138,-114.1319847,1050 -21.1803138,-114.1320705,1050 -21.1802177,-114.1313839,1050 -21.1803246,-114.1320062,1050 -21.1802065,-114.1320705,1050 -21.1803246,-114.1320276,1050 -21.1803031,-114.1321135,1050 -21.1803567,-114.1320491,1050 -21.1802924,-114.1320062,1050 -21.1803353,-114.1319847,1050 -21.1803460,-114.1320491,1050 -21.1805284,-114.1321564,1050 -21.1804104,-114.1320920,1050 -21.1803997,-114.1321349,1050 -21.1800671,-114.1319633,1050 -21.1801744,-114.1319847,1050 -21.1803246,-114.1320276,1050 -21.1802065,-114.1320705,1050 -21.1802924,-114.1321135,1050 -21.1802602,-114.1319418,1050 -21.1801207,-114.1319418,1050 -21.1802495,-114.1319418,1050 -21.1801314,-114.1320491,1050 -21.1802924,-114.1320491,1050 -21.1802924,-114.1320276,1050 +51.1803138,-114.1320062,1050 +51.1803246,-114.1320920,1050 +51.1803997,-114.1351993,1050 +51.1805069,-114.1351564,1050 +51.1801851,-114.1320062,1050 +51.1803246,-114.1319847,1050 +51.1803138,-114.1320276,1050 +51.1803782,-114.1320705,1050 +51.1807108,-114.1320705,1050 +51.1801636,-114.1351349,1050 +51.1804426,-114.1319847,1050 +51.1803460,-114.1320491,1050 +51.1803997,-114.1319203,1050 +51.1803889,-114.1320062,1050 +51.1803460,-114.1320062,1050 +51.1802924,-114.1319418,1050 +51.1804748,-114.1351993,1050 +51.1801529,-114.1320276,1050 +51.1802709,-114.1351778,1050 +51.1803246,-114.1320491,1050 +51.1803782,-114.1320062,1050 +51.1802602,-114.1320920,1050 +51.1803031,-114.1320276,1050 +51.1802280,-114.1320491,1050 +51.1802816,-114.1320062,1050 +51.1802924,-114.1319633,1050 +51.1803782,-114.1320920,1050 +51.1803567,-114.1351349,1050 +51.1805606,-114.1320062,1050 +51.1803567,-114.1351564,1050 +51.1804426,-114.1320920,1050 +51.1801314,-114.1320705,1050 +51.1802495,-114.1320062,1050 +51.1804104,-114.1320705,1050 +51.1803675,-114.1320705,1050 +51.1802280,-114.1320491,1050 +51.1803138,-114.1320062,1050 +51.1802280,-114.1351993,1050 +51.1804511,-114.1351778,1050 +51.1803675,-114.1322422,1050 +51.1801422,-114.1351564,1050 +51.1803138,-114.1323280,1050 +51.1801744,-114.1325512,1050 +51.1803246,-114.1351564,1050 +51.1804104,-114.1320062,1050 +51.1802816,-114.1319847,1050 +51.1803782,-114.1320276,1050 +51.1802816,-114.1320705,1050 +51.1802924,-114.1319203,1050 +51.1802280,-114.1320062,1050 +51.1803460,-114.1320491,1050 +51.1802495,-114.1320491,1050 +51.1803138,-114.1320920,1050 +51.1803997,-114.1320705,1050 +51.1804318,-114.1351564,1050 +51.1803889,-114.1320705,1050 +51.1804533,-114.1351135,1050 +51.1801958,-114.1320062,1050 +51.1802924,-114.1351778,1050 +51.1803567,-114.1351135,1050 +51.1803246,-114.1320062,1050 +51.1802602,-114.1320491,1050 +51.1803460,-114.1320062,1050 +51.1803889,-114.1320491,1050 +51.1802924,-114.1320705,1050 +51.1803460,-114.1320062,1050 +51.1802387,-114.1320491,1050 +51.1803675,-114.1320276,1050 +51.1802387,-114.1320705,1050 +51.1803675,-114.1320276,1050 +51.1803782,-114.1320062,1050 +51.1803031,-114.1320062,1050 +51.1803675,-114.1320491,1050 +51.1802495,-114.1320062,1050 +51.1802924,-114.1319203,1050 +51.1803138,-114.1319847,1050 +51.1803138,-114.1320705,1050 +51.1805177,-114.1313839,1050 +51.1803246,-114.1320062,1050 +51.1802065,-114.1320705,1050 +51.1803246,-114.1320276,1050 +51.1803031,-114.1351135,1050 +51.1803567,-114.1320491,1050 +51.1802924,-114.1320062,1050 +51.1803353,-114.1319847,1050 +51.1803460,-114.1320491,1050 +51.1805284,-114.1351564,1050 +51.1804104,-114.1320920,1050 +51.1803997,-114.1351349,1050 +51.1800671,-114.1319633,1050 +51.1801744,-114.1319847,1050 +51.1803246,-114.1320276,1050 +51.1802065,-114.1320705,1050 +51.1802924,-114.1351135,1050 +51.1802602,-114.1319418,1050 +51.1801207,-114.1319418,1050 +51.1802495,-114.1319418,1050 +51.1801314,-114.1320491,1050 +51.1802924,-114.1320491,1050 +51.1802924,-114.1320276,1050 \ No newline at end of file diff --git a/public/Examples/example-3D.xlsx b/public/Examples/example-3D.xlsx index 48b2597..288f9f6 100644 Binary files a/public/Examples/example-3D.xlsx and b/public/Examples/example-3D.xlsx differ diff --git a/src/Dev/Components/Visualizers/DataExports.jsx b/src/Dev/Components/Visualizers/DataExports.jsx new file mode 100644 index 0000000..dbe354a --- /dev/null +++ b/src/Dev/Components/Visualizers/DataExports.jsx @@ -0,0 +1,145 @@ +import React from "react"; +import * as XLSX from "xlsx"; +import { saveAs } from "file-saver"; + +const DataExports = (props) => { + const { + file, + refLat, + refLong, + refAlt, + meanAlt, + meanLat, + meanLong, + cep50, + cep90, + cep98, + meanCep50, + meanCep90, + meanCep98, + sep50, + sep90, + sep98, + meanSep50, + meanSep90, + meanSep98, + plotData, + altPlotData, + } = props; + + const exportToExcelAndKml = () => { + // Data for the second sheet + const fileData = file.data.map((item, index) => { + const dataEntry = { + Latitude: item.Latitude, + Longitude: item.Longitude, + "2D Fix Error": plotData[index], + }; + + // Add Altitude and 3D Fix Error if Altitude exists + if (item.Altitude !== undefined) { + dataEntry.Altitude = item.Altitude; + dataEntry["3D Fix Error"] = altPlotData[index]; + } + + return dataEntry; + }); + + // Data for the first sheet + const statsData = [ + ["Statistics", "Value"], + ["Reference Latitude", refLat], + ["Reference Longitude", refLong], + ["Reference Altitude", refAlt], + ["Mean Altitude", meanAlt], + ["Mean Latitude", meanLat], + ["Mean Longitude", meanLong], + ["CEP 50%", cep50], + ["CEP 90%", cep90], + ["CEP 98%", cep98], + ["Mean CEP 50%", meanCep50], + ["Mean CEP 90%", meanCep90], + ["Mean CEP 98%", meanCep98], + ["SEP 50%", sep50], + ["SEP 90%", sep90], + ["SEP 98%", sep98], + ["Mean SEP 50%", meanSep50], + ["Mean SEP 90%", meanSep90], + ["Mean SEP 98%", meanSep98], + ]; + + // Create a new workbook + const workbook = XLSX.utils.book_new(); + + // Create the first sheet and append it to the workbook + const ws1 = XLSX.utils.aoa_to_sheet(statsData); + XLSX.utils.book_append_sheet(workbook, ws1, "Statistics"); + + // Create the second sheet and append it to the workbook + const ws2 = XLSX.utils.json_to_sheet(fileData); + XLSX.utils.book_append_sheet(workbook, ws2, "Data"); + + // Write the workbook to a binary string + const excelBuffer = XLSX.write(workbook, { + bookType: "xlsx", + type: "array", + }); + + // Create a Blob object from the binary string + const excelBlob = new Blob([excelBuffer], { + type: "application/octet-stream", + }); + + // Generate a timestamp for the filename + const timestamp = new Date() + .toISOString() + .replace(/[-:T.]/g, "") + .slice(0, 14); + + // Trigger the file download for the Excel file + saveAs(excelBlob, `data_results_${timestamp}.xlsx`); + + // Generate KML content + const kmlContent = ` + + + Position Fixes + Position Fixes from GNSS Data + ${fileData + .map( + (item, index) => ` + + Fix ${index} + + ${item.Longitude},${item.Latitude},${ + item.Altitude ? item.Altitude : 0 + } + + ` + ) + .join("")} + + `; + + // Create a Blob object for the KML file + const kmlBlob = new Blob([kmlContent], { + type: "application/vnd.google-earth.kml+xml", + }); + + // Trigger the file download for the KML file + saveAs(kmlBlob, `data_results_${timestamp}.kml`); + }; + + return ( +
+ +
+ ); +}; + +export default DataExports; diff --git a/src/Dev/Components/Visualizers/DataStats.jsx b/src/Dev/Components/Visualizers/DataStats.jsx index b9517de..ddd4ca5 100644 --- a/src/Dev/Components/Visualizers/DataStats.jsx +++ b/src/Dev/Components/Visualizers/DataStats.jsx @@ -13,6 +13,36 @@ const DataStats = (props) => { startButton, setPlotData, setAltPlotData, + meanAlt, + setMeanAlt, + meanLat, + setMeanLat, + meanLong, + setMeanLong, + cep50, + setCep50, + cep90, + setCep90, + cep98, + setCep98, + meanCep50, + setMeanCep50, + meanCep90, + setMeanCep90, + meanCep98, + setMeanCep98, + sep50, + setSep50, + sep90, + setSep90, + sep98, + setSep98, + meanSep50, + setMeanSep50, + meanSep90, + setMeanSep90, + meanSep98, + setMeanSep98, } = props; const [markers, setMarkers] = useState([]); @@ -24,22 +54,6 @@ const DataStats = (props) => { // eslint-disable-next-line no-unused-vars const [triDMeanDistances, setTriDMeanDistances] = useState([]); - const [meanLat, setMeanLat] = useState(); - const [meanLong, setMeanLong] = useState(); - const [meanAlt, setMeanAlt] = useState(); - const [cep50, setCep50] = useState(); - const [cep90, setCep90] = useState(); - const [cep98, setCep98] = useState(); - const [meanCep50, setMeanCep50] = useState(); - const [meanCep90, setMeanCep90] = useState(); - const [meanCep98, setMeanCep98] = useState(); - const [sep50, setSep50] = useState(); - const [sep90, setSep90] = useState(); - const [sep98, setSep98] = useState(); - const [meanSep50, setMeanSep50] = useState(); - const [meanSep90, setMeanSep90] = useState(); - const [meanSep98, setMeanSep98] = useState(); - useEffect(() => { try { extractMarkers(file, setMarkers); diff --git a/src/Dev/Functions/StatsAndPlotsRender.jsx b/src/Dev/Functions/StatsAndPlotsRender.jsx index 08bad19..e9b3c8d 100644 --- a/src/Dev/Functions/StatsAndPlotsRender.jsx +++ b/src/Dev/Functions/StatsAndPlotsRender.jsx @@ -1,8 +1,9 @@ -import React from "react"; +import React, { useState } from "react"; import DataStats from "../Components/Visualizers/DataStats"; import DataPlot from "../Components/Visualizers/DataPlot"; import AltDataPlot from "../Components/Visualizers/AltDataPlot"; import DataMap from "../Components/Visualizers/DataMap"; +import DataExports from "../Components/Visualizers/DataExports"; const StatsAndPlotsRender = ({ startButton, @@ -15,6 +16,22 @@ const StatsAndPlotsRender = ({ setAltPlotData, altPlotData, }) => { + const [meanLat, setMeanLat] = useState(); + const [meanLong, setMeanLong] = useState(); + const [meanAlt, setMeanAlt] = useState(); + const [cep50, setCep50] = useState(); + const [cep90, setCep90] = useState(); + const [cep98, setCep98] = useState(); + const [meanCep50, setMeanCep50] = useState(); + const [meanCep90, setMeanCep90] = useState(); + const [meanCep98, setMeanCep98] = useState(); + const [sep50, setSep50] = useState(); + const [sep90, setSep90] = useState(); + const [sep98, setSep98] = useState(); + const [meanSep50, setMeanSep50] = useState(); + const [meanSep90, setMeanSep90] = useState(); + const [meanSep98, setMeanSep98] = useState(); + try { if (startButton) { return ( @@ -32,6 +49,36 @@ const StatsAndPlotsRender = ({ startButton={startButton} setPlotData={setPlotData} setAltPlotData={setAltPlotData} + meanAlt={meanAlt} + setMeanAlt={setMeanAlt} + meanLat={meanLat} + setMeanLat={setMeanLat} + meanLong={meanLong} + setMeanLong={setMeanLong} + cep50={cep50} + setCep50={setCep50} + cep90={cep90} + setCep90={setCep90} + cep98={cep98} + setCep98={setCep98} + meanCep50={meanCep50} + setMeanCep50={setMeanCep50} + meanCep90={meanCep90} + setMeanCep90={setMeanCep90} + meanCep98={meanCep98} + setMeanCep98={setMeanCep98} + sep50={sep50} + setSep50={setSep50} + sep90={sep90} + setSep90={setSep90} + sep98={sep98} + setSep98={setSep98} + meanSep50={meanSep50} + setMeanSep50={setMeanSep50} + meanSep90={meanSep90} + setMeanSep90={setMeanSep90} + meanSep98={meanSep98} + setMeanSep98={setMeanSep98} />
@@ -42,6 +89,31 @@ const StatsAndPlotsRender = ({
+
+ +
); }