|
RInside Version 0.2.10
|
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 }