I am plotting in xyplot() as per below. I put symbols on the plot with print(panel.points()) and it works. But I need to save the plot with the points to a variable (a in the example) so I can use grid arrange to combine it with other plots in the same picture. Ideas?
dev.off()
x <- c(1:10)
y <- c(1:10)
a <- xyplot(y ~ x, type = "l")
trellis.focus("panel", 1, 1, highlight = FALSE)
print(panel.points(x[c(5,10)],
y[c(5,10)],
pch = 19,
cex = 0.75,
col = c("red", "black")))
Use panel.points within a panel function that calls panel.xyplot to do the main plot:
b = xyplot(
y~x,type="l",
panel=function(...){
panel.xyplot(...)
panel.points(
x[c(5,10)],y[c(5,10)],
cex=0.75, col=c("red","black"),pch=19
)
}
)
Related
I am doing quarterly analysis, for which I want to plot a graph. To maintain continuity on x axis I have turned quarters into factors. But then when I am using plot function and trying to color it red, the col argument is not working.
An example:
quarterly_analysis <- data.frame(Quarter = as.factor(c(2020.1,2020.2,2020.3,2020.4,2021.1,2021.2,2021.3,2021.4)),
AvgDefault = as.numeric(c(0.24,0.27,0.17,0.35,0.32,0.42,0.38,0.40)))
plot(quarterly_analysis, col="red")
But I am getting the graph in black color as shown below:
Converting it to a factor is not ideal to plot unless you have multiple values for each factor - it tries to plot a box plot-style plot. For example, with 10 observations in the same factor, the col = "red" color shows up as the fill:
set.seed(123)
fact_example <- data.frame(factvar = as.factor(rep(LETTERS[1:3], 10)),
numvar = runif(30))
plot(fact_example$factvar, fact_example$numvar,
col = "red")
With only one observation for each factor, this is not ideal because it is just showing you the line that the box plot would make.
You could use border = "red:
plot(quarterly_analysis$Quarter,
quarterly_analysis$AvgDefault, border="red")
Or if you want more flexibility, you can plot it numerically and do a little tweaking for more control (i.e., can change the pch, or make it a line graph):
# make numeric x values to plot
x_vals <- as.numeric(substr(quarterly_analysis$Quarter,1,4)) + rep(seq(0, 1, length.out = 4))
par(mfrow=c(1,3))
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
pch = 7, main = "Square Symbol", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
type = "l", main = "Line graph", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
plot(x_vals,
quarterly_analysis$AvgDefault, col="red",
type = "b", pch = 7, main = "Both", axes = FALSE)
axis(1, at = x_vals,
labels = quarterly_analysis$Quarter)
axis(2)
Data
set.seed(123)
quarterly_analysis <- data.frame(Quarter = as.factor(paste0(2019:2022,
rep(c(".1", ".2", ".3", ".4"),
each = 4))),
AvgDefault = runif(16))
quarterly_analysis <- quarterly_analysis[order(quarterly_analysis$Quarter),]
I am planning to reproduce the attached figure, but I have no clue how to do so:
Let´s say I would be using the CO2 example dataset, and I would like to plot the relative change of the Uptake according to the Treatment. Instead of having the three variables in the example figure, I would like to show the different Plants grouped for each day/Type.
So far, I managed only to get this bit of code, but this is far away from what it should look like.
aov1 <- aov(CO2$uptake~CO2$Type+CO2$Treatment+CO2$Plant)
plot(TukeyHSD(aov1, conf.level=.95))
Axes should be switched, and I would like to add statistical significant changes indicated with letters or stars.
You can do this by building it in base R - this should get you started. See comments in code for each step, and I suggest running it line by line to see what's being done to customize for your specifications:
Set up data
# Run model
aov1 <- aov(CO2$uptake ~ CO2$Type + CO2$Treatment + CO2$Plant)
# Organize plot data
aov_plotdata <- data.frame(coef(aov1), confint(aov1))[-1,] # remove intercept
aov_plotdata$coef_label <- LETTERS[1:nrow(aov_plotdata)] # Example labels
Build plot
#set up plot elements
xvals <- 1:nrow(aov_plotdata)
yvals <- range(aov_plotdata[,2:3])
# Build plot
plot(x = range(xvals), y = yvals, type = 'n', axes = FALSE, xlab = '', ylab = '') # set up blank plot
points(x = xvals, y = aov_plotdata[,1], pch = 19, col = xvals) # add in point estimate
segments(x0 = xvals, y0 = aov_plotdata[,2], y1 = aov_plotdata[,3], lty = 1, col = xvals) # add in 95% CI lines
axis(1, at = xvals, label = aov_plotdata$coef_label) # add in x axis
axis(2, at = seq(floor(min(yvals)), ceiling(max(yvals)), 10)) # add in y axis
segments(x0=min(xvals), x1 = max(xvals), y0=0, lty = 2) #add in midline
legend(x = max(xvals)-2, y = max(yvals), aov_plotdata$coef_label, bty = "n", # add in legend
pch = 19,col = xvals, ncol = 2)
Background
I have a function called TPN. When you run this function, it produces two plots (see picture below). The bottom-row plot samples from the top-row plot.
Question
I'm wondering how I could fix the ylim of the bottom-row plot to be always (i.e., regardless of the input values) the same as ylim of the top-row plot?
R code is provided below the picture (Run the entire block of code).
############## Input Values #################
TPN = function( each.sub.pop.n = 150,
sub.pop.means = 20:10,
predict.range = 10:0,
sub.pop.sd = .75,
n.sample = 2 ) {
#############################################
par( mar = c(2, 4.1, 2.1, 2.1) )
m = matrix( c(1, 2), nrow = 2, ncol = 1 ); layout(m)
set.seed(2460986)
Vec.rnorm <- Vectorize(function(n, mean, sd) rnorm(n, mean, sd), 'mean')
y <- c( Vec.rnorm(each.sub.pop.n, sub.pop.means, sub.pop.sd) )
set.seed(NULL)
x <- rep(predict.range, each = each.sub.pop.n)
plot(x, y) ## Plot #1
sample <- lapply(split(y, x), function(z) sample(z, n.sample, replace = TRUE))
sample <- data.frame(y = unlist(sample),
x = as.numeric(rep(names(sample), each = n.sample)))
plot(sample$x, sample$y) ## Plot # 2
}
## TEST HERE:
TPN()
You can get the ylim using par("yaxp")[1:2]. So, you can change the second plot code to have its ylim as the first plot's:
plot(sample$x, sample$y, ylim = par("yaxp")[1:2]) ## Plot # 2
or as mentioned in the comments, you can simply set the ylim for both plots to be range of both data-sets and add that to both plots:
ylim = range(c(y, sample$y))
Another option: Produce the same plot again but with type = "n" and then filling the points with points(). For example, change your plot 2 to
plot(x, y, type = "n")
points(sample$x, sample$y)
A benefit of this approach is that everything in the plot will be exactly the same, not just the y-axis (which may or may not matter for your function).
I have a lattice xyplot with smoothed lines (6 different lines). I would like to change the line types- color and type of line (dashed, etc), so that they are understandable in B&W, rather than in color (which is the default). Can anyone provide advice on this? Below is my current code:
xyplot(y~x,
data=df,
group=categorical,
type = "smooth",
ylim=c(-2,0.5),
xlab="x",
ylab="y",
auto.key=list(space="top",
columns=3,
title="",
cex.title=0.1,
lines=FALSE, points=TRUE)
)
Thank you
There are two options. Either you just set the line type with lty = 1:x or you use the built in black-and-white theme -- the latter will set up a bunch of other settings as well.
library(lattice)
y <- c(rnorm(10), rnorm(10, 2, 0.2), rnorm(10, 1.5, 0.4))
x <- rep(1:10, times = 3)
z <- rep(letters[1:3], each = 10)
# Option 1
xyplot(y ~ x, groups = z, type = "l",
par.settings = standard.theme(color = FALSE))
# Option 2
xyplot(y ~ x, groups = z, type = "l", lty = 1:3, col = "black")
I have a xyplot and I want to draw grid lines on the 0 values.
How this can be done?
According to lattice changelog:
Changes in lattice 0.19
=======================
o Added new arguments 'grid' and 'abline' in panel.xyplot().
So you could do it in one line:
require(lattice)
X <- data.frame(xx=runif(20), yy=rnorm(20))
xyplot(yy~xx, X, abline=list(h=0))
If you want panel.grid like line style, then nice trick:
xyplot(yy~xx, X, abline=c(list(h=0),trellis.par.get("reference.line")))
If you're using package lattice (which is implied with xyplot), you can use panel.abline to draw lines over labeled ticks.
my.df <- data.frame(a = runif(10, min = -1, max = 1), b = runif(10, min = -1, max = 1))
my.plot <- xyplot(b ~ a, data = my.df)
update(my.plot, panel = function(...) {
panel.abline(h = 0, v = 0, lty = "dotted", col = "light grey")
panel.xyplot(...)
})
There is a lattice llines function that replaces the function of lines() functionality in base. There is also a panel.lines function.
#---------- method --------------
xyplot(-1:1 ~ -1:1, type="l")
trellis.focus("panel", 1, 1)
do.call("panel.abline", list(h=0,v=0, lty=3) )
trellis.unfocus()
# --- that method has the advantage of also demonstrating
# how to modify an existing plot
#---------- method 2--------------
xp <-xyplot(-2:1 ~ -2:1, type="l", panel=function(...){
panel.xyplot(...)
panel.abline(h=0,v=0, lty=3)} )
xp