Commit da6568e274fd1aee0da57a7141dd9c72f945fd2d

Authored by Josh Klontz
1 parent d9a2447c

introduced plot smooth argument to average over datasets

sdk/core/plot.cpp
... ... @@ -29,7 +29,6 @@
29 29 #include <QtAlgorithms>
30 30 #include <opencv2/core/core.hpp>
31 31 #include <assert.h>
32   -#include <openbr_plugin.h>
33 32  
34 33 #include "plot.h"
35 34 #include "version.h"
... ... @@ -40,9 +39,11 @@
40 39 #undef FAR // Windows preprecessor definition
41 40  
42 41 using namespace cv;
43   -using namespace br;
44 42  
45   -void br::Confusion(const QString &file, float score, int &true_positives, int &false_positives, int &true_negatives, int &false_negatives)
  43 +namespace br
  44 +{
  45 +
  46 +void Confusion(const QString &file, float score, int &true_positives, int &false_positives, int &true_negatives, int &false_negatives)
46 47 {
47 48 qDebug("Computing confusion matrix of %s at %f", qPrintable(file), score);
48 49  
... ... @@ -123,7 +124,7 @@ static float kernelDensityEstimation(const QList&lt;double&gt; &amp;vals, double x, double
123 124 return y / (vals.size() * h);
124 125 }
125 126  
126   -float br::Evaluate(const QString &simmat, const QString &mask, const QString &csv)
  127 +float Evaluate(const QString &simmat, const QString &mask, const QString &csv)
127 128 {
128 129 qDebug("Evaluating %s with %s", qPrintable(simmat), qPrintable(mask));
129 130  
... ... @@ -294,11 +295,21 @@ struct RPlot
294 295 QFile file;
295 296 QStringList pivotHeaders;
296 297 QVector< QSet<QString> > pivotItems;
297   - int majorIndex, minorIndex, majorSize, minorSize;
298   - QString majorHeader, minorHeader;
299 298 bool flip;
300 299  
301   - RPlot(QStringList files, const QString &destination, bool isEvalFormat = true)
  300 + struct Pivot
  301 + {
  302 + int index, size;
  303 + QString header;
  304 + bool smooth;
  305 + Pivot() : index(-1), size(0), smooth(false) {}
  306 + Pivot(int _index, int _size, const QString &_header)
  307 + : index(_index), size(_size), header(_header), smooth(false) {}
  308 + };
  309 +
  310 + Pivot major, minor;
  311 +
  312 + RPlot(QStringList files, const br::File &destination, bool isEvalFormat = true)
302 313 {
303 314 if (files.isEmpty()) qFatal("RPlot::RPlot() empty file list.");
304 315 qSort(files.begin(), files.end(), sortFiles);
... ... @@ -388,23 +399,25 @@ struct RPlot
388 399 file.write("\n"
389 400 "# Write figures\n");
390 401  
391   - majorIndex = -1, minorIndex = -1, majorSize = 0, minorSize = 0;
392 402 for (int i=0; i<pivotItems.size(); i++) {
393 403 const int size = pivotItems[i].size();
394   - if (size > majorSize) {
395   - minorIndex = majorIndex;
396   - minorSize = majorSize;
397   - majorIndex = i;
398   - majorSize = size;
399   - } else if (size > minorSize) {
400   - minorIndex = i;
401   - minorSize = size;
  404 + if (size > major.size) {
  405 + minor = major;
  406 + major = Pivot(i, size, pivotHeaders[i]);
  407 + } else if (size > minor.size) {
  408 + minor = Pivot(i, size, pivotHeaders[i]);
402 409 }
403 410 }
404 411  
405   - if (majorIndex != -1) majorHeader = pivotHeaders[majorIndex];
406   - if (minorIndex != -1) minorHeader = pivotHeaders[minorIndex];
407   - flip = minorHeader == "Algorithm";
  412 + const QString &smooth = destination.getString("smooth", "");
  413 + major.smooth = !smooth.isEmpty() && (major.header == smooth);
  414 + minor.smooth = !smooth.isEmpty() && (minor.header == smooth);
  415 + if (major.smooth) major.size = 1;
  416 + if (minor.smooth) minor.size = 1;
  417 + if (major.size < minor.size)
  418 + std::swap(major, minor);
  419 +
  420 + flip = minor.header == "Algorithm";
408 421 }
409 422  
410 423 bool finalize(bool show = false)
... ... @@ -424,74 +437,76 @@ struct RPlot
424 437 }
425 438 };
426 439  
427   -bool br::Plot(const QStringList &files, const QString &destination, bool show)
  440 +bool Plot(const QStringList &files, const br::File &destination, bool show)
428 441 {
429 442 qDebug("Plotting %d file(s) to %s", files.size(), qPrintable(destination));
430 443  
431 444 RPlot p(files, destination);
432 445  
433   - p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"line\"") +
434   - (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) +
435   - (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) +
  446 + p.file.write(qPrintable(QString("qplot(X, 1-Y, data=DET, geom=\"%1\"").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  447 + (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
  448 + (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
436 449 QString(", xlab=\"False Accept Rate\", ylab=\"True Accept Rate\") + theme_minimal()") +
437   - (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) +
438   - (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) +
  450 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
  451 + (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
439 452 QString(" + scale_x_log10() + scale_y_continuous(labels=percent)") +
440 453 QString("\nggsave(\"%1\")\n").arg(p.subfile("ROC"))));
441 454  
442   - p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"line\"") +
443   - (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) +
444   - (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) +
  455 + p.file.write(qPrintable(QString("qplot(X, Y, data=DET, geom=\"%1\"").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  456 + (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
  457 + (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
445 458 QString(", xlab=\"False Accept Rate\", ylab=\"False Reject Rate\") + geom_abline(alpha=0.5, colour=\"grey\", linetype=\"dashed\") + theme_minimal()") +
446   - (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) +
447   - (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) +
  459 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
  460 + (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
448 461 QString(" + scale_x_log10() + scale_y_log10()") +
449 462 QString("\nggsave(\"%1\")\n").arg(p.subfile("DET"))));
450 463  
451 464 p.file.write(qPrintable(QString("qplot(X, data=SD, geom=\"histogram\", fill=Y, position=\"identity\", alpha=I(1/2)") +
452   - QString(", xlab=\"Score%1\"").arg((p.flip ? p.majorSize : p.minorSize) > 1 ? " / " + (p.flip ? p.majorHeader : p.minorHeader) : QString()) +
453   - QString(", ylab=\"Frequency%1\"").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) +
  465 + QString(", xlab=\"Score%1\"").arg((p.flip ? p.major.size : p.minor.size) > 1 ? " / " + (p.flip ? p.major.header : p.minor.header) : QString()) +
  466 + QString(", ylab=\"Frequency%1\"").arg((p.flip ? p.minor.size : p.major.size) > 1 ? " / " + (p.flip ? p.minor.header : p.major.header) : QString()) +
454 467 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))") +
455   - (p.majorSize > 1 ? (p.minorSize > 1 ? QString(" + facet_grid(%2 ~ %1, scales=\"free\")").arg((p.flip ? p.majorHeader : p.minorHeader), (p.flip ? p.minorHeader : p.majorHeader)) : QString(" + facet_wrap(~ %1, scales = \"free\")").arg(p.majorHeader)) : QString()) +
  468 + (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()) +
456 469 QString(" + theme(aspect.ratio=1)") +
457 470 QString("\nggsave(\"%1\")\n").arg(p.subfile("SD"))));
458 471  
459   - p.file.write(qPrintable(QString("qplot(X, Y, data=CMC, geom=\"line\", xlab=\"Rank\", ylab=\"Retrieval Rate\"") +
460   - (p.majorSize > 1 ? QString(", colour=factor(%1)").arg(p.majorHeader) : QString()) +
461   - (p.minorSize > 1 ? QString(", linetype=factor(%1)").arg(p.minorHeader) : QString()) +
  472 + p.file.write(qPrintable(QString("qplot(X, Y, data=CMC, geom=\"%1\", xlab=\"Rank\", ylab=\"Retrieval Rate\"").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  473 + (p.major.size > 1 ? QString(", colour=factor(%1)").arg(p.major.header) : QString()) +
  474 + (p.minor.size > 1 ? QString(", linetype=factor(%1)").arg(p.minor.header) : QString()) +
462 475 QString(") + theme_minimal() + scale_x_continuous(limits = c(1,25), breaks = c(1,5,10,25))") +
463   - (p.majorSize > 1 ? getScale("colour", p.majorHeader, p.majorSize) : QString()) +
464   - (p.minorSize > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minorHeader) : QString()) +
  476 + (p.major.size > 1 ? getScale("colour", p.major.header, p.major.size) : QString()) +
  477 + (p.minor.size > 1 ? QString(" + scale_linetype_discrete(\"%1\")").arg(p.minor.header) : QString()) +
465 478 QString(" + scale_y_continuous(labels=percent)") +
466 479 QString("\nggsave(\"%1\")\n").arg(p.subfile("CMC"))));
467 480  
468   - p.file.write(qPrintable(QString("qplot(factor(%1), data=BC, geom=\"bar\", position=\"dodge\", weight=Y").arg(p.majorHeader) +
469   - (p.majorSize > 1 ? QString(", fill=factor(%1)").arg(p.majorHeader) : QString()) +
470   - QString(", xlab=\"%1False Accept Rate\"").arg(p.majorSize > 1 ? p.majorHeader + " / " : QString()) +
471   - QString(", ylab=\"True Accept Rate%1\") + theme_minimal()").arg(p.minorSize > 1 ? " / " + p.minorHeader : QString()) +
472   - (p.majorSize > 1 ? getScale("fill", p.majorHeader, p.majorSize) : QString()) +
473   - (p.minorSize > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minorHeader) : QString(" + facet_wrap(~ X)")) +
474   - QString(" + scale_y_continuous(labels=percent) + theme(legend.position=\"none\", axis.text.x=element_text(angle=-90, hjust=0)) + geom_text(data=BC, aes(label=Y, y=0.05))") +
  481 + p.file.write(qPrintable(QString("qplot(factor(%1)%2, data=BC, %3").arg(p.major.header, (p.major.smooth || p.minor.smooth) ? ", Y" : "", (p.major.smooth || p.minor.smooth) ? "geom=\"boxplot\"" : "geom=\"bar\", position=\"dodge\", weight=Y") +
  482 + (p.major.size > 1 ? QString(", fill=factor(%1)").arg(p.major.header) : QString()) +
  483 + QString(", xlab=\"%1False Accept Rate\"").arg(p.major.size > 1 ? p.major.header + " / " : QString()) +
  484 + QString(", ylab=\"True Accept Rate%1\") + theme_minimal()").arg(p.minor.size > 1 ? " / " + p.minor.header : QString()) +
  485 + (p.major.size > 1 ? getScale("fill", p.major.header, p.major.size) : QString()) +
  486 + (p.minor.size > 1 ? QString(" + facet_grid(%2 ~ X)").arg(p.minor.header) : QString(" + facet_wrap(~ X)")) +
  487 + 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))") +
475 488 QString("\nggsave(\"%1\")\n").arg(p.subfile("BC"))));
476 489  
477   - p.file.write(qPrintable(QString("qplot(X, Y, data=ERR, geom=\"line\", linetype=Error") +
478   - ((p.flip ? p.majorSize : p.minorSize) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.majorHeader : p.minorHeader) : QString()) +
479   - QString(", xlab=\"Score%1\", ylab=\"Error Rate\") + theme_minimal()").arg((p.flip ? p.minorSize : p.majorSize) > 1 ? " / " + (p.flip ? p.minorHeader : p.majorHeader) : QString()) +
480   - ((p.flip ? p.majorSize : p.minorSize) > 1 ? getScale("colour", p.flip ? p.majorHeader : p.minorHeader, p.flip ? p.majorSize : p.minorSize) : QString()) +
  490 + p.file.write(qPrintable(QString("qplot(X, Y, data=ERR, geom=\"%1\", linetype=Error").arg((p.major.smooth || p.minor.smooth) ? "smooth" : "line") +
  491 + ((p.flip ? p.major.size : p.minor.size) > 1 ? QString(", colour=factor(%1)").arg(p.flip ? p.major.header : p.minor.header) : QString()) +
  492 + QString(", xlab=\"Score%1\", ylab=\"Error Rate\") + theme_minimal()").arg((p.flip ? p.minor.size : p.major.size) > 1 ? " / " + (p.flip ? p.minor.header : p.major.header) : QString()) +
  493 + ((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()) +
481 494 QString(" + scale_y_log10()") +
482   - ((p.flip ? p.minorSize : p.majorSize) > 1 ? QString(" + facet_wrap(~ %1, scales=\"free_x\")").arg(p.flip ? p.minorHeader : p.majorHeader) : QString()) +
  495 + ((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()) +
483 496 QString(" + theme(aspect.ratio=1)") +
484 497 QString("\nggsave(\"%1\")\n").arg(p.subfile("ERR"))));
485 498  
486 499 return p.finalize(show);
487 500 }
488 501  
489   -bool br::PlotMetadata(const QStringList &files, const QString &columns, bool show)
  502 +bool PlotMetadata(const QStringList &files, const QString &columns, bool show)
490 503 {
491 504 qDebug("Plotting %d metadata file(s) for columns %s", files.size(), qPrintable(columns));
492 505  
493 506 RPlot p(files, "PlotMetadata", false);
494 507 foreach (const QString &column, columns.split(";"))
495   - p.file.write(qPrintable(QString("qplot(%1, %2, data=data, geom=\"violin\", fill=%1) + coord_flip() + theme_minimal()\nggsave(\"%2.pdf\")\n").arg(p.majorHeader, column)));
  508 + 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)));
496 509 return p.finalize(show);
497 510 }
  511 +
  512 +} // namespace br
... ...
sdk/core/plot.h
... ... @@ -20,13 +20,14 @@
20 20 #include <QPair>
21 21 #include <QString>
22 22 #include <QVector>
  23 +#include <openbr_plugin.h>
23 24  
24 25 namespace br
25 26 {
26 27  
27 28 void Confusion(const QString &file, float score, int &true_positives, int &false_positives, int &true_negatives, int &false_negatives);
28 29 float Evaluate(const QString &simmat, const QString &mask, const QString &csv = ""); // Returns TAR @ FAR = 0.01
29   -bool Plot(const QStringList &files, const QString &destination, bool show = false);
  30 +bool Plot(const QStringList &files, const br::File &destination, bool show = false);
30 31 bool PlotMetadata(const QStringList &files, const QString &destination, bool show = false);
31 32  
32 33 }
... ...