3 different colour regions in levelplot - r

Trying to plot this matrix so that negative values are red, 0 is blue and positive values are green.
m <- matrix(c(0,0,-1,-2,0,0,1,0,1,3,3,3,-3,0,0,2),nrow = 4)
levelplot(m,at=c(-3,0,3),col.regions=c("red","blue","green"),xlab = xlab.a, ylab="", colorkey = FALSE, panel = function(...) {
panel.fill(col = "blue")
panel.levelplot(...)
})

Here is one more generic way using boolean comparisons:
levelplot((m>=0) + (m > 0),at=c(-0.1, 0:2),col.regions=c("red","blue","green"), xlab = "", ylab="", colorkey = FALSE, panel = function(...) {
panel.fill(col = "blue")
panel.levelplot(...)
})

m <- matrix(c(0,0,-1,-2,0,0,1,0,1,3,3,3,-3,0,0,2),nrow = 4)
levelplot(m,at=c(-3,-1,0,3),col.regions=c("red","blue","green"), xlab = "", ylab="", colorkey = FALSE, panel = function(...) {
panel.fill(col = "blue")
panel.levelplot(...)
})

Related

How to adjust legend position of interaction.plot and lineplot.CI?

I'm a beginner in coding. I was trying to create an interaction plot. Here's my code:
data is clinicaltrials from the data of the book "Learning Statistics with R."
library(sciplot)
library(lsr)
library(gplots)
lineplot.CI(x.factor = clin.trial$drug,
response = clin.trial$mood.gain,
group = clin.trial$therapy,
ci.fun = ciMean,
xlab = "Drug",
ylab = "Mood Gain")
and it produces the graph like this:
As can be seen in the graph, the legend box is not within my screen.
Also I tried creating another plot using the following code:
interaction.plot(x.factor = clin.trial$drug,
trace.factor = clin.trial$therapy,
response = clin.trial$mood.gain,
fun = mean,
type = "l",
lty = 1, # line type
lwd = 2, # line width
legend = T,
xlab = "Drug", ylab = "Mood Gain",
col = c("#00AFBB", "#E7B800"),
xpd = F,
trace.label = "Therapy")
For this code, I got the graph like this:
In this graph, the legend does not have labels.
Could anyone help me with these problems regarding legend?
You probably plan to save the plot via RStudio GUI. When you resize the plot window with your mouse, you need to run the code again to refresh the legend dimensions.
However, it's advantageous to use a more sophisticated method, e.g. to save it as a png with fixed dimensions like so:
library("sciplot")
library("lsr")
library("gplots")
png("Plot_1.png", height=400, width=500)
lineplot.CI(x.factor=clin.trial$drug,
response=clin.trial$mood.gain,
group=clin.trial$therapy,
ci.fun=ciMean,
xlab="Drug",
ylab="Mood Gain"
)
dev.off()
png("Plot_2.png", height=400, width=500)
interaction.plot(x.factor=clin.trial$drug,
trace.factor=clin.trial$therapy,
response=clin.trial$mood.gain,
fun=mean,
type="l",
lty=1, # line type
lwd=2, # line width
legend=T,
xlab="Drug", ylab="Mood Gain",
col=c("#00AFBB", "#E7B800"),
xpd=F,
trace.label="Therapy")
dev.off()
The plots are saved into your working directory, check getwd() .
Edit
You could also adjust the legend position.
In lineplot.CI you may use arguments; either by using characters just for x, e.g. x.leg="topleft" or both coordinates as numeric x.leg=.8, y.leg=2.2.
interaction.plot does not provide yet this functionality. I provide a hacked version below. Arguments are called xleg and yleg, functionality as above.
See ?legend for further explanations.
interaction.plot <- function (x.factor, trace.factor, response, fun = mean,
type = c("l", "p", "b", "o", "c"), legend = TRUE,
trace.label = deparse(substitute(trace.factor)),
fixed = FALSE, xlab = deparse(substitute(x.factor)),
ylab = ylabel, ylim = range(cells, na.rm = TRUE),
lty = nc:1, col = 1, pch = c(1L:9, 0, letters),
xpd = NULL, leg.bg = par("bg"), leg.bty = "n",
xtick = FALSE, xaxt = par("xaxt"), axes = TRUE,
xleg=NULL, yleg=NULL, ...) {
ylabel <- paste(deparse(substitute(fun)), "of ", deparse(substitute(response)))
type <- match.arg(type)
cells <- tapply(response, list(x.factor, trace.factor), fun)
nr <- nrow(cells)
nc <- ncol(cells)
xvals <- 1L:nr
if (is.ordered(x.factor)) {
wn <- getOption("warn")
options(warn = -1)
xnm <- as.numeric(levels(x.factor))
options(warn = wn)
if (!anyNA(xnm))
xvals <- xnm
}
xlabs <- rownames(cells)
ylabs <- colnames(cells)
nch <- max(sapply(ylabs, nchar, type = "width"))
if (is.null(xlabs))
xlabs <- as.character(xvals)
if (is.null(ylabs))
ylabs <- as.character(1L:nc)
xlim <- range(xvals)
if (is.null(xleg)) {
xleg <- xlim[2L] + 0.05 * diff(xlim)
xlim <- xlim + c(-0.2/nr, if (legend) 0.2 + 0.02 * nch else 0.2/nr) *
diff(xlim)
}
dev.hold()
on.exit(dev.flush())
matplot(xvals, cells, ..., type = type, xlim = xlim, ylim = ylim,
xlab = xlab, ylab = ylab, axes = axes, xaxt = "n",
col = col, lty = lty, pch = pch)
if (axes && xaxt != "n") {
axisInt <- function(x, main, sub, lwd, bg, log, asp,
...) axis(1, x, ...)
mgp. <- par("mgp")
if (!xtick)
mgp.[2L] <- 0
axisInt(1, at = xvals, labels = xlabs, tick = xtick,
mgp = mgp., xaxt = xaxt, ...)
}
if (legend) {
yrng <- diff(ylim)
if (is.null(yleg))
yleg <- ylim[2L] - 0.1 * yrng
if (!is.null(xpd) || {
xpd. <- par("xpd")
!is.na(xpd.) && !xpd. && (xpd <- TRUE)
}) {
op <- par(xpd = xpd)
on.exit(par(op), add = TRUE)
}
# text(xleg, ylim[2L] - 0.05 * yrng, paste(" ",
# trace.label), adj = 0)
if (!fixed) {
ord <- sort.list(cells[nr, ], decreasing = TRUE)
ylabs <- ylabs[ord]
lty <- lty[1 + (ord - 1)%%length(lty)]
col <- col[1 + (ord - 1)%%length(col)]
pch <- pch[ord]
}
legend(xleg, yleg, legend = ylabs, col = col,
title = if (trace.label == "") NULL else trace.label,
pch = if (type %in% c("p", "b"))
pch, lty = if (type %in% c("l", "b"))
lty, bty = leg.bty, bg = leg.bg)
}
invisible()
}
Data:
lk <- "https://learningstatisticswithr.com/data.zip"
tmp <- tempfile()
tmp.dir <- tempdir()
download.file(lk, tmp)
unzip(tmp, exdir=tmp.dir)
load("data/clinicaltrial.Rdata")

