Draw only positive octant with rgl.sphere in R - 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

Related

Create faceted xy scatters using vectors of column names in R

I have two character vectors of equal length; where position one in vector.x matches position one in vector.y and so on. The elements refer to column names in a data frame (wide format). I would like to somehow loop through these vectors to produce xy scatter graphs for each pair in the vector, preferably in a faceted plot. Here is a (hopefully) reproducible example. To be clear, with this example, I would end up with 10 scatter graphs.
vector.x <- c("Aplanochytrium", "Aplanochytrium", "Aplanochytrium", "Aplanochytrium", "Aplanochytrium", "Bathycoccus", "Brockmanniella", "Brockmanniella", "Caecitellus_paraparvulus", "Caecitellus_paraparvulus")
vector.y <- c("Aliiroseovarius", "Neptuniibacter", "Pseudofulvibacter", "Thalassobius", "unclassified_Porticoccus", "Tenacibaculum", "Pseudomonas", "unclassified_GpIIa", "Marinobacter", "Thalassobius")
structure(list(Aliiroseovarius = c(0, 0, 0, 0.00487132352941176,
0.0108639420589757), Marinobacter = c(0, 0.00219023779724656,
0, 0.00137867647058824, 0.00310398344542162), Neptuniibacter = c(0.00945829750644884,
0.00959532749269921, 0.0171310629514964, 0.2796875, 0.345835488877393
), Pseudofulvibacter = c(0, 0, 0, 0.00284926470588235, 0.00362131401965856
), Pseudomonas = c(0.00466773123694878, 0.00782227784730914,
0.0282765737874097, 0.00707720588235294, 0.00400931195033627),
Tenacibaculum = c(0, 0, 0, 0.00505514705882353, 0.00362131401965856
), Thalassobius = c(0, 0.00166875260742595, 0, 0.0633272058823529,
0.147697878944646), unclassified_GpIIa = c(0, 0.000730079265748853,
0, 0.003125, 0.00103466114847387), unclassified_Porticoccus = c(0,
0, 0, 0.00119485294117647, 0.00569063631660631), Aplanochytrium = c(0,
0, 0, 0.000700770847932726, 0.0315839846865529), Bathycoccus = c(0.000388802488335925,
0, 0, 0.0227750525578136, 0.00526399744775881), Brockmanniella = c(0,
0.00383141762452107, 0, 0.000875963559915907, 0), Caecitellus_paraparvulus = c(0,
0, 0, 0.000875963559915907, 0.00797575370872547)), row.names = c("B11",
"B13", "B22", "DI5", "FF6"), class = "data.frame")
As Rui Barradas shows, it's possible to get a very nice plot from ggplot and gridExta. If you wanted to stick to base R, here's how you'd do that (assuming your data set is called df1):
# set plot sizes
par(mfcol = c(floor(sqrt(length(vector.x))), ceiling(sqrt(length(vector.x)))))
# loop through plots
for (i in 1:length(vector.x)) {
plot(df1[[vector.x[i]]], df1[[vector.y[i]]], xlab = vector.x[i], ylab = vector.y[i])
}
# reset plot size
par(mfcol = c(1,1))
This is a bit long and convoluted but it works.
library(tidyverse)
library(gridExtra)
df_list <- apply(data.frame(vector.x, vector.y), 1, function(x){
DF <- df1[which(names(df1) %in% x)]
i <- which(names(DF) %in% vector.x)
if(i == 2) DF[2:1] else DF
})
gg_list <- lapply(df_list, function(DF){
ggplot(DF, aes(x = get(names(DF)[1]), y = get(names(DF)[2]))) +
geom_point() +
xlab(label = names(DF)[1]) +
ylab(label = names(DF)[2])
})
g <- do.call(grid.arrange, gg_list)
g
Not too elegant, but should get you going:
vector.x <- c("Aplanochytrium", "Aplanochytrium", "Aplanochytrium", "Aplanochytrium", "Aplanochytrium", "Bathycoccus", "Brockmanniella", "Brockmanniella", "Caecitellus_paraparvulus", "Caecitellus_paraparvulus")
vector.y <- c("Aliiroseovarius", "Neptuniibacter", "Pseudofulvibacter", "Thalassobius", "unclassified_Porticoccus", "Tenacibaculum", "Pseudomonas", "unclassified_GpIIa", "Marinobacter", "Thalassobius")
df1 = structure(
list(Aliiroseovarius = c(0, 0, 0, 0.00487132352941176, 0.0108639420589757),
Marinobacter = c(0, 0.00219023779724656, 0, 0.00137867647058824, 0.00310398344542162),
Neptuniibacter = c(0.00945829750644884, 0.00959532749269921, 0.0171310629514964, 0.2796875, 0.345835488877393),
Pseudofulvibacter = c(0, 0, 0, 0.00284926470588235, 0.00362131401965856),
Pseudomonas = c(0.00466773123694878, 0.00782227784730914, 0.0282765737874097, 0.00707720588235294, 0.00400931195033627),
Tenacibaculum = c(0, 0, 0, 0.00505514705882353, 0.00362131401965856),
Thalassobius = c(0, 0.00166875260742595, 0, 0.0633272058823529, 0.147697878944646),
unclassified_GpIIa = c(0, 0.000730079265748853, 0, 0.003125, 0.00103466114847387),
unclassified_Porticoccus = c(0, 0, 0, 0.00119485294117647, 0.00569063631660631),
Aplanochytrium = c(0, 0, 0, 0.000700770847932726, 0.0315839846865529),
Bathycoccus = c(0.000388802488335925, 0, 0, 0.0227750525578136, 0.00526399744775881),
Brockmanniella = c(0, 0.00383141762452107, 0, 0.000875963559915907, 0),
Caecitellus_paraparvulus = c(0, 0, 0, 0.000875963559915907, 0.00797575370872547)),
row.names = c("B11", "B13", "B22", "DI5", "FF6"),
class = "data.frame"
)
df2 = NULL
for(i in 1:10) {
df.tmp = data.frame(
plot = paste0(vector.x[i], ":", vector.y[i]),
x = df1[[vector.x[i]]],
y = df1[[vector.y[i]]]
)
if(is.null(df2)) df2=df.tmp else df2 = rbind(df2, df.tmp)
}
ggplot(data=df2, aes(x, y)) +
geom_point() +
facet_grid(cols = vars(plot))

