Related
I am having the following issue with the axis() function.
axis(1,
at=1:length(stringi::stri_rand_strings(21, 15)),
labels=stringi::stri_rand_strings(21, 15),
tick=1,
lwd=1,
mgp = c(0,1,0),
col = title_colour,
col.ticks = title_colour
,lty = "solid",
cex.axis = 1,las=2,cex=0.75)
But whatI really need are the tickmarks without the continuous x'x line connecting the ticks:
How do I accomplish this using axis()??
Set col to NA but col.ticks to a value:
plot(1, type = 'n', axes = FALSE)
axis(1, c(0.75, 1, 1.25), col = NA, col.ticks = 1)
(Note my reproducible and minimal example, try to include that in your question!)
When writing a plotting function in R, I'd like to not modify the global environment, so I include something like
op <- par()
on.exit(par(op))
But this is less than satisfactory because it spits out warning messages (e.g., "In par(op) : graphical parameter "cin" cannot be set"), but more importantly, it is not compatible with multi-panel plots. For example, if I had a simple function like
pfun <- function(x) {
op <- par()
on.exit(par(op))
par(bg = "gray21", col = "deeppink", col.axis = "deeppink")
plot(x,
xaxt = "n",
yaxt = "n",
col = "deeppink",
cex = 2,
pch = 22,
bg = "deeppink",
col.lab = "deeppink")
axis(1, col = "deeppink")
axis(2, col = "deeppink")
}
it would work great for a single plot (apart from the warnings), but is incompatible with multi-panel plots, e.g.
par(mfrow = c(2, 2))
pfun(1:10)
pfun(10:1) # overwrites the first plot rather than plotting in the second panel
Is there a way to have the plot parameters reset on exit while also allowing for multi-panel plotting?
We can avoid interfering with multi-panel plots, by only saving /restoring the elements of par that we change in the function. In this case that means only storing bg, col, and axis.col. The important thing is to avoid interfering with the graphical parameters (particularly mfrow, mfcol and mfg) that control multiplot positions.
pfun <- function(x) {
op <- par('bg', 'col', 'col.axis')
on.exit(par(op))
par(bg = "gray21", col = "deeppink", col.axis = "deeppink")
plot(x,
xaxt = "n",
yaxt = "n",
col = "deeppink",
cex = 2,
pch = 22,
bg = "deeppink",
col.lab = "deeppink")
axis(1, col = "deeppink")
axis(2, col = "deeppink")
}
Or, even slightly neater is to make use of the fact that when we set parameters with par it invisibly returns a list of the old values of the parameters we changed. So just the following will work nicely:
op <- par(bg = "gray21", col = "deeppink", col.axis = "deeppink")
on.exit(par(op))
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.
My problem concerns the making of a graph for a publication in R. I have used the plot function like follows:
plot(x=data$SL, y=data$BD, xlab = "SL (mm)", ylab = "BD (mm)", pch=data$pch)
SL ranges from 51.7 to 73.7 and BD from 13.5 to 20.4. Unfortunately I am not allowed to post images yet.
However, wanting to get rid of the box I used "axes=F". Problem now is lack of control over the axis function. I used:
axis(side=1, lwd=3, xpd=TRUE, at=c(min(data$SL):max(data$SL)))
axis(side=2, lwd=3, xpd=TRUE, at=c(min(data$BD):max(data$BD)))
Problem is that I can't manage to get the y- and x-axis to come together on the same point as in the plot with the box. How to let the x- and y- axis to touch each other?
Most likely setting xaxs = "i" and yaxs = "i" will help you getting the desired behaviour.
plot(c(1,2,3),c(2,4,6),axes=F,xaxs = "i",yaxs="i",xlim=c(0,3),ylim=c(0,6))
axis(side=1, lwd=3, xpd=TRUE, at=0:3)
axis(side=2, lwd=3, xpd=TRUE, at=seq(0,6,2))
Try box(bty='L') to draw only the left and bottom parts of the box. You could also just draw the lines yourself using lines, segments, or abline and using grconvertX and grconvertY functions to find the locations where to draw the lines.
I suggest that you follow the procedure you outlined and then use:
box(which = "plot", bty = "l")
e.g.:
plot.new()
plot.window(xlim = c(1, 18), ylim = c(2, 20))
points(1:18, 2:19, pch = 1, col = "#FF7F24", cex = 1.2)
lines(1:18, 2:19, col = "#FF7F24", lwd = 2)
axis(side = 1,
lwd = 0,
lwd.ticks = 1,
at = 1:18,
cex.axis = 0.9)
title(main = "Plot",
ylab = "Y-Axis")
legend("top",
legend = c("Legend"),
col = c("#FF7F24"),
text.col = c("#FF7F24"),
pch = 1,
bty = "n",
cex = 1.2)
axis(side = 2,
lwd = 0,
lwd.ticks = 1)
box(which = "plot", bty = "l")
You should pass the options lwd = 0 and lwd.ticks = 1 to your seperate axis() calls in order to prevent some parts of your axes to appear fatter than other parts of your axis because some get overlayed by your call to box() and some do not.
The solution of using box() at the end is, I think, more general in that you can use it when e.g. you cannot or do not want to pass bty = "l" in your plot.default or plot.window call.
I am plotting correlation coefficients (values = 0.0:1.0) for two isotopes measured in each individual from two populations. I would like to have a fixed aspect-ratio for my scatter-plot so that the x- and y-axis are exactly the same size no matter the graphics device. Suggestions?
This is my first plot in R, any comments on refinements to my code is appreciated? Finally, is it worth investing in learning the basic plotting techniques or should I jump right to ggplot2 or lattice?
My plot script:
## Create dataset
WW_corr <-
structure(list(South_N15 = c(0.7976495, 0.1796725, 0.5338347,
0.4103769, 0.7447027, 0.5080296, 0.7566544, 0.7432026, 0.8927161
), South_C13 = c(0.76706752, 0.02320767, 0.88429902, 0.36648357,
0.73840937, 0.0523504, 0.52145159, 0.50707858, 0.51874445), North_N15 = c(0.7483608,
0.4294148, 0.9283554, 0.8831571, 0.5056481, 0.1945943, 0.8492716,
0.5759033, 0.7483608), North_C13 = c(0.08114805, 0.47268136,
0.94975596, 0.06023815, 0.33652839, 0.53055943, 0.30228833, 0.8864435,
0.08114805)), .Names = c("South_N15", "South_C13", "North_N15",
"North_C13"), row.names = c(NA, -9L), class = "data.frame")
opar <- par()
## Plot results
par(oma = c(1, 0, 0, 0), mar = c(4, 5, 2, 2))
plot(1,1,xlim=c(0:1.0), ylim=c(0:1.0), type="n", las=1, bty="n", main = NULL,
ylab=expression(paste("Correlation Coefficient (r) for ", delta ^{15},"N ",
"\u0028","\u2030","\u0029")),
xlab=expression(paste("Correlation Coefficient (r) for ", delta ^{13},"C ",
"\u0028","\u2030","\u0029")))
points(WW_corr$South_N15, WW_corr$South_C13, pch = 23, cex = 1.25,
bg ="antiquewhite4", col = "antiquewhite4")
points(WW_corr$North_N15, WW_corr$North_C13, pch = 15, cex = 1.25,
bg ="black")
axis(1, at = seq(0, 1.0, by = 0.1), labels = F, tick = TRUE, tck = -0.01)
axis(2, at = seq(0, 1.0, by = 0.1), labels = F, tick = TRUE, tck = -0.01)
abline(h=.86, v=.86, col = "gray60", lty = 2)
legend("topleft", c("North", "South"), pch = c(15, 23),
col = c("black", "antiquewhite4"), pt.bg = c("black", "antiquewhite4"),
horiz=TRUE, bty = "n")
par(opar)
par(pty="s")
plot(...)
sets the plot type to be square, which will do the job (I think) in your case because your x and y ranges are the same. Fairly well hidden option documented in ?par.
Using asp=1 as a parameter to plot will get interpreted by the low-level plot.window call and should give you a unitary aspect ratio. There is the potential that a call using ylim and xlim could conflict with an aspect ratio scpecification and the asp should "prevail". That's a very impressive first R graph, by the away. And an excellent question construction. High marks.
The one jarring note was your use of the construction xlim=c(0:1.0). Since xlim expects a two element vector, I would have expected xlim=c(0,1). Fewer keystrokes and less subject to error in the future if you changed to a different set of limits, since the ":" operator would give you unexpected results if you tried that with "0:2.5".