change the colors of the segments and add ellipses according to the group in plot function

I have data similar to this one, but with more groups (instead od 2 groups: grazed/ungrazed, I have 9 years):
data(varespec)
dis <- vegdist(varespec) ## Bray-Curtis distances between samples
groups <- factor(c(rep(1,16), rep(2,8)), labels = c("grazed","ungrazed")) ## First 16 sites grazed, remaining 8 sites ungrazed
I'm struggling with the following function to change the colors of the segments according to their group (grazed, ungrazed). So lines of grazed will be yellow3 and ungrazed will be indianred3.
mod <- betadisper(dis, groups) ## Calculate multivariate dispersions
## plot function
plot.betadisper <- function(x, axes = c(1,2),
cex = 0.7, pch = c(0,1), col=c("yellow1", "indianred1"),
hull = TRUE,
ylab, xlab, main, sub, ...)
{
localAxis <- function(..., col, bg, pch, cex, lty, lwd) axis(...)
localBox <- function(..., col, bg, pch, cex, lty, lwd) box(...)
localTitle <- function(..., col, bg, pch, cex, lty, lwd) title(...)
if(missing(main))
main <- deparse(substitute(x))
if(missing(sub))
sub <- paste("method = \"", attr(x, "method"), "\"", sep = "")
if(missing(xlab))
xlab <- paste("PCoA", axes[1])
if(missing(ylab))
ylab <- paste("PCoA", axes[2])
g <- scores(x, choices = axes)
ng <- length(levels(x$group))
col <- rep_len(col, ng) # make sure there are enough colors
plot(g$sites, asp = 1, type = "n", axes = FALSE, ann = FALSE, ...)
## if more than 1 group level
if(is.matrix(g$centroids)) {
for(i in levels(x$group)) {
j <- which(levels(x$group) == i)
segments(g$centroids[j, 1L], g$centroids[j, 2L],
g$sites[x$group == i, 1L],
g$sites[x$group == i, 2L], col = "grey", ...)
if(hull) {
ch <- chull(g$sites[x$group == i, ])
ch <- c(ch, ch[1])
lines(x$vectors[x$group == i, axes][ch, ],
col = "black", lty = "dashed", ...)
}
}
points(g$centroids, pch = c(21,22), cex = 1, col = c("yellow3", "indianred3"), bg = c("yellow3", "indianred3"))
} else {
## single group
segments(g$centroids[1L], g$centroids[2L],
g$sites[, 1L], g$sites[, 2L], col = "grey", ...)
if(hull) {
ch <- chull(g$sites)
ch <- c(ch, ch[1])
lines(x$vectors[, axes][ch, ],
col = "black", lty = "dashed", ...)
}
points(g$centroids[1L], g$centroids[1L],
pch = c(21,22), cex = 1, col = c("yellow3", "indianred3"), bg = c("yellow3", "indianred3"))
}
points(g$sites, pch = pch[x$group], cex = cex, col=col[x$group], ...)
localTitle(main = main, xlab = xlab, ylab = ylab, sub = sub, ...)
localAxis(1, ...)
localAxis(2, ...)
localBox(...)
class(g) <- "ordiplot"
invisible(g)
}
plot.betadisper(mod)
I will also like to add standard error ellipses, and I have tried this without finding the solution:
plot(mod, hull = FALSE, ellipse = TRUE) ## ??? Not working
Thanks!

