|
RInside Version 0.2.6
|
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8; -*- 00002 // 00003 // Wt usage example for RInside, inspired by the standard 'density sliders' example 00004 // 00005 // Copyright (C) 2011 Dirk Eddelbuettel and Romain Francois 00006 // 00007 // This file is licensed under GPL 2 or later, as are the rest of RInside and Rcpp 00008 // 00009 // Derived from hello.C in the Wt sources 00010 // Copyright (C) 2008 Emweb bvba, Heverlee, Belgium. 00011 00012 #include <cstdio> 00013 00014 #include <Wt/WApplication> 00015 #include <Wt/WBreak> 00016 #include <Wt/WContainerWidget> 00017 #include <Wt/WLineEdit> 00018 #include <Wt/WPushButton> 00019 #include <Wt/WText> 00020 #include <Wt/WImage> 00021 #include <Wt/WSpinBox> 00022 #include <Wt/WGroupBox> 00023 #include <Wt/WButtonGroup> 00024 #include <Wt/WRadioButton> 00025 #include <Wt/WHBoxLayout> 00026 #include <Wt/WEnvironment> 00027 #include <Wt/WFileResource> 00028 00029 #include <RInside.h> 00030 00031 using namespace Wt; 00032 00033 class DensityApp : public WApplication { 00034 public: 00035 DensityApp(const WEnvironment& env, RInside & R); 00036 00037 private: 00038 WLineEdit *codeEdit_; // to edit the RNG draw expression 00039 WButtonGroup *group_; // holds the radiobuttons 00040 WSpinBox *spin_; // selects the density bandwidth 00041 WImage *img_; // displays the image 00042 WFileResource *imgfile_; // controls the file resources 00043 WText *greeting_; // text label for status message 00044 00045 void reportButton(); // called when new button selected 00046 void reportEdit(); // called when RNG expression edited 00047 void reportSpinner(); // called when bandwidth changed 00048 void plot(); // to call R for new plot 00049 00050 enum Kernel { Gaussian = 0, Epanechnikov = 1, Rectangular = 2, 00051 Triangular = 3, Cosine = 4 }; 00052 00053 RInside & R_; // reference to embedded R instance 00054 std::string tempfile_; // name of file used by R for plots 00055 int bw_, kernel_; // parameters used to estimate the density 00056 std::string cmd_; // random draw command string 00057 Rcpp::NumericVector Yvec_; // the random draw 00058 }; 00059 00060 // The env argument contains information about the new session, and the initial request. 00061 // It must be passed to the WApplication // constructor so it is typically also an argument 00062 // for your custom application constructor. 00063 DensityApp::DensityApp(const WEnvironment& env, RInside & R) : WApplication(env), R_(R) { 00064 00065 setTitle("Witty WebApp With RInside"); // application title 00066 00067 std::string tfcmd = "tfile <- tempfile(pattern=\"img\", tmpdir=\"/tmp\", fileext=\".png\")"; 00068 tempfile_ = Rcpp::as<std::string>(R_.parseEval(tfcmd)); // assign to 'tfile' in R, and report back 00069 bw_ = 100; 00070 kernel_ = 0; // parameters used to estimate the density 00071 cmd_ = "c(rnorm(100,0,1), rnorm(50,5,1))"; // random draw command string 00072 00073 Wt::WGroupBox *wc = new Wt::WGroupBox("Density Estimation", root()); 00074 00075 Wt::WHBoxLayout *layout = new Wt::WHBoxLayout(); 00076 Wt::WContainerWidget *midbox = new Wt::WContainerWidget(root()); 00077 layout->addWidget(midbox); 00078 Wt::WContainerWidget *container = new Wt::WContainerWidget(root()); 00079 layout->addWidget(container); 00080 00081 wc->setLayout(layout, AlignTop | AlignJustify); 00082 00083 midbox->addWidget(new WText("Density estimation scale factor (div. by 100)")); 00084 midbox->addWidget(new WBreak()); // insert a line break 00085 spin_ = new WSpinBox(midbox); 00086 spin_->setRange(5, 200); 00087 spin_->setValue(bw_); 00088 spin_->valueChanged().connect(this, &DensityApp::reportSpinner); 00089 00090 midbox->addWidget(new WBreak()); // insert a line break 00091 midbox->addWidget(new WText("R Command for data generation")); // show some text 00092 midbox->addWidget(new WBreak()); // insert a line break 00093 codeEdit_ = new WLineEdit(midbox); // allow text input 00094 codeEdit_->setTextSize(30); 00095 codeEdit_->setText(cmd_); 00096 codeEdit_->setFocus(); // give focus 00097 codeEdit_->enterPressed().connect(this, &DensityApp::reportEdit); 00098 00099 group_ = new Wt::WButtonGroup(container); // use button group to arrange radio buttons 00100 00101 Wt::WRadioButton *button; 00102 button = new Wt::WRadioButton("Gaussian", container); 00103 new Wt::WBreak(container); 00104 group_->addButton(button, Gaussian); 00105 00106 button = new Wt::WRadioButton("Epanechnikov", container); 00107 new Wt::WBreak(container); 00108 group_->addButton(button, Epanechnikov); 00109 00110 button = new Wt::WRadioButton("Rectangular", container); 00111 new Wt::WBreak(container); 00112 group_->addButton(button, Rectangular); 00113 00114 button = new Wt::WRadioButton("Triangular", container); 00115 new Wt::WBreak(container); 00116 group_->addButton(button, Triangular); 00117 00118 button = new Wt::WRadioButton("Cosine", container); 00119 new Wt::WBreak(container); 00120 group_->addButton(button, Cosine); 00121 00122 group_->setCheckedButton(group_->button(kernel_)); 00123 group_->checkedChanged().connect(this, &DensityApp::reportButton); 00124 00125 Wt::WGroupBox *botbox = new Wt::WGroupBox("Resulting chart", root()); 00126 imgfile_ = new Wt::WFileResource("image/png", tempfile_); 00127 imgfile_->suggestFileName("density.png"); // name the clients sees of datafile 00128 img_ = new Wt::WImage(imgfile_, "PNG version", botbox); 00129 00130 Wt::WGroupBox *stbox = new Wt::WGroupBox("Status", root()); 00131 greeting_ = new WText(stbox); // empty text 00132 greeting_->setText("Setting up..."); 00133 00134 reportEdit(); // create a new RNG draw in Yvec_ 00135 plot(); // and draw a new density plot 00136 } 00137 00138 void DensityApp::reportButton() { 00139 kernel_ = group_->checkedId(); // get id of selected kernel 00140 plot(); 00141 } 00142 00143 void DensityApp::reportEdit() { 00144 cmd_ = codeEdit_->text().toUTF8(); // get text written in box, as UTF-8, assigned to string 00145 std::string rng = "y <- " + cmd_ + ";"; 00146 R_.parseEvalQ(rng); // evaluates expression, assigns to 'y' 00147 Yvec_ = R_["y"]; // cache the y vector 00148 plot(); 00149 } 00150 00151 void DensityApp::reportSpinner() { 00152 bw_ = spin_->value(); // get the value of the spin selector 00153 plot(); 00154 } 00155 00156 void DensityApp::plot() { 00157 const char *kernelstr[] = { "gaussian", "epanechnikov", "rectangular", "triangular", "cosine" }; 00158 greeting_->setText("Starting R call"); 00159 R_["tfile"] = tempfile_; 00160 R_["bw"] = bw_; 00161 R_["kernel"] = kernelstr[kernel_]; // passes the string to R 00162 R_["y"] = Yvec_; 00163 std::string cmd0 = "png(filename=tfile,width=600,height=400); plot(density(y, bw=bw/100, kernel=kernel), xlim=range(y)+c(-2,2), main=\"Kernel: "; 00164 std::string cmd1 = "\"); points(y, rep(0, length(y)), pch=16, col=rgb(0,0,0,1/4)); dev.off()"; 00165 std::string cmd = cmd0 + kernelstr[kernel_] + cmd1; // stick the selected kernel in the middle 00166 R_.parseEvalQ(cmd); // evaluate command -- generates new density plot 00167 imgfile_->setChanged(); // important: tells consumer that image has changed, forces refresh 00168 greeting_->setText("Finished request from " + this->environment().clientAddress() + " using " + this->environment().userAgent()) ; 00169 } 00170 00171 WApplication *createApplication(const WEnvironment& env) { 00172 // You could read information from the environment to decide whether 00173 // the user has permission to start a new application 00174 // 00175 // We grab an instance of the embedded R. Note we can start only one, 00176 // so resource conflicts have to be managed (eg add mutexes etc) 00177 // 00178 return new DensityApp(env, RInside::instance()); 00179 } 00180 00181 int main(int argc, char **argv) { 00182 00183 RInside R(argc, argv); // create the one embedded R instance 00184 00185 // Your main method may set up some shared resources, but should then 00186 // start the server application (FastCGI or httpd) that starts listening 00187 // for requests, and handles all of the application life cycles. 00188 // 00189 // The last argument to WRun specifies the function that will instantiate 00190 // new application objects. That function is executed when a new user surfs 00191 // to the Wt application, and after the library has negotiated browser 00192 // support. The function should return a newly instantiated application 00193 // object. 00194 return WRun(argc, argv, createApplication); 00195 }