diff --git a/Packages/MIES/MIES_Constants.ipf b/Packages/MIES/MIES_Constants.ipf index 4b8990d79b..9db77cff89 100644 --- a/Packages/MIES/MIES_Constants.ipf +++ b/Packages/MIES/MIES_Constants.ipf @@ -2141,6 +2141,11 @@ StrConstant SF_META_TRACETOFRONT = "/TraceToFront" // number, boolean, StrConstant SF_META_DONOTPLOT = "/DoNotPlot" // number, boolean, defaults to false (0) StrConstant SF_META_WINDOW_HOOK = "/WindowHook" // string StrConstant SF_META_FORMULA = "/Formula" // string +StrConstant SF_META_PLOT = "/Plot" // number, boolean, defaults to false (0) +StrConstant SF_META_XAXISOFFSET = "/XAxisOffset" // number +StrConstant SF_META_YAXISOFFSET = "/YAxisOffset" // number +StrConstant SF_META_XAXISPERCENT = "/XAxisPercent" // number +StrConstant SF_META_YAXISPERCENT = "/YAxisPercent" // number /// A color group allows to have matching colors for sweep data with the same channel type/number and sweep. /// It is applied before the matching headstage/average colors in #SF_GetTraceColor(). @@ -2541,6 +2546,7 @@ StrConstant SF_OP_TPINST = "tpinst" StrConstant SF_OP_TPBASE = "tpbase" StrConstant SF_OP_TPFIT = "tpfit" StrConstant SF_OP_EXTRACT = "extract" +StrConstant SF_OP_IVSCCAPFREQUENCY = "ivscc_apfrequency" ///@} StrConstant SF_PROPERTY_TABLE = "Table" diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index f03c706930..c6c2989c77 100644 --- a/Packages/MIES/MIES_SweepFormula.ipf +++ b/Packages/MIES/MIES_SweepFormula.ipf @@ -96,7 +96,8 @@ Function/WAVE SF_GetNamedOperations() SF_OP_MERGE, SF_OP_FIT, SF_OP_FITLINE, SF_OP_DATASET, SF_OP_SELECTVIS, SF_OP_SELECTCM, SF_OP_SELECTSTIMSET, \ SF_OP_SELECTIVSCCSWEEPQC, SF_OP_SELECTIVSCCSETQC, SF_OP_SELECTRANGE, SF_OP_SELECTEXP, SF_OP_SELECTDEV, \ SF_OP_SELECTEXPANDSCI, SF_OP_SELECTEXPANDRAC, SF_OP_SELECTSETCYCLECOUNT, SF_OP_SELECTSETSWEEPCOUNT, \ - SF_OP_SELECTSCIINDEX, SF_OP_SELECTRACINDEX, SF_OP_ANAFUNCPARAM, SF_OP_CONCAT, SF_OP_TABLE, SF_OP_EXTRACT} + SF_OP_SELECTSCIINDEX, SF_OP_SELECTRACINDEX, SF_OP_ANAFUNCPARAM, SF_OP_CONCAT, SF_OP_TABLE, SF_OP_EXTRACT, \ + SF_OP_IVSCCAPFREQUENCY} return wt End @@ -162,22 +163,31 @@ Function SF_FormulaWaveScaleTransfer(WAVE source, WAVE dest, variable dimSource, endswitch End -static Function [WAVE/WAVE formulaResults, WAVE/T plotMetaData] SF_GatherFormulaResults(string xFormula, string yFormula, string graph, variable lineNr, variable offset) +/// @brief Retrieves the plot meta data from the JSON wave note or other sources and stores it in the plotMetaData wave +static Function/WAVE SF_FillPlotMetaData(WAVE wvYRef, variable useXLabel, string dataUnits) + + WAVE/T plotMetaData = GetSFPlotMetaData() + plotMetaData[%DATATYPE] = JWN_GetStringFromWaveNote(wvYRef, SF_META_DATATYPE) + plotMetaData[%OPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_OPSTACK) + plotMetaData[%ARGSETUPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_ARGSETUPSTACK) + plotMetaData[%XAXISLABEL] = SelectString(useXLabel, SF_XLABEL_USER, JWN_GetStringFromWaveNote(wvYRef, SF_META_XAXISLABEL)) + plotMetaData[%YAXISLABEL] = JWN_GetStringFromWaveNote(wvYRef, SF_META_YAXISLABEL) + dataUnits + plotMetaData[%XAXISOFFSET] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_XAXISOFFSET), "%f") + plotMetaData[%YAXISOFFSET] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_YAXISOFFSET), "%f") + plotMetaData[%XAXISPERCENT] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_XAXISPERCENT), "%f") + plotMetaData[%YAXISPERCENT] = num2str(JWN_GetNumberFromWaveNote(wvYRef, SF_META_YAXISPERCENT), "%f") + + return plotMetaData +End + +static Function [WAVE/WAVE formulaResults, WAVE/T plotMetaData] SF_FillFormulaResults(WAVE/Z/WAVE wvYRef, WAVE/Z/WAVE wvXRef, string yFormula) variable i, numResultsY, numResultsX variable useXLabel, addDataUnitsInAnnotation string dataUnits, dataUnitCheck - WAVE/WAVE formulaResults = GetFormulaGatherWave() - WAVE/T plotMetaData = GetSFPlotMetaData() - - WAVE/Z/WAVE wvXRef = $"" - if(!IsEmpty(xFormula)) - WAVE/WAVE wvXRef = SFE_ExecuteFormula(xFormula, graph, useVariables = 0, line = lineNr, offset = offset) - SFH_ASSERT(WaveExists(wvXRef), "x part of formula returned no result.") - endif - WAVE/WAVE wvYRef = SFE_ExecuteFormula(yFormula, graph, useVariables = 0, line = lineNr, offset = 0) SFH_ASSERT(WaveExists(wvYRef), "y part of formula returned no result.") + numResultsY = DimSize(wvYRef, ROWS) if(WaveExists(wvXRef)) numResultsX = DimSize(wvXRef, ROWS) @@ -186,6 +196,7 @@ static Function [WAVE/WAVE formulaResults, WAVE/T plotMetaData] SF_GatherFormula useXLabel = 1 addDataUnitsInAnnotation = 1 + WAVE/WAVE formulaResults = GetFormulaGatherWave() Redimension/N=(numResultsY, -1) formulaResults if(DimSize(wvYRef, ROWS) > 0 && DimSize(formulaResults, ROWS) > 0) @@ -233,11 +244,21 @@ static Function [WAVE/WAVE formulaResults, WAVE/T plotMetaData] SF_GatherFormula dataUnits = SelectString(addDataUnitsInAnnotation && !IsEmpty(dataUnitCheck), "", SF_FormatUnit(dataUnitCheck)) endif - plotMetaData[%DATATYPE] = JWN_GetStringFromWaveNote(wvYRef, SF_META_DATATYPE) - plotMetaData[%OPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_OPSTACK) - plotMetaData[%ARGSETUPSTACK] = JWN_GetStringFromWaveNote(wvYRef, SF_META_ARGSETUPSTACK) - plotMetaData[%XAXISLABEL] = SelectString(useXLabel, SF_XLABEL_USER, JWN_GetStringFromWaveNote(wvYRef, SF_META_XAXISLABEL)) - plotMetaData[%YAXISLABEL] = JWN_GetStringFromWaveNote(wvYRef, SF_META_YAXISLABEL) + dataUnits + WAVE/T plotMetaData = SF_FillPlotMetaData(wvyRef, useXLabel, dataUnits) + + return [formulaResults, plotMetaData] +End + +static Function [WAVE/WAVE formulaResults, WAVE/T plotMetaData] SF_GatherFormulaResults(string xFormula, string yFormula, string graph, variable lineNr, variable offset) + + WAVE/Z/WAVE wvXRef = $"" + if(!IsEmpty(xFormula)) + WAVE/WAVE wvXRef = SFE_ExecuteFormula(xFormula, graph, useVariables = 0, line = lineNr, offset = offset) + SFH_ASSERT(WaveExists(wvXRef), "x part of formula returned no result.") + endif + WAVE/WAVE wvYRef = SFE_ExecuteFormula(yFormula, graph, useVariables = 0, line = lineNr, offset = 0) + + [WAVE/WAVE formulaResults, WAVE/T plotMetaData] = SF_FillFormulaResults(wvYRef, wvXRef, yFormula) return [formulaResults, plotMetaData] End @@ -271,7 +292,8 @@ static Function/S SF_GetTraceAnnotationText(WAVE/T plotMetaData, WAVE data) string channelId, prefix, legendPrefix string traceAnnotation, annotationPrefix - prefix = RemoveEnding(ReplaceString(";", plotMetaData[%OPSTACK], " "), " ") + prefix = RemoveEnding(ReplaceString(";", plotMetaData[%OPSTACK], " "), " ") + legendPrefix = JWN_GetStringFromWaveNote(data, SF_META_LEGEND_LINE_PREFIX) strswitch(plotMetaData[%DATATYPE]) case SF_DATATYPE_EPOCHS: // fallthrough @@ -279,8 +301,7 @@ static Function/S SF_GetTraceAnnotationText(WAVE/T plotMetaData, WAVE data) case SF_DATATYPE_LABNOTEBOOK: // fallthrough case SF_DATATYPE_ANAFUNCPARAM: // fallthrough case SF_DATATYPE_TP: - sweepNo = JWN_GetNumberFromWaveNote(data, SF_META_SWEEPNO) - legendPrefix = JWN_GetStringFromWaveNote(data, SF_META_LEGEND_LINE_PREFIX) + sweepNo = JWN_GetNumberFromWaveNote(data, SF_META_SWEEPNO) if(!IsEmpty(legendPrefix)) legendPrefix = " " + legendPrefix + " " @@ -299,7 +320,11 @@ static Function/S SF_GetTraceAnnotationText(WAVE/T plotMetaData, WAVE data) break default: if(WhichListItem(SF_OP_DATA, plotMetaData[%OPSTACK]) == -1) - sprintf traceAnnotation, "%s", prefix + if(!IsEmpty(legendPrefix)) + sprintf traceAnnotation, "%s %s", prefix, legendPrefix + else + sprintf traceAnnotation, "%s", prefix + endif else channelNumber = JWN_GetNumberFromWaveNote(data, SF_META_CHANNELNUMBER) channelType = JWN_GetNumberFromWaveNote(data, SF_META_CHANNELTYPE) @@ -491,12 +516,12 @@ End /// /// @retval traces generated trace names /// @retval traceCnt total count of all traces (input *and* output) -static Function [WAVE/T traces, variable traceCnt] SF_CreateTraceNames(variable numTraces, variable dataNum, WAVE/T plotMetaData, WAVE data) +static Function [WAVE/T traces, STRUCT SF_PlotterGraphStruct pg] SF_CreateTraceNames(variable numTraces, variable dataNum, WAVE/T plotMetaData, WAVE data) string traceAnnotation if(!numTraces) - return [$"", traceCnt] + return [$"", pg] endif traceAnnotation = SF_GetTraceAnnotationText(plotMetaData, data) @@ -505,9 +530,10 @@ static Function [WAVE/T traces, variable traceCnt] SF_CreateTraceNames(variable Make/T/N=(numTraces)/FREE traces - traces[] = GetTraceNamePrefix(traceCnt + p) + "d" + num2istr(dataNum) + "_" + traceAnnotation + traces[] = GetTraceNamePrefix(pg.traceCnt + p) + "d" + num2istr(dataNum) + "_" + traceAnnotation + pg.traceCnt += numTraces - return [traces, traceCnt + numTraces] + return [traces, pg] End /// Reduces a multi line legend to a single line if only the sweep number changes. @@ -898,7 +924,17 @@ static Function SF_IsDataForTableDisplay(WAVE wvY) return IsNaN(useTable) ? 0 : !!useTable End -static Function [variable dataCnt, variable traceCnt, variable gdIndex, string annotation, variable formulaAddedOncePerDataset, variable showLegend] SF_CreateTracesForResultsImpl(string graph, WAVE wvResultY, WAVE/Z wvResultX, WAVE/T plotMetaData, variable dataNum, WAVE/Z colorGroups, variable showInTable, string win, WAVE/T tableFormulas, WAVE plotFormData) +/// @brief Returns 1 if the result is flagged as full plotting specification, 0 otherwise +static Function SF_IsDataForFullPlotting(WAVE wv) + + variable plot + + plot = JWN_GetNumberFromWaveNote(wv, SF_META_PLOT) + + return IsNaN(plot) ? 0 : !!plot +End + +static Function [variable dataCnt, STRUCT SF_PlotterGraphStruct pg, variable gdIndex, string annotation, variable formulaAddedOncePerDataset] SF_CreateTracesForResultsImpl(WAVE wvResultY, WAVE/Z wvResultX, variable dataNum, variable showInTable, WAVE plotFormData) STRUCT RGBColor color variable numTraces, yPoints, xPoints, yMxN, xMxN, idx, splitTraces @@ -909,11 +945,11 @@ static Function [variable dataCnt, variable traceCnt, variable gdIndex, string a SFH_ASSERT(!(IsTextWave(wvResultY) && WaveDims(wvResultY) > 1), "Plotter got 2d+ text wave as y data.") - DFREF dfr = SF_GetBrowserDF(graph) + DFREF dfr = SF_GetBrowserDF(pg.graph) - [color] = SF_GetTraceColor(graph, plotMetaData[%OPSTACK], wvResultY, colorGroups) + [color] = SF_GetTraceColor(pg.graph, pg.plotMetaData[%OPSTACK], wvResultY, pg.colorGroups) - if(!WaveExists(wvResultX) && !IsEmpty(plotMetaData[%XAXISLABEL])) + if(!WaveExists(wvResultX) && !IsEmpty(pg.plotMetaData[%XAXISLABEL])) WAVE/Z wvResultX = JWN_GetNumericWaveFromWaveNote(wvResultY, SF_META_XVALUES) if(!WaveExists(wvResultX)) @@ -936,26 +972,26 @@ static Function [variable dataCnt, variable traceCnt, variable gdIndex, string a if(showInTable) if(HasDimLabels(wvY, ROWS) || HasDimLabels(wvY, COLS)) - AppendToTable/W=$win wvY.ld + AppendToTable/W=$pg.win wvY.ld else - AppendToTable/W=$win wvY.d + AppendToTable/W=$pg.win wvY.d endif if(!formulaAddedOncePerDataset) - idx = GetNumberFromWaveNote(tableFormulas, NOTE_INDEX) - EnsureLargeEnoughWave(tableFormulas, indexShouldExist = idx) - tableFormulas[idx] = JWN_GetStringFromWaveNote(wvY, SF_META_FORMULA) - SetNumberInWaveNote(tableFormulas, NOTE_INDEX, idx + 1) + idx = GetNumberFromWaveNote(pg.tableFormulas, NOTE_INDEX) + EnsureLargeEnoughWave(pg.tableFormulas, indexShouldExist = idx) + pg.tableFormulas[idx] = JWN_GetStringFromWaveNote(wvY, SF_META_FORMULA) + SetNumberInWaveNote(pg.tableFormulas, NOTE_INDEX, idx + 1) formulaAddedOncePerDataset = 1 endif dataCnt += 1 - return [dataCnt, traceCnt, gdIndex, annotation, formulaAddedOncePerDataset, showLegend] + return [dataCnt, pg, gdIndex, annotation, formulaAddedOncePerDataset] endif if(IsTextWave(wvY)) SFH_ASSERT(WaveExists(wvX), "Cannot plot a single text wave") - ModifyGraph/W=$win swapXY=1 + ModifyGraph/W=$pg.win swapXY=1 WAVE dummy = wvY WAVE wvY = wvX WAVE wvX = dummy @@ -963,48 +999,48 @@ static Function [variable dataCnt, variable traceCnt, variable gdIndex, string a if(!WaveExists(wvX)) numTraces = yMxN - SF_CheckNumTraces(graph, numTraces) - [WAVE/T traces, traceCnt] = SF_CreateTraceNames(numTraces, dataNum, plotMetaData, wvResultY) + SF_CheckNumTraces(pg.graph, numTraces) + [WAVE/T traces, pg] = SF_CreateTraceNames(numTraces, dataNum, pg.plotMetaData, wvResultY) for(i = 0; i < numTraces; i += 1) SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] - annotation += SF_GetMetaDataAnnotationText(plotMetaData, wvResultY, traces[i]) + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] + annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) endfor elseif((xMxN == 1) && (yMxN == 1)) // 1D if(yPoints == 1) // 0D vs 1D numTraces = xPoints - SF_CheckNumTraces(graph, numTraces) - [WAVE/T traces, traceCnt] = SF_CreateTraceNames(numTraces, dataNum, plotMetaData, wvResultY) + SF_CheckNumTraces(pg.graph, numTraces) + [WAVE/T traces, pg] = SF_CreateTraceNames(numTraces, dataNum, pg.plotMetaData, wvResultY) for(i = 0; i < numTraces; i += 1) SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[][0]/TN=$traces[i] vs wvX[i][] - annotation += SF_GetMetaDataAnnotationText(plotMetaData, wvResultY, traces[i]) + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][0]/TN=$traces[i] vs wvX[i][] + annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) endfor elseif(xPoints == 1) // 1D vs 0D numTraces = yPoints - SF_CheckNumTraces(graph, numTraces) - [WAVE/T traces, traceCnt] = SF_CreateTraceNames(numTraces, dataNum, plotMetaData, wvResultY) + SF_CheckNumTraces(pg.graph, numTraces) + [WAVE/T traces, pg] = SF_CreateTraceNames(numTraces, dataNum, pg.plotMetaData, wvResultY) for(i = 0; i < numTraces; i += 1) SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[i][]/TN=$traces[i] vs wvX[][0] - annotation += SF_GetMetaDataAnnotationText(plotMetaData, wvResultY, traces[i]) + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[i][]/TN=$traces[i] vs wvX[][0] + annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) endfor else // 1D vs 1D splitTraces = min(yPoints, xPoints) numTraces = floor(max(yPoints, xPoints) / splitTraces) - SF_CheckNumTraces(graph, numTraces) - [WAVE/T traces, traceCnt] = SF_CreateTraceNames(numTraces, dataNum, plotMetaData, wvResultY) + SF_CheckNumTraces(pg.graph, numTraces) + [WAVE/T traces, pg] = SF_CreateTraceNames(numTraces, dataNum, pg.plotMetaData, wvResultY) if(mod(max(yPoints, xPoints), splitTraces) == 0) DebugPrint("Unmatched Data Alignment in ROWS.") endif for(i = 0; i < numTraces; i += 1) - if(WindowExists(win) && WhichListItem("bottom", AxisList(win)) >= 0) - info = AxisInfo(win, "bottom") + if(WindowExists(pg.win) && WhichListItem("bottom", AxisList(pg.win)) >= 0) + info = AxisInfo(pg.win, "bottom") isCategoryAxis = NumberByKey("ISCAT", info) == 1 if(isCategoryAxis) @@ -1023,19 +1059,19 @@ static Function [variable dataCnt, variable traceCnt, variable gdIndex, string a SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) splitY = SF_SplitPlotting(wvY, ROWS, i, splitTraces) splitX = SF_SplitPlotting(wvX, ROWS, i, splitTraces) - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[splitY, splitY + splitTraces - 1][0]/TN=$traces[i] vs wvX[splitX, splitX + splitTraces - 1][0] - annotation += SF_GetMetaDataAnnotationText(plotMetaData, wvResultY, traces[i]) + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[splitY, splitY + splitTraces - 1][0]/TN=$traces[i] vs wvX[splitX, splitX + splitTraces - 1][0] + annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) endfor endif elseif(yMxN == 1) // 1D vs 2D numTraces = xMxN - SF_CheckNumTraces(graph, numTraces) - [WAVE/T traces, traceCnt] = SF_CreateTraceNames(numTraces, dataNum, plotMetaData, wvResultY) + SF_CheckNumTraces(pg.graph, numTraces) + [WAVE/T traces, pg] = SF_CreateTraceNames(numTraces, dataNum, pg.plotMetaData, wvResultY) for(i = 0; i < numTraces; i += 1) SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[][0]/TN=$traces[i] vs wvX[][i] - annotation += SF_GetMetaDataAnnotationText(plotMetaData, wvResultY, traces[i]) + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][0]/TN=$traces[i] vs wvX[][i] + annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) endfor elseif(xMxN == 1) // 2D vs 1D or 0D if(xPoints == 1) // 2D vs 0D -> extend X to 1D with constant value @@ -1044,18 +1080,18 @@ static Function [variable dataCnt, variable traceCnt, variable gdIndex, string a wvX = wvX[0] endif numTraces = yMxN - SF_CheckNumTraces(graph, numTraces) - [WAVE/T traces, traceCnt] = SF_CreateTraceNames(numTraces, dataNum, plotMetaData, wvResultY) + SF_CheckNumTraces(pg.graph, numTraces) + [WAVE/T traces, pg] = SF_CreateTraceNames(numTraces, dataNum, pg.plotMetaData, wvResultY) for(i = 0; i < numTraces; i += 1) SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] vs wvX - annotation += SF_GetMetaDataAnnotationText(plotMetaData, wvResultY, traces[i]) + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] vs wvX + annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) endfor else // 2D vs 2D numTraces = WaveExists(wvX) ? max(1, max(yMxN, xMxN)) : max(1, yMxN) - SF_CheckNumTraces(graph, numTraces) - [WAVE/T traces, traceCnt] = SF_CreateTraceNames(numTraces, dataNum, plotMetaData, wvResultY) + SF_CheckNumTraces(pg.graph, numTraces) + [WAVE/T traces, pg] = SF_CreateTraceNames(numTraces, dataNum, pg.plotMetaData, wvResultY) if(yPoints != xPoints) DebugPrint("Size mismatch in data rows for plotting waves.") @@ -1066,22 +1102,22 @@ static Function [variable dataCnt, variable traceCnt, variable gdIndex, string a for(i = 0; i < numTraces; i += 1) SF_CollectTraceData(gdIndex, plotFormData, traces[i], wvX, wvY) if(WaveExists(wvX)) - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[][min(yMxN - 1, i)]/TN=$traces[i] vs wvX[][min(xMxN - 1, i)] + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][min(yMxN - 1, i)]/TN=$traces[i] vs wvX[][min(xMxN - 1, i)] else - AppendTograph/W=$win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] + AppendTograph/W=$pg.win/C=(color.red, color.green, color.blue) wvY[][i]/TN=$traces[i] endif - annotation += SF_GetMetaDataAnnotationText(plotMetaData, wvResultY, traces[i]) + annotation += SF_GetMetaDataAnnotationText(pg.plotMetaData, wvResultY, traces[i]) endfor endif - showLegend = showLegend && SF_GetShowLegend(wvY) + pg.showLegend = pg.showLegend && SF_GetShowLegend(wvY) dataCnt += 1 - return [dataCnt, traceCnt, gdIndex, annotation, formulaAddedOncePerDataset, showLegend] + return [dataCnt, pg, gdIndex, annotation, formulaAddedOncePerDataset] End -static Function [variable dataCnt, variable traceCnt, WAVE/Z colorGroups, variable showLegend] SF_CreateTracesForResults(string graph, WAVE/WAVE formulaResults, variable formulaCounter, WAVE/T plotMetaData, string win, WAVE/T tableFormulas, WAVE/T wAnnotations, WAVE/T formulaArgSetup, WAVE/WAVE collPlotFormData) +static Function [variable dataCnt, STRUCT SF_PlotterGraphStruct pg] SF_CreateTracesForResults() variable i, idx, showInTable, numData, formulaAddedOncePerDataset variable gdIndex // indexes in tracesInGraph wave and dataInGraph wave in SF_CollectTraceData(), both waves are stored in plotformData @@ -1089,21 +1125,21 @@ static Function [variable dataCnt, variable traceCnt, WAVE/Z colorGroups, variab WAVE/WAVE plotFormData = SF_CreatePlotFormulaDataWave() - SF_FormulaPlotterExtendResultsIfCompatible(formulaResults) + SF_FormulaPlotterExtendResultsIfCompatible(pg.formulaResults) - if(WaveExists(colorGroups)) - Duplicate/FREE colorGroups, previousColorGroups + if(WaveExists(pg.colorGroups)) + Duplicate/FREE pg.colorGroups, previousColorGroups else WAVE/ZZ previousColorGroups endif - WAVE/Z colorGroups = SF_GetColorGroups(formulaResults, previousColorGroups) - showInTable = SF_IsDataForTableDisplay(formulaResults) + WAVE/Z pg.colorGroups = SF_GetColorGroups(pg.formulaResults, previousColorGroups) + showInTable = SF_IsDataForTableDisplay(pg.formulaResults) - numData = DimSize(formulaResults, ROWS) + numData = DimSize(pg.formulaResults, ROWS) for(i = 0; i < numData; i += 1) - WAVE/Z wvResultX = formulaResults[i][%FORMULAX] - WAVE/Z wvResultY = formulaResults[i][%FORMULAY] + WAVE/Z wvResultX = pg.formulaResults[i][%FORMULAX] + WAVE/Z wvResultY = pg.formulaResults[i][%FORMULAY] if(!WaveExists(wvResultY)) continue endif @@ -1111,26 +1147,28 @@ static Function [variable dataCnt, variable traceCnt, WAVE/Z colorGroups, variab continue endif - [dataCnt, traceCnt, gdIndex, annotation, formulaAddedOncePerDataset, showLegend] = SF_CreateTracesForResultsImpl(graph, wvResultY, wvResultX, plotMetaData, i, colorGroups, showInTable, win, tableFormulas, plotFormData) + [dataCnt, pg, gdIndex, annotation, formulaAddedOncePerDataset] = SF_CreateTracesForResultsImpl(wvResultY, wvResultX, i, showInTable, plotFormData) endfor if(!IsEmpty(annotation)) - idx = GetNumberFromWaveNote(wAnnotations, NOTE_INDEX) - EnsureLargeEnoughWave(wAnnotations, indexShouldExist = idx) - wAnnotations[idx] = annotation - SetNumberInWaveNote(wAnnotations, NOTE_INDEX, idx + 1) + idx = GetNumberFromWaveNote(pg.wAnnotations, NOTE_INDEX) + EnsureLargeEnoughWave(pg.wAnnotations, indexShouldExist = idx) + pg.wAnnotations[idx] = annotation + SetNumberInWaveNote(pg.wAnnotations, NOTE_INDEX, idx + 1) - idx = GetNumberFromWaveNote(formulaArgSetup, NOTE_INDEX) - EnsureLargeEnoughWave(formulaArgSetup, indexShouldExist = idx) - formulaArgSetup[idx] = plotMetaData[%ARGSETUPSTACK] - SetNumberInWaveNote(formulaArgSetup, NOTE_INDEX, idx + 1) + idx = GetNumberFromWaveNote(pg.formulaArgSetup, NOTE_INDEX) + EnsureLargeEnoughWave(pg.formulaArgSetup, indexShouldExist = idx) + pg.formulaArgSetup[idx] = pg.plotMetaData[%ARGSETUPSTACK] + SetNumberInWaveNote(pg.formulaArgSetup, NOTE_INDEX, idx + 1) endif - EnsureLargeEnoughWave(collPlotFormData, indexShouldExist = formulaCounter) + EnsureLargeEnoughWave(pg.collPlotFormData, indexShouldExist = pg.formulaCounter) WAVE/T tracesInGraph = plotFormData[0] WAVE/WAVE dataInGraph = plotFormData[1] Redimension/N=(gdIndex, -1) tracesInGraph, dataInGraph - collPlotFormData[formulaCounter] = plotFormData + pg.collPlotFormData[pg.formulaCounter] = plotFormData + + return [dataCnt, pg] End static Function SF_RestorePlotProperties(WAVE/WAVE prevPlotProperties) @@ -1259,6 +1297,79 @@ static Function/S SF_CreateDataDisplayWindow(string graph, WAVE/WAVE formulaResu return win End +static Structure SF_PlotterGraphStruct + + /// Name of the sweep formula graph this struct is associated with + string graph + /// Name of the window in which the plot/table is displayed + string win + /// Number of traces currently plotted + variable traceCnt + /// flag to call PSX plot creation when evaluated formulas contained psx operation + variable postPlotPSX + /// Non-zero if the legend should be shown for this plot + variable showLegend + /// Counter tracking how many formulas have been processed + variable formulaCounter + /// Wave holding x-axis labels used for the plotted data + WAVE xAxisLabels + /// Wave holding y-axis labels used for the plotted data + WAVE yAxisLabels + /// Text wave storing annotations to be displayed + WAVE/T wAnnotations + /// Text wave describing the argument setup for each formula + WAVE/T formulaArgSetup + /// Text wave containing the formulas for data displayed in tables + WAVE/T tableFormulas + /// Wave of waves storing collected plot formatting data for each formula + WAVE/WAVE collPlotFormData + /// Wave tracking which panels (graph/table) have been created + WAVE panelsCreated + /// Wave of waves with the evaluation results of a formula + WAVE/WAVE formulaResults + /// Text wave holding meta data about the plotted formulas and traces + WAVE/T plotMetaData + /// Wave assigning color groups to plotted traces + WAVE colorGroups +EndStructure + +static Function [STRUCT SF_PlotterGraphStruct pg] SF_InitPlotterGraphStruct(string graph) + + pg.graph = graph + pg.win = "" + + WAVE/Z pg.colorGroups = $"" + pg.traceCnt = 0 + pg.postPlotPSX = 0 + pg.showLegend = 1 + pg.formulaCounter = 0 + + Make/FREE/T/N=0 xAxisLabels, yAxisLabels + WAVE pg.xAxisLabels = xAxisLabels + WAVE pg.yAxisLabels = yAxisLabels + + Make/FREE=1/T/N=(MINIMUM_WAVE_SIZE) wAnnotations, formulaArgSetup, tableFormulas + SetNumberInWaveNote(wAnnotations, NOTE_INDEX, 0) + SetNumberInWaveNote(formulaArgSetup, NOTE_INDEX, 0) + SetNumberInWaveNote(tableFormulas, NOTE_INDEX, 0) + WAVE/T pg.wAnnotations = wAnnotations + WAVE/T pg.formulaArgSetup = formulaArgSetup + WAVE/T pg.tableFormulas = tableFormulas + + Make/FREE=1/WAVE/N=(MINIMUM_WAVE_SIZE) collPlotFormData + WAVE pg.collPlotFormData = collPlotFormData + + Make/FREE=1/D/N=2 panelsCreated + SetDimLabel ROWS, 0, GRAPH, panelsCreated + SetDimLabel ROWS, 1, TABLE, panelsCreated + WAVE pg.panelsCreated = panelsCreated + + WAVE/Z/WAVE pg.formulaResults = $"" + WAVE/Z/T pg.plotMetaData = $"" + + return [pg] +End + /// @brief Plot the formula using the data from graph /// /// @param graph graph to pass to SF_FormulaExecutor @@ -1267,13 +1378,12 @@ End /// @param lineVars [optional, default NaN] number of lines in the SF notebook with variable assignments in front of the formula static Function SF_FormulaPlotter(string graph, string formula, [variable dmMode, variable lineVars]) - variable i, dataCnt, splitTraces, numGraphs, traceCnt - variable winDisplayMode, showLegend, line, lineGraph, lineGraphFormula - variable keepUserSelection, formulasAreDifferent, postPlotPSX - variable formulaCounter, xFormulaOffset - variable numTableFormulas, formulaAddedOncePerDataset, showInTable - string win, wList, xAxis - string formulasRemain, moreFormulas, yAndXFormula, xFormula, yFormula, winHook + variable i, j, k, dataCnt, numGraphs, numPlotAND, numPlotWITH + variable winDisplayMode, line, lineGraph, lineGraphFormula, xFormulaOffset + variable keepUserSelection, showInTable, isFullPlot + string wList + string formulasRemain, moreFormulas, yAndXFormula, xFormula, yFormula + STRUCT SF_PlotterGraphStruct pg winDisplayMode = ParamIsDefault(dmMode) ? SF_DM_SUBWINDOWS : dmMode lineVars = ParamIsDefault(lineVars) ? NaN : lineVars @@ -1294,30 +1404,12 @@ static Function SF_FormulaPlotter(string graph, string formula, [variable dmMode WAVE/T winGraphs = outputWindows[%GRAPH] WAVE/WAVE prevPlotProperties = GetSFPlotProperties() - Make/FREE/D/N=2 panelsCreated - SetDimLabel ROWS, 0, GRAPH, panelsCreated - SetDimLabel ROWS, 1, TABLE, panelsCreated - for(i = 0; i < numGraphs; i += 1) - traceCnt = 0 - postPlotPSX = 0 - showLegend = 1 - formulaCounter = 0 - formulasAreDifferent = 0 - WAVE/Z colorGroups = $"" - FastOp panelsCreated = 0 - - Make/FREE/T/N=0 xAxisLabels, yAxisLabels - formulasRemain = graphCode[i][%GRAPHCODE] lineGraph = str2num(graphCode[i][%LINE]) - Make/FREE=1/T/N=(MINIMUM_WAVE_SIZE) wAnnotations, formulaArgSetup, tableFormulas - SetNumberInWaveNote(wAnnotations, NOTE_INDEX, 0) - SetNumberInWaveNote(formulaArgSetup, NOTE_INDEX, 0) - SetNumberInWaveNote(tableFormulas, NOTE_INDEX, 0) - Make/FREE=1/WAVE/N=(MINIMUM_WAVE_SIZE) collPlotFormData + [pg] = SF_InitPlotterGraphStruct(graph) do @@ -1334,73 +1426,70 @@ static Function SF_FormulaPlotter(string graph, string formula, [variable dmMode try [WAVE/WAVE formulaResults, WAVE/T plotMetaData] = SF_GatherFormulaResults(xFormula, yFormula, graph, line, xFormulaOffset) + WAVE/WAVE pg.formulaResults = formulaResults + WAVE/T pg.plotMetaData = plotMetaData catch SF_KillEmptyDataWindows(winGraphs) SF_KillEmptyDataWindows(winTables) Abort endtry - SF_GatherAxisLabels(formulaResults, plotMetaData[%XAXISLABEL], "FORMULAX", xAxisLabels) - SF_GatherAxisLabels(formulaResults, plotMetaData[%YAXISLABEL], "FORMULAY", yAxisLabels) - - showInTable = SF_IsDataForTableDisplay(formulaResults) - if(!panelsCreated[%GRAPH] && !showInTable) - win = SF_CreateDataDisplayWindow(graph, formulaResults, outputWindows, winDisplayMode, prevPlotProperties) - panelsCreated[%GRAPH] = 1 - if(winDisplaymode == SF_DM_NORMAL) - wList = AddListItem(win, wList) + isFullPlot = SF_IsDataForFullPlotting(formulaResults) + numPlotAND = isFullPlot ? DimSize(formulaResults, ROWS) : 1 + for(j = 0; j < numPlotAND; j += 1) + if(isFullPlot) + WAVE/WAVE plotsWITH = formulaResults[j][%FORMULAY] endif - elseif(!panelsCreated[%TABLE] && showInTable) - win = SF_CreateDataDisplayWindow(graph, formulaResults, outputWindows, winDisplayMode, prevPlotProperties) - panelsCreated[%TABLE] = 1 - if(winDisplaymode == SF_DM_NORMAL) - wList = AddListItem(win, wList) - endif - elseif(!showInTable) - win = winGraphs[GetNumberFromWaveNote(winGraphs, NOTE_INDEX) - 1] - else - win = winTables[GetNumberFromWaveNote(winTables, NOTE_INDEX) - 1] - endif - - if(!cmpstr(plotMetaData[%DATATYPE], SF_DATATYPE_PSX)) - PSX_Plot(win, graph, formulaResults, plotMetaData) - postPlotPSX = 1 - continue - endif - - [dataCnt, traceCnt, colorGroups, showLegend] = SF_CreateTracesForResults(graph, formulaResults, formulaCounter, plotMetaData, win, tableFormulas, wAnnotations, formulaArgSetup, collPlotFormData) - formulaCounter += 1 - while(1) - - numTableFormulas = GetNumberFromWaveNote(tableFormulas, NOTE_INDEX) - if(numTableFormulas) - Redimension/N=(numTableFormulas) tableFormulas - SetWindow $win, userdata($SF_UDATA_TABLEFORMULAS)=WaveToJSON(tableFormulas) - endif + numPlotWITH = isFullPlot ? DimSize(plotsWITH, ROWS) : 1 + for(k = 0; k < numPlotWITH; k += 1) + if(isFullPlot) + WAVE/Z/WAVE wvYRef = plotsWITH[k][%FORMULAY] + WAVE/Z/WAVE wvXRef = plotsWITH[k][%FORMULAX] + [WAVE/WAVE formulaResultsInner, WAVE/T plotMetaDataInner] = SF_FillFormulaResults(wvYRef, wvXRef, yFormula) + WAVE/WAVE pg.formulaResults = formulaResultsInner + WAVE/T pg.plotMetaData = plotMetaDataInner + endif - if(panelsCreated[%GRAPH]) - win = winGraphs[GetNumberFromWaveNote(winGraphs, NOTE_INDEX) - 1] - if(showLegend) - formulasAreDifferent = SF_AddPlotLegend(win, wAnnotations, formulaArgSetup, formulaResults) - endif + SF_GatherAxisLabels(pg.formulaResults, plotMetaData[%XAXISLABEL], "FORMULAX", pg.xAxisLabels) + SF_GatherAxisLabels(pg.formulaResults, plotMetaData[%YAXISLABEL], "FORMULAY", pg.yAxisLabels) - SF_AddPlotTicks(graph, win, formulaResults) + showInTable = SF_IsDataForTableDisplay(pg.formulaResults) + if(!pg.panelsCreated[%GRAPH] && !showInTable) + pg.win = SF_CreateDataDisplayWindow(pg.graph, pg.formulaResults, outputWindows, winDisplayMode, prevPlotProperties) + pg.panelsCreated[%GRAPH] = 1 + if(winDisplaymode == SF_DM_NORMAL) + wList = AddListItem(pg.win, wList) + endif + elseif(!pg.panelsCreated[%TABLE] && showInTable) + pg.win = SF_CreateDataDisplayWindow(pg.graph, pg.formulaResults, outputWindows, winDisplayMode, prevPlotProperties) + pg.panelsCreated[%TABLE] = 1 + if(winDisplaymode == SF_DM_NORMAL) + wList = AddListItem(pg.win, wList) + endif + elseif(!showInTable) + pg.win = winGraphs[GetNumberFromWaveNote(winGraphs, NOTE_INDEX) - 1] + else + pg.win = winTables[GetNumberFromWaveNote(winTables, NOTE_INDEX) - 1] + endif - winHook = JWN_GetStringFromWaveNote(formulaResults, SF_META_WINDOW_HOOK) - if(!IsEmpty(winHook)) - SetWindow $win, tooltipHook(SweepFormulaTraceValue)=$winHook - endif + if(!cmpstr(plotMetaData[%DATATYPE], SF_DATATYPE_PSX)) + PSX_Plot(pg.win, graph, pg.formulaResults, pg.plotMetaData) + pg.postPlotPSX = 1 + break + endif - SF_AddPlotTraceStyle(graph, win, formulaCounter, collPlotFormData, formulasAreDifferent) + [dataCnt, pg] = SF_CreateTracesForResults() + pg.formulaCounter += 1 + endfor - if(traceCnt > 0) - SF_AddPlotLabels(win, xAxisLabels, yAxisLabels) - endif - endif + if(j < (numPlotAND - 1)) + [pg] = SF_FinishPlotWindow(winGraphs) + [pg] = SF_InitPlotterGraphStruct(graph) + endif + endfor + while(1) - if(postPlotPSX) - PSX_PostPlot(win) - endif + [pg] = SF_FinishPlotWindow(winGraphs) endfor @@ -1417,13 +1506,80 @@ static Function SF_FormulaPlotter(string graph, string formula, [variable dmMode SF_KillOldDataDisplayWindows(graph, winDisplayMode, wList, outputWindows) End -static Function SF_AddPlotTraceStyle(string graph, string win, variable formulaCounter, WAVE/WAVE collPlotFormData, variable formulasAreDifferent) +/// @brief Sets axis properties for plots of the SF formula plotter. The properties are stored in the plotMetaData wave. +static Function [STRUCT SF_PlotterGraphStruct pg] SF_SetAxisProperties() + + variable xaxisOffset, yaxisOffset, xaxisPercent, yaxisPercent + + xaxisOffset = str2num(pg.plotMetaData[%XAXISOFFSET]) + if(!IsNaN(xaxisOffset)) + ModifyGraph/W=$pg.win axOffset(bottom)=xaxisOffset + endif + yaxisOffset = str2num(pg.plotMetaData[%YAXISOFFSET]) + if(!IsNaN(yaxisOffset)) + ModifyGraph/W=$pg.win axOffset(left)=yaxisOffset + endif + xaxisPercent = str2num(pg.plotMetaData[%XAXISPERCENT]) + if(!IsNaN(xaxisPercent)) + ModifyGraph/W=$pg.win axisEnab(bottom)={0, xaxisPercent * PERCENT_TO_ONE} + endif + yaxisPercent = str2num(pg.plotMetaData[%YAXISPERCENT]) + if(!IsNaN(yaxisPercent)) + ModifyGraph/W=$pg.win axisEnab(left)={0, yaxisPercent * PERCENT_TO_ONE} + endif + + return [pg] +End + +static Function [STRUCT SF_PlotterGraphStruct pg] SF_FinishPlotWindow(WAVE/T winGraphs) + + variable formulasAreDifferent, numTableFormulas + string winHook + + numTableFormulas = GetNumberFromWaveNote(pg.tableFormulas, NOTE_INDEX) + if(numTableFormulas) + Redimension/N=(numTableFormulas) pg.tableFormulas + SetWindow $pg.win, userdata($SF_UDATA_TABLEFORMULAS)=WaveToJSON(pg.tableFormulas) + endif + + if(pg.panelsCreated[%GRAPH]) + + pg.win = winGraphs[GetNumberFromWaveNote(winGraphs, NOTE_INDEX) - 1] + + [pg] = SF_SetAxisProperties() + + if(pg.showLegend) + [formulasAreDifferent, pg] = SF_AddPlotLegend() + endif + + SF_AddPlotTicks(pg.graph, pg.win, pg.formulaResults) + + winHook = JWN_GetStringFromWaveNote(pg.formulaResults, SF_META_WINDOW_HOOK) + if(!IsEmpty(winHook)) + SetWindow $pg.win, tooltipHook(SweepFormulaTraceValue)=$winHook + endif + + [pg] = SF_AddPlotTraceStyle(formulasAreDifferent) + + if(pg.traceCnt > 0) + SF_AddPlotLabels(pg.win, pg.xAxisLabels, pg.yAxisLabels) + endif + endif + + if(pg.postPlotPSX) + PSX_PostPlot(pg.win) + endif + + return [pg] +End + +static Function [STRUCT SF_PlotterGraphStruct pg] SF_AddPlotTraceStyle(variable formulasAreDifferent) variable i, j, numTraces, markerCode, lineCode, isCategoryAxis, tagCounter, lineStyle, overrideMarker, traceToFront string trace, info, tagText, name, wvName - for(i = 0; i < formulaCounter; i += 1) - WAVE/WAVE plotFormData = collPlotFormData[i] + for(i = 0; i < pg.formulaCounter; i += 1) + WAVE/WAVE plotFormData = pg.collPlotFormData[i] WAVE/T tracesInGraph = plotFormData[0] WAVE/WAVE dataInGraph = plotFormData[1] numTraces = DimSize(tracesInGraph, ROWS) @@ -1437,7 +1593,7 @@ static Function SF_AddPlotTraceStyle(string graph, string win, variable formulaC WAVE wvY = dataInGraph[j][%WAVEY] trace = tracesInGraph[j] - info = AxisInfo(win, "left") + info = AxisInfo(pg.win, "left") isCategoryAxis = (NumberByKey("ISCAT", info) == 1) if(isCategoryAxis) @@ -1450,10 +1606,10 @@ static Function SF_AddPlotTraceStyle(string graph, string win, variable formulaC if(WaveExists(traceColor)) switch(DimSize(traceColor, ROWS)) case 3: - ModifyGraph/W=$win rgb($trace)=(traceColor[0], traceColor[1], traceColor[2]) + ModifyGraph/W=$pg.win rgb($trace)=(traceColor[0], traceColor[1], traceColor[2]) break case 4: - ModifyGraph/W=$win rgb($trace)=(traceColor[0], traceColor[1], traceColor[2], traceColor[3]) + ModifyGraph/W=$pg.win rgb($trace)=(traceColor[0], traceColor[1], traceColor[2], traceColor[3]) break default: FATAL_ERROR("Invalid size of trace color wave") @@ -1463,25 +1619,25 @@ static Function SF_AddPlotTraceStyle(string graph, string win, variable formulaC tagText = JWN_GetStringFromWaveNote(wvY, SF_META_TAG_TEXT) if(!IsEmpty(tagText)) name = "tag" + num2str(tagCounter++) - Tag/C/N=$name/W=$win/F=0/L=0/X=0.00/Y=0.00 $trace, 0, tagText + Tag/C/N=$name/W=$pg.win/F=0/L=0/X=0.00/Y=0.00 $trace, 0, tagText endif - ModifyGraph/W=$win mode($trace)=SF_DeriveTraceDisplayMode(wvX, wvY) + ModifyGraph/W=$pg.win mode($trace)=SF_DeriveTraceDisplayMode(wvX, wvY) lineStyle = JWN_GetNumberFromWaveNote(wvY, SF_META_LINESTYLE) if(IsValidTraceLineStyle(lineStyle)) - ModifyGraph/W=$win lStyle($trace)=lineStyle + ModifyGraph/W=$pg.win lStyle($trace)=lineStyle elseif(formulasAreDifferent) - ModifyGraph/W=$win lStyle($trace)=lineCode + ModifyGraph/W=$pg.win lStyle($trace)=lineCode endif WAVE/Z customMarkerAsFree = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_MOD_MARKER) if(WaveExists(customMarkerAsFree)) - DFREF dfrWork = SFH_GetWorkingDF(graph) + DFREF dfrWork = SFH_GetWorkingDF(pg.graph) wvName = "customMarker_" + NameOfWave(wvY) WAVE customMarker = MoveFreeWaveToPermanent(customMarkerAsFree, dfrWork, wvName) ASSERT(DimSize(wvY, ROWS) == DimSize(customMarker, ROWS), "Marker size mismatch") - ModifyGraph/W=$win zmrkNum($trace)={customMarker} + ModifyGraph/W=$pg.win zmrkNum($trace)={customMarker} else overrideMarker = JWN_GetNumberFromWaveNote(wvY, SF_META_MOD_MARKER) @@ -1489,13 +1645,13 @@ static Function SF_AddPlotTraceStyle(string graph, string win, variable formulaC markerCode = overrideMarker endif - ModifyGraph/W=$win marker($trace)=markerCode + ModifyGraph/W=$pg.win marker($trace)=markerCode endif traceToFront = JWN_GetNumberFromWaveNote(wvY, SF_META_TRACETOFRONT) traceToFront = IsNaN(traceToFront) ? 0 : !!traceToFront if(traceToFront) - ReorderTraces/W=$win _front_, {$trace} + ReorderTraces/W=$pg.win _front_, {$trace} endif endfor @@ -1541,30 +1697,32 @@ static Function SF_AddPlotTicks(string graph, string win, WAVE formulaResults) endif End -static Function SF_AddPlotLegend(string win, WAVE/T wAnnotations, WAVE formulaArgSetup, WAVE formulaResults) +static Function [variable formulasAreDifferent, STRUCT SF_PlotterGraphStruct pg] SF_AddPlotLegend() - variable numAnnotations, formulasAreDifferent - string customLegend + variable numAnnotations + string customLegend string annotation = "" - numAnnotations = GetNumberFromWaveNote(wAnnotations, NOTE_INDEX) - customLegend = JWN_GetStringFromWaveNote(formulaResults, SF_META_CUSTOM_LEGEND) + formulasAreDifferent = 0 + + numAnnotations = GetNumberFromWaveNote(pg.wAnnotations, NOTE_INDEX) + customLegend = JWN_GetStringFromWaveNote(pg.formulaResults, SF_META_CUSTOM_LEGEND) if(!IsEmpty(customLegend)) annotation = customLegend elseif(numAnnotations > 0) - wAnnotations[0, numAnnotations - 1] = SF_ShrinkLegend(wAnnotations[p]) - Redimension/N=(numAnnotations) wAnnotations, formulaArgSetup - formulasAreDifferent = SFH_EnrichAnnotations(wAnnotations, formulaArgSetup) - annotation = TextWaveToList(wAnnotations, "\r") + pg.wAnnotations[0, numAnnotations - 1] = SF_ShrinkLegend(pg.wAnnotations[p]) + Redimension/N=(numAnnotations) pg.wAnnotations, pg.formulaArgSetup + formulasAreDifferent = SFH_EnrichAnnotations(pg.wAnnotations, pg.formulaArgSetup) + annotation = TextWaveToList(pg.wAnnotations, "\r") annotation = UnPadString(annotation, char2num("\r")) endif if(!IsEmpty(annotation)) - Legend/W=$win/C/N=metadata/F=2 annotation + Legend/W=$pg.win/C/N=metadata/F=2 annotation endif - return formulasAreDifferent + return [formulasAreDifferent, pg] End static Function SF_AddPlotLabels(string win, WAVE xAxisLabels, WAVE yAxisLabels) @@ -2705,3 +2863,9 @@ Function SF_TableWindowHook(STRUCT WMWinHookStruct &s) return 0 End + +/// @brief Adds an expression to a formula string with the proper termination character +Function/S SF_AddExpressionToFormula(string formula, string expr) + + return formula + expr + SF_CHAR_CR +End diff --git a/Packages/MIES/MIES_SweepFormula_Executor.ipf b/Packages/MIES/MIES_SweepFormula_Executor.ipf index e6ba507602..5559358041 100644 --- a/Packages/MIES/MIES_SweepFormula_Executor.ipf +++ b/Packages/MIES/MIES_SweepFormula_Executor.ipf @@ -517,6 +517,9 @@ Function/WAVE SFE_FormulaExecutor(STRUCT SF_ExecutionData &exd, [variable srcLoc case SF_OP_TABLE: WAVE out = SFO_OperationTable(exdop) break + case SF_OP_IVSCCAPFREQUENCY: + WAVE out = SFO_OperationIVSCCApFrequency(exdop) + break default: SFH_FATAL_ERROR("Undefined Operation", jsonId = exdop.jsonId) endswitch diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index d0e9ba1753..e57634b5de 100644 --- a/Packages/MIES/MIES_SweepFormula_Helpers.ipf +++ b/Packages/MIES/MIES_SweepFormula_Helpers.ipf @@ -2173,3 +2173,51 @@ Function/WAVE SFH_GetDatasetArrayAsResolvedWaverefs(STRUCT SF_ExecutionData &exd return dataFromEachGroup End + +/// @brief Executes a formula from within an operation with low overhead +/// - the currently active variable storage is used +/// - the formula string is not preprocessed +Function/WAVE SFH_ExecuteFormulaInternal(string graph, string formula) + + STRUCT SF_ExecutionData exd + variable jsonId, srcLocId + + exd.graph = graph + [jsonId, srcLocId] = SFP_ParseFormulaToJSON(formula) + exd.jsonId = jsonId + WAVE dataRef = SFE_FormulaExecutor(exd, srcLocId = srcLocId) + + JSON_Release(exd.jsonId) + JSON_Release(srcLocId) + + WAVE resolved = SF_ResolveDataset(dataRef) + + return resolved +End + +/// @brief Adds a variable to the variable storage. If the variable already exists it is overwritten. +Function SFH_AddVariableToStorage(string graph, string name, WAVE result) + + variable size, idx + + WAVE/WAVE varStorage = GetSFVarStorage(graph) + idx = FindDimLabel(varStorage, ROWS, name) + if(idx == -2) + size = DimSize(varStorage, ROWS) + Redimension/N=(size + 1) varStorage + idx = size + endif + varStorage[idx] = result + SetDimLabel ROWS, idx, $name, varStorage +End + +/// @brief Copy plot meta data JSON properties from a source to a target wave +Function SFH_CopyPlotMetaData(WAVE input, WAVE output) + + WAVE/Z wv = JWN_GetNumericWaveFromWaveNote(input, SF_META_TRACECOLOR) + if(WaveExists(wv)) + JWN_SetWaveInWaveNote(output, SF_META_TRACECOLOR, wv) + endif + JWN_SetNumberInWaveNote(output, SF_META_TRACETOFRONT, JWN_GetNumberFromWaveNote(input, SF_META_TRACETOFRONT)) + JWN_SetNumberInWaveNote(output, SF_META_LINESTYLE, JWN_GetNumberFromWaveNote(input, SF_META_LINESTYLE)) +End diff --git a/Packages/MIES/MIES_SweepFormula_Operations.ipf b/Packages/MIES/MIES_SweepFormula_Operations.ipf index 301cb47a02..10ddeb9951 100644 --- a/Packages/MIES/MIES_SweepFormula_Operations.ipf +++ b/Packages/MIES/MIES_SweepFormula_Operations.ipf @@ -30,9 +30,15 @@ static StrConstant SF_OP_APFREQUENCY_NONORM = "nonorm" static StrConstant SF_OP_APFREQUENCY_X_COUNT = "count" static StrConstant SF_OP_APFREQUENCY_X_TIME = "time" +static StrConstant SF_OP_IVSCCAPFREQUENCY_FIRST = "first" +static StrConstant SF_OP_IVSCCAPFREQUENCY_MIN = "min" +static StrConstant SF_OP_IVSCCAPFREQUENCY_MAX = "max" +static StrConstant SF_OP_IVSCCAPFREQUENCY_NONE = "none" + static StrConstant SF_OP_AVG_INSWEEPS = "in" static StrConstant SF_OP_AVG_OVERSWEEPS = "over" static StrConstant SF_OP_AVG_GROUPS = "group" +static StrConstant SF_OP_AVG_BINS = "bins" static StrConstant SF_OP_EPOCHS_TYPE_RANGE = "range" static StrConstant SF_OP_EPOCHS_TYPE_NAME = "name" @@ -235,6 +241,25 @@ static Function/WAVE SFO_OperationAnaFuncParamImplAllNames(WAVE/T names, WAVE/WA return GetUniqueEntries(allNames) End +static Function [variable method, variable level, string timeFreq, string normalize, string xAxisType] SFO_GetApFrequencyArguments(STRUCT SF_ExecutionData &exd, string opShort, variable offset) + + method = SFH_GetArgumentAsNumeric(exd, opShort, offset, defValue = SF_APFREQUENCY_FULL, allowedValues = {SF_APFREQUENCY_FULL, SF_APFREQUENCY_INSTANTANEOUS, SF_APFREQUENCY_APCOUNT, SF_APFREQUENCY_INSTANTANEOUS_PAIR}) + level = SFH_GetArgumentAsNumeric(exd, opShort, offset + 1, defValue = 0) + timeFreq = SFH_GetArgumentAsText(exd, opShort, offset + 2, defValue = SF_OP_APFREQUENCY_Y_FREQ, allowedValues = {SF_OP_APFREQUENCY_Y_TIME, SF_OP_APFREQUENCY_Y_FREQ}) + normalize = SFH_GetArgumentAsText(exd, opShort, offset + 3, defValue = SF_OP_APFREQUENCY_NONORM, allowedValues = { \ + SF_OP_APFREQUENCY_NONORM, \ + SF_OP_APFREQUENCY_NORMOVERSWEEPSMIN, \ + SF_OP_APFREQUENCY_NORMOVERSWEEPSMAX, \ + SF_OP_APFREQUENCY_NORMOVERSWEEPSAVG, \ + SF_OP_APFREQUENCY_NORMWITHINSWEEPMIN, \ + SF_OP_APFREQUENCY_NORMWITHINSWEEPMAX, \ + SF_OP_APFREQUENCY_NORMWITHINSWEEPAVG \ + }) + xAxisType = SFH_GetArgumentAsText(exd, opShort, offset + 4, defValue = SF_OP_APFREQUENCY_X_TIME, allowedValues = {SF_OP_APFREQUENCY_X_TIME, SF_OP_APFREQUENCY_X_COUNT}) + + return [method, level, timeFreq, normalize, xAxisType] +End + // apfrequency(data, [frequency calculation method], [spike detection crossing level], [result value type], [normalize], [x-axis type]) Function/WAVE SFO_OperationApFrequency(STRUCT SF_ExecutionData &exd) @@ -249,19 +274,7 @@ Function/WAVE SFO_OperationApFrequency(STRUCT SF_ExecutionData &exd) SFH_ASSERT(numArgs >= numArgsMin, "ApFrequency needs at least " + num2istr(numArgsMin) + " argument(s).") WAVE/WAVE input = SF_ResolveDatasetFromJSON(exd, 0) - method = SFH_GetArgumentAsNumeric(exd, opShort, 1, defValue = SF_APFREQUENCY_FULL, allowedValues = {SF_APFREQUENCY_FULL, SF_APFREQUENCY_INSTANTANEOUS, SF_APFREQUENCY_APCOUNT, SF_APFREQUENCY_INSTANTANEOUS_PAIR}) - level = SFH_GetArgumentAsNumeric(exd, opShort, 2, defValue = 0) - timeFreq = SFH_GetArgumentAsText(exd, opShort, 3, defValue = SF_OP_APFREQUENCY_Y_FREQ, allowedValues = {SF_OP_APFREQUENCY_Y_TIME, SF_OP_APFREQUENCY_Y_FREQ}) - normalize = SFH_GetArgumentAsText(exd, opShort, 4, defValue = SF_OP_APFREQUENCY_NONORM, allowedValues = { \ - SF_OP_APFREQUENCY_NONORM, \ - SF_OP_APFREQUENCY_NORMOVERSWEEPSMIN, \ - SF_OP_APFREQUENCY_NORMOVERSWEEPSMAX, \ - SF_OP_APFREQUENCY_NORMOVERSWEEPSAVG, \ - SF_OP_APFREQUENCY_NORMWITHINSWEEPMIN, \ - SF_OP_APFREQUENCY_NORMWITHINSWEEPMAX, \ - SF_OP_APFREQUENCY_NORMWITHINSWEEPAVG \ - }) - xAxisType = SFH_GetArgumentAsText(exd, opShort, 5, defValue = SF_OP_APFREQUENCY_X_TIME, allowedValues = {SF_OP_APFREQUENCY_X_TIME, SF_OP_APFREQUENCY_X_COUNT}) + [method, level, timeFreq, normalize, xAxisType] = SFO_GetApFrequencyArguments(exd, opShort, 1) WAVE/T argSetup = SFH_GetNewArgSetupWave(numArgsMax - 1) @@ -488,13 +501,13 @@ End Function/WAVE SFO_OperationAvg(STRUCT SF_ExecutionData &exd) - variable numArgs - string mode + variable numArgs, binWidth + string mode string opShort = SF_OP_AVG - numArgs = SFH_CheckArgumentCount(exd, opShort, 1, maxArgs = 2) + numArgs = SFH_CheckArgumentCount(exd, opShort, 1, maxArgs = 5) - mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS, SF_OP_AVG_GROUPS}) + mode = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_AVG_INSWEEPS, allowedValues = {SF_OP_AVG_INSWEEPS, SF_OP_AVG_OVERSWEEPS, SF_OP_AVG_GROUPS, SF_OP_AVG_BINS}) if(!CmpStr(mode, SF_OP_AVG_INSWEEPS) || !CmpStr(mode, SF_OP_AVG_OVERSWEEPS)) WAVE/WAVE input = SFH_GetArgumentAsWave(exd, opShort, 0, resolveSelect = 1) strswitch(mode) @@ -513,17 +526,113 @@ Function/WAVE SFO_OperationAvg(STRUCT SF_ExecutionData &exd) elseif(!CmpStr(mode, SF_OP_AVG_GROUPS)) WAVE/WAVE dataFromEachGroup = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 0, resolveSelect = 1) WAVE/WAVE averagedGroup = SFO_OperationAvgImplSweepGroups(dataFromEachGroup, exd.graph, opShort) - SFH_TransferFormulaDataWaveNoteAndMeta(dataFromEachGroup[0], averagedGroup, opShort, SF_DATATYPE_AVG) return SFH_GetOutputForExecutor(averagedGroup, exd.graph, opShort) - else - FATAL_ERROR("Unhandled avg operation mode") + elseif(!CmpStr(mode, SF_OP_AVG_BINS)) + WAVE/WAVE dataFromEachGroup = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 0, resolveSelect = 1) + WAVE/WAVE wTmp = SFH_GetArgumentAsWave(exd, opShort, 2) + WAVE binRange = wTmp[0] + SFH_ASSERT(DimSize(binRange, ROWS) == 2, "Expected range in the form of [start, end]") + SFH_ASSERT(binRange[1] > binRange[0], "The end of the bin range must be greater than the start") + binWidth = SFH_GetArgumentAsNumeric(exd, opShort, 3, checkFunc = IsStrictlyPositiveAndFinite) + WAVE/WAVE binData = SFH_GetDatasetArrayAsResolvedWaverefs(exd, 4, resolveSelect = 1) + SFH_ASSERT(DimSize(dataFromEachGroup, ROWS) == DimSize(binData, ROWS), "input data and bin data must have the same number of groups") + WAVE/WAVE averagedBins = SFO_OperationAvgImplBins(dataFromEachGroup, exd.graph, opShort, binData, binRange, binWidth) + return SFH_GetOutputForExecutor(averagedBins, exd.graph, opShort) endif End +static Function/WAVE SFO_OperationAvgImplBins(WAVE/WAVE input, string graph, string opShort, WAVE/WAVE binData, WAVE binRange, variable binWidth) + + variable i, j, numBins, binStart, binEnd, numGroups, numDataSets, binValue, binPos, idx + STRUCT RGBColor s + + [s] = GetTraceColorForAverage() + Make/FREE/W/U traceColor = {s.red, s.green, s.blue} + + numGroups = DimSize(input, ROWS) + binStart = binRange[0] + binEnd = binRange[1] + numBins = ceil((binEnd - binStart) / binWidth) + SFH_ASSERT(numBins < 1E6, "Maximum number of bins is 1E6.") + + // Gather + Make/FREE/WAVE/N=(numBins, numGroups) binnedPerGroup + for(i = 0; i < numGroups; i += 1) + WAVE/WAVE dataSets = input[i] + WAVE/WAVE binDataSets = binData[i] + numDataSets = DimSize(dataSets, ROWS) + SFH_ASSERT(numDataSets == DimSize(binDataSets, ROWS), "The number of datasets of the input and bins are not the same for group " + num2istr(i)) + for(j = 0; j < numDataSets; j += 1) + SFH_ASSERT(DimSize(binDataSets[j], ROWS) == 1, "A bin dataset must have exactly one value") + binValue = WaveRef(binDataSets, row = j)[0] + if(binValue < binStart || binValue >= binEnd) + continue + endif + binPos = floor((binValue - binStart) / binWidth) + // Add to bin + WAVE/Z/WAVE wavesInBin = binnedPerGroup[binPos][i] + if(!WaveExists(wavesInBin)) + Make/FREE/WAVE wavesInBin = {dataSets[j]} + SetNumberInWaveNote(wavesInBin, NOTE_INDEX, 1) + binnedPerGroup[binPos][i] = wavesInBin + continue + endif + idx = GetNumberFromWaveNote(wavesInBin, NOTE_INDEX) + EnsureLargeEnoughWave(wavesInBin, indexShouldExist = idx) + wavesInBin[idx] = dataSets[j] + SetNumberInWaveNote(wavesInBin, NOTE_INDEX, idx + 1) + endfor + endfor + // avg bins with multiple filling + for(i = 0; i < numBins; i += 1) + for(j = 0; j < numGroups; j += 1) + if(!WaveExists(binnedPerGroup[i][j])) + continue + endif + WAVE/WAVE wavesInBin = binnedPerGroup[i][j] + idx = GetNumberFromWaveNote(wavesInBin, NOTE_INDEX) + Redimension/N=(idx) wavesInBin + if(idx == 1) + continue + endif + WAVE/WAVE avg = MIES_fWaveAverage(wavesInBin, 1, IGOR_TYPE_64BIT_FLOAT) + Redimension/N=(1) wavesInBin + wavesInBin[0] = avg[0] + endfor + endfor + // avg same bins + WAVE/WAVE output = SFH_CreateSFRefWave(graph, opShort, numBins) + for(i = 0; i < numBins; i += 1) + Make/FREE/WAVE/N=(numGroups) sameBin + idx = 0 + for(j = 0; j < numGroups; j += 1) + if(!WaveExists(binnedPerGroup[i][j])) + continue + endif + WAVE/WAVE wavesInBin = binnedPerGroup[i][j] + sameBin[idx] = wavesInBin[0] + idx += 1 + endfor + if(idx == 0) + Make/FREE/D tmp = {NaN} + output[i] = tmp + else + Redimension/N=(idx) sameBin + WAVE/WAVE avg = MIES_fWaveAverage(sameBin, 1, IGOR_TYPE_64BIT_FLOAT) + output[i] = avg[0] + endif + JWN_SetWaveInWaveNote(output[i], SF_META_TRACECOLOR, traceColor) + JWN_SetNumberInWaveNote(output[i], SF_META_TRACETOFRONT, 1) + JWN_SetNumberInWaveNote(output[i], SF_META_LINESTYLE, 0) + endfor + + return output +End + static Function/WAVE SFO_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSelection, string graph, string opShort) - variable numData, numMaxSweeps, numGroups, i, j + variable numData, numMaxSweeps, numGroups, i, j, maxIdx STRUCT RGBColor s [s] = GetTraceColorForAverage() @@ -531,7 +640,9 @@ static Function/WAVE SFO_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSel numGroups = DimSize(sweepsFromEachSelection, ROWS) Make/FREE/D/N=(numGroups) sweepCnts = DimSize(sweepsFromEachSelection[p], ROWS) - numMaxSweeps = WaveMax(sweepCnts) + WaveStats/Q/M=1 sweepCnts + numMaxSweeps = V_max + maxIdx = V_maxRowLoc WAVE/WAVE output = SFH_CreateSFRefWave(graph, opShort, numMaxSweeps) for(i = 0; i < numMaxSweeps; i += 1) Make/FREE/WAVE/N=(numGroups) avgSet @@ -549,6 +660,7 @@ static Function/WAVE SFO_OperationAvgImplSweepGroups(WAVE/WAVE sweepsFromEachSel JWN_SetNumberInWaveNote(output[i], SF_META_TRACETOFRONT, 1) JWN_SetNumberInWaveNote(output[i], SF_META_LINESTYLE, 0) endfor + SFH_TransferFormulaDataWaveNoteAndMeta(sweepsFromEachSelection[maxIdx], output, opShort, SF_DATATYPE_AVG) return output End @@ -1565,6 +1677,8 @@ Function/WAVE SFO_OperationMerge(STRUCT SF_ExecutionData &exd) output[0] = content + SFH_CopyPlotMetaData(input[0], output[0]) + return SFH_GetOutputForExecutor(output, exd.graph, SF_OP_MERGE) End @@ -2481,3 +2595,161 @@ Function/WAVE SFO_OperationTable(STRUCT SF_ExecutionData &exd) return SFH_GetOutputForExecutor(output, exd.graph, SF_OP_TABLE) End + +/// @brief Sets the plot meta data for the ivscc_apfrequency operation +static Function SFO_OperationIVSCCApFrequencySetPlotProperties(WAVE wvY, variable xAxisPercentage, variable yAxisPercentage) + + JWN_SetNumberInWaveNote(wvY, SF_META_XAXISPERCENT, xAxisPercentage) + JWN_SetNumberInWaveNote(wvY, SF_META_YAXISPERCENT, yAxisPercentage) +End + +// ivscc_apfrequency([xaxisOffset, yaxisOffset, xAxisPercentage, yAxisPercentage]) +Function/WAVE SFO_OperationIVSCCApFrequency(STRUCT SF_ExecutionData &exd) + + string opShort = SF_OP_IVSCCAPFREQUENCY + variable numArgsMin = 0 + variable numArgsMax = 9 + string formula, expr, exprPart + variable i, numArgs, col, size, numExp + variable xAxisPercentage, yAxisPercentage + string xaxisOffset, yaxisOffset + variable method, level, binWidth, numBins + string timeFreq, normalize, xAxisType, freqList, currentList, expList, binList + STRUCT RGBColor s + + SFH_ASSERT(BSP_IsSweepBrowser(exd.graph), "ivscc_apfrequency only works with sweepbrowser") + + numArgs = SFH_GetNumberOfArguments(exd) + SFH_ASSERT(numArgs <= numArgsMax, "ivscc_apfrequency has " + num2istr(numArgsMax) + " arguments at most.") + SFH_ASSERT(numArgs >= numArgsMin, "ivscc_apfrequency needs at least " + num2istr(numArgsMin) + " argument(s).") + + xaxisOffset = SFH_GetArgumentAsText(exd, opShort, 0, defValue = SF_OP_IVSCCAPFREQUENCY_MIN, allowedValues = {SF_OP_IVSCCAPFREQUENCY_FIRST, SF_OP_IVSCCAPFREQUENCY_MIN, SF_OP_IVSCCAPFREQUENCY_MAX, SF_OP_IVSCCAPFREQUENCY_NONE}) + yaxisOffset = SFH_GetArgumentAsText(exd, opShort, 1, defValue = SF_OP_IVSCCAPFREQUENCY_MIN, allowedValues = {SF_OP_IVSCCAPFREQUENCY_FIRST, SF_OP_IVSCCAPFREQUENCY_MIN, SF_OP_IVSCCAPFREQUENCY_MAX, SF_OP_IVSCCAPFREQUENCY_NONE}) + xAxisPercentage = SFH_GetArgumentAsNumeric(exd, opShort, 2, defValue = 100, checkFunc = BetweenZeroAndOneHoundred) + yAxisPercentage = SFH_GetArgumentAsNumeric(exd, opShort, 3, defValue = 100, checkFunc = BetweenZeroAndOneHoundred) + WAVE/WAVE wTmp = SFH_GetArgumentAsWave(exd, opShort, 4) + WAVE binRange = wTmp[0] + binWidth = SFH_GetArgumentAsNumeric(exd, opShort, 5, checkFunc = IsStrictlyPositiveAndFinite) + [method, level, timeFreq, normalize, xAxisType] = SFO_GetApFrequencyArguments(exd, opShort, 6) + + WAVE/T sweepMap = SB_GetSweepMap(exd.graph) + col = FindDimlabel(sweepMap, COLS, "FileName") + size = GetNumberFromWaveNote(sweepMap, NOTE_INDEX) + Duplicate/FREE/RMD=[0, size - 1][col] sweepMap, fileNames + WAVE/T uniqueFiles = GetUniqueEntries(fileNames, dontDuplicate = 1) + Sort uniqueFiles, uniqueFiles + numExp = DimSize(uniqueFiles, ROWS) + SFH_ASSERT(numExp > 0, "ivscc_apfrequency: data from at least one experiment has to be loaded") + + formula = "sel = select(selsweeps(), selstimset(\"*rheo*\", \"*supra*\"), selvis(all), selivsccsweepqc(passed))\r" + for(i = 0; i < numExp; i += 1) + sprintf expr, "selexpAD%d = select(selexp(\"%s\"), $sel, selchannels(AD0), selrange(E1))", i, uniqueFiles[i] + formula = SF_AddExpressionToFormula(formula, expr) + sprintf expr, "selexpDA%d = select(selexp(\"%s\"), $sel, selchannels(DA0), selrange(E1))", i, uniqueFiles[i] + formula = SF_AddExpressionToFormula(formula, expr) + sprintf expr, "freq%d = apfrequency(data($selexpAD%d), %d, %f, %s, %s, %s)", i, i, method, level, timeFreq, normalize, xAxisType + formula = SF_AddExpressionToFormula(formula, expr) + sprintf expr, "current%d = max(data($selexpDA%d))", i, i + formula = SF_AddExpressionToFormula(formula, expr) + if(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + sprintf expr, "currentNorm%d = $current%d - extract($current%d, 0)", i, i, i + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + sprintf expr, "currentNorm%d = $current%d - min(merge($current%d))", i, i, i + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + sprintf expr, "currentNorm%d = $current%d - max(merge($current%d))", i, i, i + else // SF_OP_IVSCCAPFREQUENCY_NONE + sprintf expr, "currentNorm%d = $current%d", i, i + endif + formula = SF_AddExpressionToFormula(formula, expr) + endfor + + Make/FREE/T/N=(numExp) freqs, currents, exps + freqs[] = "$freq" + num2istr(p) + freqList = TextWaveToList(freqs, ",", trailSep = 0) + currents[] = "$currentNorm" + num2istr(p) + currentList = TextWaveToList(currents, ",", trailSep = 0) + exps[] = "\"" + uniqueFiles[p] + "\"" + expList = TextWaveToList(exps, ",", trailSep = 0) + + sprintf expr, "ivsccavg = avg([%s], bins, [%f,%f],%f,[%s])", freqList, binRange[0], binRange[1], binWidth, currentList + formula = SF_AddExpressionToFormula(formula, expr) + + sprintf expr, "ivscccurrentavg = avg([%s], bins, [%f,%f],%f,[%s])", currentList, binRange[0], binRange[1], binWidth, currentList + formula = SF_AddExpressionToFormula(formula, expr) + + sprintf expr, "ivscc_apfrequency_explist = [%s]", expList + formula = SF_AddExpressionToFormula(formula, expr) + + WAVE/WAVE varStorage = GetSFVarStorage(exd.graph) + Duplicate/FREE varStorage, varBackup + SFE_ExecuteVariableAssignments(exd.graph, formula) + + WAVE/WAVE varStorageOp = GetSFVarStorage(exd.graph) + WAVE wvResult = varStorageOp[%ivscc_apfrequency_explist] + + WAVE/WAVE plotAND = SFH_CreateSFRefWave(exd.graph, opShort, 1) + Make/FREE/WAVE/N=(numExp + 1, 2) plotWITH + SetDimlabel COLS, 0, FORMULAX, plotWITH + SetDimlabel COLS, 1, FORMULAY, plotWITH + plotAND[0] = plotWITH + + for(i = 0; i < numExp; i += 1) + if(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + sprintf formula, "merge($freq%d - extract($freq%d, 0))", i, i + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + sprintf formula, "merge($freq%d - min(merge($freq%d)))", i, i + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + sprintf formula, "merge($freq%d - max(merge($freq%d)))", i, i + else // SF_OP_IVSCCAPFREQUENCY_NONE + sprintf formula, "merge($freq%d)", i + endif + WAVE/WAVE wvY = SFH_ExecuteFormulaInternal(exd.graph, formula) + [s] = GetTraceColor(i) + Make/FREE/W/U traceColor = {s.red, s.green, s.blue} + JWN_SetWaveInWaveNote(wvY[0], SF_META_TRACECOLOR, traceColor) + JWN_SetNumberInWaveNote(wvY[0], SF_META_MOD_MARKER, 17) + JWN_SetStringInWaveNote(wvY[0], SF_META_LEGEND_LINE_PREFIX, uniqueFiles[i]) + plotWITH[i][%FORMULAY] = wvY + SFO_OperationIVSCCApFrequencySetPlotProperties(plotWITH[i][%FORMULAY], xAxisPercentage, yAxisPercentage) + sprintf formula, "merge($currentNorm%d)", i + plotWITH[i][%FORMULAX] = SFH_ExecuteFormulaInternal(exd.graph, formula) + endfor + + if(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + formula = "merge($ivsccavg - extract($ivsccavg, 0))" + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + formula = "merge($ivsccavg - min(merge($ivsccavg)))" + elseif(!CmpStr(yaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + formula = "merge($ivsccavg - max(merge($ivsccavg)))" + else // SF_OP_IVSCCAPFREQUENCY_NONE + formula = "merge($ivsccavg)" + endif + WAVE/WAVE wvY = SFH_ExecuteFormulaInternal(exd.graph, formula) + JWN_SetStringInWaveNote(wvY[0], SF_META_LEGEND_LINE_PREFIX, "ivscc_apfrequency average") + plotWITH[numExp][%FORMULAY] = wvY + SFO_OperationIVSCCApFrequencySetPlotProperties(plotWITH[i][%FORMULAY], xAxisPercentage, yAxisPercentage) + + if(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_FIRST)) + formula = "merge($ivscccurrentavg - extract($ivscccurrentavg, 0))" + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MIN)) + formula = "merge($ivscccurrentavg - min(merge($ivscccurrentavg)))" + elseif(!CmpStr(xaxisOffset, SF_OP_IVSCCAPFREQUENCY_MAX)) + formula = "merge($ivscccurrentavg - max(merge($ivscccurrentavg)))" + else // SF_OP_IVSCCAPFREQUENCY_NONE + formula = "merge($ivscccurrentavg)" + endif + + numBins = ceil((binRange[1] - binRange[0]) / binWidth) + Make/FREE/D/N=(numBins) binValues + binValues[] = binRange[0] + p * binWidth + binWidth / 2 + binList = NumericWaveToList(binValues, ",", format = "%f", trailSep = 0) + sprintf formula, "[%s]", binList + plotWITH[numExp][%FORMULAX] = SFH_ExecuteFormulaInternal(exd.graph, formula) + + Duplicate/O varBackup, varStorage + SFH_AddVariableToStorage(exd.graph, "ivscc_apfrequency_explist", wvResult) + + JWN_SetNumberInWaveNote(plotAND, SF_META_PLOT, 1) + + return SFH_GetOutputForExecutor(plotAND, exd.graph, opShort) +End diff --git a/Packages/MIES/MIES_WaveDataFolderGetters.ipf b/Packages/MIES/MIES_WaveDataFolderGetters.ipf index ec9685c2b9..d32227d065 100644 --- a/Packages/MIES/MIES_WaveDataFolderGetters.ipf +++ b/Packages/MIES/MIES_WaveDataFolderGetters.ipf @@ -9284,8 +9284,8 @@ End /// @brief Wave storing sf plot meta information per formularesult, filled in SF_GatherFormulaResults Function/WAVE GetSFPlotMetaData() - Make/FREE/T/N=(5) wv - SetDimensionLabels(wv, "DATATYPE;OPSTACK;ARGSETUPSTACK;XAXISLABEL;YAXISLABEL;", ROWS) + Make/FREE/T/N=(9) wv + SetDimensionLabels(wv, "DATATYPE;OPSTACK;ARGSETUPSTACK;XAXISLABEL;YAXISLABEL;XAXISOFFSET;YAXISOFFSET;XAXISPERCENT;YAXISPERCENT;", ROWS) return wv End