RInside Version 0.2.12
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
wtdensity.cpp
Go to the documentation of this file.
1 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8; -*-
2 //
3 // Wt usage example for RInside, inspired by the standard 'density sliders' example
4 //
5 // Copyright (C) 2011 Dirk Eddelbuettel and Romain Francois
6 //
7 // This file is licensed under GPL 2 or later, as are the rest of RInside and Rcpp
8 //
9 // Derived from hello.C in the Wt sources
10 // Copyright (C) 2008 Emweb bvba, Heverlee, Belgium.
11 
12 #include <cstdio>
13 
14 #include <Wt/WApplication>
15 #include <Wt/WBreak>
16 #include <Wt/WContainerWidget>
17 #include <Wt/WLineEdit>
18 #include <Wt/WPushButton>
19 #include <Wt/WText>
20 #include <Wt/WImage>
21 #include <Wt/WSpinBox>
22 #include <Wt/WGroupBox>
23 #include <Wt/WButtonGroup>
24 #include <Wt/WRadioButton>
25 #include <Wt/WHBoxLayout>
26 #include <Wt/WEnvironment>
27 #include <Wt/WFileResource>
28 
29 #include <RInside.h>
30 
31 using namespace Wt;
32 
33 class DensityApp : public WApplication {
34 public:
35  DensityApp(const WEnvironment& env, RInside & R);
36 
37 private:
38  WLineEdit *codeEdit_; // to edit the RNG draw expression
39  WButtonGroup *group_; // holds the radiobuttons
40  WSpinBox *spin_; // selects the density bandwidth
41  WImage *img_; // displays the image
42  WFileResource *imgfile_; // controls the file resources
43  WText *greeting_; // text label for status message
44 
45  void reportButton(); // called when new button selected
46  void reportEdit(); // called when RNG expression edited
47  void reportSpinner(); // called when bandwidth changed
48  void plot(); // to call R for new plot
49 
50  enum Kernel { Gaussian = 0, Epanechnikov = 1, Rectangular = 2,
51  Triangular = 3, Cosine = 4 };
52 
53  RInside & R_; // reference to embedded R instance
54  std::string tempfile_; // name of file used by R for plots
55  int bw_, kernel_; // parameters used to estimate the density
56  std::string cmd_; // random draw command string
57  Rcpp::NumericVector Yvec_; // the random draw
58 };
59 
60 // The env argument contains information about the new session, and the initial request.
61 // It must be passed to the WApplication // constructor so it is typically also an argument
62 // for your custom application constructor.
63 DensityApp::DensityApp(const WEnvironment& env, RInside & R) : WApplication(env), R_(R) {
64 
65  setTitle("Witty WebApp With RInside"); // application title
66 
67  setCssTheme("polished");
68  messageResourceBundle().use(appRoot() + "wtdensity");
69 
70  new WText(WString::tr("overview"), root());
71 
72  std::string tfcmd = "tfile <- tempfile(pattern=\"img\", tmpdir=\"/tmp\", fileext=\".png\")";
73  tempfile_ = Rcpp::as<std::string>(R_.parseEval(tfcmd)); // assign to 'tfile' in R, and report back
74  bw_ = 100;
75  kernel_ = 0; // parameters used to estimate the density
76  cmd_ = "c(rnorm(100,0,1), rnorm(50,5,1))"; // random draw command string
77 
78  new WText(WString::tr("user input"), root());
79  Wt::WContainerWidget *wc = new Wt::WContainerWidget(root());
80  wc->setStyleClass("box");
81 
82  Wt::WHBoxLayout *layout = new Wt::WHBoxLayout();
83  Wt::WContainerWidget *midbox = new Wt::WContainerWidget(root());
84  layout->addWidget(midbox);
85  Wt::WContainerWidget *container = new Wt::WContainerWidget(root());
86  layout->addWidget(container);
87 
88  wc->setLayout(layout, AlignTop | AlignJustify);
89 
90  midbox->addWidget(new WText("Density estimation scale factor (div. by 100)"));
91  midbox->addWidget(new WBreak()); // insert a line break
92  spin_ = new WSpinBox(midbox);
93  spin_->setRange(5, 200);
94  spin_->setValue(bw_);
95  spin_->valueChanged().connect(this, &DensityApp::reportSpinner);
96 
97  midbox->addWidget(new WBreak()); // insert a line break
98  midbox->addWidget(new WText("R Command for data generation")); // show some text
99  midbox->addWidget(new WBreak()); // insert a line break
100  codeEdit_ = new WLineEdit(midbox); // allow text input
101  codeEdit_->setTextSize(30);
102  codeEdit_->setText(cmd_);
103  codeEdit_->setFocus(); // give focus
104  codeEdit_->enterPressed().connect(this, &DensityApp::reportEdit);
105 
106  group_ = new Wt::WButtonGroup(container); // use button group to arrange radio buttons
107 
108  Wt::WRadioButton *button;
109  button = new Wt::WRadioButton("Gaussian", container);
110  new Wt::WBreak(container);
111  group_->addButton(button, Gaussian);
112 
113  button = new Wt::WRadioButton("Epanechnikov", container);
114  new Wt::WBreak(container);
115  group_->addButton(button, Epanechnikov);
116 
117  button = new Wt::WRadioButton("Rectangular", container);
118  new Wt::WBreak(container);
119  group_->addButton(button, Rectangular);
120 
121  button = new Wt::WRadioButton("Triangular", container);
122  new Wt::WBreak(container);
123  group_->addButton(button, Triangular);
124 
125  button = new Wt::WRadioButton("Cosine", container);
126  new Wt::WBreak(container);
127  group_->addButton(button, Cosine);
128 
129  group_->setCheckedButton(group_->button(kernel_));
130  group_->checkedChanged().connect(this, &DensityApp::reportButton);
131 
132  new WText(WString::tr("r result"), root());
133  Wt::WContainerWidget *botbox = new Wt::WContainerWidget(root());
134  botbox->setStyleClass("box");
135  imgfile_ = new Wt::WFileResource("image/png", tempfile_);
136  imgfile_->suggestFileName("density.png"); // name the clients sees of datafile
137  img_ = new Wt::WImage(imgfile_, "PNG version", botbox);
138 
139  new WText(WString::tr("browser info"), root());
140  Wt::WContainerWidget *stbox = new Wt::WContainerWidget(root());
141  stbox->setStyleClass("box");
142  greeting_ = new WText(stbox); // empty text
143  greeting_->setText("Setting up...");
144 
145  useStyleSheet("wtdensity.css"); // set our style sheet last
146 
147  reportEdit(); // create a new RNG draw in Yvec_
148  plot(); // and draw a new density plot
149 }
150 
152  kernel_ = group_->checkedId(); // get id of selected kernel
153  plot();
154 }
155 
157  cmd_ = codeEdit_->text().toUTF8(); // get text written in box, as UTF-8, assigned to string
158  std::string rng = "y2 <- " + cmd_ + "; y <- y2";
159  R_.parseEvalQNT(rng); // evaluates expression, assigns to 'y'
160  Yvec_ = R_["y"]; // cache the y vector
161  plot();
162 }
163 
165  bw_ = spin_->value(); // get the value of the spin selector
166  plot();
167 }
168 
170  const char *kernelstr[] = { "gaussian", "epanechnikov", "rectangular", "triangular", "cosine" };
171  greeting_->setText("Starting R call");
172  R_["tfile"] = tempfile_;
173  R_["bw"] = bw_;
174  R_["kernel"] = kernelstr[kernel_]; // passes the string to R
175  R_["y"] = Yvec_;
176  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: ";
177  std::string cmd1 = "\"); points(y, rep(0, length(y)), pch=16, col=rgb(0,0,0,1/4)); dev.off()";
178  std::string cmd = cmd0 + kernelstr[kernel_] + cmd1; // stick the selected kernel in the middle
179  R_.parseEvalQ(cmd); // evaluate command -- generates new density plot
180  imgfile_->setChanged(); // important: tells consumer that image has changed, forces refresh
181  greeting_->setText("Finished request from " + this->environment().clientAddress() + " using " + this->environment().userAgent()) ;
182 }
183 
184 WApplication *createApplication(const WEnvironment& env) {
185  // You could read information from the environment to decide whether
186  // the user has permission to start a new application
187  //
188  // We grab an instance of the embedded R. Note we can start only one,
189  // so resource conflicts have to be managed (eg add mutexes etc)
190  //
191  return new DensityApp(env, RInside::instance());
192 }
193 
194 int main(int argc, char **argv) {
195 
196  RInside R(argc, argv); // create the one embedded R instance
197 
198  // Your main method may set up some shared resources, but should then
199  // start the server application (FastCGI or httpd) that starts listening
200  // for requests, and handles all of the application life cycles.
201  //
202  // The last argument to WRun specifies the function that will instantiate
203  // new application objects. That function is executed when a new user surfs
204  // to the Wt application, and after the library has negotiated browser
205  // support. The function should return a newly instantiated application
206  // object.
207  return WRun(argc, argv, createApplication);
208 }
DensityApp(const WEnvironment &env, RInside &R)
Definition: wtdensity.cpp:63
WImage * img_
Definition: wtdensity.cpp:41
int main(int argc, char **argv)
Definition: wtdensity.cpp:194
void reportEdit()
Definition: wtdensity.cpp:156
WText * greeting_
Definition: wtdensity.cpp:43
Rcpp::NumericVector Yvec_
Definition: wtdensity.cpp:57
RInside & R_
Definition: wtdensity.cpp:53
void parseEvalQ(const std::string &line)
Definition: RInside.cpp:366
void reportSpinner()
Definition: wtdensity.cpp:164
std::string tempfile_
Definition: wtdensity.cpp:54
int parseEval(const std::string &line, SEXP &ans)
Definition: RInside.cpp:308
WSpinBox * spin_
Definition: wtdensity.cpp:40
void parseEvalQNT(const std::string &line)
Definition: RInside.cpp:374
std::string cmd_
Definition: wtdensity.cpp:56
static RInside & instance()
Definition: RInside.cpp:398
WFileResource * imgfile_
Definition: wtdensity.cpp:42
WApplication * createApplication(const WEnvironment &env)
Definition: wtdensity.cpp:184
WButtonGroup * group_
Definition: wtdensity.cpp:39
void reportButton()
Definition: wtdensity.cpp:151
void plot()
Definition: wtdensity.cpp:169
WLineEdit * codeEdit_
Definition: wtdensity.cpp:38