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