Commit 032d4ca3343451b3153b6b119fbc88a3b13269f1
Merge pull request #401 from biometrics/plotting
Move bulk of R code from plot.cpp to plot_utils.R
Showing
3 changed files
with
464 additions
and
353 deletions
docs/docs/api_docs/c_api/functions.md
| ... | ... | @@ -635,8 +635,8 @@ textSize | float | Size of text for title, legend and axes |
| 635 | 635 | xTitle/yTitle | [QString] | Title for x/y axis |
| 636 | 636 | xLog/yLog | bool | Plot log scale for x/y axis |
| 637 | 637 | xLimits/yLimits | [QPointF] | Set x/y axis limits, ex. xLimits=(lower,upper) |
| 638 | -xLabels/yLabels | [QString] | Labels for ticks on x/y axis, ex. xLabeles=percent or xLabels=c(1,5,10) | |
| 639 | -xBreaks/yBreaks | [QString] | Specify breaks/ticks on x/y axis, ex. xBreaks=pretty_breaks(n=10) or xBreaks=c(1,5,10) | |
| 638 | +xLabels/yLabels | [QString] | Labels for ticks on x/y axis, ex. xLabeles=percent or xLabels=(1,5,10) | |
| 639 | +xBreaks/yBreaks | [QString] | Specify breaks/ticks on x/y axis, ex. xBreaks=pretty_breaks(n=10) or xBreaks=(1,5,10) | |
| 640 | 640 | |
| 641 | 641 | If specifying plot options it is a good idea to wrap the destination file in single quotes to avoid parsing errors. |
| 642 | 642 | The example below plots plots the six br_eval results in the Algorithm_Dataset folder described above, sets the number of legend columns and specifies some options for the CMC plot. | ... | ... |
openbr/core/plot.cpp
| ... | ... | @@ -23,6 +23,25 @@ using namespace cv; |
| 23 | 23 | namespace br |
| 24 | 24 | { |
| 25 | 25 | |
| 26 | +// Flattens file metadata to an R list() | |
| 27 | +static QString toRList(const File &opts) | |
| 28 | +{ | |
| 29 | + QStringList retValues; | |
| 30 | + QString format = "%1=%2"; | |
| 31 | + foreach (const QString &key, opts.localKeys()) { | |
| 32 | + const QString value = QtUtils::toString(opts.value(key)); | |
| 33 | + if (value.startsWith("(")) | |
| 34 | + retValues.append(format.arg(key, "\"c" + value + "\"")); | |
| 35 | + else if (value == "true") | |
| 36 | + retValues.append(format.arg(key, "TRUE")); | |
| 37 | + else if (value == "false") | |
| 38 | + retValues.append(format.arg(key, "FALSE")); | |
| 39 | + else | |
| 40 | + retValues.append(format.arg(key, "\"" + value + "\"")); | |
| 41 | + } | |
| 42 | + return retValues.join(","); | |
| 43 | +} | |
| 44 | + | |
| 26 | 45 | static QStringList getPivots(const QString &file, bool headers) |
| 27 | 46 | { |
| 28 | 47 | QString str; |
| ... | ... | @@ -31,14 +50,6 @@ static QStringList getPivots(const QString &file, bool headers) |
| 31 | 50 | return str.split("_"); |
| 32 | 51 | } |
| 33 | 52 | |
| 34 | -static QString getScale(const QString &mode, const QString &title, int vals) | |
| 35 | -{ | |
| 36 | - if (vals > 12) return " + scale_"+mode+"_discrete(\""+title+"\")"; | |
| 37 | - else if (vals > 11) return " + scale_"+mode+"_brewer(\""+title+"\", palette=\"Set3\")"; | |
| 38 | - else if (vals > 9) return " + scale_"+mode+"_brewer(\""+title+"\", palette=\"Paired\")"; | |
| 39 | - else return " + scale_"+mode+"_brewer(\""+title+"\", palette=\"Set1\")"; | |
| 40 | -} | |
| 41 | - | |
| 42 | 53 | // Custom sorting method to ensure datasets are ordered nicely |
| 43 | 54 | static bool sortFiles(const QString &fileA, const QString &fileB) |
| 44 | 55 | { |
| ... | ... | @@ -51,10 +62,6 @@ struct RPlot |
| 51 | 62 | QFile file; |
| 52 | 63 | QStringList pivotHeaders; |
| 53 | 64 | QVector< QSet<QString> > pivotItems; |
| 54 | - float confidence; // confidence interval for plotting across splits | |
| 55 | - int ncol; // Number of columns for plot legends | |
| 56 | - | |
| 57 | - bool flip; | |
| 58 | 65 | |
| 59 | 66 | struct Pivot |
| 60 | 67 | { |
| ... | ... | @@ -68,7 +75,7 @@ struct RPlot |
| 68 | 75 | |
| 69 | 76 | Pivot major, minor; |
| 70 | 77 | |
| 71 | - RPlot(QStringList files, const File &destination, bool isEvalFormat = true) | |
| 78 | + RPlot(QStringList files, const File &destination) | |
| 72 | 79 | { |
| 73 | 80 | if (files.isEmpty()) qFatal("Empty file list."); |
| 74 | 81 | qSort(files.begin(), files.end(), sortFiles); |
| ... | ... | @@ -83,13 +90,9 @@ struct RPlot |
| 83 | 90 | bool success = file.open(QFile::WriteOnly); |
| 84 | 91 | if (!success) qFatal("Failed to open %s for writing.", qPrintable(file.fileName())); |
| 85 | 92 | |
| 86 | - file.write("# Load libraries\n" | |
| 87 | - "library(ggplot2)\n" | |
| 88 | - "library(gplots)\n" | |
| 89 | - "library(reshape)\n" | |
| 90 | - "library(scales)\n" | |
| 91 | - "\n" | |
| 92 | - "# Read CSVs\n" | |
| 93 | + // Copy plot_utils.R into output script with source() | |
| 94 | + file.write(qPrintable(QString("source(\"%1\")\n\n").arg(Globals->sdkPath + "/share/openbr/plotting/plot_utils.R"))); | |
| 95 | + file.write("# Read CSVs\n" | |
| 93 | 96 | "data <- NULL\n"); |
| 94 | 97 | |
| 95 | 98 | // Read files and retrieve pivots |
| ... | ... | @@ -123,8 +126,6 @@ struct RPlot |
| 123 | 126 | } |
| 124 | 127 | |
| 125 | 128 | const QString &smooth = destination.get<QString>("smooth", ""); |
| 126 | - confidence = destination.get<float>("confidence", 95) / 100.0; | |
| 127 | - | |
| 128 | 129 | major.smooth = !smooth.isEmpty() && (major.header == smooth) && (major.size > 1); |
| 129 | 130 | minor.smooth = !smooth.isEmpty() && (minor.header == smooth) && (minor.size > 1); |
| 130 | 131 | if (major.smooth) major.size = 1; |
| ... | ... | @@ -132,68 +133,19 @@ struct RPlot |
| 132 | 133 | if (major.size < minor.size) |
| 133 | 134 | std::swap(major, minor); |
| 134 | 135 | |
| 135 | - ncol = destination.get<int>("ncol", major.size > 1 ? major.size : (minor.header.isEmpty() ? major.size : minor.size)); | |
| 136 | - flip = minor.header == "Algorithm"; | |
| 137 | - // Format data | |
| 138 | - if (isEvalFormat) | |
| 139 | - file.write(qPrintable(QString("\n" | |
| 140 | - "# Split data into individual plots\n" | |
| 141 | - "plot_index = which(names(data)==\"Plot\")\n" | |
| 142 | - "Metadata <- data[grep(\"Metadata\",data$Plot),-c(1)]\n" | |
| 143 | - "IM <- data[grep(\"IM\",data$Plot),-c(1)]\n" | |
| 144 | - "GM <- data[grep(\"GM\",data$Plot),-c(1)]\n" | |
| 145 | - "DET <- data[grep(\"DET\",data$Plot),-c(1)]\n" | |
| 146 | - "IET <- data[grep(\"IET\",data$Plot),-c(1)]\n" | |
| 147 | - "FAR <- data[grep(\"FAR\",data$Plot),-c(1)]\n" | |
| 148 | - "FRR <- data[grep(\"FRR\",data$Plot),-c(1)]\n" | |
| 149 | - "SD <- data[grep(\"SD\",data$Plot),-c(1)]\n" | |
| 150 | - "TF <- data[grep(\"TF\",data$Plot),-c(1)]\n" | |
| 151 | - "FT <- data[grep(\"FT\",data$Plot),-c(1)]\n" | |
| 152 | - "CT <- data[grep(\"CT\",data$Plot),-c(1)]\n" | |
| 153 | - "BC <- data[grep(\"BC\",data$Plot),-c(1)]\n" | |
| 154 | - "TS <- data[grep(\"TS\",data$Plot),-c(1)]\n" | |
| 155 | - "CMC <- data[grep(\"CMC\",data$Plot),-c(1)]\n" | |
| 156 | - "FAR$Error <- \"FAR\"\n" | |
| 157 | - "FRR$Error <- \"FRR\"\n" | |
| 158 | - "ERR <- rbind(FAR, FRR)\n" | |
| 159 | - "rm(data, FAR, FRR)\n" | |
| 160 | - "\n" | |
| 161 | - "# Format data\n" | |
| 162 | - "Metadata$Y<-factor(Metadata$Y, levels=c(\"Genuine\",\"Impostor\",\"Ignored\",\"Gallery\",\"Probe\"))\n" | |
| 163 | - "IM$Y <- as.character(IM$Y)\n" | |
| 164 | - "GM$Y <- as.character(GM$Y)\n" | |
| 165 | - "DET$Y <- as.numeric(as.character(DET$Y))\n" | |
| 166 | - "IET$Y <- as.numeric(as.character(IET$Y))\n" | |
| 167 | - "ERR$Y <- as.numeric(as.character(ERR$Y))\n" | |
| 168 | - "SD$Y <- as.factor(unique(as.character(SD$Y)))\n" | |
| 169 | - "TF$Y <- as.numeric(as.character(TF$Y))\n" | |
| 170 | - "FT$Y <- as.numeric(as.character(FT$Y))\n" | |
| 171 | - "CT$Y <- as.numeric(as.character(CT$Y))\n" | |
| 172 | - "BC$Y <- as.numeric(as.character(BC$Y))\n" | |
| 173 | - "TS$Y <- as.character(TS$Y)\n" | |
| 174 | - "CMC$Y <- as.numeric(as.character(CMC$Y))\n" | |
| 175 | - "\n" | |
| 176 | - "if (%1) {\n\tsummarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE, conf.interval=%3, .drop=TRUE) {\n\t\t" | |
| 177 | - "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)" | |
| 178 | - "\n\t\t}\n\n\t\tdatac <- ddply(data, groupvars, .drop=.drop, .fun = function(xx, col) {\n\t\t\t" | |
| 179 | - "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}," | |
| 180 | - "\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)" | |
| 181 | - "\n\t\tciMult <- qt(conf.interval/2 + .5, datac$N-1)\n\t\tdatac$ci <- datac$se * ciMult\n\n\t\t" | |
| 182 | - "datac$upper <- if(datac[, measurevar] + datac$ci < 1) (datac[, measurevar] + datac$ci) else 1\n\t\t" | |
| 183 | - "datac$lower <- if(datac[, measurevar] - datac$ci > 0) (datac[, measurevar] - datac$ci) else 0\n\n\t\treturn(datac)\n\t}\n\t" | |
| 184 | - "DET <- summarySE(DET, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n\t" | |
| 185 | - "IET <- summarySE(IET, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n\t" | |
| 186 | - "CMC <- summarySE(CMC, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n\t" | |
| 187 | - "ERR <- summarySE(ERR, measurevar=\"X\", groupvars=c(\"Error\", \"%2\", \"Y\"))\n\t" | |
| 188 | - "TF <- summarySE(TF, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n\t" | |
| 189 | - "FT <- summarySE(FT, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n\t" | |
| 190 | - "CT <- summarySE(CT, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"))\n}\n\n" | |
| 191 | - "# Code to format FAR values\n" | |
| 192 | - "far_names <- list('0.001'=\"FAR = 0.1%\", '0.01'=\"FAR = 1%\")\n" | |
| 193 | - "far_labeller <- function(variable,value) { return(far_names[as.character(value)]) }\n" | |
| 194 | - "\n").arg((major.smooth || minor.smooth) ? "TRUE" : "FALSE", | |
| 195 | - major.size > 1 ? major.header : (minor.header.isEmpty() ? major.header : minor.header), | |
| 196 | - QString::number(confidence)))); | |
| 136 | + // Set variables in R | |
| 137 | + file.write(qPrintable(QString("\nconfidence <- %1\n").arg(destination.get<float>("confidence", 95) / 100.0))); | |
| 138 | + file.write(qPrintable(QString("ncol <- %1\n").arg(destination.get<int>("ncol", major.size > 1 ? major.size : (minor.header.isEmpty() ? major.size : minor.size))))); | |
| 139 | + file.write(qPrintable(QString("basename <- \"%1\"\n").arg(basename))); | |
| 140 | + file.write(qPrintable(QString("smooth <- %1\n").arg((major.smooth || minor.smooth) && (destination.get<float>("confidence", 95) / 100.0) != 0 ? "TRUE" : "FALSE"))); | |
| 141 | + file.write(qPrintable(QString("csv <- %1\n").arg(destination.getBool("csv") ? "TRUE" : "FALSE"))); | |
| 142 | + file.write(qPrintable(QString("majorHeader <- \"%1\"\n").arg(major.header))); | |
| 143 | + file.write(qPrintable(QString("majorSize <- %1\n").arg(major.size))); | |
| 144 | + file.write(qPrintable(QString("majorSmooth <- %1\n").arg(major.smooth ? "TRUE" : "FALSE"))); | |
| 145 | + file.write(qPrintable(QString("minorHeader <- \"%1\"\n").arg(minor.header))); | |
| 146 | + file.write(qPrintable(QString("minorSize <- %1\n").arg(minor.size))); | |
| 147 | + file.write(qPrintable(QString("minorSmooth <- %1\n").arg(minor.smooth ? "TRUE" : "FALSE"))); | |
| 148 | + file.write(qPrintable(QString("flip <- %1\n").arg(minor.header == "Algorithm" ? "TRUE" : "FALSE"))); | |
| 197 | 149 | |
| 198 | 150 | // Open output device |
| 199 | 151 | file.write(qPrintable(QString("\n" |
| ... | ... | @@ -205,98 +157,6 @@ struct RPlot |
| 205 | 157 | "# Write figures\n"); |
| 206 | 158 | } |
| 207 | 159 | |
| 208 | - void plotMetadata(bool csv) | |
| 209 | - { | |
| 210 | - file.write(qPrintable(QString("# Code to format TAR@FAR table\n" | |
| 211 | - "algs <- unique(%4)\n" | |
| 212 | - "algs <- algs[!duplicated(algs)]\n" | |
| 213 | - "mat <- matrix(%1,nrow=6,ncol=length(algs),byrow=FALSE)\n" | |
| 214 | - "colnames(mat) <- algs \n" | |
| 215 | - "rownames(mat) <- c(\"FAR = 1e-06\", \"FAR = 1e-05\", \"FAR = 1e-04\", \"FAR = 1e-03\", \"FAR = 1e-02\", \"FAR = 1e-01\")\n" | |
| 216 | - "TFtable <- as.table(mat)\n" | |
| 217 | - "\n" | |
| 218 | - "# Code to format FAR@TAR table\n" | |
| 219 | - "mat <- matrix(%2,nrow=6,ncol=length(algs),byrow=FALSE)\n" | |
| 220 | - "colnames(mat) <- algs \n" | |
| 221 | - "rownames(mat) <- c(\"TAR = 0.40\", \"TAR = 0.50\", \"TAR = 0.65\", \"TAR = 0.75\", \"TAR = 0.85\", \"TAR = 0.95\")\n" | |
| 222 | - "FTtable <- as.table(mat)\n" | |
| 223 | - "\n" | |
| 224 | - "# Code to format CMC Table\n" | |
| 225 | - "mat <- matrix(%3,nrow=6,ncol=length(algs),byrow=FALSE)\n" | |
| 226 | - "colnames(mat) <- algs \n" | |
| 227 | - "rownames(mat) <- c(\"Rank 1\", \"Rank 5\", \"Rank 10\", \"Rank 20\", \"Rank 50\", \"Rank 100\")\n" | |
| 228 | - "CMCtable <- as.table(mat)\n" | |
| 229 | - "\n" | |
| 230 | - "# Code to format Template Size Table\n" | |
| 231 | - "if (nrow(TS) != 0) {\n\t" | |
| 232 | - "mat <- matrix(TS$Y,nrow=1,ncol=length(algs),byrow=FALSE)\n\t" | |
| 233 | - "colnames(mat) <- algs\n\t" | |
| 234 | - "rownames(mat) <- c(\"Template Size (bytes):\")\n\t" | |
| 235 | - "TStable <- as.table(mat)\n}" | |
| 236 | - "\n").arg((major.smooth || minor.smooth) && confidence != 0 ? "paste(as.character(round(TF$Y, 3)), round(TF$ci, 3), sep=\"\\u00b1\")" : "TF$Y", | |
| 237 | - (major.smooth || minor.smooth) && confidence != 0 ? "paste(as.character(round(FT$Y, 3)), round(FT$ci, 3), sep=\"\\u00b1\")" : "FT$Y", | |
| 238 | - (major.smooth || minor.smooth) && confidence != 0 ? "paste(as.character(round(CT$Y, 3)), round(CT$ci, 3), sep=\"\\u00b1\")" : "CT$Y", | |
| 239 | - (major.size > 1 && minor.size > 1) && !(major.smooth || minor.smooth) ? QString("paste(TF$%1, TF$%2, sep=\"_\")").arg(major.header, minor.header) | |
| 240 | - : QString("TF$%1").arg(major.size > 1 ? major.header : (minor.header.isEmpty() ? major.header : minor.header))))); | |
| 241 | - | |
| 242 | - file.write("\n# Write metadata table\n"); | |
| 243 | - QString textplot = "MT <- as.data.frame(Metadata[c(1,2,3,4,5),])\n" | |
| 244 | - "par(mfrow=c(4,1))\n" | |
| 245 | - "plot.new()\n" | |
| 246 | - "print(title(paste(\"%1 - %2\",date(),sep=\"\\n\")))\n" | |
| 247 | - "mat <- matrix(MT$X[c(1,2)],ncol=2)\n" | |
| 248 | - "colnames(mat) <- c(\"Gallery\", \"Probe\")\n" | |
| 249 | - "imageTable <- as.table(mat)\n" | |
| 250 | - "print(textplot(imageTable,show.rownames=FALSE))\n" | |
| 251 | - "print(title(\"Images\"))\n" | |
| 252 | - "mat <- matrix(MT$X[c(3,4,5)],ncol=3)\n" | |
| 253 | - "colnames(mat) <- c(\"Genuine\", \"Impostor\", \"Ignored\")\n" | |
| 254 | - "matchTable <- as.table(mat)\n" | |
| 255 | - "print(textplot(matchTable,show.rownames=FALSE))\n" | |
| 256 | - "print(title(\"Matches\"))\n" | |
| 257 | - "plot.new()\n" | |
| 258 | - "print(title(\"Gallery * Probe = Genuine + Impostor + Ignored\"))\n"; | |
| 259 | - file.write(qPrintable(textplot.arg(PRODUCT_NAME, PRODUCT_VERSION))); | |
| 260 | - | |
| 261 | - if (csv) | |
| 262 | - textplot = QString("write.csv(TFtable,file=\"%1_TF.csv\")\n" | |
| 263 | - "write.csv(FTtable,file=\"%1_FT.csv\")\n" | |
| 264 | - "write.csv(CMCtable,file=\"%1_CMC.csv\")\n\n").arg(basename); | |
| 265 | - else | |
| 266 | - textplot = "plot.new()\n" | |
| 267 | - "print(textplot(TFtable))\n" | |
| 268 | - "print(title(\"Table of True Accept Rates at various False Accept Rates\"))\n" | |
| 269 | - "print(textplot(FTtable))\n" | |
| 270 | - "print(title(\"Table of False Accept Rates at various True Accept Rates\"))\n" | |
| 271 | - "print(textplot(CMCtable))\n" | |
| 272 | - "print(title(\"Table of retrieval rate at various ranks\"))\n" | |
| 273 | - "if (nrow(TS) != 0) {\n\t" | |
| 274 | - "print(textplot(TStable, cex=1.15))\n\t" | |
| 275 | - "print(title(\"Template Size by Algorithm\"))\n}\n\n"; | |
| 276 | - file.write(qPrintable(textplot)); | |
| 277 | - } | |
| 278 | - | |
| 279 | - void qplot(QString geom, QString data, bool flipY, File opts) | |
| 280 | - { | |
| 281 | - file.write(qPrintable(QString("qplot(X, %1, data=%2, geom=\"%3\", main=\"%4\"").arg(flipY ? "1-Y" : "Y", data, geom, opts.get<QString>("title", "")) + | |
| 282 | - (opts.contains("size") ? QString(", size=I(%1)").arg(opts.get<QString>("size")) : QString()) + | |
| 283 | - (major.size > 1 ? QString(", colour=factor(%1)").arg(major.header) : QString()) + | |
| 284 | - (minor.size > 1 ? QString(", linetype=factor(%1)").arg(minor.header) : QString()) + | |
| 285 | - (QString(", xlab=\"%1\", ylab=\"%2\") + theme_minimal()").arg(opts.get<QString>("xTitle"), opts.get<QString>("yTitle"))) + | |
| 286 | - ((major.smooth || minor.smooth) && confidence != 0 && data != "CMC" ? QString(" + geom_errorbar(data=%1[seq(1, NROW(%1), by = 29),], aes(x=X, ymin=%2), width=0.1, alpha=I(1/2))").arg(data, flipY ? "(1-lower), ymax=(1-upper)" : "lower, ymax=upper") : QString()) + | |
| 287 | - (major.size > 1 ? getScale("colour", major.header, major.size) : QString()) + | |
| 288 | - (minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(minor.header) : QString()) + | |
| 289 | - (opts.getBool("xLog") ? QString(" + scale_x_log10(labels=%1, breaks=%2) + annotation_logticks(sides=\"b\")").arg(opts.get<QString>("xLabels", "trans_format(\"log10\", math_format())"), opts.get<QString>("xBreaks", "waiver()")) | |
| 290 | - : QString(" + scale_x_continuous(labels=%1, breaks=%2)").arg(opts.get<QString>("xLabels", "percent"), opts.get<QString>("xBreaks", "pretty_breaks(n=10)"))) + | |
| 291 | - (opts.getBool("yLog") ? QString(" + scale_y_log10(labels=%1, breaks=%2) + annotation_logticks(sides=\"l\")").arg(opts.get<QString>("yLabels", "trans_format(\"log10\", math_format())"), opts.get<QString>("yBreaks", "waiver()")) | |
| 292 | - : QString(" + scale_y_continuous(labels=%1, breaks=%2)").arg(opts.get<QString>("yLabels", "percent"), opts.get<QString>("yBreaks", "pretty_breaks(n=10)"))) + | |
| 293 | - (opts.contains("xLimits") ? QString(" + xlim%1").arg(QtUtils::toString(opts.get<QPointF>("xLimits", QPointF()))) : QString()) + | |
| 294 | - (opts.contains("yLimits") ? QString(" + ylim%1").arg(QtUtils::toString(opts.get<QPointF>("yLimits", QPointF()))) : QString()) + | |
| 295 | - QString(" + theme(legend.title = element_text(size = %1), legend.text = 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),").arg(QString::number(opts.get<float>("textSize",12))) + | |
| 296 | - QString(" legend.position=%1, legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = \"gray\"), panel.grid.minor = element_line(colour = \"gray\", linetype = \"dashed\"))").arg(opts.contains("legendPosition") ? "c"+QtUtils::toString(opts.get<QPointF>("legendPosition")) : "'bottom'") + | |
| 297 | - QString(" + guides(col=guide_legend(ncol=%1))\n\n").arg(ncol))); | |
| 298 | - } | |
| 299 | - | |
| 300 | 160 | bool finalize(bool show = false) |
| 301 | 161 | { |
| 302 | 162 | file.write("dev.off()\n"); |
| ... | ... | @@ -315,13 +175,27 @@ bool Plot(const QStringList &files, const File &destination, bool show) |
| 315 | 175 | qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination)); |
| 316 | 176 | |
| 317 | 177 | RPlot p(files, destination); |
| 178 | + p.file.write("\nformatData()\n\n"); | |
| 179 | + p.file.write(qPrintable(QString("algs <- %1\n").arg((p.major.size > 1 && p.minor.size > 1) && !(p.major.smooth || p.minor.smooth) ? QString("paste(TF$%1, TF$%2, sep=\"_\")").arg(p.major.header, p.minor.header) | |
| 180 | + : QString("TF$%1").arg(p.major.size > 1 ? p.major.header : (p.minor.header.isEmpty() ? p.major.header : p.minor.header))))); | |
| 181 | + p.file.write("algs <- algs[!duplicated(algs)]\n"); | |
| 182 | + | |
| 183 | + if (p.major.smooth || p.minor.smooth) { | |
| 184 | + QString groupvar = p.major.size > 1 ? p.major.header : (p.minor.header.isEmpty() ? p.major.header : p.minor.header); | |
| 185 | + foreach(const QString &data, QStringList() << "DET" << "IET" << "CMC" << "TF" << "FT" << "CT") { | |
| 186 | + p.file.write(qPrintable(QString("%1 <- summarySE(%1, measurevar=\"Y\", groupvars=c(\"%2\", \"X\"), conf.interval=confidence)" | |
| 187 | + "\n").arg(data, groupvar))); | |
| 188 | + } | |
| 189 | + p.file.write(qPrintable(QString("%1 <- summarySE(%1, measurevar=\"X\", groupvars=c(\"Error\", \"%2\", \"Y\"), conf.interval=confidence)" | |
| 190 | + "\n\n").arg("ERR", groupvar))); | |
| 191 | + } | |
| 318 | 192 | |
| 319 | 193 | // Use a br::file for simple storage of plot options |
| 320 | 194 | QMap<QString,File> optMap; |
| 321 | 195 | optMap.insert("rocOptions", File(QString("[xTitle=False Accept Rate,yTitle=True Accept Rate,xLog=true,yLog=false]"))); |
| 322 | 196 | optMap.insert("detOptions", File(QString("[xTitle=False Accept Rate,yTitle=False Reject Rate,xLog=true,yLog=true]"))); |
| 323 | 197 | optMap.insert("ietOptions", File(QString("[xTitle=False Positive Identification Rate (FPIR),yTitle=False Negative Identification Rate (FNIR),xLog=true,yLog=true]"))); |
| 324 | - optMap.insert("cmcOptions", File(QString("[xTitle=Rank,yTitle=Retrieval Rate,xLog=true,yLog=false,size=1,xLabels=c(1,5,10,50,100),xBreaks=c(1,5,10,50,100)]"))); | |
| 198 | + optMap.insert("cmcOptions", File(QString("[xTitle=Rank,yTitle=Retrieval Rate,xLog=true,yLog=false,size=1,xLabels=(1,5,10,50,100),xBreaks=(1,5,10,50,100)]"))); | |
| 325 | 199 | |
| 326 | 200 | foreach (const QString &key, optMap.keys()) { |
| 327 | 201 | const QStringList options = destination.get<QStringList>(key, QStringList()); |
| ... | ... | @@ -333,56 +207,33 @@ bool Plot(const QStringList &files, const File &destination, bool show) |
| 333 | 207 | } |
| 334 | 208 | |
| 335 | 209 | // optional plot metadata and accuracy tables |
| 336 | - if (destination.getBool("metadata", true)) | |
| 337 | - p.plotMetadata(destination.getBool("csv", false)); | |
| 338 | - p.qplot("line", "DET", true, optMap["rocOptions"]); | |
| 339 | - p.qplot("line", "DET", false, optMap["detOptions"]); | |
| 340 | - p.qplot("line", "IET", false, optMap["ietOptions"]); | |
| 341 | - p.qplot("line", "CMC", false, optMap["cmcOptions"]); | |
| 342 | - | |
| 343 | - p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") + | |
| 344 | - QString(", xlab=\"Score\", ylab=\"Frequency\"") + | |
| 345 | - QString(") + scale_fill_manual(\"Ground Truth\", values=c(\"blue\", \"red\")) + theme_minimal() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + theme(axis.text.y=element_blank(), axis.ticks=element_blank(), axis.text.x=element_text(angle=-90, hjust=0))") + | |
| 346 | - (p.major.size > 1 ? (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ %1, scales=\"free\")").arg((p.flip ? p.major.header : p.minor.header), (p.flip ? p.minor.header : p.major.header)) : QString(" + facet_wrap(~ %1, scales = \"free\")").arg(p.major.header)) : QString()) + | |
| 347 | - QString(" + theme(aspect.ratio=1)\n\n"))); | |
| 348 | - | |
| 349 | - 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") + | |
| 350 | - (p.major.size > 1 ? QString(", fill=factor(%1)").arg(p.major.header) : QString()) + | |
| 351 | - QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") + | |
| 352 | - (p.major.size > 1 ? getScale("fill", p.major.header, p.major.size) : QString()) + | |
| 353 | - (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minor.header) : QString(" + facet_grid(. ~ X, labeller=far_labeller)")) + | |
| 354 | - 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")); | |
| 355 | - | |
| 356 | - p.file.write(qPrintable(QString("qplot(X, Y, data=ERR, geom=\"line\", linetype=Error") + | |
| 357 | - ((p.flip ? p.major.size : p.minor.size) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.major.header : p.minor.header) : QString()) + | |
| 358 | - QString(", xlab=\"Score\", ylab=\"Error Rate\") + theme_minimal()") + | |
| 359 | - ((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()) + | |
| 360 | - QString(" + scale_y_log10(labels=percent) + annotation_logticks(sides=\"l\")") + | |
| 361 | - ((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()) + | |
| 362 | - QString(" + theme(aspect.ratio=1)\n\n"))); | |
| 363 | - | |
| 364 | - p.file.write(qPrintable(QString("if (nrow(IM) != 0) {\n\tlibrary(jpeg)\n\tlibrary(png)\n\tlibrary(grid)\n\t") + | |
| 365 | - QString("multiplot <- function(..., plotlist=NULL, cols) {\n\t") + | |
| 366 | - QString("\trequire(grid)\n\n\t\t# Make a list from the ... arguments and plotlist\n\t\tplots <- c(list(...), plotlist)\n") + | |
| 367 | - QString("\t\tnumPlots = length(plots)\n\n\t\t# Make the panel\n\t\tplotCols = cols\n\t\tplotRows = ceiling(numPlots/plotCols)\n\n") + | |
| 368 | - QString("\t\t# Set up the page\n\t\tgrid.newpage()\n\t\tpushViewport(viewport(layout = grid.layout(plotRows, plotCols)))\n\t\tvplayout <- function(x, y)\n\t\t\tviewport(layout.pos.row = x, layout.pos.col = y)\n\n") + | |
| 369 | - QString("\t\t# Make each plot, in the correct location\n\t\tfor (i in 1:numPlots) {\n\t\t\tcurRow = ceiling(i/plotCols)\n\t\t\tcurCol = (i-1) %% plotCols + 1\n\t\t\tprint(plots[[i]], vp = vplayout(curRow, curCol))\n\t\t}\n\t}\n\n"))); | |
| 370 | - | |
| 371 | - p.file.write(qPrintable(QString("\t# Print impostor matches above the EER\n\tfor (i in 1:nrow(IM)) {\n\t\tscore <- IM[i,1]\n\t\tfiles <- IM[i,2]\n\t\talg <- IM[i,3]\n\t\tfiles <- unlist(strsplit(files, \"[:]\"))\n\n\t\text1 <- unlist(strsplit(files[2], \"[.]\"))[2]\n\t\text2 <- unlist(strsplit(files[4], \"[.]\"))[2]\n\t\t") + | |
| 372 | - QString("if (ext1 == \"jpg\" || ext1 == \"JPEG\" || ext1 == \"jpeg\" || ext1 == \"JPG\") {\n\t\t\timg1 <- readJPEG(files[2])\n\t\t} else if (ext1 == \"PNG\" || ext1 == \"png\") {\n\t\t\timg1 <- readPNG(files[2])\n\t\t} else if (ext1 == \"TIFF\" || ext1 == \"tiff\" || ext1 == \"TIF\" || ext1 == \"tif\") {\n\t\t\timg1 <- readTIFF(files[2])\n\t\t} else {\n\t\t\tnext\n\t\t}\n\t\tif (ext2 == \"jpg\" || ext2 == \"JPEG\" || ext2 == \"jpeg\" || ext2 == \"JPG\") {\n\t\t\timg2 <- readJPEG(files[4])\n\t\t} ") + | |
| 373 | - QString("else if (ext2 == \"PNG\" || ext2 == \"png\") {\n\t\t\timg2 <- readPNG(files[4])\n\t\t} else if (ext2 == \"TIFF\" || ext2 == \"tiff\" || ext2 == \"TIF\" || ext2 == \"tif\") {\n\t\t\timg2 <- readTIFF(files[4])\n\t\t} else {\n\t\t\tnext\n\t\t}") + | |
| 374 | - QString("\n\t\tname1 <- files[1]\n\t\tname2 <- files[3]\n\n\t\tg1 <- rasterGrob(img1, interpolate=TRUE)\n\t\tg2 <- rasterGrob(img2, interpolate=TRUE)\n\n\t\t") + | |
| 375 | - QString("plot1 <- qplot(1:10, 1:10, geom=\"blank\") + annotation_custom(g1, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=alg) + ylab(unlist(strsplit(files[2], \"[/]\"))[length(unlist(strsplit(files[2], \"[/]\")))]) + xlab(name1)\n\t\t") + | |
| 376 | - QString("plot2 <- qplot(1:10, 1:10, geom=\"blank\") + annotation_custom(g2, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=paste(\"Impostor score =\", score)) + ylab(unlist(strsplit(files[4], \"[/]\"))[length(unlist(strsplit(files[4], \"[/]\")))]) + xlab(name2)\n\n\t\t") + | |
| 377 | - QString("multiplot(plot1, plot2, cols=2)\n\t}"))); | |
| 378 | - | |
| 379 | - p.file.write(qPrintable(QString("\n\n\t# Print genuine matches below the EER\n\tfor (i in 1:nrow(GM)) {\n\t\tscore <- GM[i,1]\n\t\tfiles <- GM[i,2]\n\t\talg <- GM[i,3]\n\t\tfiles <- unlist(strsplit(files, \"[:]\"))\n\n\t\text1 <- unlist(strsplit(files[2], \"[.]\"))[2]\n\t\text2 <- unlist(strsplit(files[4], \"[.]\"))[2]\n\t\t") + | |
| 380 | - QString("if (ext1 == \"jpg\" || ext1 == \"JPEG\" || ext1 == \"jpeg\" || ext1 == \"JPG\") {\n\t\t\timg1 <- readJPEG(files[2])\n\t\t} else if (ext1 == \"PNG\" || ext1 == \"png\") {\n\t\t\timg1 <- readPNG(files[2])\n\t\t} else if (ext1 == \"TIFF\" || ext1 == \"tiff\" || ext1 == \"TIF\" || ext1 == \"tif\") {\n\t\t\timg1 <- readTIFF(files[2])\n\t\t} else {\n\t\t\tnext\n\t\t}\n\t\tif (ext2 == \"jpg\" || ext2 == \"JPEG\" || ext2 == \"jpeg\" || ext2 == \"JPG\") {\n\t\t\timg2 <- readJPEG(files[4])\n\t\t} ") + | |
| 381 | - QString("else if (ext2 == \"PNG\" || ext2 == \"png\") {\n\t\t\timg2 <- readPNG(files[4])\n\t\t} else if (ext2 == \"TIFF\" || ext2 == \"tiff\" || ext2 == \"TIF\" || ext2 == \"tif\") {\n\t\t\timg2 <- readTIFF(files[4])\n\t\t} else {\n\t\t\tnext\n\t\t}") + | |
| 382 | - QString("\n\t\tname1 <- files[1]\n\t\tname2 <- files[3]\n\n\t\tg1 <- rasterGrob(img1, interpolate=TRUE)\n\t\tg2 <- rasterGrob(img2, interpolate=TRUE)\n\n\t\t") + | |
| 383 | - QString("plot1 <- qplot(1:10, 1:10, geom=\"blank\") + annotation_custom(g1, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=alg) + ylab(unlist(strsplit(files[2], \"[/]\"))[length(unlist(strsplit(files[2], \"[/]\")))]) + xlab(name1)\n\t\t") + | |
| 384 | - QString("plot2 <- qplot(1:10, 1:10, geom=\"blank\") + annotation_custom(g2, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=paste(\"Genuine score =\", score)) + ylab(unlist(strsplit(files[4], \"[/]\"))[length(unlist(strsplit(files[4], \"[/]\")))]) + xlab(name2)\n\n\t\t") + | |
| 385 | - QString("multiplot(plot1, plot2, cols=2)\n\t}\n}\n\n"))); | |
| 210 | + if (destination.getBool("metadata", true)) { | |
| 211 | + p.file.write("\n# Write metadata table\n"); | |
| 212 | + p.file.write(qPrintable(QString("plotMetadata(metadata=Metadata, title=\"%1 - %2\")\n").arg(PRODUCT_NAME, PRODUCT_VERSION))); | |
| 213 | + | |
| 214 | + if (!destination.getBool("csv")) p.file.write("plot.new()\n"); | |
| 215 | + QString table = "plotTable(tableData=%1, name=%2, labels=%3)\n"; | |
| 216 | + p.file.write(qPrintable(table.arg("TF", "\"Table of True Accept Rates at various False Accept Rates\"", | |
| 217 | + "c(\"FAR = 1e-06\", \"FAR = 1e-05\", \"FAR = 1e-04\", \"FAR = 1e-03\", \"FAR = 1e-02\", \"FAR = 1e-01\")"))); | |
| 218 | + p.file.write(qPrintable(table.arg("FT", "\"Table of False Accept Rates at various True Accept Rates\"", | |
| 219 | + "c(\"TAR = 0.40\", \"TAR = 0.50\", \"TAR = 0.65\", \"TAR = 0.75\", \"TAR = 0.85\", \"TAR = 0.95\")"))); | |
| 220 | + p.file.write(qPrintable(table.arg("CT", "\"Table of retrieval rate at various ranks\"", | |
| 221 | + "c(\"Rank 1\", \"Rank 5\", \"Rank 10\", \"Rank 20\", \"Rank 50\", \"Rank 100\")"))); | |
| 222 | + p.file.write(qPrintable(table.arg("TS", "\"Template Size by Algorithm\"", | |
| 223 | + "c(\"Template Size (bytes):\")"))); | |
| 224 | + p.file.write("\n"); | |
| 225 | + } | |
| 226 | + | |
| 227 | + // Write plots | |
| 228 | + QString plot = "plot <- plotLine(lineData=%1, options=list(%2), flipY=%3)\nplot\n"; | |
| 229 | + p.file.write(qPrintable(QString(plot).arg("DET", toRList(optMap["rocOptions"]), "TRUE"))); | |
| 230 | + p.file.write(qPrintable(QString(plot).arg("DET", toRList(optMap["detOptions"]), "FALSE"))); | |
| 231 | + p.file.write(qPrintable(QString(plot).arg("IET", toRList(optMap["ietOptions"]), "FALSE"))); | |
| 232 | + p.file.write(qPrintable(QString(plot).arg("CMC", toRList(optMap["cmcOptions"]), "FALSE"))); | |
| 233 | + p.file.write("plot <- plotSD(sdData=SD)\nplot\n"); | |
| 234 | + p.file.write("plot <- plotBC(bcData=BC)\nplot\n"); | |
| 235 | + p.file.write("plot <- plotERR(errData=ERR)\nplot\n"); | |
| 236 | + p.file.write("plotEERSamples(imData=IM, gmData=GM)\n\n"); | |
| 386 | 237 | |
| 387 | 238 | return p.finalize(show); |
| 388 | 239 | } |
| ... | ... | @@ -420,7 +271,8 @@ bool filesHaveSinglePoint(const QStringList &files) { |
| 420 | 271 | bool PlotDetection(const QStringList &files, const File &destination, bool show) |
| 421 | 272 | { |
| 422 | 273 | qDebug("Plotting %d detection file(s) to %s", files.size(), qPrintable(destination)); |
| 423 | - RPlot p(files, destination, false); | |
| 274 | + RPlot p(files, destination); | |
| 275 | + p.file.write("\nformatData(type=\"detection\")\n\n"); | |
| 424 | 276 | |
| 425 | 277 | // Use a br::file for simple storage of plot options |
| 426 | 278 | QMap<QString,File> optMap; |
| ... | ... | @@ -436,40 +288,26 @@ bool PlotDetection(const QStringList &files, const File &destination, bool show) |
| 436 | 288 | } |
| 437 | 289 | } |
| 438 | 290 | |
| 439 | - p.file.write("# Split data into individual plots\n" | |
| 440 | - "plot_index = which(names(data)==\"Plot\")\n" | |
| 441 | - "DiscreteROC <- data[grep(\"DiscreteROC\",data$Plot),-c(1)]\n" | |
| 442 | - "ContinuousROC <- data[grep(\"ContinuousROC\",data$Plot),-c(1)]\n" | |
| 443 | - "DiscretePR <- data[grep(\"DiscretePR\",data$Plot),-c(1)]\n" | |
| 444 | - "ContinuousPR <- data[grep(\"ContinuousPR\",data$Plot),-c(1)]\n" | |
| 445 | - "Overlap <- data[grep(\"Overlap\",data$Plot),-c(1)]\n" | |
| 446 | - "AverageOverlap <- data[grep(\"AverageOverlap\",data$Plot),-c(1)]\n" | |
| 447 | - "rm(data)\n" | |
| 448 | - "\n"); | |
| 449 | - | |
| 450 | 291 | QString plotType("line"); |
| 451 | 292 | if (filesHaveSinglePoint(files)) |
| 452 | 293 | plotType = QString("point"); |
| 453 | 294 | |
| 295 | + QString plot = "plot <- plotLine(lineData=%1, options=list(%2), flipY=%3, geometry=%4)\nplot\n"; | |
| 454 | 296 | foreach (const QString &type, QStringList() << "Discrete" << "Continuous") { |
| 455 | 297 | optMap["rocOptions"].set("title", type); |
| 456 | - p.qplot(plotType, type + "ROC", false, optMap["rocOptions"]); | |
| 298 | + p.file.write(qPrintable(QString(plot).arg(type + "ROC", toRList(optMap["rocOptions"]), "FALSE", "\"" + plotType + "\""))); | |
| 457 | 299 | } |
| 458 | 300 | |
| 459 | 301 | foreach (const QString &type, QStringList() << "Discrete" << "Continuous") { |
| 460 | 302 | optMap["prOptions"].set("title", type); |
| 461 | - p.qplot(plotType, type + "PR", false, optMap["prOptions"]); | |
| 303 | + p.file.write(qPrintable(QString(plot).arg(type + "PR", toRList(optMap["prOptions"]), "FALSE", "\"" + plotType + "\""))); | |
| 462 | 304 | } |
| 463 | - | |
| 464 | - p.file.write(qPrintable(QString("qplot(X, data=Overlap, geom=\"histogram\", position=\"identity\", xlab=\"Overlap\", ylab=\"Frequency\")") + | |
| 465 | - QString(" + theme_minimal() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + theme(axis.text.y=element_blank(), axis.ticks=element_blank(), axis.text.x=element_text(angle=-90, hjust=0))") + | |
| 466 | - (p.major.size > 1 ? (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ %1, scales=\"free\")").arg(p.minor.header, p.major.header) : QString(" + facet_wrap(~ %1, scales = \"free\")").arg(p.major.header)) : QString()) + | |
| 467 | - QString(" + theme(aspect.ratio=1, legend.position=\"bottom\")\n\n"))); | |
| 305 | + p.file.write("plot <- plotOverlap(overlapData=Overlap)\nplot\n"); | |
| 468 | 306 | |
| 469 | 307 | p.file.write(qPrintable(QString("ggplot(AverageOverlap, aes(x=%1, y=%2, label=round(X,3)), main=\"Average Overlap\") + geom_text() + theme_minimal()").arg(p.minor.size > 1 ? p.minor.header : "'X'", p.major.size > 1 ? p.major.header : "'Y'") + |
| 470 | 308 | QString("%1%2\n\n").arg(p.minor.size > 1 ? "" : " + xlab(NULL)", p.major.size > 1 ? "" : " + ylab(NULL)"))); |
| 471 | 309 | |
| 472 | - p.file.write(qPrintable(QString("ggplot(AverageOverlap, aes(x=%1, y=%2, fill=X)) + geom_tile() + scale_fill_continuous(\"Average Overlap\") + theme_minimal()").arg(p.minor.size > 1 ? p.minor.header : "'X'", p.major.size > 1 ? p.major.header : "'Y'") + | |
| 310 | + p.file.write(qPrintable(QString("ggplot(AverageOverlap, aes(x=%1, y=%2, fill=X)) + geom_tile() + scale_fill_continuous(\"Average Overlap\", guide=FALSE) + theme_minimal()").arg(p.minor.size > 1 ? p.minor.header : "'X'", p.major.size > 1 ? p.major.header : "'Y'") + | |
| 473 | 311 | QString("%1%2\n\n").arg(p.minor.size > 1 ? "" : " + xlab(NULL)", p.major.size > 1 ? "" : " + ylab(NULL)"))); |
| 474 | 312 | |
| 475 | 313 | return p.finalize(show); |
| ... | ... | @@ -478,109 +316,12 @@ bool PlotDetection(const QStringList &files, const File &destination, bool show) |
| 478 | 316 | bool PlotLandmarking(const QStringList &files, const File &destination, bool show) |
| 479 | 317 | { |
| 480 | 318 | qDebug("Plotting %d landmarking file(s) to %s", files.size(), qPrintable(destination)); |
| 481 | - RPlot p(files, destination, false); | |
| 482 | - | |
| 483 | - p.file.write(qPrintable(QString("# Split data into individual plots\n" | |
| 484 | - "plot_index = which(names(data)==\"Plot\")\n" | |
| 485 | - "Box <- data[grep(\"Box\",data$Plot),-c(1)]\n" | |
| 486 | - "Box$X <- factor(Box$X, levels = Box$X, ordered = TRUE)\n" | |
| 487 | - "Sample <- data[grep(\"Sample\",data$Plot),-c(1)]\n" | |
| 488 | - "Sample$X <- as.character(Sample$X)\n" | |
| 489 | - "EXT <- data[grep(\"EXT\",data$Plot),-c(1)]\n" | |
| 490 | - "EXT$X <- as.character(EXT$X)\n" | |
| 491 | - "EXP <- data[grep(\"EXP\",data$Plot),-c(1)]\n" | |
| 492 | - "EXP$X <- as.character(EXP$X)\n" | |
| 493 | - "NormLength <- data[grep(\"NormLength\",data$Plot),-c(1)]\n" | |
| 494 | - "rm(data)\n" | |
| 495 | - "\n"))); | |
| 496 | - | |
| 497 | - p.file.write(qPrintable(QString("summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE, conf.interval=.95, .drop=TRUE) {\n\t" | |
| 498 | - "require(plyr)\n\n\tlength2 <- function (x, na.rm=FALSE) {\n\t\tif (na.rm) sum(!is.na(x))\n\t\telse length(x)" | |
| 499 | - "\n\t}\n\n\tdatac <- ddply(data, groupvars, .drop=.drop, .fun = function(xx, col) {\n\t\t" | |
| 500 | - "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}," | |
| 501 | - "\n\t\tmeasurevar\n\t)\n\n\tdatac <- rename(datac, c(\"mean\" = measurevar))\n\tdatac$se <- datac$sd / sqrt(datac$N)" | |
| 502 | - "\n\tciMult <- qt(conf.interval/2 + .5, datac$N-1)\n\tdatac$ci <- datac$se * ciMult\n\n\treturn(datac)\n}\n"))); | |
| 503 | - | |
| 504 | - | |
| 505 | - p.file.write(qPrintable(QString("\nreadData <- function(data) {\n\texamples <- list()\n" | |
| 506 | - "\tfor (i in 1:nrow(data)) {\n" | |
| 507 | - "\t\tpath <- data[i,1]\n" | |
| 508 | - "\t\tvalue <- data[i,2]\n" | |
| 509 | - "\t\tfile <- unlist(strsplit(path, \"[.]\"))[1]\n" | |
| 510 | - "\t\text <- unlist(strsplit(path, \"[.]\"))[2]\n" | |
| 511 | - "\t\tif (ext == \"jpg\" || ext == \"JPEG\" || ext == \"jpeg\" || ext == \"JPG\") {\n" | |
| 512 | - "\t\t\timg <- readJPEG(path)\n" | |
| 513 | - "\t\t} else if (ext == \"PNG\" || ext == \"png\") {\n" | |
| 514 | - "\t\t\timg <- readPNG(path)\n" | |
| 515 | - "\t\t} else if (ext == \"TIFF\" || ext == \"tiff\" || ext == \"TIF\" || ext == \"tif\") { \n" | |
| 516 | - "\t\t\timg <- readTIFF(path)\n" | |
| 517 | - "}else {\n" | |
| 518 | - "\t\t\tnext\n" | |
| 519 | - "\t\t}\n" | |
| 520 | - "\t\texample <- list(file = file, value = value, image = img)\n" | |
| 521 | - "\t\texamples[[i]] <- example\n" | |
| 522 | - "\t}\n" | |
| 523 | - "\treturn(examples)\n" | |
| 524 | - "}\n"))); | |
| 525 | - | |
| 526 | - p.file.write(qPrintable(QString("\nlibrary(jpeg)\n" | |
| 527 | - "library(png)\n" | |
| 528 | - "library(grid)\n" | |
| 529 | - "multiplot <- function(..., plotlist=NULL, cols) {\n" | |
| 530 | - "\trequire(grid)\n" | |
| 531 | - "\t# Make a list from the ... arguments and plotlist\n" | |
| 532 | - "\tplots <- c(list(...), plotlist)\n" | |
| 533 | - "\tnumPlots = length(plots)\n" | |
| 534 | - "\t# Make the panel\n" | |
| 535 | - "\tplotCols = cols\n" | |
| 536 | - "\tplotRows = ceiling(numPlots/plotCols)\n" | |
| 537 | - "\t# Set up the page\n" | |
| 538 | - "\tgrid.newpage()\n" | |
| 539 | - "\tpushViewport(viewport(layout = grid.layout(plotRows, plotCols)))\n" | |
| 540 | - "\tvplayout <- function(x, y)\n" | |
| 541 | - "\tviewport(layout.pos.row = x, layout.pos.col = y)\n" | |
| 542 | - "\t# Make each plot, in the correct location\n" | |
| 543 | - "\tfor (i in 1:numPlots) {\n" | |
| 544 | - "\t\tcurRow = ceiling(i/plotCols)\n" | |
| 545 | - "\t\tcurCol = (i-1) %% plotCols + 1\n" | |
| 546 | - "\t\tprint(plots[[i]], vp = vplayout(curRow, curCol))\n" | |
| 547 | - "\t}\n" | |
| 548 | - "}\n"))); | |
| 549 | - | |
| 550 | - p.file.write(qPrintable(QString("\nplotImage <- function(image, title=NULL, label=NULL) { \n" | |
| 551 | - "\tp <- qplot(1:10, 1:10, geom=\"blank\") + annotation_custom(rasterGrob(image$image), xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.title.y=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), line=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=title) + xlab(label)\n" | |
| 552 | - "\treturn(p)" | |
| 553 | - "}\n"))); | |
| 554 | - | |
| 555 | - p.file.write(qPrintable(QString("\nsample <- readData(Sample) \n" | |
| 556 | - "rows <- sample[[1]]$value\n" | |
| 557 | - "algs <- unique(Box$%1)\n" | |
| 558 | - "algs <- algs[!duplicated(algs)]\n" | |
| 559 | - "print(plotImage(sample[[1]],\"Sample Landmarks\",sprintf(\"Total Landmarks: %s\",sample[[1]]$value))) \n" | |
| 560 | - "if (nrow(EXT) != 0 && nrow(EXP)) {\n" | |
| 561 | - "\tfor (j in 1:length(algs)) {\n" | |
| 562 | - "\ttruthSample <- readData(EXT[EXT$. == algs[[j]],])\n" | |
| 563 | - "\tpredictedSample <- readData(EXP[EXP$. == algs[[j]],])\n" | |
| 564 | - "\t\tfor (i in 1:length(predictedSample)) {\n" | |
| 565 | - "\t\t\tmultiplot(plotImage(predictedSample[[i]],sprintf(\"%s\\nPredicted Landmarks\",algs[[j]]),sprintf(\"Average Landmark Error: %.3f\",predictedSample[[i]]$value)),plotImage(truthSample[[i]],\"Ground Truth\\nLandmarks\",\"\"),cols=2)\n" | |
| 566 | - "\t\t}\n" | |
| 567 | - "\t}\n" | |
| 568 | - "}\n").arg(p.major.size > 1 ? p.major.header : (p.minor.header.isEmpty() ? p.major.header : p.minor.header)))); | |
| 569 | - | |
| 570 | - p.file.write(qPrintable(QString("\n" | |
| 571 | - "# Code to format error table\n" | |
| 572 | - "StatBox <- summarySE(Box, measurevar=\"Y\", groupvars=c(\"%1\",\"X\"))\n" | |
| 573 | - "OverallStatBox <- summarySE(Box, measurevar=\"Y\", groupvars=c(\"%1\"))\n" | |
| 574 | - "mat <- matrix(paste(as.character(round(StatBox$Y, 3)), round(StatBox$ci, 3), sep=\" \\u00b1 \"),nrow=rows,ncol=length(algs),byrow=FALSE)\n" | |
| 575 | - "mat <- rbind(mat, paste(as.character(round(OverallStatBox$Y, 3)), round(OverallStatBox$ci, 3), sep=\" \\u00b1 \"))\n" | |
| 576 | - "mat <- rbind(mat, as.character(round(NormLength$Y, 3)))\n" | |
| 577 | - "colnames(mat) <- algs\n" | |
| 578 | - "rownames(mat) <- c(seq(0,rows-1),\"Aggregate\",\"Average IPD\")\n" | |
| 579 | - "ETable <- as.table(mat)\n").arg(p.major.size > 1 ? p.major.header : (p.minor.header.isEmpty() ? p.major.header : p.minor.header)))); | |
| 580 | - | |
| 581 | - p.file.write(qPrintable(QString("\n" | |
| 582 | - "print(textplot(ETable))\n" | |
| 583 | - "print(title(\"Landmarking Error Rates\"))\n"))); | |
| 319 | + RPlot p(files, destination); | |
| 320 | + p.file.write("\nformatData(type=\"landmarking\")\n\n"); | |
| 321 | + p.file.write(qPrintable(QString("algs <- uniqueBox$%1)\n").arg(p.major.size > 1 ? p.major.header : (p.minor.header.isEmpty() ? p.major.header : p.minor.header)))); | |
| 322 | + p.file.write("algs <- algs[!duplicated(algs)]\n"); | |
| 323 | + p.file.write("plotLandmarkSamples(samples=sample, expData=EXP, extData=EXT)\n"); | |
| 324 | + p.file.write("plotLandmarkTables(tableData=Box)\n"); | |
| 584 | 325 | |
| 585 | 326 | p.file.write(qPrintable(QString("ggplot(Box, aes(Y,%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), |
| 586 | 327 | p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) + |
| ... | ... | @@ -599,7 +340,7 @@ bool PlotMetadata(const QStringList &files, const QString &columns, bool show) |
| 599 | 340 | { |
| 600 | 341 | qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns)); |
| 601 | 342 | |
| 602 | - RPlot p(files, "PlotMetadata", false); | |
| 343 | + RPlot p(files, "PlotMetadata"); | |
| 603 | 344 | foreach (const QString &column, columns.split(";")) |
| 604 | 345 | p.file.write(qPrintable(QString("qplot(%1, %2, data=data, geom=\"violin\", fill=%1) + coord_flip() + theme_minimal()\nggsave(\"%2.pdf\")\n").arg(p.major.header, column))); |
| 605 | 346 | return p.finalize(show); | ... | ... |
share/openbr/plotting/plot_utils.R
0 โ 100644
| 1 | +# Load libraries | |
| 2 | +library("ggplot2") | |
| 3 | +library("gplots") | |
| 4 | +library("reshape") | |
| 5 | +library("scales") | |
| 6 | +library("jpeg") | |
| 7 | +library("png") | |
| 8 | +library("grid") | |
| 9 | + | |
| 10 | +# Code to format FAR values | |
| 11 | +far_names <- list('0.001'="FAR = 0.1%", '0.01'="FAR = 1%") | |
| 12 | +far_labeller <- function(variable,value) { return(far_names[as.character(value)]) } | |
| 13 | + | |
| 14 | +getScale <- function(mode, title, vals) { | |
| 15 | + if (vals > 12) return(do.call(paste("scale", mode, "discrete", sep="_"), list(title))) | |
| 16 | + else if (vals > 11) return(do.call(paste("scale", mode, "brewer", sep="_"), list(title, palette="Set3"))) | |
| 17 | + else if (vals > 9) return(do.call(paste("scale", mode, "brewer", sep="_"), list(title, palette="Paired"))) | |
| 18 | + else return(do.call(paste("scale", mode, "brewer", sep="_"), list(title, palette="Set1"))) | |
| 19 | +} | |
| 20 | + | |
| 21 | +plotMetadata <- function(metadata=NULL, title=NULL) { | |
| 22 | + MT <- as.data.frame(metadata[c(1, 2, 3, 4, 5),]) | |
| 23 | + par(mfrow=c(4, 1)) | |
| 24 | + plot.new() | |
| 25 | + print(title(paste(title, date(), sep="\n"))) | |
| 26 | + mat <- matrix(MT$X[c(1, 2)], ncol=2) | |
| 27 | + colnames(mat) <- c("Gallery", "Probe") | |
| 28 | + imageTable <- as.table(mat) | |
| 29 | + print(textplot(imageTable, show.rownames=FALSE)) | |
| 30 | + print(title("Images")) | |
| 31 | + mat <- matrix(MT$X[c(3, 4, 5)], ncol=3) | |
| 32 | + colnames(mat) <- c("Genuine", "Impostor", "Ignored") | |
| 33 | + matchTable <- as.table(mat) | |
| 34 | + print(textplot(matchTable, show.rownames=FALSE)) | |
| 35 | + print(title("Matches")) | |
| 36 | + plot.new() | |
| 37 | + print(title("Gallery * Probe = Genuine + Impostor + Ignored")) | |
| 38 | +} | |
| 39 | + | |
| 40 | +plotTable <- function(tableData=NULL, name=NULL, labels=NULL) { | |
| 41 | + if (nrow(tableData) == 0) return() | |
| 42 | + if (smooth && confidence != 0) { | |
| 43 | + input = paste(as.character(round(tableData$Y, 3)), round(tableData$ci, 3), sep="\u00b1") | |
| 44 | + } else { | |
| 45 | + input = tableData$Y | |
| 46 | + } | |
| 47 | + mat <- matrix(input, nrow=length(labels), ncol=length(algs), byrow=FALSE) | |
| 48 | + colnames(mat) <- algs | |
| 49 | + rownames(mat) <- labels | |
| 50 | + table <- as.table(mat) | |
| 51 | + if (csv) { | |
| 52 | + write.csv(table, file=paste(paste(basename, deparse(substitute(data)), sep="_"), ".csv", sep="")) | |
| 53 | + } else { | |
| 54 | + print(textplot(table)) | |
| 55 | + print(title(name)) | |
| 56 | + } | |
| 57 | +} | |
| 58 | + | |
| 59 | +plotLandmarkTables <- function(tableData=NULL) { | |
| 60 | + if(majorSize > 1) { | |
| 61 | + var <- majorHeader | |
| 62 | + } else { | |
| 63 | + if(minorHeader == "") var <- majorHeader else var <- minorHeader | |
| 64 | + } | |
| 65 | + StatBox <- summarySE(tableData, measurevar="Y", groupvars=c(var,"X")) | |
| 66 | + OverallStatBox <- summarySE(tableData, measurevar="Y", groupvars=c(var)) | |
| 67 | + mat <- matrix(paste(as.character(round(StatBox$Y, 3)), round(StatBox$ci, 3), sep=" \u00b1 "), nrow=rows, ncol=length(algs), byrow=FALSE) | |
| 68 | + mat <- rbind(mat, paste(as.character(round(OverallStatBox$Y, 3)), round(OverallStatBox$ci, 3), sep=" \u00b1 ")) | |
| 69 | + mat <- rbind(mat, as.character(round(NormLength$Y, 3))) | |
| 70 | + colnames(mat) <- algs | |
| 71 | + rownames(mat) <- c(seq(0, rows-1), "Aggregate","Average IPD") | |
| 72 | + ETable <- as.table(mat) | |
| 73 | + print(textplot(ETable)) | |
| 74 | + print(title("Landmarking Error Rates")) | |
| 75 | +} | |
| 76 | + | |
| 77 | +plotLine <- function(lineData=NULL, options=NULL, flipY=FALSE, geometry="line") { | |
| 78 | + textSize <- if("textSize" %in% names(options)) as.numeric(options$textSize) else 12 | |
| 79 | + p <- qplot(X, if(flipY) 1-Y else Y, data=lineData, main=options$title, geom=geometry, size=if("size" %in% names(options)) I(as.numeric(options$size)) else I(.5), colour=if(majorSize > 1) factor(eval(parse(text=majorHeader))) else NULL, linetype=if(minorSize > 1) factor(eval(parse(text=minorHeader))) else NULL, xlab=options$xTitle, ylab=options$yTitle) + theme_minimal() | |
| 80 | + if (smooth && deparse(substitute(lineData)) != "CMC" && confidence != 0) p <- p + geom_errorbar(data=lineData[seq(1, NROW(lineData), by = 29),], aes(x=X, ymin=if(flipY) (1-lower) else lower, ymax=if(flipY) (1-upper) else upper), width=0.1, alpha=I(1/2)) | |
| 81 | + if (majorSize > 1) p <- p + getScale("colour", majorHeader, majorSize) | |
| 82 | + if (minorSize > 1) p <- p + scale_linetype_discrete(minorHeader) | |
| 83 | + | |
| 84 | + # Set log/continuous scales, breaks and labels | |
| 85 | + if (options$xLog) | |
| 86 | + p <- p + scale_x_log10(labels=if("xLabels" %in% names(options)) eval(parse(text=options$xLabels)) else trans_format("log10", math_format()), breaks=if("xBreaks" %in% names(options)) eval(parse(text=options$xBreaks)) else waiver()) + annotation_logticks(sides="b") | |
| 87 | + else | |
| 88 | + p <- p + scale_x_continuous(labels=if("xLabels" %in% names(options)) eval(parse(text=options$xLabels)) else percent, breaks=if("xBreaks" %in% names(options)) eval(parse(text=options$xBreaks)) else pretty_breaks(n=10)) | |
| 89 | + if (options$yLog) | |
| 90 | + p <- p + scale_y_log10(labels=if("yLabels" %in% names(options)) eval(parse(text=options$yLabels)) else trans_format("log10", math_format()), breaks=if("yBreaks" %in% names(options)) eval(parse(text=options$yBreaks)) else waiver()) + annotation_logticks(sides="l") | |
| 91 | + else | |
| 92 | + p <- p + scale_y_continuous(labels=if("yLabels" %in% names(options)) eval(parse(text=options$yLabels)) else percent, breaks=if("yBreaks" %in% names(options)) eval(parse(text=options$yBreaks)) else pretty_breaks(n=10)) | |
| 93 | + | |
| 94 | + if ("xLimits" %in% names(options)) p <- p + xlim(eval(parse(text=options$xLimits))) | |
| 95 | + if ("yLimits" %in% names(options)) p <- p + ylim(eval(parse(text=options$yLimits))) | |
| 96 | + p <- p + theme(legend.title = element_text(size = textSize), legend.text = element_text(size = textSize), plot.title = element_text(size = textSize), axis.text = element_text(size = textSize), axis.title.x = element_text(size = textSize), axis.title.y = element_text(size = textSize), legend.position=if("legendPosition" %in% names(options)) eval(parse(text=options$legendPosition)) else "bottom", legend.background = element_rect(fill = 'white'), panel.grid.major = element_line(colour = "gray"), panel.grid.minor = element_line(colour = "gray", linetype = "dashed")) | |
| 97 | + p <- p + guides(col=guide_legend(ncol=ncol)) | |
| 98 | + return(p) | |
| 99 | +} | |
| 100 | + | |
| 101 | +plotSD <- function(sdData=NULL) { | |
| 102 | + p <- qplot(X, data=sdData, geom="histogram", fill=Y, position="identity", alpha=I(1/2), xlab="Score", ylab="Frequency") | |
| 103 | + p <- p + scale_fill_manual("Ground Truth", values=c("blue", "red")) + theme_minimal() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + theme(axis.text.y=element_blank(), axis.ticks=element_blank(), axis.text.x=element_text(angle=-90, hjust=0)) | |
| 104 | + if (majorSize > 1) { | |
| 105 | + if (minorSize > 1) { | |
| 106 | + if (flip) { | |
| 107 | + A <- minorHeader | |
| 108 | + B <- majorHeader | |
| 109 | + } else { | |
| 110 | + A <- majorHeader | |
| 111 | + B <- minorHeader | |
| 112 | + } | |
| 113 | + p <- p + facet_grid(facets=as.formula(paste(A, "~", B)), scales="free") | |
| 114 | + } else { | |
| 115 | + p <- p + facet_wrap(facets=as.formula(paste("~", majorHeader)), scales="free") | |
| 116 | + } | |
| 117 | + } | |
| 118 | + p <- p + theme(aspect.ratio=1) | |
| 119 | + return(p) | |
| 120 | +} | |
| 121 | + | |
| 122 | +plotBC <- function(bcData=NULL) { | |
| 123 | + factor <- if (majorSmooth) minorHeader else majorHeader | |
| 124 | + plotString <- paste("qplot(factor(", factor, ")", if(smooth) ", Y" else "", ", data=bcData, ", if(smooth) "geom=\"boxplot\"" else "geom=\"bar\", position=\"dodge\", weight=Y", sep="") | |
| 125 | + p <- eval(parse(text=paste(plotString, if(majorSize > 1) paste(", fill=factor(", majorHeader, ")", sep="") else "", ", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()", sep=""))) | |
| 126 | + if(majorSize > 1) p <- p + getScale("fill", majorHeader, majorSize) | |
| 127 | + if(minorSize > 1) p <- p + facet_grid(facets=as.formula(paste(minorHeader, "~", "X"))) else p <- p + facet_grid(. ~ X, labeller=far_labeller) | |
| 128 | + p <- p + scale_y_continuous(labels=percent) + theme(legend.position="none", axis.text.x=element_text(angle=-90, hjust=0)) | |
| 129 | + if(!smooth) p <- p + geom_text(data=bcData, aes(label=bcData$Y, y=0.05)) | |
| 130 | + return(p) | |
| 131 | +} | |
| 132 | + | |
| 133 | +plotERR <- function(errData=NULL) { | |
| 134 | + if(flip) { | |
| 135 | + if(majorSize > 1) color <- majorHeader | |
| 136 | + } else { | |
| 137 | + if(minorSize > 1) color <- minorHeader | |
| 138 | + } | |
| 139 | + p <- qplot(X, Y, data=errData, geom="line", linetype=Error, colour=if(exists("color")) factor(eval(parse(text=color))) else NULL, xlab="Score", ylab="Error Rate") + theme_minimal() | |
| 140 | + if(flip) { | |
| 141 | + if(majorSize > 1) | |
| 142 | + p <- p + getScale("colour", majorHeader, majorSize) | |
| 143 | + else if(minorSize > 1) | |
| 144 | + p <- p + getScale("colour", minorHeader, minorSize) | |
| 145 | + } | |
| 146 | + p <- p + scale_y_log10(labels=percent) + annotation_logticks(sides="l") | |
| 147 | + if(flip) { | |
| 148 | + if(minorSize > 1) { | |
| 149 | + facet <- minorHeader | |
| 150 | + p <- p + facet_wrap(as.formula(paste("~", facet)), scales="free_x") | |
| 151 | + } | |
| 152 | + } else { | |
| 153 | + if(majorSize >1) { | |
| 154 | + facet <- majorHeader | |
| 155 | + p <- p + facet_wrap(as.formula(paste("~", facet)), scales="free_x") | |
| 156 | + } | |
| 157 | + } | |
| 158 | + p <- p + theme(aspect.ratio=1) | |
| 159 | + return(p) | |
| 160 | +} | |
| 161 | + | |
| 162 | +plotOverlap <- function(overlapData=NULL) { | |
| 163 | + p <- qplot(X, data=overlapData, geom="histogram", position="identity", xlab="Overlap", ylab="Frequency") | |
| 164 | + p <- p + theme_minimal() + scale_x_continuous(minor_breaks=NULL) + scale_y_continuous(minor_breaks=NULL) + theme(axis.text.y=element_blank(), axis.ticks=element_blank(), axis.text.x=element_text(angle=-90, hjust=0)) | |
| 165 | + if(majorSize > 1) { | |
| 166 | + if(minorSize) { | |
| 167 | + p <- p + facet_grid(facets=as.formula(paste(minorHeader, "~", majorHeader)), scales="free") | |
| 168 | + } else { | |
| 169 | + p <- p + facet_wrap(facets=as.formula(paste("~", majorHeader)), scales="free") | |
| 170 | + } | |
| 171 | + } | |
| 172 | + p <- p + theme(aspect.ratio=1, legend.position="bottom") | |
| 173 | + return(p) | |
| 174 | +} | |
| 175 | + | |
| 176 | +formatData <- function(type="eval") { | |
| 177 | + if (type == "eval") { | |
| 178 | + # Split data into individual plots | |
| 179 | + plot_index <<- which(names(data)=="Plot") | |
| 180 | + Metadata <<- data[grep("Metadata",data$Plot),-c(1)] | |
| 181 | + IM <<- data[grep("IM",data$Plot),-c(1)] | |
| 182 | + GM <<- data[grep("GM",data$Plot),-c(1)] | |
| 183 | + DET <<- data[grep("DET",data$Plot),-c(1)] | |
| 184 | + IET <<- data[grep("IET",data$Plot),-c(1)] | |
| 185 | + FAR <- data[grep("FAR",data$Plot),-c(1)] | |
| 186 | + FRR <- data[grep("FRR",data$Plot),-c(1)] | |
| 187 | + SD <<- data[grep("SD",data$Plot),-c(1)] | |
| 188 | + TF <<- data[grep("TF",data$Plot),-c(1)] | |
| 189 | + FT <<- data[grep("FT",data$Plot),-c(1)] | |
| 190 | + CT <<- data[grep("CT",data$Plot),-c(1)] | |
| 191 | + BC <<- data[grep("BC",data$Plot),-c(1)] | |
| 192 | + TS <<- data[grep("TS",data$Plot),-c(1)] | |
| 193 | + CMC <<- data[grep("CMC",data$Plot),-c(1)] | |
| 194 | + FAR$Error <- "FAR" | |
| 195 | + FRR$Error <- "FRR" | |
| 196 | + ERR <<- rbind(FAR, FRR) | |
| 197 | + | |
| 198 | + # Format data | |
| 199 | + Metadata$Y<-factor(Metadata$Y, levels=c("Genuine", "Impostor", "Ignored", "Gallery", "Probe")) | |
| 200 | + IM$Y <<- as.character(IM$Y) | |
| 201 | + GM$Y <<- as.character(GM$Y) | |
| 202 | + DET$Y <<- as.numeric(as.character(DET$Y)) | |
| 203 | + IET$Y <<- as.numeric(as.character(IET$Y)) | |
| 204 | + ERR$Y <<- as.numeric(as.character(ERR$Y)) | |
| 205 | + SD$Y <<- as.factor(unique(as.character(SD$Y))) | |
| 206 | + TF$Y <<- as.numeric(as.character(TF$Y)) | |
| 207 | + FT$Y <<- as.numeric(as.character(FT$Y)) | |
| 208 | + CT$Y <<- as.numeric(as.character(CT$Y)) | |
| 209 | + BC$Y <<- as.numeric(as.character(BC$Y)) | |
| 210 | + TS$Y <<- as.character(TS$Y) | |
| 211 | + CMC$Y <<- as.numeric(as.character(CMC$Y)) | |
| 212 | + } else if (type == "detection") { | |
| 213 | + # Split data into individual plots | |
| 214 | + DiscreteROC <<- data[grep("DiscreteROC",data$Plot),-c(1)] | |
| 215 | + ContinuousROC <<- data[grep("ContinuousROC",data$Plot),-c(1)] | |
| 216 | + DiscretePR <<- data[grep("DiscretePR",data$Plot),-c(1)] | |
| 217 | + ContinuousPR <<- data[grep("ContinuousPR",data$Plot),-c(1)] | |
| 218 | + Overlap <<- data[grep("Overlap",data$Plot),-c(1)] | |
| 219 | + AverageOverlap <<- data[grep("AverageOverlap",data$Plot),-c(1)] | |
| 220 | + } else if (type == "landmarking") { | |
| 221 | + # Split data into individual plots | |
| 222 | + Box <<- data[grep("Box",data$Plot),-c(1)] | |
| 223 | + Box$X <<- factor(Box$X, levels = Box$X, ordered = TRUE) | |
| 224 | + Sample <<- data[grep("Sample",data$Plot),-c(1)] | |
| 225 | + Sample$X <<- as.character(Sample$X) | |
| 226 | + EXT <<- data[grep("EXT",data$Plot),-c(1)] | |
| 227 | + EXT$X <<- as.character(EXT$X) | |
| 228 | + EXP <<- data[grep("EXP",data$Plot),-c(1)] | |
| 229 | + EXP$X <<- as.character(EXP$X) | |
| 230 | + NormLength <<- data[grep("NormLength",data$Plot),-c(1)] | |
| 231 | + sample <<- readImageData(Sample) | |
| 232 | + rows <<- sample[[1]]$value | |
| 233 | + } | |
| 234 | +} | |
| 235 | + | |
| 236 | +summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE, conf.interval=0.95, .drop=TRUE) { | |
| 237 | + # derived from http://www.cookbook-r.com/Manipulating_data/Summarizing_data/ | |
| 238 | + require(plyr) | |
| 239 | + | |
| 240 | + length2 <- function (x, na.rm=FALSE) { | |
| 241 | + if (na.rm) sum(!is.na(x)) | |
| 242 | + else length(x) | |
| 243 | + } | |
| 244 | + | |
| 245 | + datac <- ddply(data, groupvars, .drop=.drop, .fun = function(xx, col) { | |
| 246 | + 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)) | |
| 247 | + }, | |
| 248 | + measurevar | |
| 249 | + ) | |
| 250 | + | |
| 251 | + datac <- rename(datac, c("mean" = measurevar)) | |
| 252 | + datac$se <- datac$sd / sqrt(datac$N) | |
| 253 | + ciMult <- qt(conf.interval/2 + .5, datac$N-1) | |
| 254 | + datac$ci <- datac$se * ciMult | |
| 255 | + | |
| 256 | + datac$upper <- if(datac[, measurevar] + datac$ci < 1) (datac[, measurevar] + datac$ci) else 1 | |
| 257 | + datac$lower <- if(datac[, measurevar] - datac$ci > 0) (datac[, measurevar] - datac$ci) else 0 | |
| 258 | + | |
| 259 | + return(datac) | |
| 260 | +} | |
| 261 | + | |
| 262 | +multiplot <- function(..., plotlist=NULL, cols) { | |
| 263 | + require(grid) | |
| 264 | + # Make a list from the ... arguments and plotlist | |
| 265 | + plots <- c(list(...), plotlist) | |
| 266 | + numPlots = length(plots) | |
| 267 | + # Make the panel | |
| 268 | + plotCols = cols | |
| 269 | + plotRows = ceiling(numPlots/plotCols) | |
| 270 | + # Set up the page | |
| 271 | + grid.newpage() | |
| 272 | + pushViewport(viewport(layout = grid.layout(plotRows, plotCols))) | |
| 273 | + vplayout <- function(x, y) | |
| 274 | + viewport(layout.pos.row = x, layout.pos.col = y) | |
| 275 | + # Make each plot, in the correct location | |
| 276 | + for (i in 1:numPlots) { | |
| 277 | + curRow = ceiling(i/plotCols) | |
| 278 | + curCol = (i-1) %% plotCols + 1 | |
| 279 | + print(plots[[i]], vp = vplayout(curRow, curCol)) | |
| 280 | + } | |
| 281 | +} | |
| 282 | + | |
| 283 | +plotEERSamples <- function(imData=NULL, gmData=NULL) { | |
| 284 | + if(nrow(imData) == 0) return() | |
| 285 | + | |
| 286 | + printImages <- function(images, label) { | |
| 287 | + for (i in 1:nrow(images)) { | |
| 288 | + score <- images[i,1] | |
| 289 | + files <- images[i,2] | |
| 290 | + alg <- images[i,3] | |
| 291 | + files <- unlist(strsplit(files, "[:]")) | |
| 292 | + | |
| 293 | + ext1 <- unlist(strsplit(files[2], "[.]"))[2] | |
| 294 | + ext2 <- unlist(strsplit(files[4], "[.]"))[2] | |
| 295 | + if (ext1 == "jpg" || ext1 == "JPEG" || ext1 == "jpeg" || ext1 == "JPG") { | |
| 296 | + img1 <- readJPEG(files[2]) | |
| 297 | + } else if (ext1 == "PNG" || ext1 == "png") { | |
| 298 | + img1 <- readPNG(files[2]) | |
| 299 | + } else if (ext1 == "TIFF" || ext1 == "tiff" || ext1 == "TIF" || ext1 == "tif") { | |
| 300 | + img1 <- readTIFF(files[2]) | |
| 301 | + } else { | |
| 302 | + next | |
| 303 | + } | |
| 304 | + if (ext2 == "jpg" || ext2 == "JPEG" || ext2 == "jpeg" || ext2 == "JPG") { | |
| 305 | + img2 <- readJPEG(files[4]) | |
| 306 | + } else if (ext2 == "PNG" || ext2 == "png") { | |
| 307 | + img2 <- readPNG(files[4]) | |
| 308 | + } else if (ext2 == "TIFF" || ext2 == "tiff" || ext2 == "TIF" || ext2 == "tif") { | |
| 309 | + img2 <- readTIFF(files[4]) | |
| 310 | + } else { | |
| 311 | + next | |
| 312 | + } | |
| 313 | + name1 <- files[1] | |
| 314 | + name2 <- files[3] | |
| 315 | + | |
| 316 | + g1 <- rasterGrob(img1, interpolate=TRUE) | |
| 317 | + g2 <- rasterGrob(img2, interpolate=TRUE) | |
| 318 | + | |
| 319 | + plot1 <- qplot(1:10, 1:10, geom="blank") + annotation_custom(g1, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=alg) + ylab(unlist(strsplit(files[2], "[/]"))[length(unlist(strsplit(files[2], "[/]")))]) + xlab(name1) | |
| 320 | + plot2 <- qplot(1:10, 1:10, geom="blank") + annotation_custom(g2, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=paste(label, " score =", score)) + ylab(unlist(strsplit(files[4], "[/]"))[length(unlist(strsplit(files[4], "[/]")))]) + xlab(name2) | |
| 321 | + | |
| 322 | + multiplot(plot1, plot2, cols=2) | |
| 323 | + } | |
| 324 | + } | |
| 325 | + printImages(imData, "Impostor") | |
| 326 | + printImages(gmData, "Genuine") | |
| 327 | +} | |
| 328 | + | |
| 329 | +plotLandmarkSamples <- function(samples=NULL, expData=NULL, extData=NULL) { | |
| 330 | + print(plotImage(samples[[1]], "Sample Landmarks", sprintf("Total Landmarks: %s", samples[[1]]$value))) | |
| 331 | + if (nrow(EXT) != 0 && nrow(EXP)) { | |
| 332 | + for (j in 1:length(algs)) { | |
| 333 | + truthSample <- readData(EXT[EXT$. == algs[[j]],]) | |
| 334 | + predictedSample <- readData(EXP[EXP$. == algs[[j]],]) | |
| 335 | + for (i in 1:length(predictedSample)) { | |
| 336 | + multiplot(plotImage(predictedSample[[i]], sprintf("%s\nPredicted Landmarks", algs[[j]]), sprintf("Average Landmark Error: %.3f", predictedSample[[i]]$value)), plotImage(truthSample[[i]], "Ground Truth\nLandmarks", ""), cols=2) | |
| 337 | + } | |
| 338 | + } | |
| 339 | + } | |
| 340 | +} | |
| 341 | + | |
| 342 | +readImageData <- function(data) { | |
| 343 | + examples <- list() | |
| 344 | + for (i in 1:nrow(data)) { | |
| 345 | + path <- data[i,1] | |
| 346 | + value <- data[i,2] | |
| 347 | + file <- unlist(strsplit(path, "[.]"))[1] | |
| 348 | + ext <- unlist(strsplit(path, "[.]"))[2] | |
| 349 | + if (ext == "jpg" || ext == "JPEG" || ext == "jpeg" || ext == "JPG") { | |
| 350 | + img <- readJPEG(path) | |
| 351 | + } else if (ext == "PNG" || ext == "png") { | |
| 352 | + img <- readPNG(path) | |
| 353 | + } else if (ext == "TIFF" || ext == "tiff" || ext == "TIF" || ext == "tif") { | |
| 354 | + img <- readTIFF(path) | |
| 355 | + }else { | |
| 356 | + next | |
| 357 | + } | |
| 358 | + example <- list(file = file, value = value, image = img) | |
| 359 | + examples[[i]] <- example | |
| 360 | + } | |
| 361 | + return(examples) | |
| 362 | +} | |
| 363 | + | |
| 364 | +plotImage <- function(image, title=NULL, label=NULL) { | |
| 365 | + p <- qplot(1:10, 1:10, geom="blank") + annotation_custom(rasterGrob(image$image), xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) | |
| 366 | + p <- p + theme(axis.line=element_blank(), axis.title.y=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), line=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) | |
| 367 | + p <- p + labs(title=title) + xlab(label) | |
| 368 | + return(p) | |
| 369 | +} | |
| 370 | + | ... | ... |