I have a plot(x,y) associated with two other factors z and t. There are three levels in z and two levels in t. How do I properly use legend function to insert legend to give three levels of z with t1, such as z1t1, z2t1, z3t1, and three levels of z with t2, such as z1t2, z2t2, z3t2? In other words, the legends should show a total of six.
with(df, plot(x, y,
pch = as.numeric(as.factor(paste(z,t))),
col = as.numeric(as.factor(paste(z, t)))))
This looks like what you are looking for.
UPDATE: Factors in the legend are sorted now.
#creating test data
x <- rnorm(20)
y <- x + runif(20)
dat <- data.frame("x" = x, "y" = y,
z = sample(c("z1", "z2", "z3"), 20, replace = TRUE),
t = sample(c("t1", "t2"), 20, replace = TRUE))
#it's quicker to do the pasting outside
dat$zt <- as.numeric(as.factor(paste(dat$z,dat$t)))
with(dat, plot(x, y,
pch = zt,
col = zt))
with(dat, legend(x = "bottomright",
legend = sort(unique(paste(z,t))),
pch = unique(zt),
col = unique(zt)))
Hope it helps.
Related
I have a Grid with n*m size and pch Symbols from 1-13 with 8 Colors(so 104 different combinations)
Grid empty:
And now I am trying to draw the symbols as pairs randomly onto my grid.
My thinking was I create a matrix with the same size as my grid and random integer numbers and a data frame with all combinations of pch and color and draw them on the grid.
My Goal:
row <- 4
col <- 13
n <- row * col
plot.new()
plot.window(xlim = c(1, col), ylim = c(1, row))
grid(nx = col, ny = row, col = "black")
box(lwd = 2)
axis(1, at=1:col,tick=FALSE,las = 1)
axis(2,at = 1:row,tick= FALSE,las = 2)
pch_v <- c(1:13)
col_v <- c(1:8)
board <- matrix(sample(1:n),nrow = row,ncol=col)
unique_combination <- expand.grid(pch_v,col_v)
Thats the point where I am stuck. If somebody got an idea I would appreciate it.
Shuffle the unique_combination, then plot:
row <- 4
col <- 13
pch_v <- c(1:col)
col_v <- c(1:row)
unique_combination <- expand.grid(pch_v,col_v)
# random sort
# set.seed(1) # if we want to reproduce
ucr <- unique_combination[ sample(nrow(unique_combination)), ]
d <- data.frame(x = 1:col, y = 1:row, pch = ucr$Var1, col = ucr$Var2)
with(d, plot(x, y, col = col, pch = pch, bty = "n"))
If we need to plot X points, subset before the data:
# subset x rows then plot
with(head(d, 6), plot(x, y, col = col, pch = pch, bty = "n"))
I'm hoping to keep in the image below the ticks on the vertical z axis, but remove ticks and numbers from the x and y axes. I would like to be able to label my x and y axes with a label for each condition in my matrix, but have not figured out how to do this with text3D. For some reason (because I'm on a mac?) I can't download axes3D, which is one potential solution I've seen in other responses.
Here is my code:
x = c(0,1)
y = c(0,1)
zval = c(104.1861, 108.529, 110.3675, 110.4112)
z = matrix (zval, nrow=2, ncol=2, byrow=TRUE)
hist3D(x,y,z, zlim=c(101,111), colvar = NULL, d=2, col = "lightblue", NAcol = "white", breaks = NULL, colkey = NULL, theta=-60, phi=20, nticks=10, axes=TRUE, ticktype="detailed", space=0.5, lighting=TRUE, light="diffuse", shade=.5, ltheta = 50, bty = "g")
My output

