diff --git a/Packages/MIES/MIES_AnalysisFunctionHelpers.ipf b/Packages/MIES/MIES_AnalysisFunctionHelpers.ipf index da9127c777..8ddcb0a6c9 100644 --- a/Packages/MIES/MIES_AnalysisFunctionHelpers.ipf +++ b/Packages/MIES/MIES_AnalysisFunctionHelpers.ipf @@ -935,6 +935,50 @@ Function AFH_AddAnalysisParameter(string setName, string name, [variable var, st endif End +/// @brief Return a stringified version of the analysis parameter value +/// +/// @param name name of the parameter +/// @param params serialized parameters, usually just #AnalysisFunction_V3.params +Function/S AFH_GetAnalysisParameterAsText(string name, string params) + + string type + variable numericValue + + ASSERT(AFH_IsValidAnalysisParameter(name), "Name is not a legal non-liberal igor object name") + + type = AFH_GetAnalysisParamType(name, params, typeCheck = 0) + + strswitch(type) + case "variable": + numericValue = AFH_GetAnalysisParamNumerical(name, params) + if(!IsNan(numericValue)) + return num2str(numericValue) + endif + break + case "string": + return AFH_GetAnalysisParamTextual(name, params) + break + case "wave": + WAVE/Z wv = AFH_GetAnalysisParamWave(name, params) + if(WaveExists(wv)) + return NumericWaveToList(wv, ";") + endif + break + case "textwave": + WAVE/Z wv = AFH_GetAnalysisParamTextWave(name, params) + if(WaveExists(wv)) + return TextWaveToList(wv, ";") + endif + break + case "": // unknown name + break + default: + ASSERT(0, "invalid type") + endswitch + + return "" +End + /// @brief Return the headstage from the given active AD count /// /// @param statusADC channel status as returned by GetLastSetting() diff --git a/Packages/MIES/MIES_SweepFormula.ipf b/Packages/MIES/MIES_SweepFormula.ipf index 2cf92ca180..2dcbec1711 100644 --- a/Packages/MIES/MIES_SweepFormula.ipf +++ b/Packages/MIES/MIES_SweepFormula.ipf @@ -1217,6 +1217,8 @@ static Function/S SF_GetAnnotationPrefix(string dataType) return "" case SF_DATATYPE_TP: return "TP " + case SF_DATATYPE_LABNOTEBOOK: + return "LB " default: ASSERT(0, "Invalid dataType") endswitch @@ -1232,7 +1234,8 @@ static Function/S SF_GetTraceAnnotationText(STRUCT SF_PlotMetaData& plotMetaData strswitch(plotMetaData.dataType) case SF_DATATYPE_EPOCHS: // fallthrough - case SF_DATATYPE_SWEEP: // fallthrough + case SF_DATATYPE_SWEEP: // fallthrough + case SF_DATATYPE_LABNOTEBOOK: // fallthrough case SF_DATATYPE_TP: sweepNo = JWN_GetNumberFromWaveNote(data, SF_META_SWEEPNO) annotationPrefix = SF_GetAnnotationPrefix(plotMetaData.dataType) @@ -1288,7 +1291,7 @@ Function [STRUCT RGBColor s] SF_GetTraceColor(string graph, string opStack, WAVE s.blue = 0x0000 Make/FREE/T stopInheritance = {SF_OPSHORT_MINUS, SF_OPSHORT_PLUS, SF_OPSHORT_DIV, SF_OPSHORT_MULT} - Make/FREE/T doInheritance = {SF_OP_DATA, SF_OP_TP, SF_OP_PSX, SF_OP_PSX_STATS, SF_OP_EPOCHS} + Make/FREE/T doInheritance = {SF_OP_DATA, SF_OP_TP, SF_OP_PSX, SF_OP_PSX_STATS, SF_OP_EPOCHS, SF_OP_LABNOTEBOOK} WAVE/T opStackW = ListToTextWave(opStack, ";") numDoInh = DimSize(doInheritance, ROWS) @@ -1900,7 +1903,16 @@ static Function SF_FormulaPlotter(string graph, string formula, [DFREF dfr, vari WAVE wvY = dataInGraph[l][%WAVEY] trace = tracesInGraph[l] - WAVE/Z traceColor = JWN_GetNumericWaveFromWaveNote(wvY, SF_META_TRACECOLOR) + info = AxisInfo(win, "left") + isCategoryAxis = (NumberByKey("ISCAT", info) == 1) + + if(isCategoryAxis) + WAVE traceColorHolder = wvX + else + WAVE traceColorHolder = wvY + endif + + WAVE/Z traceColor = JWN_GetNumericWaveFromWaveNote(traceColorHolder, SF_META_TRACECOLOR) if(WaveExists(traceColor)) ASSERT(DimSize(traceColor, ROWS) == 3, "Need 3-element wave for color specification.") ModifyGraph/W=$win rgb($trace)=(traceColor[0], traceColor[1], traceColor[2]) @@ -5459,7 +5471,7 @@ Function/WAVE SF_OperationFitLine(variable jsonId, string jsonPath, string graph SFH_CheckArgumentCount(jsonId, jsonPath, SF_OP_FITLINE, 0, maxArgs = 1) - WAVE/T/Z constraints = SFH_GetArgumentAsWave(jsonId, jsonPath, graph, SF_OP_FITLINE, 0, defOp = "wave()", singleResult = 1) + WAVE/T/Z constraints = SFH_GetArgumentAsWave(jsonId, jsonPath, graph, SF_OP_FITLINE, 0, defWave = $"", singleResult = 1) [WAVE holdWave, WAVE initialValues] = SF_ParseFitConstraints(constraints, 2) diff --git a/Packages/MIES/MIES_SweepFormula_Helpers.ipf b/Packages/MIES/MIES_SweepFormula_Helpers.ipf index 95cb93952c..6a33a79218 100644 --- a/Packages/MIES/MIES_SweepFormula_Helpers.ipf +++ b/Packages/MIES/MIES_SweepFormula_Helpers.ipf @@ -215,7 +215,7 @@ End /// /// opShort = "countBirds" /// WAVE/D birds = SFH_GetArgumentAsWave(jsonId, jsonPath, graph, opShort, 0, singleResult = 1) -/// WAVE/T types = SFH_GetArgumentAsWave(jsonId, jsonPath, graph, opShort, 1, defOp = "birdTypes()", singleResult = 1) +/// WAVE/T types = SFH_GetArgumentAsWave(jsonId, jsonPath, graph, opShort, 1, defOp = "birdTypes()", singleResult = 1, expectedWaveType = IGOR_TYPE_TEXT_WAVE) /// /// \endrst /// @@ -223,18 +223,24 @@ End /// unpacks the outer wave reference wave container. It should always be passed if you only expect one wave to be /// returned. /// -/// The second argument `birdTypes` is optional, if not present the operation `birdTypes()` is called and its result returned. -Function/WAVE SFH_GetArgumentAsWave(variable jsonId, string jsonPath, string graph, string opShort, variable argNum, [string defOp, variable singleResult]) +/// The second argument `birdTypes` is optional, if not present the operation `birdTypes()` is called and its result returned. Alternatively `defWave` can be supplied which is then returned if the argument is not present. +Function/WAVE SFH_GetArgumentAsWave(variable jsonId, string jsonPath, string graph, string opShort, variable argNum, [string defOp, WAVE/Z defWave, variable singleResult, variable expectedWaveType]) - variable checkExist, numArgs + variable checkExist, numArgs, checkWaveType, realWaveType string msg - if(ParamIsDefault(defOp)) + if(ParamIsDefault(defOp) && ParamIsDefault(defWave)) checkExist = 1 else checkExist = 0 endif + if(ParamIsDefault(expectedWaveType)) + checkWaveType = 0 + else + checkWaveType = !!checkWaveType + endif + if(ParamIsDefault(singleResult)) singleResult = 0 else @@ -252,8 +258,23 @@ Function/WAVE SFH_GetArgumentAsWave(variable jsonId, string jsonPath, string gra WAVE/Z data = input[0] SFH_CleanUpInput(input) + + Make/FREE types = {WaveType(data)} else WAVE data = input + Make/FREE/N=(DimSize(input, ROWS)) types = WaveType(input[p]) + endif + + if(checkWaveType) + if(expectedWaveType == IGOR_TYPE_TEXT_WAVE) + // we are using selector 0 for WaveType + realWaveType = 0 + else + realWaveType = expectedWaveType + endif + + sprintf msg, "Argument #%d of operation %s: Expected wave type %d", argNum, opShort, expectedWaveType + SFH_ASSERT(IsConstant(types, realWaveType), msg) endif return data @@ -262,7 +283,11 @@ Function/WAVE SFH_GetArgumentAsWave(variable jsonId, string jsonPath, string gra sprintf msg, "Argument #%d of operation %s is mandatory", argNum, opShort SFH_ASSERT(!checkExist, msg) - return SF_ExecuteFormula(defOp, graph, singleResult = singleResult, useVariables=0) + if(!ParamIsDefault(defOp)) + return SF_ExecuteFormula(defOp, graph, singleResult = singleResult, useVariables=0) + endif + + return defWave End /// @brief Assertion for sweep formula diff --git a/Packages/MIES/MIES_SweepFormula_PSX.ipf b/Packages/MIES/MIES_SweepFormula_PSX.ipf index e2d9a345cf..8e84a98427 100644 --- a/Packages/MIES/MIES_SweepFormula_PSX.ipf +++ b/Packages/MIES/MIES_SweepFormula_PSX.ipf @@ -4222,7 +4222,7 @@ Function/WAVE PSX_Operation(variable jsonId, string jsonPath, string graph) sweepFilterLow = SFH_GetArgumentAsNumeric(jsonID, jsonPath, graph, SF_OP_PSX, 3, defValue = PSX_DEFAULT_FILTER_LOW, checkFunc = IsNullOrPositiveAndFinite) sweepFilterHigh = SFH_GetArgumentAsNumeric(jsonID, jsonPath, graph, SF_OP_PSX, 4, defValue = PSX_DEFAULT_FILTER_HIGH, checkFunc = IsNullOrPositiveAndFinite) maxTauFactor = SFH_GetArgumentAsNumeric(jsonID, jsonPath, graph, SF_OP_PSX, 5, defValue = PSX_DEFAULT_MAX_TAU_FACTOR, checkFunc = IsStrictlyPositiveAndFinite) - WAVE riseTime = SFH_GetArgumentAsWave(jsonID, jsonPath, graph, SF_OP_PSX, 6, defOp = "psxRiseTime()", singleResult = 1) + WAVE riseTime = SFH_GetArgumentAsWave(jsonID, jsonPath, graph, SF_OP_PSX, 6, defOp = "psxRiseTime()", expectedWaveType = IGOR_TYPE_64BIT_FLOAT, singleResult = 1) ASSERT(IsNumericWave(riseTime), "Invalid return from psxRiseTime") WAVE deconvFilter = SFH_GetArgumentAsWave(jsonID, jsonPath, graph, SF_OP_PSX, 7, defOp = "psxDeconvFilter()", singleResult = 1) diff --git a/Packages/MIES/MIES_WaveBuilderPanel.ipf b/Packages/MIES/MIES_WaveBuilderPanel.ipf index 704a503f2e..78c70b5dc7 100644 --- a/Packages/MIES/MIES_WaveBuilderPanel.ipf +++ b/Packages/MIES/MIES_WaveBuilderPanel.ipf @@ -2016,36 +2016,10 @@ Function WBP_ListBoxProc_AnalysisParams(lba) : ListBoxControl params = WBP_GetAnalysisParameters() name = listWave[row][%Name] - value = "" + value = AFH_GetAnalysisParameterAsText(name, params) type = listWave[row][%Type] - if(!IsEmpty(type)) - strswitch(type) - case "variable": - numericValue = AFH_GetAnalysisParamNumerical(name, params) - if(!IsNan(numericValue)) - value = num2str(numericValue) - endif - break - case "string": - value = AFH_GetAnalysisParamTextual(name, params) - break - case "wave": - WAVE/Z wv = AFH_GetAnalysisParamWave(name, params) - if(WaveExists(wv)) - value = NumericWaveToList(wv, ";") - endif - break - case "textwave": - WAVE/Z wv = AFH_GetAnalysisParamTextWave(name, params) - if(WaveExists(wv)) - value = TextWaveToList(wv, ";") - endif - break - default: - ASSERT(0, "invalid type") - break - endswitch + if(!IsEmpty(type)) SetPopupMenuString(win, "popup_param_types", type) endif diff --git a/Packages/MIES/analysis_function_parameters.itx b/Packages/MIES/analysis_function_parameters.itx index c35e3a4878..be353705a8 100644 --- a/Packages/MIES/analysis_function_parameters.itx +++ b/Packages/MIES/analysis_function_parameters.itx @@ -14,8 +14,8 @@ BEGIN "BaselineRMSShortThreshold" "variable" "optional" "AR, CR, DA, PB, RA, RB, SE, VM" "Threshold value in mV for the short RMS baseline QC check (defaults to 0.07)" "BaselineTargetVThreshold" "variable" "optional" "CR, DA, RA, RB" "Threshold value in mV for the target V baseline QC check (defaults to 1)" "BoundsEvaluationMode" "string" "required" "CR" "Select the bounds evaluation mode: Symmetric (Lower and Upper), Depolarized (Upper) or Hyperpolarized (Lower)" - "DAScaleModifier" "variable" "mixed" "CR, DA, SC" "Modifier value to the DA Scale of headstages for too few spikes\rPercentage how the DAScale value is adapted if it is outside of the MinimumSpikeCount\"/\"MaximumSpikeCount\" band. Only for \"Supra\".\rModifier value to the DA Scale of headstages with spikes during chirp" - "DAScaleOperator" "string" "mixed" "CR, SC" "Set the math operator to use for combining the DAScale and the too few spikes modifier. Valid strings are \"+\" (addition) and \"*\" (multiplication).\rSet the math operator to use for combining the DAScale and the modifier. Valid strings are \"+\" (addition) and \"*\" (multiplication)." + "DAScaleModifier" "variable" "mixed" "CR, DA, SC" "Modifier value to the DA Scale of headstages with spikes during chirp\rPercentage how the DAScale value is adapted if it is outside of the MinimumSpikeCount\"/\"MaximumSpikeCount\" band. Only for \"Supra\".\rModifier value to the DA Scale of headstages for too few spikes" + "DAScaleOperator" "string" "mixed" "CR, SC" "Set the math operator to use for combining the DAScale and the modifier. Valid strings are \"+\" (addition) and \"*\" (multiplication).\rSet the math operator to use for combining the DAScale and the too few spikes modifier. Valid strings are \"+\" (addition) and \"*\" (multiplication)." "DAScales" "wave" "required" "DA, DS" "DA Scale Factors in pA" "DAScaleSpikePositionModifier" "variable" "required" "SC" "Modifier value to the DA Scale of headstages with failing spike positions." "DAScaleSpikePositionOperator" "string" "required" "SC" "Set the math operator to use for combining the DAScale and the spike position modifier. Valid strings are \"+\" (addition) and \"*\" (multiplication)." @@ -51,7 +51,7 @@ BEGIN "PostDAQDAScaleForFailedHS" "variable" "required" "FR" "Failed headstages will be set to this DAScale value [pA] in the post set event" "PostDAQDAScaleMinOffset" "variable" "required" "FR" "Mininum absolute offset value applied to the found DAScale [pA]" "RelativeVoltageDiff" "variable" "required" "VM" "Maximum relative allowed difference of the baseline membrane potentials [%].\r Set to `inf` to disable this check." - "SamplingFrequency" "variable" "optional" "AR, CR, DA, PB, RA, RB, SE, SP, VM" "Required sampling frequency for the acquired data [kHz]. Defaults to ITC:50 NI:50.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:200 NI:250.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:200 NI:250.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:200 NI:250.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:50 NI:50." + "SamplingFrequency" "variable" "optional" "AR, CR, DA, PB, RA, RB, SE, SP, VM" "Required sampling frequency for the acquired data [kHz]. Defaults to ITC:50 NI:50.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:200 NI:250.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:50 NI:50.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:50 NI:50.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:200 NI:250.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:50 NI:50.\rRequired sampling frequency for the acquired data [kHz]. Defaults to ITC:200 NI:250." "SamplingMultiplier" "variable" "required" "AR, CR, DA, FR, PB, RA, RB, SE, SP, VM" "Sampling multiplier, use 1 for no multiplier" "SealThreshold" "variable" "required" "SE" "Minimum required seal threshold [GΩ]" "ShowPlot" "variable" "optional" "DA" "Show the resistance (\"Sub\") or the f-I (\"Supra\") plot, defaults to true." diff --git a/Packages/tests/Basic/UTF_AnalysisFunctionParameters.ipf b/Packages/tests/Basic/UTF_AnalysisFunctionParameters.ipf index 4af0684707..e6fcf9f026 100644 --- a/Packages/tests/Basic/UTF_AnalysisFunctionParameters.ipf +++ b/Packages/tests/Basic/UTF_AnalysisFunctionParameters.ipf @@ -764,6 +764,8 @@ static Function/WAVE GetAnalysisFunctions() SetDimensionLabels(wv, funcs, ROWS) + Sort/DIML wv, wv + return wv End @@ -928,7 +930,7 @@ static Function GenerateAnalysisFunctionTable() // if this test fails and the CRC changes // commit the file `Packages/MIES/analysis_function_parameters.itx` // and check that the changes therein are intentional - CHECK_EQUAL_VAR(WaveCRC(0, output, 0), 303837295) + CHECK_EQUAL_VAR(WaveCRC(0, output, 0), 2280254664) StoreWaveOnDisk(output, "analysis_function_parameters") End @@ -957,3 +959,67 @@ static Function GenerateAnalysisFunctionLegend() CHECK_EQUAL_VAR(WaveCRC(0, output, 0), 2579934075) StoreWaveOnDisk(output, "analysis_function_abrev_legend") End + +/// @name AFH_GetAnalysisParameterAsText +/// @{ +Function GAPasT_AbortsWithEmptyName() + + try + AFH_GetAnalysisParameterAsText("", "name:textwave=0") + FAIL() + catch + PASS() + endtry +End + +Function GAPasT_AbortsWithIllegalName() + + try + AFH_GetAnalysisParameterAsText("123", "name:textwave=0") + FAIL() + catch + PASS() + endtry +End + +Function GAPasT_AbortsWithIllegalType() + + try + AFH_GetAnalysisParameterAsText("name", "name:invalidType=0") + FAIL() + catch + PASS() + endtry +End + +static Function/WAVE GetAnalysisParameterValues() + + Make/FREE/N=(5)/WAVE waves + + Make/FREE/T wv0 = {"var", "123"} + waves[0] = wv0 + + Make/FREE/T wv1 = {"str", "abcd"} + waves[1] = wv1 + + Make/FREE/T wv2 = {"wv", "1;2;"} + waves[2] = wv2 + + Make/FREE/T wv3 = {"txtwv", "a;b;"} + waves[3] = wv3 + + Make/FREE/T wv4 = {"i_dont_exist", ""} + waves[4] = wv4 + + return waves +End + +/// UTF_TD_GENERATOR GetAnalysisParameterValues +Function GAPasT_Works([WAVE/T wv]) + + string result + + result = AFH_GetAnalysisParameterAsText(wv[0], "var:variable=123,str:string=abcd,wv:wave=1|2,txtwv:textwave=a|b") + CHECK_EQUAL_STR(result, wv[1]) +End +/// @}