diff --git a/luminex/resources/transformscripts/labkey_luminex_transform.R b/luminex/resources/transformscripts/labkey_luminex_transform.R index 6bc3a4b0f3..7bd715d81d 100644 --- a/luminex/resources/transformscripts/labkey_luminex_transform.R +++ b/luminex/resources/transformscripts/labkey_luminex_transform.R @@ -5,17 +5,10 @@ # # Transform script for Luminex Assay. # -# First, the script subtracts the FI-Bkgd value for the negative bead from the FI-Bkgd value +# The script subtracts the FI-Bkgd value for the negative bead from the FI-Bkgd value # for the other analytes within a given run data file. It also converts FI-Bkgd and FI-Bkgd-Neg # values that are <= 0 to 1 (as per the lab's request). # -# Next, the script calculates curve fit parameters for each titration/analyte combination using both -# 4PL and 5PL curve fits (from the fit.drc function in the Ruminex package (developed by Youyi at SCHARP). -# -# Then, the script calculates new estimated concentration values for unknown samples using the -# rumi function. The rumi function takes a dataframe as input and uses the given Standard curve data to -# calculate est.log.conc an se for the unknowns. -# # CHANGES : # - 2.1.20111216 : Issue 13696: Luminex transform script should use excel file titration "Type" for EC50 and Conc calculations # - 2.2.20120217 : Issue 14070: Value out of range error when importing curve fit parameters for titrated unknown with flat dilution curve @@ -37,17 +30,16 @@ # - 9.2.20141103 : Issue 21268: Add OtherControl titrations to PDF output of curves from transform script # - 10.0.20150910 : Changes for LabKey server 15.2. Issue 23230: Luminex transform script error when standard or QC control name has a slash in it # - 10.1.20180903 : Use transform script helper functions from Rlabkey package +# - 11.0.20230206 : Remove Ruminex package usage and calculations # # Author: Cory Nathe, LabKey -transformVersion = "10.1.20180903"; +transformVersion = "11.0.20230206"; # print the starting time for the transform script writeLines(paste("Processing start time:",Sys.time(),"\n",sep=" ")); source("${srcDirectory}/youtil.R"); -# Ruminex package available from https://www.labkey.org/Documentation/wiki-page.view?name=configureLuminexScript -suppressMessages(library(Ruminex)); -ruminexVersion = installed.packages()["Ruminex","Version"]; +suppressMessages(library(drc)); suppressMessages(library(Rlabkey)); @@ -247,7 +239,6 @@ bothRawAndSummary = any(run.data$summary == "true") & any(run.data$summary == "f runprop.output.file = labkey.transform.getRunPropertyValue(run.props, "transformedRunPropertiesFile"); fileConn<-file(runprop.output.file); writeLines(c(paste("TransformVersion",transformVersion,sep="\t"), - paste("RuminexVersion",ruminexVersion,sep="\t"), paste("RVersion",rVersion,sep="\t")), fileConn); close(fileConn); @@ -264,31 +255,10 @@ run.data$Upper_4pl = NA; run.data$Inflection_4pl = NA; run.data$EC50_4pl = NA; run.data$Flag_4pl = NA; -run.data$Slope_5pl = NA; -run.data$Lower_5pl = NA; -run.data$Upper_5pl = NA; -run.data$Inflection_5pl = NA; -run.data$Asymmetry_5pl = NA; -run.data$EC50_5pl = NA; -run.data$Flag_5pl = NA; # get the unique analyte values analytes = unique(run.data$name); -# determine if the curve fits should be done with or without log transform -curveFitLogTransform = TRUE; -if (any(run.props$name == "CurveFitLogTransform")) { - propVal = labkey.transform.getRunPropertyValue(run.props, "CurveFitLogTransform"); - if (!is.na(propVal) & propVal != "1") curveFitLogTransform = FALSE; -} - -# set the weighting variance variable for use in the non-log tranform curve fits -drm.weights.var.power = -1.8; -if (any(run.props$name == "WeightingPower")) { - propVal = labkey.transform.getRunPropertyValue(run.props, "WeightingPower"); - if (!is.na(propVal) & propVal != "") drm.weights.var.power = as.numeric(propVal); -} - # loop through the possible titrations and to see if it is a standard, qc control, or titrated unknown if (nrow(titration.data) > 0) { @@ -303,8 +273,8 @@ if (nrow(titration.data) > 0) { titrationName = as.character(titrationDataRow$Name); - # 2 types of curve fits for the EC50 calculations, with separate PDFs for the QC Curves - fitTypes = c("4pl", "5pl"); + # use 4pl curve fit for the EC50 calculations, with separate PDFs for the QC Curves + fitTypes = c("4pl"); for (typeIndex in 1:length(fitTypes)) { # we want to create PDF plots of the curves for QC Controls @@ -413,75 +383,11 @@ if (nrow(titration.data) > 0) if (all(is.na(run.data[runDataIndex,]$EC50_4pl))) { run.data[runDataIndex,]$Flag_4pl = TRUE; } - } else if (fitTypes[typeIndex] == "5pl") - { - tryCatch({ - if (curveFitLogTransform) { - formula = log(fi)~dose - weighting = FALSE - } else { - formula = fi~dose - weighting = TRUE - dat.avg=aggregate(dat$fi, by = list(dat$name, dat$dose, dat$dataId), mean) - names(dat.avg) = c("name", "dose","dataId", "fi.avg") - dat = merge(dat, dat.avg, by=c("name", "dose", "dataId"), all.x=T, all.y=T) - } - fit = fit.drc(formula, data=dat, weighting=weighting, force.fit=TRUE, fit.4pl=FALSE); - run.data[runDataIndex,]$Slope_5pl = maxValueConversion(as.numeric(coef(fit))[1]); - run.data[runDataIndex,]$Lower_5pl = maxValueConversion(as.numeric(coef(fit))[2]); - run.data[runDataIndex,]$Upper_5pl = maxValueConversion(as.numeric(coef(fit))[3]); - run.data[runDataIndex,]$Inflection_5pl = maxValueConversion(as.numeric(coef(fit))[4]); - run.data[runDataIndex,]$Asymmetry_5pl = maxValueConversion(as.numeric(coef(fit))[5]); - - if (curveFitLogTransform) { - yLabel = paste("log(",yLabel,")", sep=""); - y = log((exp(run.data[runDataIndex,]$Lower_5pl) + exp(run.data[runDataIndex,]$Upper_5pl)) / 2) - } else { - y = (run.data[runDataIndex,]$Lower_5pl + run.data[runDataIndex,]$Upper_5pl) / 2; - } - ec50 = unname(getConc(fit, y))[3]; - if (is.nan(ec50) | ec50 > 10e6) { - writeErrorOrWarning("warn", paste("Warning: EC50 5pl value out of acceptable range (either outside standards MFI or greater than 10e6) for ", titrationName, " ", analyteName, ".", sep="")); - } else { - run.data[runDataIndex,]$EC50_5pl = ec50; - } - - # plot the curve fit for the QC Controls - if (titrationDataRow$QCControl == "true" | titrationDataRow$OtherControl == "true") { - plot(fit, type="all", main=analyteName, cex=.5, ylab=yLabel, xlab=xLabel); - } - }, - error = function(e) { - print(e); - - # plot the individual data points for the QC Controls - if (curveFitLogTransform) { - yLabel = paste("log(",yLabel,")", sep=""); - logAxes = "xy" - } else { - logAxes = "x"; - } - if (titrationDataRow$QCControl == "true" | titrationDataRow$OtherControl == "true") { - plot(fi ~ dose, data = dat, log=logAxes, cex=.5, las=1, main=paste("FAILED:", analyteName, sep=" "), ylab=yLabel, xlab=xLabel); - } - } - ); - - # set the failure flag if there is no EC50 value at this point - if (all(is.na(run.data[runDataIndex,]$EC50_5pl))) { - run.data[runDataIndex,]$Flag_5pl = TRUE; - } } } else { # create an empty plot indicating that there is no data available if (titrationDataRow$QCControl == "true" | titrationDataRow$OtherControl == "true") { - if (curveFitLogTransform) { - yLabel = paste("log(",yLabel,")", sep=""); - logAxes = "xy" - } else { - logAxes = "x"; - } - plot(NA, NA, log=logAxes, cex=.5, las=1, main=paste("FAILED:", analyteName, sep=" "), ylab=yLabel, xlab=xLabel, xlim=c(1,1), ylim=c(0,1)); + plot(NA, NA, log="x", cex=.5, las=1, main=paste("FAILED:", analyteName, sep=" "), ylab=yLabel, xlab=xLabel, xlim=c(1,1), ylim=c(0,1)); text(1, 0.5, "Data Not Available"); } } @@ -496,247 +402,7 @@ if (nrow(titration.data) > 0) } } -################################## STEP 4: CALCULATE EST CONC ################################# - -# initialize the columns to be calculated -run.data$EstLogConc_5pl = NA; -run.data$EstConc_5pl = NA; -run.data$SE_5pl = NA; - -run.data$EstLogConc_4pl = NA; -run.data$EstConc_4pl = NA; -run.data$SE_4pl = NA; - -run.data$Standard = NA; -run.data$well_role = ""; # initialize to empty string and set to Standard accordingly, well_role used by Rumi function - -# determine if the Ruminex curve fits should be run -runRumiCalculation = TRUE; -if (any(run.props$name == "SkipRumiCalculation")) { - propVal = labkey.transform.getRunPropertyValue(run.props, "SkipRumiCalculation"); - if (!is.na(propVal) & propVal == "1") runRumiCalculation = FALSE; -} - -if (runRumiCalculation) -{ - # get the analyte associated standard/titration information from the analyte data file and put it into the run.data object - for (index in 1:nrow(analyte.data)) - { - # hold on to the run data for the given analyte - run.analyte.data = subset(run.data, as.character(name) == as.character(analyte.data$Name[index])); - - # some analytes may have > 1 standard selected - stndSet = unlist(strsplit(as.character(analyte.data$titrations[index]), ",")); - - # if there are more than 1 standard for this analyte, duplicate run.data records for that analyte and set standard accordingly - if (length(stndSet) > 0) - { - for (stndIndex in 1:length(stndSet)) - { - if (stndIndex == 1) - { - run.data$Standard[as.character(run.data$name) == as.character(analyte.data$Name[index])] = stndSet[stndIndex]; - run.data$well_role[as.character(run.data$name) == as.character(analyte.data$Name[index]) & run.data$description == stndSet[stndIndex]] = "Standard"; - } else - { - temp.data = run.analyte.data; - temp.data$Standard = stndSet[stndIndex]; - temp.data$well_role[temp.data$description == stndSet[stndIndex]] = "Standard"; - temp.data$lsid = NA; # lsid will be set by the server - run.data = rbind(run.data, temp.data); - } - } - } - } - - # get the unique standards (not including NA or empty string) - standards = setdiff(unique(run.data$Standard), c(NA, "")); - - # setup the dataframe needed for the call to rumi - dat = subset(run.data, select=c("dataFile", "Standard", "lsid", "well", "description", "name", "expConc", "fi", "fiBackground", "FIBackgroundNegative", "dilution", "well_role", "summary", "FlaggedAsExcluded", "isStandard", "isQCControl", "isOtherControl", "isUnknown")); - - # if both raw and summary data are available, just use the raw data for the calc - if (bothRawAndSummary) { - dat = subset(dat, summary == "false"); - } - - # remove any excluded standard replicate groups - dat = subset(dat, (isStandard & tolower(FlaggedAsExcluded) == "false") | !isStandard); - - if (any(dat$isStandard) & length(standards) > 0) - { - # change column name from "name" to "analyte" - colnames(dat)[colnames(dat) == "name"] = "analyte"; - - # change column name from expConc to expected_conc - colnames(dat)[colnames(dat) == "expConc"] = "expected_conc"; - - # set the sample_id to be description||dilution or description||expected_conc - dat$sample_id[!is.na(dat$expected_conc)] = paste(dat$description[!is.na(dat$expected_conc)], "||", dat$expected_conc[!is.na(dat$expected_conc)], sep=""); - dat$sample_id[is.na(dat$expected_conc)] = paste(dat$description[is.na(dat$expected_conc)], "||", dat$dilution[is.na(dat$expected_conc)], sep=""); - - # choose the FI column for standards and qc controls based on the run property provided by the user, default to the original FI value - if (any(run.props$name == "StndCurveFitInput")) - { - fiCol = getCurveFitInputCol(run.props, "StndCurveFitInput", "fi") - dat$fi[dat$isStandard] = dat[dat$isStandard, fiCol] - dat$fi[dat$isQCControl] = dat[dat$isQCControl, fiCol] - dat$fi[dat$isOtherControl] = dat[dat$isOtherControl, fiCol] - } - - # choose the FI column for unknowns based on the run property provided by the user, default to the original FI value - if (any(dat$isUnknown)) - { - if (any(run.props$name == "UnkCurveFitInput")) - { - fiCol = getCurveFitInputCol(run.props, "UnkCurveFitInput", "fi") - dat$fi[dat$isUnknown] = dat[dat$isUnknown, fiCol] - } - } - - # subset the dat object to just those records that have an FI - dat = subset(dat, !is.na(fi)); - - # loop through the selected standards in the data.frame and call the rumi function once for each - # this will also create one pdf for each standard - for (s in 1:length(standards)) - { - stndVal = as.character(standards[s]); - - # subset the data for those analytes set to use the given standard curve - # note: also need to subset the standard records for only those where description matches the given standard - standard.dat = subset(dat, Standard == stndVal & (!isStandard | (isStandard & description == stndVal))); - - # LabKey Issue 13034: replicate standard records as unknowns so that Rumi will calculated estimated concentrations - tempStnd.dat = subset(standard.dat, well_role=="Standard"); - if (nrow(tempStnd.dat) > 0) - { - tempStnd.dat$well_role = ""; - tempStnd.dat$sample_id = paste(tempStnd.dat$description, "||", tempStnd.dat$expected_conc, sep=""); - standard.dat=rbind(standard.dat, tempStnd.dat); - } - - # LabKey Issue 13033: check if we need to "add" standard data for any analytes if this is a subclass assay - # (i.e. standard data from "Anti-Human" analyte to be used for other analytes) - selectedAnalytes = unique(standard.dat$analyte); - subclass.dat = subset(dat, well_role == "Standard" & description == stndVal & !is.na(lsid)); - subclass.dat = subset(subclass.dat, regexpr("^blank", analyte, ignore.case=TRUE) == -1); - # if we only have standard data for one analyte, it is the subclass standard data to be used - if (length(unique(subclass.dat$analyte)) == 1) - { - subclassAnalyte = subclass.dat$analyte[1]; - for (a in 1:length(selectedAnalytes)) - { - analyteStnd.dat = subset(standard.dat, well_role == "Standard" & analyte == selectedAnalytes[a]); - # if there is no standard data for this analyte/standard, "use" the subclass analyte standard data - if (nrow(analyteStnd.dat) == 0) - { - print(paste("Using ", subclassAnalyte, " standard data for analyte ", selectedAnalytes[a], sep="")); - subclass.dat$sample_id = NA; - subclass.dat$analyte = selectedAnalytes[a]; - standard.dat = rbind(standard.dat, subclass.dat); - } - } - } - - # set the assay_id (this value will be used in the PDF plot header) - standard.dat$assay_id = stndVal; - - # check to make sure there are expected_conc values in the standard data frame that will be passed to Rumi - if (any(!is.na(standard.dat$expected_conc))) - { - # use the decided upon conversion function for handling of negative values - standard.dat$fi = sapply(standard.dat$fi, fiConversion); - - # LabKey issue 13445: Don't calculate estimated concentrations for analytes where max(FI) is < 1000 - agg.dat = subset(standard.dat, well_role == "Standard"); - if (nrow(agg.dat) > 0) - { - agg.dat = aggregate(agg.dat$fi, by = list(Standard=agg.dat$Standard,Analyte=agg.dat$analyte), FUN = max); - for (aggIndex in 1:nrow(agg.dat)) - { - # remove the rows from the standard.dat object where the max FI < 1000 - if (agg.dat$x[aggIndex] < 1000) - { - writeErrorOrWarning("warn", paste("Warning: Max(FI) is < 1000 for ", agg.dat$Standard[aggIndex], " ", agg.dat$Analyte[aggIndex], ", not calculating estimated concentrations for this standard/analyte.", sep="")); - standard.dat = subset(standard.dat, !(Standard == agg.dat$Standard[aggIndex] & analyte == agg.dat$Analyte[aggIndex])); - } - } - } - - # check to make sure that we still have some standard data to pass to the rumi function calculations - if (nrow(standard.dat) == 0 | !any(standard.dat$isStandard)) - { - next(); - } - - # call the rumi function to calculate new estimated log concentrations using 5PL for the unknowns - mypdf(file=paste(convertToFileName(stndVal), "5PL", sep="_"), mfrow=c(2,2)); - fits = rumi(standard.dat, force.fit=TRUE, log.transform=curveFitLogTransform, plot.se.profile=curveFitLogTransform, verbose=TRUE); - fits$"est.conc" = 2.71828183 ^ fits$"est.log.conc"; - dev.off(); - - # put the calculated values back into the run.data dataframe by matching on analyte, description, expConc OR dilution, and standard - if (nrow(fits) > 0) - { - for (index in 1:nrow(fits)) - { - a = fits$analyte[index]; - dil = fits$dilution[index]; - desc = fits$description[index]; - exp = fits$expected_conc[index]; - - elc = fits$"est.log.conc"[index]; - ec = fits$"est.conc"[index]; - se = fits$"se"[index]; - - if (!is.na(exp)) { - runDataIndex = run.data$name == a & run.data$expConc == exp & run.data$description == desc & run.data$Standard == stndVal - } else { - runDataIndex = run.data$name == a & run.data$dilution == dil & run.data$description == desc & run.data$Standard == stndVal - } - run.data$EstLogConc_5pl[runDataIndex] = elc; - run.data$EstConc_5pl[runDataIndex] = ec; - run.data$SE_5pl[runDataIndex] = se; - } - } - - # call the rumi function to calculate new estimated log concentrations using 4PL for the unknowns - mypdf(file=paste(convertToFileName(stndVal), "4PL", sep="_"), mfrow=c(2,2)); - fits = rumi(standard.dat, fit.4pl=TRUE, force.fit=TRUE, log.transform=curveFitLogTransform, plot.se.profile=curveFitLogTransform, verbose=TRUE); - fits$"est.conc" = 2.71828183 ^ fits$"est.log.conc"; - dev.off(); - - # put the calculated values back into the run.data dataframe by matching on analyte, description, dilution, and standard - if (nrow(fits) > 0) - { - for (index in 1:nrow(fits)) - { - a = fits$analyte[index]; - dil = fits$dilution[index]; - desc = fits$description[index]; - exp = fits$expected_conc[index]; - - elc = fits$"est.log.conc"[index]; - ec = fits$"est.conc"[index]; - se = fits$"se"[index]; - - if (!is.na(exp)) { - runDataIndex = run.data$name == a & run.data$expConc == exp & run.data$description == desc & run.data$Standard == stndVal - } else { - runDataIndex = run.data$name == a & run.data$dilution == dil & run.data$description == desc & run.data$Standard == stndVal - } - run.data$EstLogConc_4pl[runDataIndex] = elc; - run.data$EstConc_4pl[runDataIndex] = ec; - run.data$SE_4pl[runDataIndex] = se; - } - } - } - } - } -} - -##################### STEP 5: WRITE THE RESULTS TO THE OUTPUT FILE LOCATION ##################### +##################### STEP 4: WRITE THE RESULTS TO THE OUTPUT FILE LOCATION ##################### # write the new set of run data out to an output file write.table(run.data, file=run.output.file, sep="\t", na="", row.names=FALSE, quote=FALSE); diff --git a/luminex/src/org/labkey/luminex/LuminexDataHandler.java b/luminex/src/org/labkey/luminex/LuminexDataHandler.java index 359fe6925b..806098632f 100644 --- a/luminex/src/org/labkey/luminex/LuminexDataHandler.java +++ b/luminex/src/org/labkey/luminex/LuminexDataHandler.java @@ -1055,7 +1055,7 @@ else if (well.getDose() == 0.0) return null; } - /** @return null if we can't find matching Rumi curve fit data */ + /** @return null if we can't find matching Rumi/drc curve fit data */ @Nullable private CurveFit importRumiCurveFit(StatsService.CurveFitType fitType, LuminexDataRow dataRow, LuminexWellGroup wellGroup, User user, Titration titration, Analyte analyte, CurveFit[] existingCurveFits) { diff --git a/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java b/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java index 86eee4ccfc..cdcdd7b710 100644 --- a/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java +++ b/luminex/src/org/labkey/luminex/query/AnalyteTitrationTable.java @@ -116,6 +116,7 @@ public DisplayColumn createRenderer(ColumnInfo colInfo) addColumn(wrapColumn(getRealTable().getColumn("IncludeInGuideSetCalculation"))); + List curveTypes = _userSchema.getCurveTypes(); addCurveTypeColumns(); var ljPlots = addWrapColumn("L-J Plots", getRealTable().getColumn(FieldKey.fromParts("TitrationId"))); @@ -144,8 +145,10 @@ public void renderGridCellContents(RenderContext ctx, Writer out) throws IOExcep NavTree ljPlotsNav = new NavTree("Levey-Jennings Plot Menu"); ljPlotsNav.setImage(AppProps.getInstance().getContextPath() + "/luminex/ljPlotIcon.png", 27, 20); - ljPlotsNav.addChild("EC50 - 4PL", String.format(jsFuncCall, protocolId, analyte, titration, "EC504PL")); - ljPlotsNav.addChild("EC50 - 5PL Rumi", String.format(jsFuncCall, protocolId, analyte, titration, "EC505PL")); + if (curveTypes.contains(StatsService.CurveFitType.FOUR_PARAMETER.getLabel())) + ljPlotsNav.addChild("EC50 - 4PL", String.format(jsFuncCall, protocolId, analyte, titration, "EC504PL")); + if (curveTypes.contains(StatsService.CurveFitType.FIVE_PARAMETER.getLabel())) + ljPlotsNav.addChild("EC50 - 5PL Rumi", String.format(jsFuncCall, protocolId, analyte, titration, "EC505PL")); ljPlotsNav.addChild("AUC", String.format(jsFuncCall, protocolId, analyte, titration, "AUC")); ljPlotsNav.addChild("High MFI", String.format(jsFuncCall, protocolId, analyte, titration, "HighMFI")); @@ -187,8 +190,10 @@ public boolean isFilterable() defaultCols.add(FieldKey.fromParts("Titration", "Run", "Conjugate")); defaultCols.add(FieldKey.fromParts("Analyte", "Properties", "LotNumber")); defaultCols.add(FieldKey.fromParts("GuideSet", "Created")); - defaultCols.add(FieldKey.fromParts(StatsService.CurveFitType.FOUR_PARAMETER.getLabel() + "CurveFit", "EC50")); - defaultCols.add(FieldKey.fromParts(StatsService.CurveFitType.FIVE_PARAMETER.getLabel() + "CurveFit", "EC50")); + if (curveTypes.contains(StatsService.CurveFitType.FOUR_PARAMETER.getLabel())) + defaultCols.add(FieldKey.fromParts(StatsService.CurveFitType.FOUR_PARAMETER.getLabel() + "CurveFit", "EC50")); + if (curveTypes.contains(StatsService.CurveFitType.FIVE_PARAMETER.getLabel())) + defaultCols.add(FieldKey.fromParts(StatsService.CurveFitType.FIVE_PARAMETER.getLabel() + "CurveFit", "EC50")); defaultCols.add(FieldKey.fromParts("MaxFI")); defaultCols.add(FieldKey.fromParts("TrapezoidalCurveFit", "AUC")); setDefaultVisibleColumns(defaultCols); diff --git a/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp b/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp index 4f47a3e783..f232529729 100644 --- a/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp +++ b/luminex/src/org/labkey/luminex/view/leveyJenningsReport.jsp @@ -62,7 +62,9 @@ var defaultRowSize = 30; // local variables for storing the selected graph parameters - var _protocolId, _protocolName, _controlName, _controlType, _analyte, _isotype, _conjugate, _protocolExists = false, _networkExists = false; + var _protocolId, _protocolName, _controlName, _controlType, _analyte, _isotype, _conjugate, + _protocolExists = false, _networkExists = false, + _has4PLCurveFit = false, _has5PLCurveFit = false; function init() { @@ -87,13 +89,28 @@ return; } - var getByNameQueryComplete = false, executeSqlQueryComplete = false; + var getByNameQueryComplete = false, executeSqlQueryComplete = false, getCurveFitTypes = false; var loader = function() { - if (getByNameQueryComplete && executeSqlQueryComplete) { + if (getByNameQueryComplete && executeSqlQueryComplete && getCurveFitTypes) { initializeReportPanels(); } }; + // Query to see if 4PL and/or 5PL curve fit data exists for this assay + LABKEY.Query.selectDistinctRows({ + schemaName: 'assay.Luminex.' + _protocolName, + queryName: 'CurveFit', + column: 'CurveType', + scope: this, + success: function(results){ + var curveTypes = results.values; + _has4PLCurveFit = curveTypes.indexOf('Four Parameter') > -1; + _has5PLCurveFit = curveTypes.indexOf('Five Parameter') > -1; + getCurveFitTypes = true; + loader(); + } + }); + // Query the assay design to check for the required columns for the L-J report and the existance of Network and Protocol columns LABKEY.Assay.getByName({ name: _protocolName, @@ -208,6 +225,8 @@ assayName: _protocolName, networkExists: _networkExists, protocolExists: _protocolExists, + has4PLCurveFit: _has4PLCurveFit, + has5PLCurveFit: _has5PLCurveFit, listeners: { 'currentGuideSetUpdated': function() { guideSetPanel.toggleExportBtn(false); @@ -233,6 +252,8 @@ defaultRowSize: defaultRowSize, networkExists: _networkExists, protocolExists: _protocolExists, + has4PLCurveFit: _has4PLCurveFit, + has5PLCurveFit: _has5PLCurveFit, listeners: { 'reportFilterApplied': function(startDate, endDate, network, networkAny, protocol, protocolAny) { trendPlotPanel.setTrendPlotLoading(); @@ -254,6 +275,8 @@ defaultRowSize: defaultRowSize, networkExists: _networkExists, protocolExists: _protocolExists, + has4PLCurveFit: _has4PLCurveFit, + has5PLCurveFit: _has5PLCurveFit, listeners: { 'appliedGuideSetUpdated': function() { guideSetPanel.toggleExportBtn(false); diff --git a/luminex/test/sampledata/luminex/TestLuminexAssay.xar b/luminex/test/sampledata/luminex/TestLuminexAssay.xar index b787920666..738dfdf524 100644 Binary files a/luminex/test/sampledata/luminex/TestLuminexAssay.xar and b/luminex/test/sampledata/luminex/TestLuminexAssay.xar differ diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexAsyncImportTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexAsyncImportTest.java index 5eae3f2e35..b9ce8d40b5 100644 --- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexAsyncImportTest.java +++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexAsyncImportTest.java @@ -141,7 +141,6 @@ private void reimportLuminexRunPageTwo(String runId, String isotype, String conj assertFormElementEquals(Locator.name("conjugate"), conjugate); assertFormElementEquals(Locator.name("stndCurveFitInput"), stndCurveFitInput); assertFormElementEquals(Locator.name("unkCurveFitInput"), unkCurveFitInput); - uncheckCheckbox(Locator.name("curveFitLogTransform")); assertFormElementEquals(Locator.name("notebookNo"), notebookNo); assertFormElementEquals(Locator.name("assayType"), assayType); assertFormElementEquals(Locator.name("expPerformer"), expPerformer); @@ -169,12 +168,12 @@ private void assertLuminexLogInfoPresent() assertTextPresentInThisOrder("----- Start Run Properties -----", "----- End Run Properties -----"); assertTextPresent("Uploaded Files", "Assay ID", "Isotype", "Conjugate", "Test Date", "Replaces Previous File", "Date file was modified", "Specimen Type", "Additive", "Derivative", "Subtract Negative Bead", "Calc of Standards", "Calc of Unknown", - "Curve Fit Log", "Notebook Number", "Assay Type", "Experiment Performer", "Calculate Positivity", + "Notebook Number", "Assay Type", "Experiment Performer", "Calculate Positivity", "Baseline Visit", "Positivity Fold Change"); //Check for Batch Properties assertTextPresentInThisOrder("----- Start Batch Properties -----", "----- End Batch Properties -----"); - assertTextPresent("Participant Visit", "Species", "Lab ID", "Analysis", "Network", "Transform Script Version", "Ruminex Version"); + assertTextPresent("Participant Visit", "Species", "Lab ID", "Analysis", "Network", "Transform Script Version"); } @LogMethod diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexEC50Test.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexEC50Test.java index 4368aeccbf..0f0b180dfa 100644 --- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexEC50Test.java +++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexEC50Test.java @@ -20,14 +20,11 @@ import org.junit.experimental.categories.Category; import org.labkey.test.BaseWebDriverTest; import org.labkey.test.Locator; -import org.labkey.test.SortDirection; import org.labkey.test.categories.Assays; import org.labkey.test.categories.Daily; import org.labkey.test.pages.ReactAssayDesignerPage; import org.labkey.test.util.DataRegionTable; -import org.labkey.test.util.RReportHelper; -import java.io.IOException; import java.util.List; import static org.junit.Assert.assertEquals; @@ -38,8 +35,7 @@ public class LuminexEC50Test extends LuminexTest { private final String EC50_RUN_NAME = "EC50"; - private final String rum4 = "Four Parameter"; - private final String rum5 = "Five Parameter"; + private final String drc4 = "Four Parameter"; private final String trapezoidal = "Trapezoidal"; @BeforeClass @@ -58,11 +54,9 @@ public static void updateAssayDefinition() public void testEC50() { LuminexRTransformTest rTransformTest = new LuminexRTransformTest(); - rTransformTest.uploadRunWithoutRumiCalc(); - rTransformTest.reImportRunWithRumiCalc(); + rTransformTest.uploadRun(); createNewAssayRun(TEST_ASSAY_LUM, EC50_RUN_NAME); - checkCheckbox(Locator.name("curveFitLogTransform")); uploadMultipleCurveData(); clickButton("Save and Finish", longWaitForPage); @@ -73,14 +67,6 @@ public void testEC50() checkEC50dataAndFailureFlag(); } - private boolean checkRversion() throws IOException - { - // quick check to see if we are using 32-bit or 64-bit R - log("Checking R 32-bit vs 64-bit"); - RReportHelper _rReportHelper = new RReportHelper(this); - return _rReportHelper.getRScriptOutput(".Machine$sizeof.pointer").contains("[1] 8"); - } - private void checkEC50dataAndFailureFlag() { // expect to already be viewing CurveFit query @@ -98,27 +84,17 @@ private void checkEC50dataAndFailureFlag() List ec50 = table.getColumnDataAsText("EC50"); List auc= table.getColumnDataAsText("AUC"); List inflectionPoint = table.getColumnDataAsText("Inflection"); - int rum5ec50count = 0; log("Write this"); for(int i=0; i 0) - rum5ec50count++; - - // auc should not be populated - assertEquals(" ", auc.get(i)); - } else if(formula.get(i).equals(trapezoidal)) { //ec50 should not be populated @@ -128,30 +104,6 @@ else if(formula.get(i).equals(trapezoidal)) assertTrue( "AUC was unpopulated for row " + i, auc.get(i).length()>0); } } - assertEquals("Unexpected number of Five Parameter EC50 values (expected 10 of 14).", 10, rum5ec50count); - - // check that the 5PL parameters are within the expected ranges (note: exact values can change based on R 32-bit vs R 64-bit) - // NOTE: the first two EC50s will be significantly different on Mac due to machine episolon. The test is adjusted for this, as these are "blanks" and thus provide the noisiest answers. - Double[] FiveParameterEC50mins = {107.64, 460.75, 36465.56, 21075.08, 7826.89, 32211.66, 44972.77, 107.64, 0.4199, 0.03962}; - Double[] FiveParameterEC50maxs = {112.85, 486.5, 36469.5, 21075.29, 7826.90, 32211.67, 45012.09, 112.85, 0.43771, 0.03967}; - table.setFilter("CurveType", "Equals", "Five Parameter"); - table.setFilter("EC50", "Is Not Blank", ""); - table.setSort("EC50", SortDirection.ASC); - table.setSort("AnalyteId", SortDirection.ASC); - table.setSort("TitrationId", SortDirection.ASC); - ec50 = table.getColumnDataAsText("EC50"); - assertEquals("Unexpected number of Five Parameter EC50 values (expected " + FiveParameterEC50maxs.length + ")", FiveParameterEC50maxs.length, ec50.size()); - for (int i = 0; i < ec50.size(); i++) - { - Double val = Double.parseDouble(ec50.get(i)); - Double min = FiveParameterEC50mins[i]; - Double max = FiveParameterEC50maxs[i]; - Double expected = (max + min) / 2; - Double delta = (max - min) / 2; - assertEquals(String.format("Unexpected 5PL EC50 value for %s - %s", table.getDataAsText(i, "Titration"), table.getDataAsText(i, "Analyte")), expected, val, delta); - } - table.clearFilter("EC50"); - table.clearFilter("CurveType"); // expect to already be viewing CurveFit query assertTextPresent("CurveFit"); @@ -166,9 +118,9 @@ else if(formula.get(i).equals(trapezoidal)) assertTrue("Unexpected analyte for Four Parameter curve fit failure", values.size() == 1 && values.get(0).equals("ENV6")); table.clearFilter("CurveType"); - // expect four 5PL curve fit failures + // expect no 5PL curve fits table.setFilter("CurveType", "Equals", "Five Parameter"); - assertEquals("Unexpected number of Five Parameter curve fit failure flags", 4, table.getDataRowCount()); + assertEquals("Unexpected number of Five Parameter curve fit rows", 0, table.getDataRowCount()); table.clearFilter("CurveType"); table.clearFilter("FailureFlag"); diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java index 9500649a68..c20cf3c523 100644 --- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java +++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetDisablingTest.java @@ -133,8 +133,6 @@ private void createValueBasedGuideSet() metricInputs.put("EC504PLAverage", 42158.22); metricInputs.put("EC504PLStdDev", 4833.76); - metricInputs.put("EC505PLAverage", 40987.31); - metricInputs.put("EC505PLStdDev", 4280.84); metricInputs.put("AUCAverage", 85268.04); metricInputs.put("AUCStdDev", 738.55); metricInputs.put("MaxFIAverage", 32507.27); @@ -187,7 +185,6 @@ public void verifyQCFlagsDisabledOnImport() clickButtonContainingText("Details", 0); waitForElement(Locator.checkboxByName("EC504PLCheckBox")); click(Locator.checkboxByName("EC504PLCheckBox")); - click(Locator.checkboxByName("EC505PLCheckBox")); click(Locator.checkboxByName("MFICheckBox")); click(Locator.checkboxByName("AUCCheckBox")); click(SAVE_BTN); @@ -216,10 +213,8 @@ public void verifyQCFlagToggling() _guideSetHelper.setUpLeveyJenningsGraphParams(RUN_BASED_ANALYTE); final String plate1_AUC = "64608.73"; final String plate2_AUC = "61889.88"; - final String plate1_EC50_5PL = "2.66"; - final String plate2_EC50_5PL = "5.67"; - validateFlaggedForQC(plate1_EC50_5PL, plate1_AUC, plate2_AUC); + validateFlaggedForQC(plate1_AUC, plate2_AUC); clickButtonContainingText("Details", 0); // toggle off the AUC QC flag and then validate errors @@ -227,13 +222,10 @@ public void verifyQCFlagToggling() click(Locator.checkboxByName("AUCCheckBox")); saveGuideSetParameters(); - validateFlaggedForQC(plate1_EC50_5PL); - // toggle off the rest of the QC flags and then validate errors clickButtonContainingText("Details", 0); waitForElement(Locator.checkboxByName("EC504PLCheckBox")); click(Locator.checkboxByName("EC504PLCheckBox")); - click(Locator.checkboxByName("EC505PLCheckBox")); click(Locator.checkboxByName("MFICheckBox")); saveGuideSetParameters(); @@ -243,12 +235,11 @@ public void verifyQCFlagToggling() clickButtonContainingText("Details", 0); waitForElement(Locator.checkboxByName("EC504PLCheckBox")); click(Locator.checkboxByName("EC504PLCheckBox")); - click(Locator.checkboxByName("EC505PLCheckBox")); click(Locator.checkboxByName("MFICheckBox")); click(Locator.checkboxByName("AUCCheckBox")); saveGuideSetParameters(); - validateFlaggedForQC(plate2_AUC, plate1_EC50_5PL, plate1_AUC); + validateFlaggedForQC(plate2_AUC, plate1_AUC); } private void saveGuideSetParameters() @@ -287,10 +278,9 @@ public void verifyGuideSetParameterDetailsWindow() clickGuideSetDetailsByComment(RUN_BASED_COMMENT); validateGuideSetRunDetails("Run-based", "Titration"); validateGuideSetMetricsDetails(new String[][]{ - {"5.284", "0.323", "2" }, - {"5.339", "0.540", "2" }, - {"32086.500", "331.633", "2" }, - {"63299.346", "149.318", "2" }, + {"5.284", "0.323", "2" }, // EC50 4PL + {"32086.500", "331.633", "2" }, // MFI + {"63299.346", "149.318", "2" }, // AUC }); // validate checkboxes are not displayed assertTextPresent("# Runs"); @@ -301,10 +291,9 @@ public void verifyGuideSetParameterDetailsWindow() clickGuideSetDetailsByComment(VALUE_BASED_COMMENT); validateGuideSetRunDetails("Value-based", "Titration"); validateGuideSetMetricsDetails(new String[][]{ - {"42158.220", "4833.760"}, - {"40987.310", "4280.840"}, - {"32507.270", "189.830"}, - {"85268.040", "738.550"} + {"42158.220", "4833.760"}, // EC50 4PL + {"32507.270", "189.830"}, // MFI + {"85268.040", "738.550"} // AUC }); // validate checkboxes are not displayed assertTextNotPresent("# Runs"); diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java index d922927e55..66acb7096f 100644 --- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java +++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexGuideSetTest.java @@ -44,7 +44,7 @@ public final class LuminexGuideSetTest extends LuminexTest { public LuminexGuideSetHelper _guideSetHelper = new LuminexGuideSetHelper(this); public static final File[] GUIDE_SET_FILES = {TEST_ASSAY_LUM_FILE5, TEST_ASSAY_LUM_FILE6, TEST_ASSAY_LUM_FILE7, TEST_ASSAY_LUM_FILE8, TEST_ASSAY_LUM_FILE9}; - public static final String[] INITIAL_EXPECTED_FLAGS = {"AUC, EC50-4, HMFI, PCV", "AUC, EC50-4, EC50-5, HMFI", "EC50-5, HMFI", "", "PCV"}; + public static final String[] INITIAL_EXPECTED_FLAGS = {"AUC, EC50-4, HMFI, PCV", "AUC, EC50-4, HMFI", "HMFI", "", "PCV"}; private final String GUIDE_SET_5_COMMENT = "analyte 2 guide set run removed"; @@ -54,7 +54,7 @@ public LuminexGuideSetTest() _guideSetHelper.TESTDATE.add(Calendar.DATE, -GUIDE_SET_FILES.length); } - //requires drc, Ruminex, rlabkey and xtable packages installed in R + //requires drc, rlabkey and xtable packages installed in R @Test public void testGuideSet() { @@ -284,7 +284,7 @@ private boolean verifyRunFileAssociations(int index) clickAndWait(Locator.linkWithText("Text View")); waitForElement(Locator.css(".labkey-protocol-applications")); // bottom section of the "Text View" tab for the run details page waitForElements(Locator.linkWithText("Guide Set plate " + index + ".Standard1_Control_Curves_4PL.pdf"), 3); - assertElementPresent(Locator.linkWithText("Guide Set plate " + index + ".Standard1_Control_Curves_5PL.pdf"), 3); + assertElementNotPresent(Locator.linkWithText("Guide Set plate " + index + ".Standard1_Control_Curves_5PL.pdf")); assertElementPresent(Locator.linkWithText("Guide Set plate " + index + ".xls"), 4); assertElementPresent(Locator.linkWithText("Guide Set plate " + index + ".labkey_luminex_transform.Rout"), 3); @@ -395,10 +395,10 @@ private void verifyLeveyJenningsPlots() _guideSetHelper.waitForLeveyJenningsTrendPlot(); assertElementPresent(Locator.id("EC504PLTrendPlotDiv")); - // check5PL ec50 trending plot - click(Locator.tagWithText("span", "EC50 - 5PL Rumi")); - _guideSetHelper.waitForLeveyJenningsTrendPlot(); - assertElementPresent(Locator.id("EC505PLTrendPlotDiv")); + // check 5PL ec50 trending plot tab not shown + assertElementNotPresent(Locator.linkWithText("EC50 - 5PL Rumi")); + assertTextNotPresent("EC50 - 5PL Rumi"); + assertElementNotPresent(Locator.id("EC505PLTrendPlotDiv")); // check auc trending plot click(Locator.tagWithText("span", "AUC")); @@ -474,20 +474,19 @@ private void verifyQCFlagUpdatesAfterWellChange() // - QC Flags added for EC50 and HMFI _guideSetHelper.goToLeveyJenningsGraphPage(TEST_ASSAY_LUM, "Standard1"); _guideSetHelper.setUpLeveyJenningsGraphParams("GS Analyte B"); - String newQcFlags = "AUC, EC50-4, EC50-5, HMFI"; + String newQcFlags = "AUC, EC50-4, HMFI"; assertTextNotPresent(newQcFlags); _guideSetHelper.applyGuideSetToRun("NETWORK5", GUIDE_SET_5_COMMENT, false); //assert ec50 and HMFI red text present waitForText(newQcFlags); - assertElementPresent(Locator.xpath("//div[text()='28040.51' and contains(@style,'red')]")); - assertElementPresent(Locator.xpath("//div[text()='27950.49' and contains(@style,'red')]")); - assertElementPresent(Locator.xpath("//div[text()='79121.45' and contains(@style,'red')]")); - assertElementPresent(Locator.xpath("//div[text()='32145.80' and contains(@style,'red')]")); + assertElementPresent(Locator.xpath("//div[text()='28040.51' and contains(@style,'red')]")); // EC50 + assertElementPresent(Locator.xpath("//div[text()='79121.45' and contains(@style,'red')]")); // AUC + assertElementPresent(Locator.xpath("//div[text()='32145.80' and contains(@style,'red')]")); // High MFI //verify new flags present in run list goToTestAssayHome(); drt = new DataRegionTable("Runs", getDriver()); drt.goToView("QC Flags View"); - assertTextPresent("AUC, EC50-4, EC50-5, HMFI, PCV"); + assertTextPresent("AUC, EC50-4, HMFI, PCV"); //5. For GS Analyte B, apply the guide set for plate 5a back to the current guide set // - the EC50 and HMFI QC Flags that were added in step 4 are removed @@ -537,8 +536,7 @@ private void assertExpectedAnalyte1QCFlagsPresent() private void assertQCFlagsNotPresent() { - // NOTE: don't check EC50-5 as it is inconsistent - for(String flag : new String[] {"AUC", "HMFI", "EC50-4", "PCV"}) + for (String flag : new String[] {"AUC", "HMFI", "EC50-4", "EC50-5", "PCV"}) { assertElementNotPresent(Locator.xpath("//a[contains(text(),'" + flag + "')]")); } @@ -596,10 +594,7 @@ private void verifyHighlightUpdatesAfterQCFlagChange() String[] newColumns = {"AnalyteTitration/MaxFIQCFlagsEnabled", "AnalyteTitration/MaxFI", "AnalyteTitration/Four ParameterCurveFit/EC50", "AnalyteTitration/Four ParameterCurveFit/AUC", "AnalyteTitration/Four ParameterCurveFit/EC50QCFlagsEnabled", - "AnalyteTitration/Four ParameterCurveFit/AUCQCFlagsEnabled", - "AnalyteTitration/Five ParameterCurveFit/EC50", "AnalyteTitration/Five ParameterCurveFit/AUC", - "AnalyteTitration/Five ParameterCurveFit/EC50QCFlagsEnabled", - "AnalyteTitration/Five ParameterCurveFit/AUCQCFlagsEnabled"}; + "AnalyteTitration/Four ParameterCurveFit/AUCQCFlagsEnabled"}; for(String column : newColumns) { _customizeViewsHelper.addColumn(column); diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java index bb99d11a5e..575b1512dc 100644 --- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java +++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexRTransformTest.java @@ -28,8 +28,11 @@ import org.labkey.test.util.LogMethod; import org.openqa.selenium.WebElement; +import java.io.File; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; @Category({Daily.class, Assays.class}) @BaseWebDriverTest.ClassTimeout(minutes = 12) @@ -41,17 +44,6 @@ public final class LuminexRTransformTest extends LuminexTest private static final String ANALYTE3 = "Blank"; private static final String ANALYTE4 = "MyNegative"; - private static final String[] RTRANS_FIBKGDNEG_VALUES = {"-50.5", "-70.0", "25031.5", "25584.5", "391.5", "336.5", "263.8", "290.8", - "35.2", "35.2", "63.0", "71.0", "-34.0", "-33.0", "-29.8", "-19.8", "-639.8", "-640.2", "26430.8", "26556.2", "-216.2", "-204.2", "-158.5", - "-208.0", "-4.0", "-4.0", "194.2", "198.8", "-261.2", "-265.2", "-211.5", "-213.0"}; - private static final String[] RTRANS_ESTLOGCONC_VALUES_5PL = {"-6.9", "-6.9", "4.3", "4.3", "0.4", "0.4", "-0.0", "-0.0", "-6.9", "-6.9", - "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "4.2", "4.2", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", - "-6.9", "-0.6", "-0.6", "-6.9", "-6.9", "-6.9", "-6.9"}; - - private static final String[] RTRANS_ESTLOGCONC_VALUES_4PL = {"-6.9", "-6.9", "5.0", "5.0", "0.4", "0.4", "0.1", "0.1", "-6.9", "-6.9", - "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "5.5", "5.5", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", "-6.9", - "-0.8", "-0.8", "-6.9", "-6.9", "-6.9", "-6.9"}; - @BeforeClass public static void updateAssayDefinition() { @@ -66,24 +58,15 @@ public static void updateAssayDefinition() assayDesigner.clickFinish(); } - //requires drc, Ruminex and xtable packages installed in R + //requires drc and xtable packages installed in R @Test public void testRTransform() { log("Uploading Luminex run with a R transform script"); - - uploadRunWithoutRumiCalc(); - verifyPDFsGenerated(false); - verifyScriptVersions(); - verifyLotNumber(); - verifyRumiCalculatedValues(false, ANALYTE3); - verifyAnalyteProperties(new String[]{ANALYTE3, ANALYTE3, " ", " "}); - - reImportRunWithRumiCalc(); - verifyPDFsGenerated(true); + uploadRun(); + verifyPDFsGenerated(); verifyScriptVersions(); verifyLotNumber(); - verifyRumiCalculatedValues(true, ANALYTE4); verifyAnalyteProperties(new String[]{ANALYTE4, ANALYTE4, " ", " "}); } @@ -98,65 +81,6 @@ private void verifyAnalyteProperties(String[] expectedNegBead) } } - private void verifyRumiCalculatedValues(boolean hasRumiCalcData, String negativeBead) - { - DataRegionTable table = new DataRegionTable("Data", this); - table.setFilter("FIBackgroundNegative", "Is Not Blank", null); - waitForElement(Locator.paginationText(1, 80, 80)); - table.setFilter("Type", "Equals", "C9"); // issue 20457 - assertEquals(4, table.getDataRowCount()); - for(int i = 0; i < table.getDataRowCount(); i++) - { - assertEquals(table.getDataAsText(i, "FI-Bkgd"), table.getDataAsText(i, "FI-Bkgd-Neg")); - } - table.clearFilter("Type"); - table.setFilter("Type", "Starts With", "X"); // filter to just the unknowns - waitForElement(Locator.paginationText(1, 32, 32)); - assertTextPresent(negativeBead, 32); - // check values in the fi-bkgd-neg column - for(int i = 0; i < RTRANS_FIBKGDNEG_VALUES.length; i++) - { - assertEquals(RTRANS_FIBKGDNEG_VALUES[i], table.getDataAsText(i, "FI-Bkgd-Neg")); - } - table.clearFilter("FIBackgroundNegative"); - - table.setFilter("EstLogConc_5pl", "Is Not Blank", null); - if (!hasRumiCalcData) - { - waitForText("No data to show."); - assertEquals(0, table.getDataRowCount()); - } - else - { - waitForElement(Locator.paginationText(1, 32, 32)); - // check values in the est log conc 5pl column - for(int i = 0; i < RTRANS_ESTLOGCONC_VALUES_5PL.length; i++) - { - assertEquals(RTRANS_ESTLOGCONC_VALUES_5PL[i], table.getDataAsText(i, "Est Log Conc Rumi 5 PL")); - } - } - table.clearFilter("EstLogConc_5pl"); - - table.setFilter("EstLogConc_4pl", "Is Not Blank", null); - if (!hasRumiCalcData) - { - waitForText("No data to show."); - assertEquals(0, table.getDataRowCount()); - } - else - { - waitForElement(Locator.paginationText(1, 32, 32)); - // check values in the est log conc 4pl column - for(int i = 0; i < RTRANS_ESTLOGCONC_VALUES_4PL.length; i++) - { - assertEquals(RTRANS_ESTLOGCONC_VALUES_4PL[i], table.getDataAsText(i, "Est Log Conc Rumi 4 PL")); - } - } - table.clearFilter("EstLogConc_4pl"); - - table.clearFilter("Type"); - } - private void verifyLotNumber() { clickAndWait(Locator.linkWithText("r script transformed assayId")); @@ -174,30 +98,22 @@ private void verifyScriptVersions() { assertTextPresent(TEST_ASSAY_LUM + " Runs"); DataRegionTable table = new DataRegionTable("Runs", this); - assertEquals("Unexpected Transform Script Version number", "10.1.20180903", table.getDataAsText(0, "Transform Script Version")); + assertEquals("Unexpected Transform Script Version number", "11.0.20230206", table.getDataAsText(0, "Transform Script Version")); assertEquals("Unexpected Lab Transform Script Version number", "3.1.20180903", table.getDataAsText(0, "Lab Transform Script Version")); - assertEquals("Unexpected Ruminex Version number", "0.0.9", table.getDataAsText(0, "Ruminex Version")); assertNotNull(table.getDataAsText(0, "R Version")); } - private void verifyPDFsGenerated(boolean hasStandardPDFs) + private void verifyPDFsGenerated() { DataRegionTable.DataRegion(getDriver()).find(); // Make sure page is loaded WebElement curvePng = Locator.tagWithAttribute("img", "src", "/labkey/_images/sigmoidal_curve.png").findElement(getDriver()); shortWait().until(LabKeyExpectedConditions.animationIsDone(curvePng)); - mouseOver(curvePng); - curvePng.click(); - assertElementPresent(Locator.linkContainingText(".Standard1_Control_Curves_4PL.pdf")); - assertElementPresent(Locator.linkContainingText(".Standard1_Control_Curves_5PL.pdf")); - if (hasStandardPDFs) - { - assertElementPresent(Locator.linkWithText("WithAltNegativeBead.Standard1_5PL.pdf")); - assertElementPresent(Locator.linkWithText("WithAltNegativeBead.Standard1_4PL.pdf")); - } + File curvePdf = clickAndWaitForDownload(curvePng); + assertEquals("Curve PDF has wrong name: " + curvePdf.getName(), "WithAltNegativeBead.Standard1_Control_Curves_4PL.pdf", curvePdf.getName()); } @LogMethod - public void uploadRunWithoutRumiCalc() + public void uploadRun() { goToProjectHome(); clickAndWait(Locator.linkWithText(TEST_ASSAY_LUM)); @@ -209,8 +125,6 @@ public void uploadRunWithoutRumiCalc() checkCheckbox(Locator.name("subtNegativeFromAll")); setFormElement(Locator.name("stndCurveFitInput"), "FI"); setFormElement(Locator.name("unkCurveFitInput"), "FI-Bkgd-Neg"); - checkCheckbox(Locator.name("curveFitLogTransform")); - checkCheckbox(Locator.name("skipRumiCalculation")); setFormElement(Locator.name("__primaryFile__"), TEST_ASSAY_LUM_FILE4); clickButton("Next", defaultWaitForPage * 2); @@ -227,22 +141,6 @@ public void uploadRunWithoutRumiCalc() checkCheckbox(Locator.name("_analyte_" + ANALYTE3 + "_NegativeControl")); selectOptionByText(Locator.name("_analyte_" + ANALYTE1 + "_NegativeBead"), ANALYTE3); selectOptionByText(Locator.name("_analyte_" + ANALYTE2 + "_NegativeBead"), ANALYTE3); - clickButton("Save and Finish"); - } - - @LogMethod - public void reImportRunWithRumiCalc() - { - goToProjectHome(); - clickAndWait(Locator.linkWithText(TEST_ASSAY_LUM)); - - // all batch, run, analyte properties should be remembered from the first upload - DataRegionTable table = new DataRegionTable("Runs", this); - table.checkCheckbox(0); - clickButton("Re-import run"); - clickButton("Next"); - uncheckCheckbox(Locator.name("skipRumiCalculation")); - clickButton("Next", defaultWaitForPage * 2); // switch to using MyNegative bead for subtraction checkCheckbox(Locator.name("_analyte_" + ANALYTE4 + "_NegativeControl")); selectOptionByText(Locator.name("_analyte_" + ANALYTE1 + "_NegativeBead"), ANALYTE4); diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexTest.java index 37639f4b24..d7081cbb32 100644 --- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexTest.java +++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexTest.java @@ -213,14 +213,13 @@ private void doInit() throws Exception assayProtocol.setName(TEST_ASSAY_LUM) .setDescription(TEST_ASSAY_LUM_DESC); - // add batch properties for transform and Ruminex version numbers + // add batch properties for transform and R version numbers Domain batchesDomain = assayProtocol.getDomains().stream().filter(a->a.getName().equals("Batch Fields")).findFirst() .orElseThrow(()-> new IllegalStateException("The protocol template did not supply a [Batch Fields] domain")); List batchFields = batchesDomain.getFields(); // keep the template-supplied fields, add the following batchFields.add(new PropertyDescriptor("Network", "Network", "string")); batchFields.add(new PropertyDescriptor("TransformVersion", "Transform Script Version", "string")); batchFields.add(new PropertyDescriptor("LabTransformVersion", "Lab Transform Script Version", "string")); - batchFields.add(new PropertyDescriptor("RuminexVersion", "Ruminex Version", "string")); batchFields.add(new PropertyDescriptor("RVersion", "R Version", "string")); setFieldsToDomain(batchFields, batchesDomain); @@ -231,8 +230,6 @@ private void doInit() throws Exception runFields.add(new PropertyDescriptor("SubtNegativeFromAll", "Subtract Negative Bead from All Wells", "boolean")); runFields.add(new PropertyDescriptor("StndCurveFitInput", "Input Var for CurveFit Calc of Standards", "string")); runFields.add(new PropertyDescriptor("UnkCurveFitInput", "Input Var for Curve Fit Calc of Unknowns", "string")); - runFields.add(new PropertyDescriptor("CurveFitLogTransform", "Curve Fit Log Transform", "boolean")); - runFields.add(new PropertyDescriptor("SkipRumiCalculation", "Skip Ruminex Calculations", "boolean")); // add run properties for use with the Guide Set test runFields.add(new PropertyDescriptor("NotebookNo", "Notebook Number", "string")); @@ -258,22 +255,10 @@ private void doInit() throws Exception .orElseThrow(()-> new IllegalStateException("The protocol template did not supply a [Data Fields] domain")); List resultsFields = resultsDomain.getFields(); resultsFields.add(new PropertyDescriptor("FIBackgroundNegative", "FI-Bkgd-Neg", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("Standard", "Stnd for Calc", "string")); - resultsFields.add(new PropertyDescriptor("EstLogConc_5pl", "Est Log Conc Rumi 5 PL", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("EstConc_5pl", "Est Conc Rumi 5 PL", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("SE_5pl", "SE Rumi 5 PL", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("EstLogConc_4pl", "Est Log Conc Rumi 4 PL", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("EstConc_4pl", "Est Conc Rumi 4 PL", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("SE_4pl", "SE Rumi 4 PL", "float").setFormat("0.0")); resultsFields.add(new PropertyDescriptor("Slope_4pl", "Slope_4pl", "float").setFormat("0.0")); resultsFields.add(new PropertyDescriptor("Lower_4pl", "Lower_4pl", "float").setFormat("0.0")); resultsFields.add(new PropertyDescriptor("Upper_4pl", "Upper_4pl", "float").setFormat("0.0")); resultsFields.add(new PropertyDescriptor("Inflection_4pl", "Inflection_4pl", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("Slope_5pl", "Slope_5pl", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("Lower_5pl", "Lower_5pl", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("Upper_5pl", "Upper_5pl", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("Inflection_5pl", "Inflection_5pl", "float").setFormat("0.0")); - resultsFields.add(new PropertyDescriptor("Asymmetry_5pl", "Asymmetry_5pl", "float").setFormat("0.0")); resultsFields.add(new PropertyDescriptor("Positivity", "Positivity", "string")); setFieldsToDomain(resultsFields, resultsDomain); @@ -614,7 +599,6 @@ protected void importLuminexRunPageTwo(String runId, String isotype, String conj setFormElement(Locator.name("conjugate"), conjugate); setFormElement(Locator.name("stndCurveFitInput"), stndCurveFitInput); setFormElement(Locator.name("unkCurveFitInput"), unkCurveFitInput); - uncheckCheckbox(Locator.name("curveFitLogTransform")); setFormElement(Locator.name("notebookNo"), notebookNo); setFormElement(Locator.name("assayType"), assayType); setFormElement(Locator.name("expPerformer"), expPerformer); @@ -730,9 +714,8 @@ protected void verifyQCReport() //make sure all the columns we want are viable _customizeViewsHelper.openCustomizeViewPanel(); _customizeViewsHelper.showHiddenItems(); - _customizeViewsHelper.addColumn("Five ParameterCurveFit/FailureFlag"); _customizeViewsHelper.addColumn("Four ParameterCurveFit/FailureFlag"); - _customizeViewsHelper.addColumn("Five ParameterCurveFit/EC50"); + _customizeViewsHelper.addColumn("Four ParameterCurveFit/EC50"); _customizeViewsHelper.saveCustomView(); assertTextPresent("Titration QC Report"); @@ -751,14 +734,6 @@ protected void verifyQCReport() assertEquals(" ", flag); } - List fiveParamFlag = drt.getColumnDataAsText("Five Parameter Curve Fit Failure Flag"); - List fiveParamData = drt.getColumnDataAsText("Five Parameter Curve Fit EC50"); - - for (int i=0; i < fiveParamData.size(); i++) - { - assertTrue("Row " + i + " was flagged as 5PL failure but had EC50 data", ((fiveParamFlag.get(i).equals(" ")) ^ (fiveParamData.get(i).equals(" ")))); - } - //verify link to Levey-Jennings plot clickAndWait(Locator.linkWithText("graph").index(0)); waitForText(" - " + isotype + " " + conjugate); diff --git a/luminex/test/src/org/labkey/test/tests/luminex/LuminexValueBasedGuideSetTest.java b/luminex/test/src/org/labkey/test/tests/luminex/LuminexValueBasedGuideSetTest.java index 6b228bfdc9..c9130d7374 100644 --- a/luminex/test/src/org/labkey/test/tests/luminex/LuminexValueBasedGuideSetTest.java +++ b/luminex/test/src/org/labkey/test/tests/luminex/LuminexValueBasedGuideSetTest.java @@ -83,8 +83,6 @@ private void createInitialGuideSets() _guideSetHelper.createGuideSet(true); metricInputs.put("EC504PLAverage", 179.60); metricInputs.put("EC504PLStdDev", 22.48); - metricInputs.put("EC505PLAverage", 249.04); - metricInputs.put("EC505PLStdDev", 12.41); metricInputs.put("AUCAverage", 8701.37); metricInputs.put("AUCStdDev", 466.82); metricInputs.put("MaxFIAverage", 11457.15); @@ -98,8 +96,6 @@ private void createInitialGuideSets() _guideSetHelper.createGuideSet(true); metricInputs.put("EC504PLAverage", 43426.10); metricInputs.put("EC504PLStdDev", 794.96); - metricInputs.put("EC505PLAverage", 45242.19); - metricInputs.put("EC505PLStdDev", 10007.113); metricInputs.put("AUCAverage", 80851.74); metricInputs.put("AUCStdDev", 6523.05); metricInputs.put("MaxFIAverage", 30992.25); @@ -131,8 +127,6 @@ private void updateGuideSets() // The automation library clears a txt box before entering a new value, so we need to update both the Avg and the StdDev. _guideSetHelper.setUpLeveyJenningsGraphParams(LuminexGuideSetHelper.GUIDE_SET_ANALYTE_NAMES[0]); clickButtonContainingText("Edit", 0); - metricInputs.put("EC505PLAverage", 325.0); - metricInputs.put("EC505PLStdDev", 100.0); metricInputs.put("AUCAverage", 7800.0); metricInputs.put("AUCStdDev", 466.82); metricInputs.put("MaxFIAverage", 10200.0); @@ -144,8 +138,6 @@ private void updateGuideSets() _guideSetHelper.createGuideSet(false); metricInputs.put("EC504PLAverage", 42158.38); metricInputs.put("EC504PLStdDev", 4833.95); - metricInputs.put("EC505PLAverage", 44249.59); - metricInputs.put("EC505PLStdDev", 8084.973); metricInputs.put("AUCAverage", 85267.94); metricInputs.put("AUCStdDev", 738.53); metricInputs.put("MaxFIAverage", 32507.27); diff --git a/luminex/webapp/luminex/GuideSetWindow.js b/luminex/webapp/luminex/GuideSetWindow.js index eb332571b0..8eb9644c3b 100644 --- a/luminex/webapp/luminex/GuideSetWindow.js +++ b/luminex/webapp/luminex/GuideSetWindow.js @@ -22,6 +22,10 @@ Ext4.define('LABKEY.luminex.GuideSetWindow', { currentGuideSetId: null, canEdit: false, + // These values will be set in the constructor via the LABKEY.Query.selectDistinctRows call + has4PLCurveFit: false, + has5PLCurveFit: false, + statics: { viewTpl: new Ext4.XTemplate( '', @@ -56,24 +60,28 @@ Ext4.define('LABKEY.luminex.GuideSetWindow', { '', '', '', - '', - 'EC50 4PL', - '{[this.formatNumber(values.EC504PLAverage)]}', - '{[this.formatNumber(values.EC504PLStdDev)]}', - '', - '{EC504PLRunCount}', - '', - '', - '', - '', - 'EC50 5PL', - '{[this.formatNumber(values.EC505PLAverage)]}', - '{[this.formatNumber(values.EC505PLStdDev)]}', - '', - '{EC505PLRunCount}', - '', + '', + '', + 'EC50 4PL', + '{[this.formatNumber(values.EC504PLAverage)]}', + '{[this.formatNumber(values.EC504PLStdDev)]}', + '', + '{EC504PLRunCount}', + '', + '', + '', + '', + '', + '', + 'EC50 5PL', + '{[this.formatNumber(values.EC505PLAverage)]}', + '{[this.formatNumber(values.EC505PLStdDev)]}', + '', + '{EC505PLRunCount}', + '', '', - '', + '', + '', '', '', 'MFI', @@ -176,9 +184,23 @@ Ext4.define('LABKEY.luminex.GuideSetWindow', { this.assayName = config['assayName']; this.addEvents('aftersave'); this.callParent([config]); - // wait till after constructed so that currentGuideSetId is set and assayName - this.getGuideSetStore().load(); - this.show(); + + // Query to see if 4PL and/or 5PL curve fit data exists for this assay + LABKEY.Query.selectDistinctRows({ + schemaName: 'assay.Luminex.'+LABKEY.QueryKey.encodePart(this.assayName), + queryName: 'CurveFit', + column: 'CurveType', + scope: this, + success: function(results){ + var curveTypes = results.values; + this.has4PLCurveFit = curveTypes.indexOf('Four Parameter') > -1; + this.has5PLCurveFit = curveTypes.indexOf('Five Parameter') > -1; + + // wait till after constructed so that currentGuideSetId is set and assayName + this.getGuideSetStore().load(); + this.show(); + } + }); }, // NOTE: consider putting store/model into seperate file... @@ -215,12 +237,15 @@ Ext4.define('LABKEY.luminex.GuideSetWindow', { {name: 'EC505PLRunCount', type: 'int'}, {name: 'AUCRunCount', type: 'int'}, {name: 'ControlType'}, + {name: 'has4PLCurveFit', type: 'boolean'}, + {name: 'has5PLCurveFit', type: 'boolean'}, {name: 'UserCanEdit', type: 'boolean', defaultValue: this.canEdit} ] }); var assayName = this.assayName; var currentGuideSetId = this.currentGuideSetId; + var gsWindow = this; Ext4.define('Luminex.store.GuideSet', { extend: 'Ext.data.Store', @@ -263,6 +288,10 @@ Ext4.define('LABKEY.luminex.GuideSetWindow', { return; } + // add in the has4PLCurveFit and has5PLCurveFit info to the record so that it can be used in the tpl + response.rows[0]['has4PLCurveFit'] = gsWindow.has4PLCurveFit; + response.rows[0]['has5PLCurveFit'] = gsWindow.has5PLCurveFit; + this.removeAll(); var record = Ext4.create('Luminex.model.GuideSet', response.rows[0]); this.add(record); @@ -275,8 +304,8 @@ Ext4.define('LABKEY.luminex.GuideSetWindow', { form.elements['MFICheckBox'].initial = record.get("MaxFIEnabled"); if(record.get("ControlType") == "Titration") { - form.elements['EC504PLCheckBox'].initial = record.get("EC504PLEnabled"); - form.elements['EC505PLCheckBox'].initial = record.get("EC505PLEnabled"); + if (gsWindow.has4PLCurveFit) form.elements['EC504PLCheckBox'].initial = record.get("EC504PLEnabled"); + if (gsWindow.has5PLCurveFit) form.elements['EC505PLCheckBox'].initial = record.get("EC505PLEnabled"); form.elements['AUCCheckBox'].initial = record.get("AUCEnabled"); } } diff --git a/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js b/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js index 4bdfc7207c..b65e0705c4 100644 --- a/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js +++ b/luminex/webapp/luminex/LeveyJenningsGuideSetPanel.js @@ -306,6 +306,8 @@ LABKEY.LeveyJenningsGuideSetPanel = Ext.extend(Ext.FormPanel, { conjugate: this.conjugate, networkExists: this.networkExists, protocolExists: this.protocolExists, + has4PLCurveFit: this.has4PLCurveFit, + has5PLCurveFit: this.has5PLCurveFit, listeners: { scope: this, 'closeManageGuideSetPanel': function(saveResults) { diff --git a/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js b/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js index cde7435080..ae4dd4e7dd 100644 --- a/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js +++ b/luminex/webapp/luminex/LeveyJenningsTrackingDataPanel.js @@ -187,9 +187,9 @@ LABKEY.LeveyJenningsTrackingDataPanel = Ext.extend(Ext.grid.GridPanel, { if (this.controlType == "Titration") { cols.splice(2, 0, {header: 'Titration', dataIndex: 'Titration', hidden: true, renderer: this.encodingRenderer}); - cols.push({header: 'EC50 4PL', dataIndex: 'EC504PL', width: 75, renderer: this.outOfRangeRenderer("EC504PLQCFlagsEnabled"), scope: this, align: 'right'}); + cols.push({header: 'EC50 4PL', dataIndex: 'EC504PL', width: 75, renderer: this.outOfRangeRenderer("EC504PLQCFlagsEnabled"), scope: this, align: 'right', hidden: !this.has4PLCurveFit}); cols.push({header: 'EC50 4PL QC Flags Enabled', dataIndex: 'EC504PLQCFlagsEnabled', hidden: true}); - cols.push({header: 'EC50 5PL', dataIndex: 'EC505PL', width: 75, renderer: this.outOfRangeRenderer("EC505PLQCFlagsEnabled"), scope: this, align: 'right'}); + cols.push({header: 'EC50 5PL', dataIndex: 'EC505PL', width: 75, renderer: this.outOfRangeRenderer("EC505PLQCFlagsEnabled"), scope: this, align: 'right', hidden: !this.has5PLCurveFit}); cols.push({header: 'EC50 5PL QC Flags Enabled', dataIndex: 'EC505PLQCFlagsEnabled', hidden: true}); cols.push({header: 'AUC', dataIndex: 'AUC', width: 75, renderer: this.outOfRangeRenderer("AUCQCFlagsEnabled"), scope: this, align: 'right'}); cols.push({header: 'AUC QC Flags Enabled', dataIndex: 'AUCQCFlagsEnabled', hidden: true}); diff --git a/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js b/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js index 1e713ad02e..8c7c81a2d2 100644 --- a/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js +++ b/luminex/webapp/luminex/LeveyJenningsTrendPlotPanel.js @@ -505,7 +505,12 @@ LABKEY.LeveyJenningsTrendPlotPanel = Ext.extend(Ext.FormPanel, { getTitrationSinglePointControlItems: function() { if (this.controlType == "Titration") { - return([this.ec504plPanel, this.ec505plPanel, this.aucPanel, this.mfiPanel]); + var panels = []; + if (this.has4PLCurveFit) panels.push(this.ec504plPanel); + if (this.has5PLCurveFit) panels.push(this.ec505plPanel); + panels.push(this.aucPanel); + panels.push(this.mfiPanel); + return(panels); } else if (this.controlType = "SinglePoint") { return([this.singlePointControlPanel]); } diff --git a/luminex/webapp/luminex/ManageGuideSetPanel.js b/luminex/webapp/luminex/ManageGuideSetPanel.js index 69a0445697..10c11d66b2 100644 --- a/luminex/webapp/luminex/ManageGuideSetPanel.js +++ b/luminex/webapp/luminex/ManageGuideSetPanel.js @@ -30,12 +30,7 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { labelStyleStr : 'padding: 0; margin: 0;', - metrics : [ - {name: 'EC504PL', label: 'EC50 4PL', includeForSinglePointControl: false}, - {name: 'EC505PL', label: 'EC50 5PL (Rumi)', includeForSinglePointControl: false}, - {name: 'AUC', label: 'AUC', includeForSinglePointControl: false}, - {name: 'MaxFI', label: 'High MFI', includeForSinglePointControl: true} - ], + metrics : [], constructor : function(config){ // check that the config properties needed are present @@ -63,9 +58,16 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { initComponent : function() { LABKEY.ManageGuideSetPanel.superclass.initComponent.call(this); + this.metrics = [ + {name: 'EC504PL', label: 'EC50 4PL', includeForSinglePointControl: false, hidden: !this.has4PLCurveFit}, + {name: 'EC505PL', label: 'EC50 5PL (Rumi)', includeForSinglePointControl: false, hidden: !this.has5PLCurveFit}, + {name: 'AUC', label: 'AUC', includeForSinglePointControl: false, hidden: false}, + {name: 'MaxFI', label: 'High MFI', includeForSinglePointControl: true, hidden: false} + ]; + var columns = 'RowId, CurrentGuideSet, Comment, Created, ValueBased'; Ext.each(this.metrics, function(metric){ - if (this.isTitrationControlType() || metric.includeForSinglePointControl) + if ((this.isTitrationControlType() || metric.includeForSinglePointControl) && !metric.hidden) columns += ', ' + metric.name + 'Average, ' + metric.name + 'StdDev'; }, this); @@ -219,8 +221,8 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { allRunsCols.push({header:'Acquisition Date', dataIndex:'Analyte/Data/AcquisitionDate', renderer: this.dateRenderer, width:100}); if (this.isTitrationControlType()) { - allRunsCols.push({header:'EC50 4PL', dataIndex:'Four ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right'}); - allRunsCols.push({header:'EC50 5PL', dataIndex:'Five ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right'}); + allRunsCols.push({header:'EC50 4PL', dataIndex:'Four ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right', hidden: !this.has4PLCurveFit}); + allRunsCols.push({header:'EC50 5PL', dataIndex:'Five ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right', hidden: !this.has5PLCurveFit}); allRunsCols.push({header:'AUC', dataIndex:'TrapezoidalCurveFit/AUC', width:75, renderer: this.numberRenderer, align: 'right'}); allRunsCols.push({header:'High MFI', dataIndex:'MaxFI', width:75, renderer: this.numberRenderer, align: 'right'}); } @@ -300,8 +302,8 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { guideRunSetCols.push({header:'Acquisition Date', dataIndex:'Analyte/Data/AcquisitionDate', renderer: this.dateRenderer, width:100}); if (this.isTitrationControlType()) { - guideRunSetCols.push({header:'EC50 4PL', dataIndex:'Four ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right'}); - guideRunSetCols.push({header:'EC50 5PL', dataIndex:'Five ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right'}); + guideRunSetCols.push({header:'EC50 4PL', dataIndex:'Four ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right', hidden: !this.has4PLCurveFit}); + guideRunSetCols.push({header:'EC50 5PL', dataIndex:'Five ParameterCurveFit/EC50', width:75, renderer: this.numberRenderer, align: 'right', hidden: !this.has5PLCurveFit}); guideRunSetCols.push({header:'AUC', dataIndex:'TrapezoidalCurveFit/AUC', width:75, renderer: this.numberRenderer, align: 'right'}); guideRunSetCols.push({header:'High MFI', dataIndex:'MaxFI', width:75, renderer: this.numberRenderer, align: 'right'}); } @@ -492,7 +494,7 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { }); Ext.each(this.metrics, function(metric){ - if (this.isTitrationControlType() || metric.includeForSinglePointControl) + if ((this.isTitrationControlType() || metric.includeForSinglePointControl) && !metric.hidden) this.metricLabelsPanel.add(this.createLabelField(metric.label + ':')); }, this); } @@ -510,7 +512,7 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { }); Ext.each(this.metrics, function(metric){ - if (this.isTitrationControlType() || metric.includeForSinglePointControl) + if ((this.isTitrationControlType() || metric.includeForSinglePointControl) && !metric.hidden) this.metricMeanValuesPanel.add(this.createNumberField(metric.name + 'Average')); }, this); } @@ -528,7 +530,7 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { }); Ext.each(this.metrics, function(metric){ - if (this.isTitrationControlType() || metric.includeForSinglePointControl) + if ((this.isTitrationControlType() || metric.includeForSinglePointControl) && !metric.hidden) { // issue 20152: don't allow std dev if average is blank var stdDevField = this.createNumberField(metric.name + 'StdDev'); @@ -547,7 +549,7 @@ LABKEY.ManageGuideSetPanel = Ext.extend(Ext.FormPanel, { var values = {}; Ext.each(this.metrics, function(metric){ - if (this.isTitrationControlType() || metric.includeForSinglePointControl) + if ((this.isTitrationControlType() || metric.includeForSinglePointControl) && !metric.hidden) { var numFld = this.getMetricMeanValuesPanel().getComponent(metric.name + 'Average'); values[numFld.getName()] = numFld.getValue();