Customizing ggpairs to make the correlation matrix more readable

The following code creates a correlation matrix visulization that is not very readable:
1) The text is too large and the numbers inside the cells are not readable
2) The ticks in the x and y axes do not offer information because they are too congested
Could you advise me how to deal with these problems:
The code is the following:
library(GGally)
library(ggplot2)
library(data.table)
library(ROSE)
library(dplyr)
#===================================================================================================================
# LOAD THE DATA
#===================================================================================================================
data(hacide)
train <- hacide.train
#=============================================================================================================
# FEATURE EXTRACTION
#=================================================================================================================
setDT(train)
train <- train %>% mutate(
x11 = ifelse(x1 < -1.4, 1, 0),
x12 = ifelse(((x1 >= -1.4) & (x1 < -0.74)), 1, 0),
x13 = ifelse(((x1 >= -0.74) & (x1 < 1)), 1, 0),
x14 = ifelse(x2 >= 1, 1, 0),
x21 = ifelse(x2 < -1.4, 1, 0),
x22 = ifelse(((x2 >= -1.4) & (x2 < -1)), 1, 0),
x23 = ifelse(((x2 >= -1) & (x2 < 0.5)), 1, 0),
x24 = ifelse(x2 >= 0.5, 1, 0),
x3 = x1 ^ 2 - x2
)
#=========================================================================================================
# EXAMINE CORRELATIONS
#=========================================================================================================
ggpairs(train ,
lower = list(continuous = wrap("points", color = "red", alpha = 0.5),
combo = wrap("box", color = "orange", alpha = 0.3),
discrete = wrap("facetbar", color = "yellow", alpha = 0.3) ),
diag = list(continuous = wrap("densityDiag", color = "blue", alpha = 0.5) ))
The plot is the following:

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

How to assign name to every circle in a Venn diagram using R (Venndiagram package)

I would assign a name for every circle in a Venn diagram. I have tried to change options in category but seems this is the only set I can use. I attach my code, please where is the wrong part?
goterm3 = c(1,2,3,4,5,6)
goterm2 =c(2,2,3,4,3,5)
goterm1=c(4,5,3,2,4,3,2,4)
int12 = intersect(goterm1, goterm2)
int13 = intersect(goterm1, goterm3)
int23 = intersect(goterm2, goterm3)
intall = intersect(int12, goterm3)
require(VennDiagram)
venn.plot = draw.triple.venn(length(goterm1), length(goterm2), length(goterm3),
length(int12), length(int23), length(int13),length(intall),
category = rep("ORG1, ORG2,Org",3) ,rotation = 1, reverse = FALSE, euler.d = FALSE,
scaled = FALSE, lwd = rep(2, 3), lty = rep("solid", 3),
col = rep("black", 3), fill = c("blue", "red", "green"),
alpha = rep(0.5, 3),
label.col = rep("black", 7), cex = rep(1, 7), fontface = rep("plain", 7),
fontfamily = rep("serif", 7), cat.pos = c(0, 0, 180),
cat.dist = c(0.05, 0.05, 0.025), cat.col = rep("black", 3),
cat.cex = rep(1, 3), cat.fontface = rep("plain", 3),
cat.fontfamily = rep("serif", 3),
cat.just = list(c(0.5, 1), c(0.5, 1), c(0.5, 0)), cat.default.pos = "outer",
cat.prompts = FALSE, rotation.degree = 0, rotation.centre = c(0.5, 0.5),
ind = TRUE, sep.dist = 0.05, offset = 0)
This is what I get and it does have the same labels as your categories (after I unmangled the string values for the categories:
category = c("ORG1", "ORG2","Org") # no rep needed and proper quotes

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