Dynamic background in plot() based on x-axis values? - r

I'm looking to implement EXACTLY this, but using plot() instead of ggplot2. There is even a reply on the blog by someone saying they did this with plot, but the link to their code is dead. I'm literally trying to do the exact same thing. I've downloaded data from FRED using quantmod's getSymbols(), and I have that data in a df, which I'm plotting with plot(). The x-axis are dates, and I want to change the background color based on a specific set of dates. Any ideas or hints how I can do this with plot?
Thank you!

Based on this question: R: change background color of plot for specific area only (based on x-values)
## plotting area with no axes
plot(unrate.df, type = "n")
lim <- par("usr")
## adding one rectangle
for (i in 1:nrow(recessions.trim)) {
rect(recessions.trim[i, 1], lim[3],
recessions.trim[i, 2], lim[4], border = "pink", col = "pink")
}
## adding the data
lines(unrate.df)
box()

You can use this:
plot(unrate.df, type="n")
makeRectangles(recessions.trim, col="pink", alpha=0.5)
lines(unrate.df)
grid()
where the function makeRectangles is defined as:
makeRectangles = function(x, col, alpha=1, border=NA, ...) {
col = col2rgb(col=col, alpha=FALSE)
col = rgb(red=col[1], green=col[2], blue=col[3],
alpha=floor(255*alpha) , maxColorValue=255)
rect(x[,1], par("usr")[3], x[,2], par("usr")[4], col=col, border=border, ...)
return(invisible())
}

Related

Half coloured boxplot in R

Is there anyway to have the native R boxplot function produce boxplots with different colours for the top and bottom boxes? Something like this:
Here is the function I came up with:
h.boxplot <- function(..., col.top='orange', col.bottom='yellow', col.scheme='none'){
cols = c(col.top, col.bottom)
if(col.scheme != 'none'){
cs = list(blue=c('#0071c1', '#3198ff'), green=c('#008001', '#99cc00'), yellow=c('#ffcc00', '#cc9900'))
stopifnot(col.scheme %in% names(cs))
cols = cs[[col.scheme]]
}
bx<-boxplot(..., col = "white", lty=1, boxlwd=0.00001)
n = length(bx$names)
rect(1:n-.4, bx$stats[2,], 1:n+.4, bx$stats[3,], col=cols[2], border=NA)
rect(1:n-.4, bx$stats[3,], 1:n+.4, bx$stats[4,], col=cols[1], border=NA)
return(bx)
}
# Examples
data = list(A=1:10, B=20:50)
h.boxplot(data, col.scheme='green', outline=F, frame=F)
h.boxplot(data, col.scheme='blue', outline=F, frame=F)
Should give something like:
There's not a parameter that you can set on the base boxplot function to get that behavior, but you can kind of fake it by drawing rectangles over the plot with different colors. For example
bx<-boxplot(count ~ spray, data = InsectSprays, col = "lightgray")
rect(1:6-.4, bx$stats[2,], 1:6+.4, bx$stats[3,], col="orange")
rect(1:6-.4, bx$stats[3,], 1:6+.4, bx$stats[4,], col="yellow")
You can continue to customize that however you like.

spplot: put labels on the map