Fix layout / plot options of plot(fevd()) function

I am currently busy with a Vector Autoregressive Analysis in R, using the vars package. I was wondering if the following things are possible:
1) the previous solution for a better fit on the page worked properly, but now with more variables, we have more plots and the layout is screwed again. I already played with some of the win.graph() parameters, but nothing gives me a proper readable solution.
2) The plot(irf(...) function of the vars package gives a one-graph per page output. I was wondering if this is also possible for the plot(fevd() function by adding some extra (unkown to me) parameters options
3) Also, for readability, I would like to color the graphs, plot(fevd() gives an all-kinds-of-gray output, Is it possible to change those colors?
Thank you in advance
Olivier
You will have to modify the plot function for fevd to do what you want. Here's a modified plot.varfevd function that removes all calls to par(). This allows to use layout properly. The lines that have been removed have been commented out (#). I also removed the parameter that asked for confirmation in "single" plots.
plot.varfevd <-function (x, plot.type = c("multiple", "single"), names = NULL,
main = NULL, col = NULL, ylim = NULL, ylab = NULL, xlab = NULL,
legend = NULL, names.arg = NULL, nc, mar = par("mar"), oma = par("oma"),
addbars = 1, ...)
{
K <- length(x)
ynames <- names(x)
plot.type <- match.arg(plot.type)
if (is.null(names)) {
names <- ynames
}
else {
names <- as.character(names)
if (!(all(names %in% ynames))) {
warning("\nInvalid variable name(s) supplied, using first variable.\n")
names <- ynames[1]
}
}
nv <- length(names)
# op <- par(no.readonly = TRUE)
ifelse(is.null(main), main <- paste("FEVD for", names), main <- rep(main,
nv)[1:nv])
ifelse(is.null(col), col <- gray.colors(K), col <- rep(col,
K)[1:K])
ifelse(is.null(ylab), ylab <- rep("Percentage", nv), ylab <- rep(ylab,
nv)[1:nv])
ifelse(is.null(xlab), xlab <- rep("Horizon", nv), xlab <- rep(xlab,
nv)[1:nv])
ifelse(is.null(ylim), ylim <- c(0, 1), ylim <- ylim)
ifelse(is.null(legend), legend <- ynames, legend <- legend)
if (is.null(names.arg))
names.arg <- c(paste(1:nrow(x[[1]])), rep(NA, addbars))
plotfevd <- function(x, main, col, ylab, xlab, names.arg,
ylim, ...) {
addbars <- as.integer(addbars)
if (addbars > 0) {
hmat <- matrix(0, nrow = K, ncol = addbars)
xvalue <- cbind(t(x), hmat)
barplot(xvalue, main = main, col = col, ylab = ylab,
xlab = xlab, names.arg = names.arg, ylim = ylim,
legend.text = legend, ...)
abline(h = 0)
}
else {
xvalue <- t(x)
barplot(xvalue, main = main, col = col, ylab = ylab,
xlab = xlab, names.arg = names.arg, ylim = ylim,
...)
abline(h = 0)
}
}
if (plot.type == "single") {
# par(mar = mar, oma = oma)
# if (nv > 1)
# par(ask = TRUE)
for (i in 1:nv) {
plotfevd(x = x[[names[i]]], main = main[i], col = col,
ylab = ylab[i], xlab = xlab[i], names.arg = names.arg,
ylim = ylim, ...)
}
}
else if (plot.type == "multiple") {
if (missing(nc)) {
nc <- ifelse(nv > 4, 2, 1)
}
nr <- ceiling(nv/nc)
par(mfcol = c(nr, nc), mar = mar, oma = oma)
for (i in 1:nv) {
plotfevd(x = x[[names[i]]], main = main[i], col = col,
ylab = ylab[i], xlab = xlab[i], names.arg = names.arg,
ylim = ylim, ...)
}
}
# on.exit(par(op))
}
Then, you will need short variable names. Pick acronyms if needed.
library(vars)
data(Canada)
colnames(Canada) <-c("name1","name2","name3","name4")
var <- VAR(Canada , p=4 , type = "both")
Using a wide plot window (using win.graph) and using layout (to get the placement of your eight plots), you can get all charts displayed properly. I also changed the colors of the plots as requested. Finally, we are now using single plots as there are no calls to par() which do not sit well with layout().
win.graph(width=15,height=8)
layout(matrix(1:8,ncol=2))
plot.varfevd(fevd(var, n.ahead = 10 ),plot.type = "single", col=1:4)
plot.varfevd(fevd(var, n.ahead = 10 ),plot.type = "single", col=1:4)

ScatterPlot and ONLY one Histogram plot together

I want to visualize time series data with a 'scatter plot' and a histogram on the right side, but I haven't been able to figure out how to turn OFF the histogram on the upper side.
Code Example:
install.packages("psych")
library(psych)
data = matrix(rnorm(n=100000,mean=2,sd=1.5), nrow = 100, ncol=1000)
fs = list()
fs$p_Z = 1*(data>2)
n_p = 1;
for(i in floor(seq(1,dim(data)[2],length.out=n_p)))
{
scatter.hist(x = rep(1:length(data[,i])), y = data[,i],
xlab = 'observations',
ylab = 'log(TPM)',
title = 'Mixture Plot',
col = c("red","blue")[fs$p_Z[,i]+1],
correl = FALSE, ellipse = FALSE, smooth = FALSE)
}
Result:
Expected Result:
Same as the one I have but with no histogram on the upper side. I.e., ONLY the histogram on the right side for log(TPM).
Note: I am using psych package, scatter.hist function which seemed easy and nice to use, but couldn't find how to turn off one histogram.
Where flexibility ends, hacking begins. If you look at scatter.hist function, you will see that it is pretty basic usage of R base graphics. Following modified code would create the plot you want:
scat.hist <- function(x, y, xlab = NULL, ylab = NULL, title = "", ...) {
## Create layout
layout(matrix(c(1,2),1,2,byrow=TRUE), c(3,1), c(1,3))
## Plot scatter
par(mar=c(5,5,3,1))
plot(x= x, y = y, xlab = xlab, ylab = ylab, main = title, ...)
## Right histogram
yhist <- hist(y, plot = FALSE, breaks = 11)
par(mar=c(5,2,3,1))
mp <- barplot(yhist$density, space=0, horiz=TRUE, axes = FALSE)
## Density
d <- density(y, na.rm = TRUE, bw = "nrd", adjust = 1.2)
temp <- d$y
d$y <- (mp[length(mp)] - mp[1] + 1) * (d$x - min(yhist$breaks))/(max(yhist$breaks) - min(yhist$breaks))
d$x <- temp
lines(d)
}
Let's try it for the first row:
i = 1
scat.hist(x = seq_along(data[,i]), y = data[,i], col = c("red", "blue")[fs$p_Z[,i]+1], xlab = 'observations', ylab = 'log(TPM)', title = 'Mixture Plot')

Change plot area background color

I would like to do a graph in R using our company colors. This means the background of all charts should be a light blue, the plotting region however should be white. I was searching for answers and found that drawing a rect does the job (almost). However the plotting region is now white and the graph not visible anymore. Is this even possible?
getSymbols('SPY', from='1998-01-01', to='2011-07-31', adjust=T)
GRAPH_BLUE<-rgb(43/255, 71/255,153/255)
GRAPH_ORANGE<-rgb(243/255, 112/255, 33/255)
GRAPH_BACKGROUND<-rgb(180/255, 226/255, 244/255)
par(bg=GRAPH_BACKGROUND)
colorPlottingBackground<-function(PlottingBackgroundColor = "white"){
rect(par("usr")[1], par("usr")[3], par("usr")[2], par("usr")[4], col ="white")
}
plot.xts(SPY, col=GRAPH_BLUE)
colorPlottingBackground()
I know you already accepted #plannapus's answer, but this is a much simpler solution
par(bg="lightblue")
plot(0, 0, type="n", ann=FALSE, axes=FALSE)
u <- par("usr") # The coordinates of the plot area
rect(u[1], u[3], u[2], u[4], col="white", border=NA)
par(new=TRUE)
plot(1:10, cumsum(rnorm(10)))
What you basically do is to overlay two plots using par(new=TRUE): one with only a white rectangle; and another one with the contents you actually want to plot.
The issue is that you plot your white rectangle after plotting your data, therefore overwriting them. Since plot.xts doesn't have an argument add that would allow you to call it after drawing the rectangle, the only solution I see would be to modify function plot.xts.
plot.xtsMODIFIED<-function (x, y = NULL, type = "l", auto.grid = TRUE, major.ticks = "auto",
minor.ticks = TRUE, major.format = TRUE, bar.col = "grey",
candle.col = "white", ann = TRUE, axes = TRUE, ...)
{
series.title <- deparse(substitute(x))
ep <- axTicksByTime(x, major.ticks, format.labels = major.format)
otype <- type
if (is.OHLC(x) && type %in% c("candles", "bars")) {
x <- x[, has.OHLC(x, TRUE)]
xycoords <- list(x = .index(x), y = seq(min(x), max(x),
length.out = NROW(x)))
type <- "n"
}
else {
if (NCOL(x) > 1)
warning("only the univariate series will be plotted")
if (is.null(y))
xycoords <- xy.coords(.index(x), x[, 1])
}
###The next three lines are the only modifications i made to the function####
plot(xycoords$x, xycoords$y, type = "n", axes = FALSE, ann = FALSE)
rect(par("usr")[1], par("usr")[3], par("usr")[2], par("usr")[4], col ="white")
if(type=="l"){lines(xycoords$x, xycoords$y, ...)}
if (auto.grid) {
abline(v = xycoords$x[ep], col = "grey", lty = 4)
grid(NA, NULL)
}
if (is.OHLC(x) && otype == "candles")
plot.ohlc.candles(x, bar.col = bar.col, candle.col = candle.col,
...)
dots <- list(...)
if (axes) {
if (minor.ticks)
axis(1, at = xycoords$x, labels = FALSE, col = "#BBBBBB",
...)
axis(1, at = xycoords$x[ep], labels = names(ep), las = 1,
lwd = 1, mgp = c(3, 2, 0), ...)
axis(2, ...)
}
box()
if (!"main" %in% names(dots))
title(main = series.title)
do.call("title", list(...))
assign(".plot.xts", recordPlot(), .GlobalEnv)
}
Then your script become:
library(quantmod)
getSymbols('SPY', from='1998-01-01', to='2011-07-31', adjust=T)
GRAPH_BLUE<-rgb(43/255, 71/255,153/255)
GRAPH_BACKGROUND<-rgb(180/255, 226/255, 244/255)
par(bg=GRAPH_BACKGROUND)
plot.xtsMODIFIED(SPY, col=GRAPH_BLUE)
The error you're getting (Error in axis(1, at = xycoords$x, labels = FALSE, col = "#BBBBBB", ...) : formal argument "col" matched by multiple actual arguments.) was also thrown with your previous script. It has to do with the fact that plot.xts uses several time argument ... and that argument col is both valid for axis and plot(or here in my modified version, lines). If you want to avoid it, i see two solutions:
Either you want your axis to be of the same color as your line and therefore you have to change the line that says:
...
axis(1, at = xycoords$x, labels = FALSE, col = "#BBBBBB",
...)
...
Into
...
axis(1, at = xycoords$x, labels = FALSE, ...)
...
Or you want the axis to have the color intended by the writer of the original plot.xts in which case you need to differenciate the color of the lines and that of the axis.
plot.xtsMODIFIED<-function (x, y = NULL, type = "l", auto.grid = TRUE, major.ticks = "auto",
minor.ticks = TRUE, major.format = TRUE, bar.col = "grey",
candle.col = "white", ann = TRUE, axes = TRUE,
lcol, ...)
{
...
if(type=="l"){lines(xycoords$x, xycoords$y, lcol, ...)}
...
}
And then in your actual call:
plot.xtsMODIFIED(SPY, lcol=GRAPH_BLUE)
plot.xts will accept the panel.first argument, which is another way to draw the rectangle before plotting the line.
library(quantmod)
getSymbols('SPY', from='1998-01-01', to='2011-07-31', adjust=T)
GRAPH_BLUE<-rgb(43/255, 71/255,153/255)
GRAPH_BACKGROUND<-rgb(180/255, 226/255, 244/255)
par(bg=GRAPH_BACKGROUND)
white.rect=function() do.call(rect,as.list(c(par()$usr[c(1,3,2,4)],col="white")))
plot.xts(SPY,panel.first=white.rect())
This does not address the issue with col=GRAPH_BLUE pointed out by #plannapus.

Resources