Ultimately, I'd like something more along the lines of this:
I'm very new to R.
stackoverflow.com/questions/26794236/ggplot2-3d-bar-plot
^ this seems like it might be what I need, but I couldn't replicate the code without an error. When I tried to run this piece I got an error because my x and z (in this case) axes aren't numerical:
cloud(y~x+z, d, panel.3d.cloud=panel.3dbars, col.facet='grey', xbase=0.4, ybase=0.4, scales=list(arrows=FALSE, col=1), par.settings = list(axis.line = list(col = "transparent")))
Maybe this might be helpful (with the caveat that 3D plots can sometimes make interpretation more challenging).
First, I recreated a data frame d based on something similar to what you started with:
x = c(0, 0, 1, 1)
y = c(0, 1, 0, 1)
z = c(104.1861, 108.529, 110.3675, 110.4112)
d <- data.frame(
x = factor(as.logical(x)),
y = factor(as.logical(y)),
z = z
)
Note that for x and y I converted the 0 and 1 to FALSE and TRUE with as.logical, then made them factors.
Then for the plot:
library(latticeExtra)
cloud(z ~ x + y, data = d, panel.3d.cloud=panel.3dbars, col.facet='grey',
xbase=0.4, ybase=0.4, scales=list(arrows=FALSE, col=1),
par.settings = list(axis.line = list(col = "transparent")))
You will want the formula as z ~ x + y where z is a numeric response.
Edit: If you wish to customize the axis labels, you can set the factor labels as follows (for example):
d <- data.frame(
x = factor(as.logical(x), labels = c("Hi", "Lo")),
y = factor(as.logical(y), labels = c("Label1", "Label2")),
z = z
)
Plot
I'm trying to create a very simple 3D plot using the rgl package: I have a function that just maps x values into y values. For a given z (in my example: z = 1), I can plot this function in a 3D plot:
library(rgl)
mycurve <- function(x) { return (1/x)}
myx <- seq(1, 10, by = 0.1)
plot3d(x = NA, xlim = c(0, 10), ylim = c(0, 10), zlim = c(0, 5),
xlab = "x", ylab = "y", zlab = "height")
lines3d(x = myx, y = mycurve(myx), z = 1)
However, even after hours of trying to understand the documentation of ?persp3d and ?surface3d, I still have no idea how to add a surface to my plot that "connects" my line to the x-y plane – like this:
(To generate this image, I cheated by plotting many lines: for (i in seq(0, 1, by = 0.01)) { lines3d(x = myx, y = mycurve(myx), z = i) }.)
I suppose that I need to supply the correct values to surface3d somehow. From ?surface3d:
The surface is defined by the matrix of height values in z, with rows corresponding to the values in x and columns corresponding to the values in y.
Given that my space curve is "vertical", each value of x corresponds to only 1 value of y. Still, I need to specify two z values for each xy pair, which is why I do not know how to proceed.
How can I plot a space curve as shown in the second image?
In persp3d, all 3 arguments can be matrices, so you can plot arbitrary surfaces. For your needs, this works:
mycurve <- function(x) { return (1/x)}
myx <- seq(1, 10, by = 0.1)
xmat <- matrix(NA, 2, length(myx))
ymat <- matrix(NA, 2, length(myx))
zmat <- matrix(NA, 2, length(myx))
for (i in 0:1) {
xmat[i+1,] <- myx
ymat[i+1,] <- mycurve(myx)
zmat[i+1,] <- i
}
library(rgl)
persp3d(x = xmat, y = ymat, z = zmat, xlim = c(0, 10), ylim = c(0, 10), zlim = c(0, 5),
xlab = "x", ylab = "y", zlab = "height", col = "gray")
The image produced looks like this:
If you want z to depend on x or y, you'll likely want a smaller step size, but this works for the surface you're after.
To use the persp3d function one needs to create a matrix for z to correspond to all of the x and y values in the desired range.
I revised your function to take both the x and y parameters and return the desired z value. The outer function will call the function repeatedly to fill the matrix. Then plot, with the defined x and y axis and z (from the outer function)
library(rgl)
mycurve <- function(x, y) { return (1/x)}
myx <- seq(1, 10, by = 0.4)
myy <-seq(1, 10, by =0.4)
#create matrix
data<-outer(myx, myy, mycurve)
#plot points
persp3d(x=myx, y=myy, z=data,
xlab = "x", ylab = "y", zlab = "height")
I have data-frame DOTS with following columns: DOT, X, Y. There are 10 dots.
I want to display all possible connections: (a) between dots 1,2,3,4,5; (b) 5,6,7; and (c) between 7,8,9,10?
# what I tried so far
plot(DOTS$X, DOTS$Y, main= "DOTS", xlab= "X", ylab= "Y",
col= "blue", pch = 19, cex = 1, lty = "solid", lwd = 2)
text(DOTS$X, DOTS$Y, labels=DOTS$Dot, cex= 0.7, pos = 3)
lines(DOTS$X,DOTS$Y)
# the last line displays connection from 1 to 2 to 3 etc only
Thank you in advance for your suggestions.
I make a dataset first :
x <- runif(10, 0, 10)
y <- runif(10, 0, 10)
df <- data.frame(dot = LETTERS[1:10], x = x, y = y)
I think it's flexible to create a custom function and use combn() to generate all possible combinations of two dots. And then connect them with segments() respectively. In the custom function below, you can put any dots set and arguments e.g. col, lwd... etc.
plot(df$x, df$y)
text(df$x, df$y, labels = df$dot, pos = 3)
line.fun <- function(index, ...){
comb <- combn(index, 2)
start <- comb[1, ] # starting points
end <- comb[2, ] # end points
segments(df$x[start], df$y[start], df$x[end], df$y[end], ...)
}
line.fun(1:5, col = 2)
line.fun(5:7, col = 3)
line.fun(7:10, col = 4)
Attempting to code a function that returns a bubble chart from aggregated data.
I'm passing it a column of a data.frame in "agg".
aggs2 <- function(agg, deporur=0, all=TRUE){
##create aggregate from library data
agg1 <- aggregate(agg, by=list(NoNA$IMD_NATIONAL_QUINTILE, NoNA$UR),
FUN=function(x) c(mn=mean(x), n=length(x)))
##bind into a dataframe
agg1 <- cbind(agg1[,1:2], agg1[,3])
##add column holding values of Deprivation Quantile and Urban/Rural status
agg1$NewCol <- do.call(paste, c("Deprivation Quantile", agg1[c("Group.1", "Group.2")],
sep = " "))
##set column names
colnames(agg1) <- c("Deprivation", "Urban and Rural", "Mean", "Count", "DepUR")
##remove categories with low counts
if(all==FALSE){
agg1 <- subset(agg1, agg1$Count > 9)
}
##order data.frame by mean
agg1 <- agg1[order(agg1$Mean, decreasing=TRUE),]
##create bubble chart
if(deporur==1){
radius3 <- sqrt(agg1$Count/pi)
symbols(factor(agg1$DepUR), agg1$Mean, circles=radius3, inches=0.35,
xlim=c(0,10.0), ylim=c(min(agg1$Mean-0.25),10.0), fg="white", bg="purple",
xlab="Deprivation Quantile and Urban/Rural Status", ylab="Mean Response")
text(factor(agg1$DepUR), agg1$Mean-.1, agg1$DepUR, cex=0.7)
}
#return ordered dataframe
agg1
}
This returns a sorted data.frame by mean, and the following chart:
Because this function will need to create graphs from a variety of different documents and columns, I would like to code it so that the labels do not overlap the bubbles, or other labels.
I have looked at the directlabels library, but I have been unable to work out how to code it properly.
Would greatly appreciate any assistance.
I'm not aware of any solution for non-overlapping labels with regards to other labels AND other circles. Nevertheless, wordcloud::textplot might be a starting point:
library(wordcloud)
set.seed(8)
df <- data.frame(x = runif(10), y = runif(10), size = sample(10:20, 10), lab = paste0("label", 1:10))
par(mfrow = c(1,2))
with(df, {
plot(x, y, cex = size, pch = 19, col = adjustcolor("violet", alpha.f = .4), main = "non-overlapping")
textplot(x, y, lab, new = FALSE, show.lines = FALSE, cex = 2)
plot(x, y, cex = size, pch = 19, col = adjustcolor("violet", alpha.f = .4), main = "overlapping")
text(x, y, lab, cex = 2)
})