Adding main title to Bullet Graph - r

Can you suggest a way to add a main title to that graph? The gridBulletGraphV function can be found here.
ytd2005 <- data.frame(
measure=c("Revenue", "Profit", "Avg Order Size", "New Customers", "Cust Satisfaction"),
units=c("U.S. $ (1,000s)", "%", "U.S. $", "Count", "Top Rating of 5"),
low=c(150, 20, 350, 1400, 3.5),
mean=c(225, 25, 500, 2000, 4.25),
high=c(300, 30, 600, 2500, 5),
target=c(250, 26, 550, 2100, 4.2),
value=c(275, 22.5, 310, 1700, 4.5)
)
nticks <- c(7, 7, 7, 6, 7)
format <- c("s", "p", "s", "k", "s")
col1 <- c("#a5a7a9", "#c5c6c8", "#e6e6e7")
gridBulletGraphV(ytd2005, nticks=nticks, format=format, bcol=col1, font=11, scfont=9)

You can do that by changing the function. I added a ptitle="text" parameter to the function and added the following code just before for (i in 1:n) {:
# Title
vp <- viewport(layout.pos.row = 1)
pushViewport(vp)
grid.text(label = ptitle,
just = "centre",
gp = gpar(fontsize=font*1.5, col="black", fontface="bold"),
x = .5,
y = 0.1)
upViewport()
You can now call the function with:
gridBulletGraphV(ytd2005, nticks=nticks, format=format, bcol=col1, font=11,
scfont=9, ptitle="Plot Title")
which gives the following result:
The revised gridBulletGraphV function:
gridBulletGraphV <- function(bgData, nticks=3, format="s", bcol=c("red", "yellow", "green"), tcol="black", vcol="black", font=25, scfont=15, ptitle="text") {
# Data Prep
n <- nrow(bgData)
nam <- c("low", "mean", "high", "target", "value")
datMat <- as.matrix(bgData[, nam])
# Nticks/Format Prep
if (length(nticks) == 1) {
nticks <- rep(nticks, n)
}
if (length(format) == 1) {
format <- rep(format, n)
}
# Layout
hl <- rep(1, n + 2)
hu <- c("lines", rep("null", n), "lines")
layout <- grid.layout(4, n + 2, widths = unit(hl, hu),
heights = unit(c(1, 1, 5, 2), c("lines", "null", "null", "lines")))
# Set Layout
grid.newpage()
pushViewport(plotViewport(c(0, 0, 0, 0), layout = layout))
# Title
vp <- viewport(layout.pos.row = 1)
pushViewport(vp)
grid.text(label = ptitle,
just = "centre",
gp = gpar(fontsize=font*1.5, col="black", fontface="bold"),
x = .5,
y = 0.1)
upViewport()
for (i in 1:n) {
#
vp <- viewport(layout.pos.row = 3,
layout.pos.col = i+1)
pushViewport(vp)
# Sublayout
subLayout <- grid.layout(nrow = 1,
widths = unit(c(1, 2, 1), c("null", "null", "null")),
ncol = 3)
pushViewport(plotViewport(c(0, 0, 0, 0), layout=subLayout))
vp <- viewport(layout.pos.row = 1,
layout.pos.col = 2,
yscale = c(0, datMat[i, 3]))
pushViewport(vp)
# x-Axis Labels
# Formatierung Label
if (format[i] == "s") {
brks <- labels <- round(seq(0, datMat[i, 3], length=nticks[i]), 0)
} else if (format[i] == "p"){
brks <- labels <- round(seq(0, datMat[i, 3], length=nticks[i]), 0)
labels <- paste0(labels, "%")
} else if (format[i] == "k") {
brks <- labels <- round(seq(0, datMat[i, 3], length=nticks[i]), 0)
labels <- format(labels, digits=10, nsmall=0, decimal.mark=".", big.mark=",")
}
grid.yaxis(at=brks, label=labels, gp=gpar(fontsize=scfont, col="black", fontface="bold"))
grid.rect(y = c(0, datMat[i, 1:2]) / datMat[i, 3],
height = unit(diff(c(0, datMat[i, 1:3])), "native"),
x = rep(0.5, 3),
width = 1,
just = "bottom",
gp = gpar(fill=bcol, col=bcol))
grid.rect(y = c(0, datMat[i, 5]),
height = unit(diff(c(0, datMat[i, 5])), "native"),
x = 0.5,
width = 0.5,
gp = gpar(fill=vcol, col=vcol), just="bottom")
a <- datMat[i, 1] * 0.01
grid.rect(y = datMat[i, 4] / datMat[i, 3],
height = unit(a, "native"),
x = 0.5,
width = 0.8,
gp = gpar(fill=tcol, col=tcol), just="bottom")
upViewport(n=3)
# Annotation
pushViewport(plotViewport(c(0, 0, 0, 0), layout=layout))
vp <- viewport(layout.pos.row = 2,
layout.pos.col = i+1)
pushViewport(vp)
# Sublayout 1: Same layout as graph
subLayout <- grid.layout(nrow = 1,
ncol = 3,
widths = unit(c(1, 2, 1), c("null", "null", "null")))
pushViewport(plotViewport(c(0, 0, 0, 0), layout=subLayout))
vp <- viewport(layout.pos.row = 1,
layout.pos.col = 2)
pushViewport(vp)
# Sublayout 2: two rows of text; centred middle of graph
subLayout <- grid.layout(nrow = 3,
ncol = 1,
widths = unit(c(1, 1), c("null", "null")))
pushViewport(plotViewport(c(0, 0, 0, 0), layout=subLayout))
# First Text: Measure
vp <- viewport(layout.pos.row = 2,
layout.pos.col = 1)
pushViewport(vp)
grid.text(label = bgData$measure[i],
just = "bottom",
gp = gpar(fontsize=font, col="black", fontface="bold"),
x = .5,
y = 0.1)
upViewport()
# Second Text: Unit
vp <- viewport(layout.pos.row = 3,
layout.pos.col = 1)
pushViewport(vp)
grid.text(label = bgData$units[i],
just = "bottom",
gp = gpar(fontsize=font, col="black"),
x = .5,
y = .5)
upViewport(n=5)
}
}

Related

Draw only positive octant with rgl.sphere in R

I would like to display only the positive octant of a unit sphere. So far, using the rgl package in R, I could show the entire sphere. Is it possible to "truncate" it? I am open to any other package that does the trick.
# Fake data
norm_vec <- function(x) sqrt(sum(x ^ 2))
data <- data.frame(T3 = runif(100), T6 = runif(100), P4 = runif(100))
norms <- apply(data, 1, norm_vec)
data <- data / norms
cluster <- sample(1:6, 100, replace = T)
#' Initialize a rgl device
#'
#' #param new.device a logical value. If TRUE, creates a new device
#' #param bg the background color of the device
#' #param width the width of the device
rgl_init <- function(new.device = FALSE, bg = "white", width = 640) {
if( new.device | rgl.cur() == 0 ) {
rgl.open()
par3d(windowRect = 50 + c( 0, 0, width, width ) )
rgl.bg(color = bg )
}
rgl.clear(type = c("shapes", "bboxdeco"))
rgl.viewpoint(theta = 30, phi = 0, zoom = 0.90)
}
#' Get colors for the different levels of a factor variable
#'
#' #param groups a factor variable containing the groups of observations
#' #param colors a vector containing the names of the default colors to be used
get_colors <- function(groups, group.col = palette()){
groups <- as.factor(groups)
ngrps <- length(levels(groups))
if(ngrps > length(group.col))
group.col <- rep(group.col, ngrps)
color <- group.col[as.numeric(groups)]
names(color) <- as.vector(groups)
return(color)
}
# Setting colors according to the cluster column
my_cols <- get_colors(cluster, c("#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7"))
# Ploting sphere
rgl_init()
par3d(cex = 1.35)
plot3d(x = data[, "T3"], y = data[, "P4"], z = data[, "T6"],
type = "s", r = .04,
col = my_cols,
xlab = 'T3', ylab = 'P4', zlab = 'T6')
rgl.spheres(0, 0, 0, radius = 0.995, col = 'lightgray', alpha = 0.6, back = 'lines')
arc3d(c(1, 0, 0), c(0, 1, 0), c(0, 0, 0), radius = 1, lwd = 7.5, col = "black")
arc3d(c(1, 0, 0), c(0, 0, 1), c(0, 0, 0), radius = 1, lwd = 7.5, col = "black")
arc3d(c(0, 0, 1), c(0, 1, 0), c(0, 0, 0), radius = 1, lwd = 7.5, col = "black")
bbox3d(col = c("black", "black"),
xat = c(0, 0.5, 1), yat = c(0, 0.5, 1), zat = c(0, 0.5, 1),
polygon_offset = 1)
aspect3d(1, 1, 1)
You can use cliplanes3d() to do that. You should also avoid using any of the rgl.* functions; use the *3d alternatives instead unless you really know what you're doing. It's almost never a good idea to mix the two types.
For example:
# Fake data
norm_vec <- function(x) sqrt(sum(x ^ 2))
data <- data.frame(T3 = runif(100), T6 = runif(100), P4 = runif(100))
norms <- apply(data, 1, norm_vec)
data <- data / norms
cluster <- sample(1:6, 100, replace = T)
#' Initialize a rgl device
#'
#' #param new.device a logical value. If TRUE, creates a new device
#' #param bg the background color of the device
#' #param width the width of the device
rgl_init <- function(new.device = FALSE, bg = "white", width = 640) {
if( new.device || rgl.cur() == 0 ) {
open3d(windowRect = 50 + c( 0, 0, width, width ) )
bg3d(color = bg )
}
clear3d(type = c("shapes", "bboxdeco"))
view3d(theta = 30, phi = 0, zoom = 0.90)
}
#' Get colors for the different levels of a factor variable
#'
#' #param groups a factor variable containing the groups of observations
#' #param colors a vector containing the names of the default colors to be used
get_colors <- function(groups, group.col = palette()){
groups <- as.factor(groups)
ngrps <- length(levels(groups))
if(ngrps > length(group.col))
group.col <- rep(group.col, ngrps)
color <- group.col[as.numeric(groups)]
names(color) <- as.vector(groups)
return(color)
}
# Setting colors according to the cluster column
my_cols <- get_colors(cluster, c("#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7"))
# Ploting sphere
rgl_init()
par3d(cex = 1.35)
plot3d(x = data[, "T3"], y = data[, "P4"], z = data[, "T6"],
type = "s", r = .04,
col = my_cols,
xlab = 'T3', ylab = 'P4', zlab = 'T6')
spheres3d(0, 0, 0, radius = 0.995, col = 'lightgray', alpha = 0.6, back = 'lines')
arc3d(c(1, 0, 0), c(0, 1, 0), c(0, 0, 0), radius = 1, lwd = 7.5, col = "black")
arc3d(c(1, 0, 0), c(0, 0, 1), c(0, 0, 0), radius = 1, lwd = 7.5, col = "black")
arc3d(c(0, 0, 1), c(0, 1, 0), c(0, 0, 0), radius = 1, lwd = 7.5, col = "black")
bbox3d(col = c("black", "black"),
xat = c(0, 0.5, 1), yat = c(0, 0.5, 1), zat = c(0, 0.5, 1),
polygon_offset = 1)
aspect3d(1, 1, 1)
clipplanes3d(c(1,0,0), c(0,1,0), c(0,0,1), d=0)
This produces

What color does plot.xts use?

Does anybody know what colours plot.xts uses? I can't find anything on the help page.
I would like to use the same colours in my legend.
Or is there another way to get the same plot with addLegend()?
Here the code I am using:
library(xts)
library(PerformanceAnalytics)
library(TTR)
xts1 <- xts(matrix(rnorm(300), ncol = 3), order.by = as.Date(1:100))
xts2 <- xts(matrix(rnorm(300), ncol = 3), order.by = as.Date(1:100))
colnames(xts1) <- c("A", "B", "C")
colnames(xts2) <- c("A", "B", "C")
plot_chart <- function(x) {
ff <- tempfile()
png(filename = ff)
chart.CumReturns(x)
dev.off()
unlink(ff)
}
m <- matrix(c(1, 2, 3, 3), nrow = 2, ncol = 2, byrow = TRUE)
layout(mat = m, heights = c(0.8, 0.1))
par(mar = c(2, 2, 1, 1))
plot_chart(xts1)
addSeries(reclass(apply(xts1, 2, runSD), xts1))
par(mar = c(2, 2, 1, 1))
plot_chart(xts2)
addSeries(reclass(apply(xts2, 2, runSD), xts2))
par(mar=c(0, 0, 1, 0))
plot(1, type = "n", axes = FALSE, xlab = "", ylab = "")
# which colors do I have to insert in here?
plot_colors <- c("blue", "green", "pink")
legend(x = "top", inset = 0,
legend = colnames(xts1),
col = plot_colors, lwd = 7, cex = .7, horiz = TRUE)
Answer
Use the colorset argument of chart.CumReturns:
plot_chart <- function(x, col) {
ff <- tempfile()
png(filename = ff)
chart.CumReturns(x, colorset = col)
dev.off()
unlink(ff)
}
par(mar = c(2, 2, 1, 1))
plot_chart(xts1, col = plot_colors)
addSeries(reclass(apply(xts1, 2, runSD), xts1))
par(mar = c(2, 2, 1, 1))
plot_chart(xts2, col = plot_colors)
addSeries(reclass(apply(xts2, 2, runSD), xts2))

What pars to eliminate margin in a `png file` for the following R plot?

I was wondering given the R code for the plot below, how I can get a png file of this plot such that the plot fills all the image with no margin left?
What I have tried so far was playing with mar and oma with no success:
N = 20 ; df = N-1
par(oma = rep(0, 4), mar = rep(0, 4))
png("plot.png", width = 4, height = 5, units = "in", res = 500)
BB = curve( dt(x*sqrt(N), df)*sqrt(N), -1, 1, n = 1e4, xlab = "d",
ylab = NA, font = 2, font.lab = 2, type = "n", yaxt = "n", bty = "n", mgp = c(2, 1, -.5))
polygon(BB, col = rgb(1, 0, 0, .4), border = NA)
dev.off()
Finally, the following worked for me with the help of one of the colleagues from SO:
N = 20 ; df = N-1
par(oma = rep(0, 4), mar = c(2.5, .01, 0, .01), mgp = c(1.5, .3, 0), xpd = NA)
BB = curve( dt(x*sqrt(N), df)*sqrt(N), -1, 1, n = 1e4, xlab = "d",
ylab = NA, font = 2, font.lab = 4, type = "n", yaxt = "n",
bty = "n", cex.axis = .7, cex.lab = .9)
polygon(BB, col = rgb(1, 0, 0, .4), border = NA)
dev.copy(png, "plot.png", width = 2, height = 3, units = "in", res = 500)
dev.off()
dev.off()

hist3D 2D plot in background in R

Is it possible to add a 2d plot to a 3D plot in R?
I have the following R code that generates a 3d bar plot.
dt = structure(c(1, 1, 1, 3,
0, 2, 2, 1,
1, 2, 1, 3,
2, 6, 3, 1,
1, 2, 3, 0,
1, 0, 2, 1,
1,2,2,2), .Dim = c(4L, 7L), .Dimnames = list(c("0-50",
"51-60", "61-70", "71-80"
), c("0-50", "51-60", "61-70", "71-80", "81-90", "91-100", "101-Inf")))
m <- matrix(rep(seq(4),each=7), ncol=7, nrow=4, byrow = TRUE)
hist3D(x = 1:4, z = dt, scale = T,bty="g", phi=35,theta=30,border="black",space=0.15,col = jet.col(5, alpha = 0.8), add = F, colvar = m, colkey = F, ticktype = "detailed")
The hist3d call only:
hist3D(x = 1:4, z = dt, scale = T,bty="g", phi=35,theta=30, border="black", space=0.15,col = jet.col(5, alpha = 0.8), add = F, colvar = m, colkey = F, ticktype = "detailed")
This generates the following 3d plot:
What I'm looking for is being able to add a plot in the position where the grey grid is. Is it possible?
Thanks!
As far as I know, there isn't a good function to make a barplot in RGL. I suggest a manual method.
dt = structure(c(1, 1, 1, 3,
0, 2, 2, 1,
1, 2, 1, 3,
2, 6, 3, 1,
1, 2, 3, 0,
1, 0, 2, 1,
1,2,2,2), .Dim = c(4L, 7L), .Dimnames = list(c("0-50",
"51-60", "61-70", "71-80"
), c("0-50", "51-60", "61-70", "71-80", "81-90", "91-100", "101-Inf")))
Making 3D barplot in RGL
library(rgl)
# make dt xyz coordinates data
dt2 <- cbind( expand.grid(x = 1:4, y = 1:7), z = c(dt) )
# define each bar's width and depth
bar_w <- 1 * 0.85
bar_d <- 1 * 0.85
# make a base bar (center of undersurface is c(0,0,0), width = bar_w, depth = bar_d, height = 1)
base <- translate3d( scale3d( cube3d(), bar_w/2, bar_d/2, 1/2 ), 0, 0, 1/2 )
# make each bar data and integrate them
bar.list <- shapelist3d(
apply(dt2, 1, function(a) translate3d(scale3d(base, 1, 1, a[3]), a[1], a[2], 0)),
plot=F)
# set colors
for(i in seq_len(nrow(dt2))) bar.list[[i]]$material$col <- rep(jet.col(5)[c(1:3,5)], 7)[i]
open3d()
plot3d(0,0,0, type="n", xlab="x", ylab="y", zlab="z", box=F,
xlim=c(0.5, 4.5), ylim=c(0.5, 7.5), zlim=c(0, 6.2), aspect=T, expand=1)
shade3d(bar.list, alpha=0.8)
wire3d(bar.list, col="black")
light3d(ambient="black", diffuse="gray30", specular="black") # light up a little
Add a 2d plot
# show2d() uses 2d plot function's output as a texture
# If you need the same coordinates of 2d and 3d, plot3d(expand=1) and show2d(expand=1),
# the same xlims, equivalent plot3d(zlim) to 2d plot's ylim, 2d plot(xaxs="i", yaxs="i") are needed.
show2d({
par(mar = c(0,0,0,0))
barplot(c(3,4,5,6), yaxs="i", ylim=c(0, 6.2))
},
expand = 1 , face = "y+", texmipmap = F) # texmipmap=F makes tone clear

Combine lattice xyplot and histogram

Could someone help me please to upgrade my plot?
a) In the plot, there should be print only one y-scale per row.
b) To print a more comfortable legend, that means
1) change the order of symbols and description,
2) print line in the same x-position like superpose.symbols,
3) and print symbols for the histogram.
d1 <- data.frame(x=c(NA, 13:20, NA), y = 25, z = c(rep('march', 5),
rep("april", 5)), color = c(c(rep(c("red", "green"), 2), "red"),
c(rep(c("blue", "yellow"), 2), "blue")), stringsAsFactors = FALSE)
d2 <- data.frame(x=c(NA, 20:27, NA), y = 23, z = c(rep('may', 5),
rep("june", 5)), color = c(c(rep(c("blue", "red"), 2), "red"),
c(rep(c("blue", "yellow"), 2), "blue")), stringsAsFactors = FALSE)
d1<-rbind(d1,d2)
sup.sym <- trellis.par.get("superpose.symbol")
sup.sym$alpha<-c(1, 0, 0, 0, 0, 0, 0)
sup.sym$col<-c(1,2,3,4,5,6,7)
sup.lin <- trellis.par.get("superpose.line")
sup.lin$col<-c(1,2,7,5,5,6,7)
sup.lin$alpha<-c(0, 1, 1, 1, 0, 0, 0)
settings<-list(superpose.symbol = sup.sym,superpose.line = sup.lin)
xyplot(y ~ x | factor(z), data = d1
,ylim = list( c(22, 26),c(22, 26), c(0, 1),c(0, 1) )
,layout=c(2,2)
,scales = list(y = list( relation = "free" ))
,par.settings = settings
,auto.key = list(text = c("A","B","C", "D")
,space = "right"
,lines = TRUE
)
,panel = function(x, y, subscripts) {
if(panel.number()>2){
panel.histogram(x,breaks=3)
}else{
panel.xyplot(x = x, y = y,
subscripts=subscripts,
col = d1[subscripts, "color"])
}
})

Resources