Commit 6ebad57b201989a25d35171b914269ac7876eeab

Authored by bhklein
1 parent cb9c5416

Sample ROC points at fixed FAR values for easy vertical averaging. Display conf…

…idence intervals in tables and plots.
openbr/core/eval.cpp
@@ -48,22 +48,26 @@ struct OperatingPoint @@ -48,22 +48,26 @@ struct OperatingPoint
48 : score(_score), FAR(_FAR), TAR(_TAR) {} 48 : score(_score), FAR(_FAR), TAR(_TAR) {}
49 }; 49 };
50 50
51 -static float getTAR(const QList<OperatingPoint> &operatingPoints, float FAR) 51 +static OperatingPoint getOperatingPoint(const QList<OperatingPoint> &operatingPoints, float FAR)
52 { 52 {
53 int index = 0; 53 int index = 0;
54 while (operatingPoints[index].FAR < FAR) { 54 while (operatingPoints[index].FAR < FAR) {
55 index++; 55 index++;
56 if (index == operatingPoints.size()) 56 if (index == operatingPoints.size())
57 - return 1; 57 + return OperatingPoint(operatingPoints.last().score, FAR, operatingPoints.last().TAR);
58 } 58 }
59 59
60 - const float x1 = (index == 0 ? 0 : operatingPoints[index-1].FAR);  
61 - const float y1 = (index == 0 ? 0 : operatingPoints[index-1].TAR);  
62 - const float x2 = operatingPoints[index].FAR;  
63 - const float y2 = operatingPoints[index].TAR;  
64 - const float m = (y2 - y1) / (x2 - x1);  
65 - const float b = y1 - m*x1;  
66 - return m * FAR + b; 60 + const float FAR1 = (index == 0 ? 0 : operatingPoints[index-1].FAR);
  61 + const float TAR1 = (index == 0 ? 0 : operatingPoints[index-1].TAR);
  62 + const float score1 = (index == 0 ? operatingPoints[index].score : operatingPoints[index-1].score);
  63 + const float FAR2 = operatingPoints[index].FAR;
  64 + const float TAR2 = operatingPoints[index].TAR;
  65 + const float score2 = operatingPoints[index].score;
  66 + const float mTAR = (TAR2 - TAR1) / (FAR2 - FAR1);
  67 + const float bTAR = TAR1 - mTAR*FAR1;
  68 + const float mScore = (score2 - score1) / (FAR2 - FAR1);
  69 + const float bScore = score1 - mScore*FAR1;
  70 + return OperatingPoint(mScore * FAR + bScore,FAR, mTAR * FAR + bTAR);
67 } 71 }
68 72
69 static float getCMC(const QVector<int> &firstGenuineReturns, int rank) 73 static float getCMC(const QVector<int> &firstGenuineReturns, int rank)
@@ -266,23 +270,26 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv, const QSt @@ -266,23 +270,26 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv, const QSt
266 } 270 }
267 271
268 // Write Detection Error Tradeoff (DET), PRE, REC 272 // Write Detection Error Tradeoff (DET), PRE, REC
269 - int points = qMin(operatingPoints.size(), Max_Points);  
270 - for (int i=0; i<points; i++) {  
271 - const OperatingPoint &operatingPoint = operatingPoints[double(i) / double(points-1) * double(operatingPoints.size()-1)];  
272 - lines.append(QString("DET,%1,%2").arg(QString::number(operatingPoint.FAR), 273 + float FAR=0.000001;
  274 + for (int i=0; i<Max_Points; i++) {
  275 + OperatingPoint operatingPoint = getOperatingPoint(operatingPoints, FAR);
  276 + lines.append(QString("DET,%1,%2").arg(QString::number(FAR),
273 QString::number(1-operatingPoint.TAR))); 277 QString::number(1-operatingPoint.TAR)));
274 lines.append(QString("FAR,%1,%2").arg(QString::number(operatingPoint.score), 278 lines.append(QString("FAR,%1,%2").arg(QString::number(operatingPoint.score),
275 - QString::number(operatingPoint.FAR))); 279 + QString::number(FAR)));
276 lines.append(QString("FRR,%1,%2").arg(QString::number(operatingPoint.score), 280 lines.append(QString("FRR,%1,%2").arg(QString::number(operatingPoint.score),
277 QString::number(1-operatingPoint.TAR))); 281 QString::number(1-operatingPoint.TAR)));
  282 + //multiplier roughly spans 10E-6 to 1
  283 + FAR *=1.02807;
278 } 284 }
  285 +