I seek help on how to change font size and font color for sp.text labels on the attached map—to avoid overlapping of labels and to improve readability.
Map was produced as below. If needed, one may download the SpatialPolygonsDataframe object 'mymap' here.
trellis.par.set() is not solving my problem. Am I using it incorrectly?
library(sp)
library(latticeExtra)
# Create list object for sp.layout (Got these functions here on stackoverflow, thank you owner)
sp.label <- function(x, label) {list("sp.text", coordinates(x), label)}
NUMB.sp.label <- function(x) {sp.label(x, as.vector(x#data$NUMB))}
make.NUMB.sp.label <- function(x) {do.call("list", NUMB.sp.label(x))}
# Spplot
tps <- list(fontsize=list(text=5), fontcolor=list(text="green"))
trellis.par.set(tps)
spplot(mymap, "indic",
col.regions=c("#D3D3D3","#A9A9A9"),
sp.layout = make.NUMB.sp.label(mymap),
cex = 0.5,
bg = "white", col="light grey", border="light grey")
Found the solution: Needed to add cex, col arguments in the list:
list("sp.text", coordinates(x), label, cex=0.5, col="green")

How to add multiple straight lines in a multi plot.zoo

I have multiple time series data plots and I need an horizontal line in each plot but with different horizontal values (es. 1st plot: h=50, 2nd plot: h=48...).
I tried abline(h=50... and I get the horizontal line in each plot.
I tried abline(h=c(50,48... and I get multilple horizontal lines in each plot.
I can't figure out how to get the plot.zoo index in order to plot h=50 in the 1st plot, h=48 in the 2nd plot and so on.
library(xts)
data(sample_matrix)
x <- as.xts(sample_matrix)
# plot with single line
my.panel <- function(x, ...) {
lines(x, ...)
abline(h=50, col = "red", lty="solid", lwd=1.5 )
}
plot.zoo(x, main="title",
plot.type="multiple", type="o", lwd=1.5, col="blue",
panel=my.panel)
# plot multiple lines in all plots
my.panel <- function(x, ...) {
lines(x, ...)
abline(h=c(50,50,48,50), col = "red", lty="solid", lwd=1.5 )}
plot.zoo(x, main="title",
plot.type="multiple", type="o", lwd=1.5, col="blue",
panel=my.panel)
To customize single panels in a multipanel plot is not thoroughly described in the actual ?plot.zoo text. In the 'Details' section you find:
"In the case of a custom panel the panel can reference parent.frame$panel.number in order to determine which frame the panel is being called from. See examples.". And there are quite a few examples. Using them as template, I found that this could be a way to call separate panels, and draw a separate hline in each.
Update. Thanks to #G. Grothendieck for an edit that made the code much cleaner!
# create values for hline, one for each panel
hlines <- c(50, 50, 48, 50)
# panel function that loops over panels
my.panel <- function(x, ...) {
lines(x, ...)
panel.number <- parent.frame()$panel.number
abline(h = hlines[panel.number], col = "red", lty = "solid", lwd = 1.5)
}
plot.zoo(x, main = "title", type = "o", lwd = 1.5, col = "blue", panel = my.panel)

how to create a plot with customized points in R?

I know I can create a plot with line and dots using the type = "o" argument in the plot command. I would like some more control over this -- I want to be able to draw the "o" as full dots, with black border and fill-in color of my choice, of customized size and of a different color than the line. Same for the line, I want to make it thicker, and of my choice of color. How would I go on about doing that?
What I found until now is just a plain
plot(y, type= "o")
which is too poor for my needs.
I am not interested in using ggplot, but instead use the internal plot library of R.
Any help appreciated.
All the information you need should be present in ?plot and ?points, as suggested by #BenBolker. In particular, you want to be using pch=21, and specifying background colour with the bg argument, size with cex, and line width with lwd.
If you want the line to be a different thickness to the point borders, you need to plot the line first, and then overlay the points.
For example:
y <- sample(10)
plot(y, lwd=6, type='l')
points(y, bg='tomato2', pch=21, cex=3, lwd=3) # tomato2 is a personal fave
You could also provide a vector of lwd, cex and col to the points call:
plot(y, lwd=6, type='l')
points(y, bg=rainbow(10), pch=21, cex=seq(1, by=0.2, length.out=10),
lwd=seq(2, by=1, length.out=10))
You could use layering (I don't work in base too much any more as a social researcher I love the facet_grid of ggplot, so there may be a better way) as in:
x <- sort(rnorm(25))
y <- sort(rnorm(25))
z <- as.factor(sample(LETTERS[1:5], 25, r=TRUE))
plot(x, y, pch = 19, cex = 1.3)
par(new = TRUE)
plot(x, y, pch = 19, cex = 1, col = z)
Which gives you:

Get plot() bounding box values

I'm generating numerous plots with xlim and ylim values that I'm calculating on a per-plot basis. I want to put my legend outside the plot area (just above the box around the actual plot), but I can't figure out how to get the maximum y-value of the box around my plot area.
Is there a method for even doing this? I can move the legend where I want it by manually changing the legend() x and y values, but this takes a LONG time for the amount of graphs I'm creating.
Thanks!
-JM
Here's a basic example illustrating what I think you're looking for using one of the code examples from ?legend.
#Construct some data and start the plot
x <- 0:64/64
y <- sin(3*pi*x)
plot(x, y, type="l", col="blue")
points(x, y, pch=21, bg="white")
#Grab the plotting region dimensions
rng <- par("usr")
#Call your legend with plot = FALSE to get its dimensions
lg <- legend(rng[1],rng[2], "sin(c x)", pch=21,
pt.bg="white", lty=1, col = "blue",plot = FALSE)
#Once you have the dimensions in lg, use them to adjust
# the legend position
#Note the use of xpd = NA to allow plotting outside plotting region
legend(rng[1],rng[4] + lg$rect$h, "sin(c x)", pch=21,
pt.bg="white", lty=1, col = "blue",plot = TRUE, xpd = NA)
The command par('usr') will return the coordinates of the bounding box, but you can also use the grconvertX and grconvertY functions. A simple example:
plot(1:10)
par(xpd=NA)
legend(par('usr')[1], par('usr')[4], yjust=0, legend='anything', pch=1)
legend( grconvertX(1, from='npc'), grconvertY(1, from='npc'), yjust=0,
xjust=1, legend='something', lty=1)
The oma, omd, and omi arguments of par() control boundaries and margins of plots - they can be queried using par()$omd (etc). and set (if needed) using par(oma=c()) (where the vector can have up to 4 values - see ?par)

Resources