RInside Version 0.2.10
inst/examples/qt/qtdensity.cpp
Go to the documentation of this file.
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
00002 //
00003 // Qt usage example for RInside, inspired by the standard 'density
00004 // sliders' example for other GUI toolkits -- this time with SVG
00005 //
00006 // Copyright (C) 2011  Dirk Eddelbuettel and Romain Francois
00007 
00008 #include <QtGui>
00009 
00010 #include "qtdensity.h"
00011 
00012 QtDensity::QtDensity(RInside & R) : m_R(R)
00013 {
00014     m_bw = 100;                 // initial bandwidth, will be scaled by 100 so 1.0
00015     m_kernel = 0;               // initial kernel: gaussian
00016     m_cmd = "c(rnorm(100,0,1), rnorm(50,5,1))"; // simple mixture
00017     m_R["bw"] = m_bw;           // pass bandwidth to R, and have R compute a temp.file name
00018     m_tempfile = QString::fromStdString(Rcpp::as<std::string>(m_R.parseEval("tfile <- tempfile()")));
00019     m_svgfile = QString::fromStdString(Rcpp::as<std::string>(m_R.parseEval("sfile <- tempfile()")));
00020     setupDisplay();
00021 }
00022 
00023 void QtDensity::setupDisplay(void)  {
00024     QWidget *window = new QWidget;
00025     window->setWindowTitle("Qt and RInside demo: density estimation");
00026 
00027     QSpinBox *spinBox = new QSpinBox;
00028     QSlider *slider = new QSlider(Qt::Horizontal);
00029     spinBox->setRange(5, 200);
00030     slider->setRange(5, 200);
00031     QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int)));
00032     QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int)));
00033     spinBox->setValue(m_bw);
00034     QObject::connect(spinBox, SIGNAL(valueChanged(int)), this, SLOT(getBandwidth(int)));
00035 
00036     QLabel *cmdLabel = new QLabel("R command for random data creation");
00037     QLineEdit *cmdEntry = new QLineEdit(m_cmd);
00038     QObject::connect(cmdEntry,  SIGNAL(textEdited(QString)), this, SLOT(getRandomDataCmd(QString)));
00039     QObject::connect(cmdEntry,  SIGNAL(editingFinished()), this, SLOT(runRandomDataCmd()));
00040 
00041     QGroupBox *kernelRadioBox = new QGroupBox("Density Estimation kernel");
00042     QRadioButton *radio1 = new QRadioButton("&Gaussian");
00043     QRadioButton *radio2 = new QRadioButton("&Epanechnikov");
00044     QRadioButton *radio3 = new QRadioButton("&Rectangular");
00045     QRadioButton *radio4 = new QRadioButton("&Triangular");
00046     QRadioButton *radio5 = new QRadioButton("&Cosine");
00047     radio1->setChecked(true);
00048     QVBoxLayout *vbox = new QVBoxLayout;
00049     vbox->addWidget(radio1);
00050     vbox->addWidget(radio2);
00051     vbox->addWidget(radio3);
00052     vbox->addWidget(radio4);
00053     vbox->addWidget(radio5);
00054     kernelRadioBox->setMinimumSize(260,140);
00055     kernelRadioBox->setMaximumSize(260,140);
00056     kernelRadioBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00057     kernelRadioBox->setLayout(vbox);
00058 
00059     QButtonGroup *kernelGroup = new QButtonGroup;
00060     kernelGroup->addButton(radio1, 0);
00061     kernelGroup->addButton(radio2, 1);
00062     kernelGroup->addButton(radio3, 2);
00063     kernelGroup->addButton(radio4, 3);
00064     kernelGroup->addButton(radio5, 4);
00065     QObject::connect(kernelGroup, SIGNAL(buttonClicked(int)), this, SLOT(getKernel(int)));
00066 
00067     m_svg = new QSvgWidget();
00068     runRandomDataCmd();         // also calls plot()
00069 
00070     QGroupBox *estimationBox = new QGroupBox("Density estimation bandwidth (scaled by 100)");
00071     QHBoxLayout *spinners = new QHBoxLayout;
00072     spinners->addWidget(spinBox);
00073     spinners->addWidget(slider);
00074     QVBoxLayout *topright = new QVBoxLayout;
00075     topright->addLayout(spinners);
00076     topright->addWidget(cmdLabel);
00077     topright->addWidget(cmdEntry);
00078     estimationBox->setMinimumSize(360,140);
00079     estimationBox->setMaximumSize(360,140);
00080     estimationBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
00081     estimationBox->setLayout(topright);
00082     QHBoxLayout *upperlayout = new QHBoxLayout;
00083     upperlayout->addWidget(kernelRadioBox);
00084     upperlayout->addWidget(estimationBox);
00085 
00086     QHBoxLayout *lowerlayout = new QHBoxLayout;
00087     lowerlayout->addWidget(m_svg);
00088 
00089     QVBoxLayout *outer = new QVBoxLayout;
00090     outer->addLayout(upperlayout);
00091     outer->addLayout(lowerlayout);
00092     window->setLayout(outer);
00093     window->show();
00094 }
00095 
00096 void QtDensity::plot(void) {
00097     const char *kernelstrings[] = { "gaussian", "epanechnikov", "rectangular", "triangular", "cosine" };
00098     m_R["bw"] = m_bw;
00099     m_R["kernel"] = kernelstrings[m_kernel]; // that passes the string to R
00100     std::string cmd0 = "svg(width=6,height=6,pointsize=10,filename=tfile); ";
00101     std::string cmd1 = "plot(density(y, bw=bw/100, kernel=kernel), xlim=range(y)+c(-2,2), main=\"Kernel: ";
00102     std::string cmd2 = "\"); points(y, rep(0, length(y)), pch=16, col=rgb(0,0,0,1/4));  dev.off()";
00103     std::string cmd = cmd0 + cmd1 + kernelstrings[m_kernel] + cmd2; // stick the selected kernel in the middle
00104     m_R.parseEvalQ(cmd);
00105     filterFile();               // we need to simplify the svg file for display by Qt 
00106     m_svg->load(m_svgfile);
00107 }
00108 
00109 void QtDensity::getBandwidth(int bw) {
00110     if (bw != m_bw) {
00111         m_bw = bw;
00112         plot();
00113     }
00114 }
00115 
00116 void QtDensity::getKernel(int kernel) {
00117     if (kernel != m_kernel) {
00118         m_kernel = kernel;
00119         plot();
00120     }
00121 }
00122 
00123 void QtDensity::getRandomDataCmd(QString txt) {
00124     m_cmd = txt;
00125 }
00126 
00127 void QtDensity::runRandomDataCmd(void) {
00128     std::string cmd = "y2 <- " + m_cmd.toStdString() + "; y <- y2";
00129     m_R.parseEvalQNT(cmd);
00130     plot();                     // after each random draw, update plot with estimate
00131 }
00132 
00133 void QtDensity::filterFile() {
00134     // cairoDevice creates richer SVG than Qt can display
00135     // but per Michaele Lawrence, a simple trick is to s/symbol/g/ which we do here
00136     QFile infile(m_tempfile);
00137     infile.open(QFile::ReadOnly);
00138     QFile outfile(m_svgfile);
00139     outfile.open(QFile::WriteOnly | QFile::Truncate);
00140     
00141     QTextStream in(&infile);
00142     QTextStream out(&outfile);
00143     QRegExp rx1("<symbol"); 
00144     QRegExp rx2("</symbol");    
00145     while (!in.atEnd()) {
00146         QString line = in.readLine();
00147         line.replace(rx1, "<g"); // so '<symbol' becomes '<g ...'
00148         line.replace(rx2, "</g");// and '</symbol becomes '</g'
00149         out << line << "\n";
00150     }
00151     infile.close();
00152     outfile.close();
00153 }
 All Classes Files Functions Variables Enumerations Enumerator Defines