279 // Write FAR/TAR Table (FT) 286 // Write FAR/TAR Table (FT)
280 - lines.append(qPrintable(QString("FT,0.000001,%1").arg(QString::number(getTAR(operatingPoints, 0.000001), 'f', 3))));  
281 - lines.append(qPrintable(QString("FT,0.00001,%1").arg(QString::number(getTAR(operatingPoints, 0.00001), 'f', 3))));  
282 - lines.append(qPrintable(QString("FT,0.0001,%1").arg(QString::number(getTAR(operatingPoints, 0.0001), 'f', 3))));  
283 - lines.append(qPrintable(QString("FT,0.001,%1").arg(QString::number(getTAR(operatingPoints, 0.001), 'f', 3))));  
284 - lines.append(qPrintable(QString("FT,0.01,%1").arg(QString::number(getTAR(operatingPoints, 0.01), 'f', 3))));  
285 - lines.append(qPrintable(QString("FT,0.1,%1").arg(QString::number(getTAR(operatingPoints, 0.1), 'f', 3)))); 287 + lines.append(qPrintable(QString("FT,0.000001,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.000001).TAR, 'f', 3))));
  288 + lines.append(qPrintable(QString("FT,0.00001,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.00001).TAR, 'f', 3))));
  289 + lines.append(qPrintable(QString("FT,0.0001,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.0001).TAR, 'f', 3))));
  290 + lines.append(qPrintable(QString("FT,0.001,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.001).TAR, 'f', 3))));
  291 + lines.append(qPrintable(QString("FT,0.01,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.01).TAR, 'f', 3))));
  292 + lines.append(qPrintable(QString("FT,0.1,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.1).TAR, 'f', 3))));
286 293
287 //Write CMC Table (CT) 294 //Write CMC Table (CT)
288 lines.append(qPrintable(QString("CT,1,%1").arg(QString::number(getCMC(firstGenuineReturns, 1), 'f', 3)))); 295 lines.append(qPrintable(QString("CT,1,%1").arg(QString::number(getCMC(firstGenuineReturns, 1), 'f', 3))));
@@ -293,19 +300,18 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv, const QSt @@ -293,19 +300,18 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv, const QSt
293 lines.append(qPrintable(QString("CT,100,%1").arg(QString::number(getCMC(firstGenuineReturns, 100), 'f', 3)))); 300 lines.append(qPrintable(QString("CT,100,%1").arg(QString::number(getCMC(firstGenuineReturns, 100), 'f', 3))));
294 301
295 // Write FAR/TAR Bar Chart (BC) 302 // Write FAR/TAR Bar Chart (BC)
296 - lines.append(qPrintable(QString("BC,0.001,%1").arg(QString::number(getTAR(operatingPoints, 0.001), 'f', 3))));  
297 - lines.append(qPrintable(QString("BC,0.01,%1").arg(QString::number(result = getTAR(operatingPoints, 0.01), 'f', 3)))); 303 + lines.append(qPrintable(QString("BC,0.001,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.001).TAR, 'f', 3))));
  304 + lines.append(qPrintable(QString("BC,0.01,%1").arg(QString::number(result = getOperatingPoint(operatingPoints, 0.01).TAR, 'f', 3))));
298 305
299 // Attempt to read template size from enrolled gallery and write to output CSV 306 // Attempt to read template size from enrolled gallery and write to output CSV
300 size_t maxSize(0); 307 size_t maxSize(0);
301 if (target.endsWith(".gal")) { 308 if (target.endsWith(".gal")) {
302 foreach (const Template &t, TemplateList::fromGallery(target)) maxSize = max(maxSize, t.bytes()); 309 foreach (const Template &t, TemplateList::fromGallery(target)) maxSize = max(maxSize, t.bytes());
  310 + lines.append(QString("TS,,%1").arg(QString::number(maxSize)));
303 } 311 }
304 312
305 - lines.append(QString("TS,,%1").arg(QString::number(maxSize)));  
306 -  
307 // Write SD & KDE 313 // Write SD & KDE
308 - points = qMin(qMin(Max_Points, genuines.size()), impostors.size()); 314 + int points = qMin(qMin(Max_Points, genuines.size()), impostors.size());
309 QList<double> sampledGenuineScores; sampledGenuineScores.reserve(points); 315 QList<double> sampledGenuineScores; sampledGenuineScores.reserve(points);
310 QList<double> sampledImpostorScores; sampledImpostorScores.reserve(points); 316 QList<double> sampledImpostorScores; sampledImpostorScores.reserve(points);
311 317
@@ -332,10 +338,10 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv, const QSt @@ -332,10 +338,10 @@ float Evaluate(const Mat &amp;simmat, const Mat &amp;mask, const QString &amp;csv, const QSt
332 338
333 QtUtils::writeFile(csv, lines); 339 QtUtils::writeFile(csv, lines);
334 if (maxSize > 0) qDebug("Template Size: %i bytes", (int)maxSize); 340 if (maxSize > 0) qDebug("Template Size: %i bytes", (int)maxSize);
335 - qDebug("TAR @ FAR = 0.01: %.3f",getTAR(operatingPoints, 0.01));  
336 - qDebug("TAR @ FAR = 0.001: %.3f",getTAR(operatingPoints, 0.001));  
337 - qDebug("TAR @ FAR = 0.0001: %.3f",getTAR(operatingPoints, 0.0001));  
338 - qDebug("TAR @ FAR = 0.00001: %.3f",getTAR(operatingPoints, 0.00001)); 341 + qDebug("TAR @ FAR = 0.01: %.3f",getOperatingPoint(operatingPoints, 0.01).TAR);
  342 + qDebug("TAR @ FAR = 0.001: %.3f",getOperatingPoint(operatingPoints, 0.001).TAR);
  343 + qDebug("TAR @ FAR = 0.0001: %.3f",getOperatingPoint(operatingPoints, 0.0001).TAR);
  344 + qDebug("TAR @ FAR = 0.00001: %.3f",getOperatingPoint(operatingPoints, 0.00001).TAR);
339 345
340 qDebug("\nRetrieval Rate @ Rank = %d: %.3f", Report_Retrieval, getCMC(firstGenuineReturns, Report_Retrieval)); 346 qDebug("\nRetrieval Rate @ Rank = %d: %.3f", Report_Retrieval, getCMC(firstGenuineReturns, Report_Retrieval));
341 347
@@ -560,8 +566,8 @@ float InplaceEval(const QString &amp;simmat, const QString &amp;target, const QString &amp;q @@ -560,8 +566,8 @@ float InplaceEval(const QString &amp;simmat, const QString &amp;target, const QString &amp;q
560 566
561 float result; 567 float result;
562 // Write FAR/TAR Bar Chart (BC) 568 // Write FAR/TAR Bar Chart (BC)
563 - lines.append(qPrintable(QString("BC,0.001,%1").arg(QString::number(getTAR(operatingPoints, 0.001), 'f', 3))));  
564 - lines.append(qPrintable(QString("BC,0.01,%1").arg(QString::number(result = getTAR(operatingPoints, 0.01), 'f', 3)))); 569 + lines.append(qPrintable(QString("BC,0.001,%1").arg(QString::number(getOperatingPoint(operatingPoints, 0.001).TAR, 'f', 3))));
  570 + lines.append(qPrintable(QString("BC,0.01,%1").arg(QString::number(result = getOperatingPoint(operatingPoints, 0.01).TAR, 'f', 3))));
565 571
566 qDebug("TAR @ FAR = 0.01: %.3f", result); 572 qDebug("TAR @ FAR = 0.01: %.3f", result);
567 QtUtils::writeFile(csv, lines); 573 QtUtils::writeFile(csv, lines);
openbr/core/plot.cpp
@@ -108,7 +108,6 @@ struct RPlot @@ -108,7 +108,6 @@ struct RPlot
108 pivotItems = QVector< QSet<QString> >(pivotHeaders.size()); 108 pivotItems = QVector< QSet<QString> >(pivotHeaders.size());
109 foreach (const QString &fileName, files) { 109 foreach (const QString &fileName, files) {
110 QStringList pivots = getPivots(fileName, false); 110 QStringList pivots = getPivots(fileName, false);
111 -  
112 // If the number of pivots don't match, abandon the directory/filename labeling scheme 111 // If the number of pivots don't match, abandon the directory/filename labeling scheme
113 if (pivots.size() != pivotHeaders.size()) { 112 if (pivots.size() != pivotHeaders.size()) {
114 pivots.clear(); 113 pivots.clear();
@@ -132,7 +131,6 @@ struct RPlot @@ -132,7 +131,6 @@ struct RPlot
132 minor = Pivot(i, size, pivotHeaders[i]); 131 minor = Pivot(i, size, pivotHeaders[i]);
133 } 132 }
134 } 133 }
135 -  
136 const QString &smooth = destination.get<QString>("smooth", ""); 134 const QString &smooth = destination.get<QString>("smooth", "");
137 major.smooth = !smooth.isEmpty() && (major.header == smooth) && (major.size > 1); 135 major.smooth = !smooth.isEmpty() && (major.header == smooth) && (major.size > 1);
138 minor.smooth = !smooth.isEmpty() && (minor.header == smooth) && (minor.size > 1); 136 minor.smooth = !smooth.isEmpty() && (minor.header == smooth) && (minor.size > 1);
@@ -177,29 +175,42 @@ struct RPlot @@ -177,29 +175,42 @@ struct RPlot
177 "TS$Y <- as.character(TS$Y)\n" 175 "TS$Y <- as.character(TS$Y)\n"
178 "CMC$Y <- as.numeric(as.character(CMC$Y))\n" 176 "CMC$Y <- as.numeric(as.character(CMC$Y))\n"
179 "\n" 177 "\n"
  178 + "if (%1) {\n\tsummarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE, conf.interval=.95, .drop=TRUE) {\n\t\t"
  179 + "require(plyr)\n\n\t\tlength2 <- function (x, na.rm=FALSE) {\n\t\t\tif (na.rm) sum(!is.na(x))\n\t\t\telse length(x)"
  180 + "\n\t\t}\n\n\t\tdatac <- ddply(data, groupvars, .drop=.drop, .fun = function(xx, col) {\n\t\t\t"
  181 + "c(N=length2(xx[[col]], na.rm=na.rm), mean=mean(xx[[col]], na.rm=na.rm), sd=sd(xx[[col]], na.rm=na.rm))\n\t\t\t},"
  182 + "\n\t\t\tmeasurevar\n\t\t)\n\n\t\tdatac <- rename(datac, c(\"mean\" = measurevar))\n\t\tdatac$se <- datac$sd / sqrt(datac$N)"
  183 + "\n\t\tciMult <- qt(conf.interval/2 + .5, datac$N-1)\n\t\tdatac$ci <- datac$se * ciMult\n\n\t\treturn(datac)\n\t}\n\t"
  184 + "DET <- summarySE(DET, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n\t"
  185 + "ERR <- summarySE(ERR, measurevar=\"X\", groupvars=c(\"Error\", \"%2\", \"Y\"))\n\t"
  186 + "FT <- summarySE(FT, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n\t"
  187 + "CT <- summarySE(CT, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n}\n\n"
180 "# Code to format FAR values\n" 188 "# Code to format FAR values\n"
181 "far_names <- list('0.001'=\"FAR = 0.1%\", '0.01'=\"FAR = 1%\")\n" 189 "far_names <- list('0.001'=\"FAR = 0.1%\", '0.01'=\"FAR = 1%\")\n"
182 "far_labeller <- function(variable,value) { return(far_names[as.character(value)]) }\n" 190 "far_labeller <- function(variable,value) { return(far_names[as.character(value)]) }\n"
183 "\n" 191 "\n"
184 "# Code to format TAR@FAR table\n" 192 "# Code to format TAR@FAR table\n"
185 - "algs <- unique(FT$%1)\n" 193 + "algs <- unique(FT$%2)\n"
186 "algs <- algs[!duplicated(algs)]\n" 194 "algs <- algs[!duplicated(algs)]\n"
187 - "mat <- matrix(FT$Y,nrow=6,ncol=length(algs),byrow=FALSE)\n" 195 + "mat <- matrix(%3,nrow=6,ncol=length(algs),byrow=FALSE)\n"
188 "colnames(mat) <- algs \n" 196 "colnames(mat) <- algs \n"
189 "rownames(mat) <- c(\"FAR = 1e-06\", \"FAR = 1e-05\", \"FAR = 1e-04\", \"FAR = 1e-03\", \"FAR = 1e-02\", \"FAR = 1e-01\")\n" 197 "rownames(mat) <- c(\"FAR = 1e-06\", \"FAR = 1e-05\", \"FAR = 1e-04\", \"FAR = 1e-03\", \"FAR = 1e-02\", \"FAR = 1e-01\")\n"
190 "FTtable <- as.table(mat)\n" 198 "FTtable <- as.table(mat)\n"
191 "\n" 199 "\n"
192 "# Code to format CMC Table\n" 200 "# Code to format CMC Table\n"
193 - "mat <- matrix(CT$Y,nrow=6,ncol=length(algs),byrow=FALSE)\n" 201 + "mat <- matrix(%4,nrow=6,ncol=length(algs),byrow=FALSE)\n"
194 "colnames(mat) <- algs \n" 202 "colnames(mat) <- algs \n"
195 "rownames(mat) <- c(\" Rank 1\", \"Rank 5\", \"Rank 10\", \"Rank 20\", \"Rank 50\", \"Rank 100\")\n" 203 "rownames(mat) <- c(\" Rank 1\", \"Rank 5\", \"Rank 10\", \"Rank 20\", \"Rank 50\", \"Rank 100\")\n"
196 "CMCtable <- as.table(mat)\n" 204 "CMCtable <- as.table(mat)\n"
197 "\n" 205 "\n"
198 "# Code to format Template Size Table\n" 206 "# Code to format Template Size Table\n"
199 - "mat <- matrix(TS$Y,nrow=1,ncol=length(algs),byrow=FALSE)\n"  
200 - "colnames(mat) <- algs\n"  
201 - "rownames(mat) <- c(\"Template Size (bytes):\")\n"  
202 - "TStable <- as.table(mat)\n").arg(major.header))); 207 + "if (nrow(TS) != 0) {\n\t"
  208 + "mat <- matrix(TS$Y,nrow=1,ncol=length(algs),byrow=FALSE)\n\t"
  209 + "colnames(mat) <- algs\n\t"
  210 + "rownames(mat) <- c(\"Template Size (bytes):\")\n\t"
  211 + "TStable <- as.table(mat)\n}\n").arg(((major.smooth || minor.smooth) ? "TRUE" : "FALSE"), major.size > 1 ? major.header : (minor.header.isEmpty() ? major.header : minor.header),
  212 + (major.smooth || minor.smooth) ? "paste(as.character(round(FT$Y, 3)), round(FT$ci, 3), sep=\"\\u00b1\")" : "FT$Y",
  213 + (major.smooth || minor.smooth) ? "paste(as.character(round(CT$Y, 3)), round(CT$ci, 3), sep=\"\\u00b1\")" : "CT$Y")));
203 214
204 // Open output device 215 // Open output device
205 file.write(qPrintable(QString("\n" 216 file.write(qPrintable(QString("\n"
@@ -231,8 +242,9 @@ struct RPlot @@ -231,8 +242,9 @@ struct RPlot
231 "print(title(\"Table of True Accept Rates at various False Accept Rates\"))\n" 242 "print(title(\"Table of True Accept Rates at various False Accept Rates\"))\n"
232 "print(textplot(CMCtable))\n" 243 "print(textplot(CMCtable))\n"
233 "print(title(\"Table of retrieval rate at various ranks\"))\n" 244 "print(title(\"Table of retrieval rate at various ranks\"))\n"
234 - "print(textplot(TStable, cex=1.15))\n"  
235 - "print(title(\"Template Size by Algorithm\"))\n"; 245 + "if (nrow(TS) != 0) {\n\t"
  246 + "print(textplot(TStable, cex=1.15))\n\t"
  247 + "print(title(\"Template Size by Algorithm\"))\n}\n";
236 file.write(qPrintable(textplot.arg(PRODUCT_NAME, PRODUCT_VERSION))); 248 file.write(qPrintable(textplot.arg(PRODUCT_NAME, PRODUCT_VERSION)));
237 } 249 }
238 250
@@ -281,11 +293,12 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -281,11 +293,12 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
281 293
282 RPlot p(files, destination); 294 RPlot p(files, destination);
283 295
284 - p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET%1, main=\"%2\"").arg((p.major.smooth || p.minor.smooth) ? ", geom=\"smooth\", method=loess, level=0.99" : ", geom=\"line\"", rocOpts.get<QString>("title",QString())) + 296 + p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"line\", main=\"%1\"").arg(rocOpts.get<QString>("title",QString())) +
285 (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) + 297 (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
286 (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) + 298 (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
287 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") + 299 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") +
288 - (p.major.size > 1 ? getScale("colour", "Algorithm", p.major.size) : QString()) + 300 + ((p.major.smooth || p.minor.smooth) ? " + geom_errorbar(data=DET[seq(1, NROW(DET), by = 29),], aes(x=X, ymin=(1-Y)-ci, ymax=(1-Y)+ci), width=0.1, alpha=I(1/2))" : QString()) +
  301 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
289 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) + 302 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
290 QString(" + scale_x_log10(labels=trans_format(\"log10\", math_format()))") + 303 QString(" + scale_x_log10(labels=trans_format(\"log10\", math_format()))") +
291 (rocOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent) + coord_cartesian(ylim=%1)").arg("c"+QtUtils::toString(rocOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) + 304 (rocOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent) + coord_cartesian(ylim=%1)").arg("c"+QtUtils::toString(rocOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) +
@@ -293,12 +306,14 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -293,12 +306,14 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
293 QString(" + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1)," 306 QString(" + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1),"
294 " legend.position=%2, legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = \"gray\"), panel.grid.minor = element_line(colour = \"gray\", linetype = \"dashed\"), legend.text = element_text(size = %1))\n\n").arg(QString::number(rocOpts.get<float>("textSize",12)), rocOpts.contains("legendPosition") ? "c"+QtUtils::toString(rocOpts.get<QPointF>("legendPosition")) : "'bottom'"))); 307 " legend.position=%2, legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = \"gray\"), panel.grid.minor = element_line(colour = \"gray\", linetype = \"dashed\"), legend.text = element_text(size = %1))\n\n").arg(QString::number(rocOpts.get<float>("textSize",12)), rocOpts.contains("legendPosition") ? "c"+QtUtils::toString(rocOpts.get<QPointF>("legendPosition")) : "'bottom'")));
295 308
296 - p.file.write(qPrintable(QString("qplot(X, Y, data=DET%1").arg((p.major.smooth || p.minor.smooth) ? ", geom=\"smooth\", method=loess, level=0.99" : ", geom=\"line\"") + 309 + p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"line\"") +
297 (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) + 310 (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
298 (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) + 311 (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
299 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") + 312 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") +
300 - (p.major.size > 1 ? getScale("colour", "Algorithm", p.major.size) : QString()) + 313 + ((p.major.smooth || p.minor.smooth) ? " + geom_errorbar(data=DET[seq(1, NROW(DET), by = 29),], aes(x=X, ymin=Y-ci, ymax=Y+ci), width=0.1, alpha=I(1/2))" : QString()) +
  314 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
301 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) + 315 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
  316 + QString(" + theme(legend.position=%1)").arg(rocOpts.contains("legendPosition") ? "c"+QtUtils::toString(rocOpts.get<QPointF>("legendPosition")) : "'bottom'") +
302 QString(" + scale_x_log10(labels=trans_format(\"log10\", math_format())) + scale_y_log10(labels=trans_format(\"log10\", math_format())) + annotation_logticks()\n\n"))); 317 QString(" + scale_x_log10(labels=trans_format(\"log10\", math_format())) + scale_y_log10(labels=trans_format(\"log10\", math_format())) + annotation_logticks()\n\n")));
303 318
304 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") + 319 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") +
@@ -311,7 +326,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -311,7 +326,7 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
311 QString(((p.major.smooth || p.minor.smooth) ? (!uncertainty ? " + stat_summary(geom=\"line\", fun.y=mean, size=%1)" : " + stat_summary(geom=\"line\", fun.y=min, aes(linetype=\"Min/Max\"), size=%1) + stat_summary(geom=\"line\", " 326 QString(((p.major.smooth || p.minor.smooth) ? (!uncertainty ? " + stat_summary(geom=\"line\", fun.y=mean, size=%1)" : " + stat_summary(geom=\"line\", fun.y=min, aes(linetype=\"Min/Max\"), size=%1) + stat_summary(geom=\"line\", "
312 "fun.y=max, aes(linetype=\"Min/Max\"), size=%1) + stat_summary(geom=\"line\", fun.y=mean, aes(linetype=\"Mean\"), size=%1) + scale_linetype_manual(\"Legend\", values=c(\"Mean\"=1, \"Min/Max\"=2))") : " + geom_line(size=%1)")).arg(QString::number(cmcOpts.get<float>("thickness",1))) + 327 "fun.y=max, aes(linetype=\"Min/Max\"), size=%1) + stat_summary(geom=\"line\", fun.y=mean, aes(linetype=\"Mean\"), size=%1) + scale_linetype_manual(\"Legend\", values=c(\"Mean\"=1, \"Min/Max\"=2))") : " + geom_line(size=%1)")).arg(QString::number(cmcOpts.get<float>("thickness",1))) +
313 (minimalist ? "" : " + scale_x_log10(labels=c(1,5,10,50,100), breaks=c(1,5,10,50,100)) + annotation_logticks(sides=\"b\")") + 328 (minimalist ? "" : " + scale_x_log10(labels=c(1,5,10,50,100), breaks=c(1,5,10,50,100)) + annotation_logticks(sides=\"b\")") +
314 - (p.major.size > 1 ? getScale("colour", "Algorithm", p.major.size) : QString()) + 329 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
315 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) + 330 (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
316 (cmcOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent) + coord_cartesian(ylim=%1)").arg("c"+QtUtils::toString(cmcOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) + 331 (cmcOpts.contains("yLimits") ? QString(" + scale_y_continuous(labels=percent) + coord_cartesian(ylim=%1)").arg("c"+QtUtils::toString(cmcOpts.get<QPointF>("yLimits",QPointF()))) : QString(" + scale_y_continuous(labels=percent)")) +
317 QString(" + theme_minimal() + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1)," 332 QString(" + theme_minimal() + theme(legend.title = element_text(size = %1), plot.title = element_text(size = %1), axis.text = element_text(size = %1), axis.title.x = element_text(size = %1), axis.title.y = element_text(size = %1),"
@@ -320,14 +335,14 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show) @@ -320,14 +335,14 @@ bool Plot(const QStringList &amp;files, const File &amp;destination, bool show)
320 p.file.write(qPrintable(QString("qplot(factor(%1)%2, data=BC, %3").arg(p.major.smooth ? (p.minor.header.isEmpty() ? "Algorithm" : p.minor.header) : p.major.header, (p.major.smooth || p.minor.smooth) ? ", Y" : "", (p.major.smooth || p.minor.smooth) ? "geom=\"boxplot\"" : "geom=\"bar\", position=\"dodge\", weight=Y") + 335 p.file.write(qPrintable(QString("qplot(factor(%1)%2, data=BC, %3").arg(p.major.smooth ? (p.minor.header.isEmpty() ? "Algorithm" : p.minor.header) : p.major.header, (p.major.smooth || p.minor.smooth) ? ", Y" : "", (p.major.smooth || p.minor.smooth) ? "geom=\"boxplot\"" : "geom=\"bar\", position=\"dodge\", weight=Y") +
321 (p.major.size > 1 ? QString(", fill=factor(%1)").arg(p.major.header) : QString()) + 336 (p.major.size > 1 ? QString(", fill=factor(%1)").arg(p.major.header) : QString()) +
322 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") + 337 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") +
323 - (p.major.size > 1 ? getScale("fill", "Algorithm", p.major.size) : QString()) + 338 + (p.major.size > 1 ? getScale("fill", p.major.header, p.major.size) : QString()) +
324 (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minor.header) : QString(" + facet_grid(. ~ X, labeller=far_labeller)")) + 339 (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minor.header) : QString(" + facet_grid(. ~ X, labeller=far_labeller)")) +
325 QString(" + scale_y_continuous(labels=percent) + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0))%1").arg((p.major.smooth || p.minor.smooth) ? "" : " + geom_text(data=BC, aes(label=Y, y=0.05))") + "\n\n")); 340 QString(" + scale_y_continuous(labels=percent) + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0))%1").arg((p.major.smooth || p.minor.smooth) ? "" : " + geom_text(data=BC, aes(label=Y, y=0.05))") + "\n\n"));
326 341
327 - p.file.write(qPrintable(QString("qplot(X, Y, data=ERR%1, linetype=Error").arg((p.major.smooth || p.minor.smooth) ? ", geom=\"smooth\", method=loess, level=0.99" : ", geom=\"line\"") + 342 + p.file.write(qPrintable(QString("qplot(X, Y, data=ERR, geom=\"line\", linetype=Error") +
328 ((p.flip ? p.major.size : p.minor.size) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.major.header : p.minor.header) : QString()) + 343 ((p.flip ? p.major.size : p.minor.size) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.major.header : p.minor.header) : QString()) +
329 QString(", xlab=\"Score\", ylab=\"Error Rate\") + theme_minimal()") + 344 QString(", xlab=\"Score\", ylab=\"Error Rate\") + theme_minimal()") +
330 - ((p.flip ? p.major.size : p.minor.size) > 1 ? getScale("colour", p.flip ? "Algorithm" : "Algorithm", p.flip ? p.major.size : p.minor.size) : QString()) + 345 + ((p.flip ? p.major.size : p.minor.size) > 1 ? getScale("colour", p.flip ? p.major.header : p.minor.header, p.flip ? p.major.size : p.minor.size) : QString()) +
331 QString(" + scale_y_log10(labels=percent) + annotation_logticks(sides=\"l\")") + 346 QString(" + scale_y_log10(labels=percent) + annotation_logticks(sides=\"l\")") +
332 ((p.flip ? p.minor.size : p.major.size) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minor.header : p.major.header) : QString()) + 347 ((p.flip ? p.minor.size : p.major.size) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minor.header : p.major.header) : QString()) +
333 QString(" + theme(aspect.ratio=1)\n\n"))); 348 QString(" + theme(aspect.ratio=1)\n\n")));