diff --git a/.github/workflows/matlab.yml b/.github/workflows/matlab.yml index 0c17cee8..64e1d083 100644 --- a/.github/workflows/matlab.yml +++ b/.github/workflows/matlab.yml @@ -22,7 +22,7 @@ jobs: release: ${{ matrix.release }} products: Signal_Processing_Toolbox Statistics_and_Machine_Learning_Toolbox Text_Analytics_Toolbox - name: Run tests - uses: matlab-actions/run-build@v2.4.1 + uses: matlab-actions/run-build@v2.5.0 with: tasks: check test - name: Report results @@ -46,7 +46,7 @@ jobs: if: github.ref == 'refs/heads/main' needs: test env: - VERSION: "4.6.0" + VERSION: "4.6.1" steps: - name: Check out repository uses: actions/checkout@v4 @@ -55,11 +55,11 @@ jobs: with: release: R2023b - name: Package toolbox - uses: matlab-actions/run-build@v2.4.1 + uses: matlab-actions/run-build@v2.5.0 with: tasks: package("${{ env.VERSION }}") - name: Upload toolbox - uses: actions/upload-artifact@v4.3.6 + uses: actions/upload-artifact@v4.4.0 with: name: 'MAG Data Visualization.mltbx' path: artifacts diff --git a/resources/release-notes.md b/resources/release-notes.md index f95b9721..dcd4d118 100644 --- a/resources/release-notes.md +++ b/resources/release-notes.md @@ -1,6 +1,3 @@ # Software -- Add comparison view `mag.graphics.view.Comparison` for comparing science, I-ALiRT and SID5 data -- Add `RangeVariable` as option in `mag.process.Calibration` -- Improve management of compression in `mag.process.SignedInteger` -- Fix issues with processing of SID5 data (signedness, calibration) +- Remove `mag.graphics.view.IALiRT` in favor of `mag.graphics.view.Comparison` diff --git a/src/visualize/+mag/+graphics/+view/Comparison.m b/src/visualize/+mag/+graphics/+view/Comparison.m index ef37628a..8bd62d2a 100644 --- a/src/visualize/+mag/+graphics/+view/Comparison.m +++ b/src/visualize/+mag/+graphics/+view/Comparison.m @@ -22,34 +22,83 @@ function visualize(this) [primarySensor, secondarySensor] = this.getSensorNames(); sid5HK = this.getHKType("SCI"); - if isempty(this.Results.HasData) || (isempty(this.Results.IALiRT) || ~this.Results.IALiRT.HasData) || (isempty(sid5HK) || ~sid5HK.HasData) - return; - end - primaryScience = this.Results.Primary; secondaryScience = this.Results.Secondary; - primaryIALiRT = this.Results.IALiRT.Primary; - secondaryIALiRT = this.Results.IALiRT.Secondary; - - primaryData = this.combineDataSources(primaryScience, primaryIALiRT, sid5HK, "FOB"); - secondaryData = this.combineDataSources(secondaryScience, secondaryIALiRT, sid5HK, "FIB"); - - primaryCharts = this.generateComparisonGraph(primarySensor, "left"); - secondaryCharts = this.generateComparisonGraph(secondarySensor, "right"); - - this.Figures = this.Factory.assemble( ... - primaryData, ... - primaryCharts, ... - secondaryData, ... - secondaryCharts, ... - Title = "Science Sources Comparison", ... - Name = "Science - I-AliRT - SID5 Comparison", ... - GlobalLegend = ["Science", "I-ALiRT", "SID5"], ... - Arrangement = [3, 2], ... - TileIndexing = "columnmajor", ... - LinkXAxes = true, ... - WindowState = "maximized"); + hasScience = ~isempty(this.Results.HasData); + hasIALiRT = ~isempty(this.Results.IALiRT) && this.Results.IALiRT.HasData; + hasSID5 = ~isempty(sid5HK) && sid5HK.HasData; + + if hasScience && hasIALiRT && hasSID5 + + primaryIALiRT = this.Results.IALiRT.Primary; + secondaryIALiRT = this.Results.IALiRT.Secondary; + + primaryData = this.combineDataSources(primaryScience, primaryIALiRT, sid5HK, "FOB"); + secondaryData = this.combineDataSources(secondaryScience, secondaryIALiRT, sid5HK, "FIB"); + + primaryCharts = this.generateOverlayGraph(primarySensor, "left"); + secondaryCharts = this.generateOverlayGraph(secondarySensor, "right"); + + this.Figures(end + 1) = this.Factory.assemble( ... + primaryData, ... + primaryCharts, ... + secondaryData, ... + secondaryCharts, ... + Title = "Science Sources Comparison", ... + Name = "Science - I-AliRT - SID5 Comparison", ... + GlobalLegend = ["Science", "I-ALiRT", "SID5"], ... + Arrangement = [3, 2], ... + TileIndexing = "columnmajor", ... + LinkXAxes = true, ... + WindowState = "maximized"); + end + + if hasIALiRT + + primaryIALiRT = this.Results.IALiRT.Primary; + secondaryIALiRT = this.Results.IALiRT.Secondary; + + primaryIALiRTComparison = synchronize(timetable(primaryIALiRT.Time, primaryIALiRT.X, primaryIALiRT.Y, primaryIALiRT.Z, primaryIALiRT.Quality.isPlottable(), VariableNames = ["xc", "yc", "zc", "qc"]), ... + timetable(primaryScience.Time, primaryScience.X, primaryScience.Y, primaryScience.Z, primaryScience.Quality.isPlottable(), VariableNames = ["xs", "ys", "zs", "qs"]), "first", "nearest"); + secondaryIALiRTComparison = synchronize(timetable(secondaryIALiRT.Time, secondaryIALiRT.X, secondaryIALiRT.Y, secondaryIALiRT.Z, secondaryIALiRT.Quality.isPlottable(), VariableNames = ["xc", "yc", "zc", "qc"]), ... + timetable(secondaryScience.Time, secondaryScience.X, secondaryScience.Y, secondaryScience.Z, secondaryScience.Quality.isPlottable(), VariableNames = ["xs", "ys", "zs", "qs"]), "first", "nearest"); + + primaryGraphs = this.generateComparisonGraph(primaryIALiRTComparison, "left"); + secondaryGraphs = this.generateComparisonGraph(secondaryIALiRTComparison, "right"); + + this.Figures(end + 1) = this.Factory.assemble( ... + primaryIALiRTComparison, primaryGraphs, secondaryIALiRTComparison, secondaryGraphs, ... + Name = "Science vs. I-ALiRT (Closest Vector)", ... + Arrangement = [9, 2], ... + GlobalLegend = ["Science", "I-ALiRT"], ... + LinkXAxes = true, ... + TileIndexing = "columnmajor", ... + WindowState = "maximized"); + end + + if hasSID5 + + sid5HK.Data(ismissing(sid5HK.FOBT), :) = []; + sid5HK.Data(ismissing(sid5HK.FIBT), :) = []; + + primarySID5Comparison = synchronize(timetable(sid5HK.FOBT, sid5HK.FOBX, sid5HK.FOBY, sid5HK.FOBZ, true(height(sid5HK.Data), 1), VariableNames = ["xc", "yc", "zc", "qc"]), ... + timetable(primaryScience.Time, primaryScience.X, primaryScience.Y, primaryScience.Z, primaryScience.Quality.isPlottable(), VariableNames = ["xs", "ys", "zs", "qs"]), "first", "nearest"); + secondarySID5Comparison = synchronize(timetable(sid5HK.FIBT, sid5HK.FIBX, sid5HK.FIBY, sid5HK.FIBZ, true(height(sid5HK.Data), 1), VariableNames = ["xc", "yc", "zc", "qc"]), ... + timetable(secondaryScience.Time, secondaryScience.X, secondaryScience.Y, secondaryScience.Z, secondaryScience.Quality.isPlottable(), VariableNames = ["xs", "ys", "zs", "qs"]), "first", "nearest"); + + primaryGraphs = this.generateComparisonGraph(primarySID5Comparison, "left"); + secondaryGraphs = this.generateComparisonGraph(secondarySID5Comparison, "right"); + + this.Figures(end + 1) = this.Factory.assemble( ... + primarySID5Comparison, primaryGraphs, secondarySID5Comparison, secondaryGraphs, ... + Name = "Science vs. SID5 (Closest Vector)", ... + Arrangement = [9, 2], ... + GlobalLegend = ["Science", "SID5"], ... + LinkXAxes = true, ... + TileIndexing = "columnmajor", ... + WindowState = "maximized"); + end end end @@ -81,7 +130,7 @@ function visualize(this) data = outerjoin(data, sid5); end - function charts = generateComparisonGraph(sensorName, yAxisLocation) + function charts = generateOverlayGraph(sensorName, yAxisLocation) arguments (Input) sensorName (1, 1) string @@ -103,5 +152,27 @@ function visualize(this) charts(1).Title = sensorName; end + + function charts = generateComparisonGraph(comparisonData, yAxisLocation) + + arguments (Input) + comparisonData timetable + yAxisLocation (1, 1) string {mustBeMember(yAxisLocation, ["left", "right"])} + end + + arguments (Output) + charts (1, 6) mag.graphics.style.Default + end + + defaultColors = colororder(); + + charts = [ ... + mag.graphics.style.Default(YLabel = "x [nT]", YAxisLocation = yAxisLocation, Layout = [2, 1], Charts = [mag.graphics.chart.Plot(YVariables = "xs", Marker = "o", Filter = comparisonData.qs), mag.graphics.chart.Plot(YVariables = "xc", Marker = "x", Filter = comparisonData.qc)]), ... + mag.graphics.style.Default(YLabel = "\Deltax [nT]", YAxisLocation = yAxisLocation, Charts = mag.graphics.chart.Plot(YVariables = mag.graphics.operation.Subtract(Minuend = "xs", Subtrahend = "xc"), Colors = defaultColors(3, :), Filter = comparisonData.qs & comparisonData.qc)), ... + mag.graphics.style.Default(YLabel = "y [nT]", YAxisLocation = yAxisLocation, Layout = [2, 1], Charts = [mag.graphics.chart.Plot(YVariables = "ys", Marker = "o", Filter = comparisonData.qs), mag.graphics.chart.Plot(YVariables = "yc", Marker = "x", Filter = comparisonData.qc)]), ... + mag.graphics.style.Default(YLabel = "\Deltay [nT]", YAxisLocation = yAxisLocation, Charts = mag.graphics.chart.Plot(YVariables = mag.graphics.operation.Subtract(Minuend = "ys", Subtrahend = "yc"), Colors = defaultColors(3, :), Filter = comparisonData.qs & comparisonData.qc)), ... + mag.graphics.style.Default(YLabel = "z [nT]", YAxisLocation = yAxisLocation, Layout = [2, 1], Charts = [mag.graphics.chart.Plot(YVariables = "zs", Marker = "o", Filter = comparisonData.qs), mag.graphics.chart.Plot(YVariables = "zc", Marker = "x", Filter = comparisonData.qc)]), ... + mag.graphics.style.Default(YLabel = "\Deltaz [nT]", YAxisLocation = yAxisLocation, Charts = mag.graphics.chart.Plot(YVariables = mag.graphics.operation.Subtract(Minuend = "zs", Subtrahend = "zc"), Colors = defaultColors(3, :), Filter = comparisonData.qs & comparisonData.qc))]; + end end end diff --git a/src/visualize/+mag/+graphics/+view/IALiRT.m b/src/visualize/+mag/+graphics/+view/IALiRT.m deleted file mode 100644 index c1c240b7..00000000 --- a/src/visualize/+mag/+graphics/+view/IALiRT.m +++ /dev/null @@ -1,99 +0,0 @@ -classdef IALiRT < mag.graphics.view.Science -% IALIRT Show IALiRT. - - methods - - function this = IALiRT(results, options) - - arguments - results - options.?mag.graphics.view.IALiRT - end - - this.Results = results; - - this.assignProperties(options); - end - - function visualize(this) - - this.Figures = matlab.ui.Figure.empty(); - - primaryIALiRT = this.Results.IALiRT.Primary; - secondaryIALiRT = this.Results.IALiRT.Secondary; - - % Plot only I-ALiRT. - this.Figures(1) = this.Factory.assemble( ... - primaryIALiRT, mag.graphics.style.Stackedplot(Title = this.getFieldTitle(primaryIALiRT), YLabels = ["x [nT]", "y [nT]", "z [nT]", "|B| [nT]"], Charts = mag.graphics.chart.Stackedplot(YVariables = ["X", "Y", "Z", "B"], Filter = primaryIALiRT.Quality.isPlottable())), ... - secondaryIALiRT, mag.graphics.style.Stackedplot(Title = this.getFieldTitle(secondaryIALiRT), YLabels = ["x [nT]", "y [nT]", "z [nT]", "|B| [nT]"], YAxisLocation = "right", Charts = mag.graphics.chart.Stackedplot(YVariables = ["X", "Y", "Z", "B"], Filter = secondaryIALiRT.Quality.isPlottable())), ... - Title = this.getFigureTitle(primaryIALiRT, secondaryIALiRT), ... - Name = this.getFigureName(primaryIALiRT, secondaryIALiRT), ... - Arrangement = [1, 2], ... - LinkXAxes = true, ... - WindowState = "maximized"); - - % Plot I-ALiRT and science (full). - primaryScience = this.Results.Primary; - secondaryScience = this.Results.Secondary; - - primaryOverlay = this.generateOverlayGraph(primaryScience, primaryIALiRT); - - secondaryOverlay = this.generateOverlayGraph(secondaryScience, secondaryIALiRT); - [secondaryOverlay{2}.YAxisLocation] = deal("right"); - - this.Figures(2) = this.Factory.assemble( ... - primaryOverlay{:}, secondaryOverlay{:}, ... - Name = "Science vs. I-ALiRT (Full)", ... - Arrangement = [3, 2], ... - GlobalLegend = ["Science", "I-ALiRT"], ... - LinkXAxes = true, ... - TileIndexing = "columnmajor", ... - WindowState = "maximized"); - - % Plot I-ALiRT and science (closest vector). - primaryComparison = synchronize(timetable(primaryIALiRT.Time, primaryIALiRT.X, primaryIALiRT.Y, primaryIALiRT.Z, primaryIALiRT.Quality.isPlottable(), VariableNames = ["xi", "yi", "zi", "qi"]), ... - timetable(primaryScience.Time, primaryScience.X, primaryScience.Y, primaryScience.Z, primaryScience.Quality.isPlottable(), VariableNames = ["xs", "ys", "zs", "qs"]), "first", "nearest"); - secondaryComparison = synchronize(timetable(secondaryIALiRT.Time, secondaryIALiRT.X, secondaryIALiRT.Y, secondaryIALiRT.Z, secondaryIALiRT.Quality.isPlottable(), VariableNames = ["xi", "yi", "zi", "qi"]), ... - timetable(secondaryScience.Time, secondaryScience.X, secondaryScience.Y, secondaryScience.Z, secondaryScience.Quality.isPlottable(), VariableNames = ["xs", "ys", "zs", "qs"]), "first", "nearest"); - - primaryGraphs = this.generateComparisonGraph(primaryIALiRT, primaryComparison); - - secondaryGraphs = this.generateComparisonGraph(secondaryIALiRT, secondaryComparison); - [secondaryGraphs.YAxisLocation] = deal("right"); - - this.Figures(3) = this.Factory.assemble( ... - primaryComparison, primaryGraphs, secondaryComparison, secondaryGraphs, ... - Name = "Science vs. I-ALiRT (Closest Vector)", ... - Arrangement = [9, 2], ... - GlobalLegend = ["Science", "I-ALiRT"], ... - LinkXAxes = true, ... - TileIndexing = "columnmajor", ... - WindowState = "maximized"); - end - end - - methods (Access = private) - - function overlayGraphs = generateOverlayGraph(this, scienceData, iALiRTData) - - combinedData = outerjoin(scienceData.Data(scienceData.Quality.isPlottable(), :), iALiRTData.Data(iALiRTData.Quality.isPlottable(), :)); - - overlayGraphs = {combinedData, ... - [mag.graphics.style.Default(Title = this.getFieldTitle(iALiRTData), YLabel = "x [nT]", Charts = [mag.graphics.chart.Plot(YVariables = "x_left", Filter = ~ismissing(combinedData.x_left)), mag.graphics.chart.Scatter(YVariables = "x_right", Filter = ~ismissing(combinedData.x_right), Marker = "x")]), ... - mag.graphics.style.Default(YLabel = "y [nT]", Charts = [mag.graphics.chart.Plot(YVariables = "y_left", Filter = ~ismissing(combinedData.y_left)), mag.graphics.chart.Scatter(YVariables = "y_right", Filter = ~ismissing(combinedData.y_right), Marker = "x")]), ... - mag.graphics.style.Default(YLabel = "z [nT]", Charts = [mag.graphics.chart.Plot(YVariables = "z_left", Filter = ~ismissing(combinedData.z_left)), mag.graphics.chart.Scatter(YVariables = "z_right", Filter = ~ismissing(combinedData.z_right), Marker = "x")])]}; - end - - function comparisonGraphs = generateComparisonGraph(this, iALiRTData, comparisonData) - - defaultColors = colororder(); - - comparisonGraphs = [mag.graphics.style.Default(Title = this.getFieldTitle(iALiRTData), YLabel = "x [nT]", Layout = [2, 1], Charts = [mag.graphics.chart.Plot(YVariables = "xs", Marker = "o", Filter = comparisonData.qs), mag.graphics.chart.Plot(YVariables = "xi", Marker = "x", Filter = comparisonData.qi)]), ... - mag.graphics.style.Default(YLabel = "\Deltax [nT]", Charts = mag.graphics.chart.Plot(YVariables = mag.graphics.operation.Subtract(Minuend = "xs", Subtrahend = "xi"), Colors = defaultColors(3, :), Filter = comparisonData.qs & comparisonData.qi)), ... - mag.graphics.style.Default(YLabel = "y [nT]", Layout = [2, 1], Charts = [mag.graphics.chart.Plot(YVariables = "ys", Marker = "o", Filter = comparisonData.qs), mag.graphics.chart.Plot(YVariables = "yi", Marker = "x", Filter = comparisonData.qi)]), ... - mag.graphics.style.Default(YLabel = "\Deltay [nT]", Charts = mag.graphics.chart.Plot(YVariables = mag.graphics.operation.Subtract(Minuend = "ys", Subtrahend = "yi"), Colors = defaultColors(3, :), Filter = comparisonData.qs & comparisonData.qi)), ... - mag.graphics.style.Default(YLabel = "z [nT]", Layout = [2, 1], Charts = [mag.graphics.chart.Plot(YVariables = "zs", Marker = "o", Filter = comparisonData.qs), mag.graphics.chart.Plot(YVariables = "zi", Marker = "x", Filter = comparisonData.qi)]), ... - mag.graphics.style.Default(YLabel = "\Deltaz [nT]", Charts = mag.graphics.chart.Plot(YVariables = mag.graphics.operation.Subtract(Minuend = "zs", Subtrahend = "zi"), Colors = defaultColors(3, :), Filter = comparisonData.qs & comparisonData.qi))]; - end - end -end diff --git a/src/visualize/+mag/+graphics/sftPlots.m b/src/visualize/+mag/+graphics/sftPlots.m index a7b7cb25..9349f12f 100644 --- a/src/visualize/+mag/+graphics/sftPlots.m +++ b/src/visualize/+mag/+graphics/sftPlots.m @@ -49,8 +49,10 @@ end % Show I-ALiRT. - if ~isempty(croppedAnalysis.Results.IALiRT) - views(end + 1) = mag.graphics.view.IALiRT(croppedAnalysis.Results); + if ~isempty(croppedAnalysis.Results.IALiRT) && croppedAnalysis.Results.IALiRT.HasData + + tempInstrument = mag.Instrument(Science = croppedAnalysis.Results.IALiRT.Science); + views(end + 1) = mag.graphics.view.Field(tempInstrument); end % Show science comparison.