The following code uses Rook
to build a very simple webapp for plotting a stock candle chart built with ggplot2
. It follows the same pattern as the original example by Jeff Horner.
The error message I get in my RStudio when I execute the script is:
Warning Message: In Multipart$parse(env) : bad content body
Any ideas where I am going wrong and losing the image for my web page?
(Updated to assign my.plot <- ggplot
)
(Updated to include ggplot(plot=my.plot, ...)
)
require(Rook) # for web functionality
require(ggplot2) # for graphing
require(tseries) # used to grab time series from yahoo for stock symbols
require(plyr) # data tweaks
# define the web page form
newapp = function(env) {
req = Rook::Request$new(env)
res = Rook::Response$new()
res$write('What stock ticker would you like to see:\n')
res$write('<BR/>')
res$write('Stock Symbol:\n')
res$write('<form method="POST">\n')
res$write('<input type="text" name="stock.symbol" value="AAPL"> \n')
res$write('<form method="POST">\n')
res$write('<input type="radio" name="day.window" value="30">30 Days \n')
res$write('<input type="radio" name="day.window" value="60" checked>60 Days \n')
res$write('<input type="radio" name="day.window" value="90">90 Days \n')
res$write('<input type="submit" name="Go!">\n</form>\n<br>')
myNormalize = function (target) {
return((target - min(target))/(max(target) - min(target)))
}
if (!is.null(req$POST())) {
stock.symbol <- req$POST()[["stock.symbol"]]
day.window <- req$POST()[["day.window"]]
# get the stock data as a data frame
df <- as.data.frame(get.hist.quote(stock.symbol,start=as.character(Sys.Date() - as.numeric(day.window)),quote=c("Open", "High", "Low", "Close")))
# add an average and the top/bottom for the candle
df <- mutate(df, Average =(High + Low + Close)/3, Bottom = pmin(Open, Close), Top = pmax(Open, Close), Open.to.Close = ifelse(sign(Open - Close) == 1,'Increase','Decrease'), Date = row.names(df), Date.Label = ifelse(weekdays(as.Date(row.names(df))) == 'Friday',row.names(df),'')) # this gets the date from row.names into a column
# create a box plot
my.plot <- ggplot(data=df, aes(x=Date, lower=Bottom, upper=Top, middle=Average, ymin=Low, ymax=High, color=Open.to.Close, fill=Open.to.Close), xlab='Date', ylab='Price') +
geom_boxplot(stat='identity') +
# add the line for average price from HCL
geom_line(data=df, aes(x=Date,y=Average, group=0), color='black') +
# tweak the labeling
opts(axis.text.x = theme_text(angle=270), legend.position = 'top', legend.direction='horizontal') +
scale_x_discrete(labels=df$Date.Label)
ggsave(plot=my.plot, paste("/tmp/pic", stock.symbol, day.window, ".png", sep = ""))
res$write(paste(day.window,' days stock price trend for ',stock.symbol,'<BR/>', sep=''))
res$write(paste("<img src='", s$full_url("pic"), stock.symbol, day.window, ".png'", " />", sep = ""))
}
res$finish()
}
s = Rhttpd$new()
s$add(app = newapp, name = "visbin")
s$add(app = File$new("/tmp"), name = "pic")
s$start()
s$browse("visbin")
I have solved this, after much trial and error, by setting up a directory called pic
at the same level of the R
script and saving the images into it, then retrieving the charts from that location. I am not sure if the problem is a permissions issue on the /tmp
directory or just a result of the way the img src
attribute was constructed, but anyway the solution below has none of those problems.
While the code below works, the Warning
about the content still appears, but it does not seem to stop the script from working and still allows new queries to be made in succession, and new images to be viewed.
library(Rook) # for web functionality
library(ggplot2) # for graphing
library(tseries) # used to grab time series from yahoo for stock symbols
library(plyr) # data tweaks
PIC.DIR = paste(getwd(), 'pic', sep='/')
# define the web page form
newapp = function(env) {
req = Rook::Request$new(env)
res = Rook::Response$new()
if (!is.null(req$POST())) {
stock.symbol <- req$POST()[["stock.symbol"]]
day.window <- req$POST()[["day.window"]]
} else {
stock.symbol <- 'AAPL'
day.window <- 60
}
res$write('What stock ticker would you like to see:\n')
res$write('<BR/>')
res$write('Stock Symbol:\n')
res$write('<form method="POST">\n')
stock.input <- paste('<input type="text" name="stock.symbol" value="',
stock.symbol,
'">\n', sep='')
res$write( stock.input )
res$write('<form method="POST">\n')
res$write('<input type="radio" name="day.window" value="30">30 Days \n')
res$write('<input type="radio" name="day.window" value="60" checked>60 Days \n')
res$write('<input type="radio" name="day.window" value="90">90 Days \n')
res$write('<input type="submit" name="Go!">\n</form>\n<br>')
myNormalize = function (target) {
return((target - min(target))/(max(target) - min(target)))
}
if (!is.null(req$POST())) {
# get the stock data as a data frame
df <- as.data.frame(get.hist.quote(stock.symbol,start=as.character(Sys.Date() - as.numeric(day.window)),quote=c("Open", "High", "Low", "Close")))
# add an average and the top/bottom for the candle
df <- mutate(df, Average =(High + Low + Close)/3, Bottom = pmin(Open, Close), Top = pmax(Open, Close), Open.to.Close = ifelse(sign(Open - Close) == 1,'Increase','Decrease'), Date = row.names(df), Date.Label = ifelse(weekdays(as.Date(row.names(df))) == 'Friday',row.names(df),'')) # this gets the date from row.names into a column
# create a box plot
my.plot <- ggplot(data=df, aes(x=Date, lower=Bottom, upper=Top, middle=Average, ymin=Low, ymax=High, color=Open.to.Close, fill=Open.to.Close), xlab='Date', ylab='Price') +
geom_boxplot(stat='identity') +
# add the line for average price from HCL
geom_line(data=df, aes(x=Date,y=Average, group=0), color='black') +
# tweak the labeling
opts(axis.text.x = theme_text(angle=270), legend.position = 'top', legend.direction='horizontal') +
scale_x_discrete(labels=df$Date.Label)
ggsave(plot=my.plot, paste(PIC.DIR, "/pic", stock.symbol, day.window, ".png", sep = ""))
res$write(paste(day.window,' days stock price trend for ',stock.symbol,'<BR/>', sep=''))
res$write(paste("<img src='",
s$full_url("pic"),
'/pic', stock.symbol, day.window, ".png'",
"width='650 px' height='650 px' />", sep = ""))
}
res$finish()
}
s = Rhttpd$new()
s$add(app = newapp, name = "visbin")
s$add(app = File$new(PIC.DIR), name = "pic")
s$start()
s$browse("visbin")
I hope this helps, and maybe someone can work out what the warning is about. My theory is that it has to do with the headers beng formulated by Rook
or with the fact that the HTML being pulled served is not valid. Since I have solved the core problem, I have somehow lost energy to chase those theories...