Base R get raster image to fill entire plot area - r

I'm trying to use base R to plot an image with points overlaid on top, but the image is not taking up the whole plot area. How can I make sure the image is utilizing the whole plot area (essentially making it larger) while still maintaining the spatial boundaries provided by points()? For example:
library(EBImage)
library(magrittr)
url <- "https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png"
img <- EBImage::readImage(url)
if (Sys.info()[["sysname"]] == "Linux") {
img <- EBImage::rotate(img, 180) %>%
EBImage::flop(.)
}
res = dim(img)[1:2]
par(bg = 'grey')
plot(1,1,xlim=c(0,res[1]),ylim=c(res[2],0),asp=1,type='n',xaxs='i',yaxs='i',
xaxt='n',yaxt='n',xlab='',ylab='',bty='n')
graphics::rasterImage(img,1,1,res[1],res[2])
points(266,266, pch = 20, cex = 0.75, col="red")
points(329, 266, pch = 20, cex = 0.75, col="red")
points(315, 318, pch = 20, cex = 0.75, col="red")
Results in an image like this:
Ideally, I'd like to have the image fill the entire area of the plot (in grey).

By default, R allows a certain margin around the figure region to allow for labels, axes, and annotations. The default is c(5, 4, 4, 2) + 0.1.
To change these margins, do this:
par(bg = 'grey', mar=c(0,0,0,0))

Related

Moving legend outside of plot area (Vegan package)

I'm trying to use vegan package in R to create NMDS plots for my research. I'm having problems placing the legend in the correct area, however. The legend always covers some of the points and gets cut off by the outline of the plot. Anyone have any ideas of how I could format the legend outside of the plot area, or move it so that it doesn't cover up any points?
Here is an exported image of what my graph looks like now, with part of the legend missing and covering up some points.
Here is the script I've been using:
op <- ordiplot(nmds, type = 'n')
cols = c('darkred', 'darkgreen', 'darkblue', 'yellow', 'pink', 'lightgreen', 'lightblue', 'black')
points(nmds, cex = 2, pch = 16, col = cols[coral_ENV$Year])
ordispider(nmds, groups = coral_ENV$Year, label = TRUE, label.size = 0.2)
ordihull(nmds, groups = coral_ENV$Year, lty = 'dotted')
legend("topleft", inset = 0.03, pch = 16, col = cols, text.width = 0.05, legend = levels(coral_ENV$Year))
I'm pretty new to R so I'd appreciate any help!

Rotate text in outer margin of device region

I'd like to add text to the right outer margin of multiple plots that is parallel to the axis but oriented towards the center of the plot (the orientation of the words "red" and "blue" in the below plot:
par(mfcol=2:1)
curve(sin,-2*pi,2*pi,col=2)
limits <- par("usr")
text(limits[2]+.25, mean(limits[3:4]),
"red", srt=270, xpd=T)
curve(sin,-2*pi,2*pi,col=4)
text(limits[2]+.25, mean(limits[3:4]),
"blue", srt=270, xpd=T)
mtext("Color of line",side=4,outer=T)
If the mtext function used the srt parameter rather than las (which was apparently the case for S plus), this would be trivial and the above workaround using usr would be unnecessary. But I'd like to be able to orient text in the outer margin ("Color of line" above) this same way, which I appear to be unable to do even manually with text (using xpd=T still constrains the text to the most recent figure region rather than the device region).
Is there a way to do this that doesn't require using layout as in the answer of #mrflick here? This seems like it should be trivial but I don't see how it can be done.
To find the y coordinates of the center of the device, you can use grconvertY to convert from "normalized device coordinates" ("ndc"; ranges from 0 to 1) to user coordinates.
The x value is here simply adjusted with an appropriate factor (e.g. limits[2] * 1.2).
windows()
par(mfrow = c(2, 1), oma = c(0, 0, 0, 2))
curve(sin, -2*pi, 2*pi, col = 2)
limits <- par("usr")
text(limits[2] + 0.25, mean(limits[3:4]),
"red", srt = 270, xpd = TRUE)
curve(sin, -2*pi, 2*pi, col = 4)
text(limits[2] + 0.25, mean(limits[3:4]),
"blue", srt = 270, xpd = TRUE)
text(x = limits[2] * 1.2, y = grconvertY(0.5, from = "ndc"),
labels = "color of line", xpd = NA, srt = 270)
Please see previous revisions if you rather want to calculate y position from user coordinates ("usr") and plot margins ("mai").

Add second barplot to existing one manually (using add=T)

Is there a way in base R to manually add a second barplot to an existing one. I know how to do it if the two series are from the same data object (using barplot( ... beside=T)) or I guess one could draw rectangles (rect(...)) which barplot wraps. If your data is from different objects how can you then do it with the barplot function ? How to control bar positions?
I tried this using the space parameter (obviously not working):
h1 <- c(10,5,1)
h2 <- c(8, 3, 1)
barplot(h1, width = 0.5, space = 2, col='red')
barplot(h2, width = 0.5, space = 2.5, col='blue', add=T)
It is impossible to get the bars besides each other as when using the beside=T argument.
Desired output is something along this:
barplot(matrix(c(h1, h2), nrow=2, byrow=T), beside=T, col=c('red', 'blue'))
UPDATE: how it works
In order for me to finally - I hope - understand the width and space arguments, we can plot an axis and play with the parameters for the blue data.
barplot(h1, width = 0.5, space = 2, col='red')
axis(1, seq(0, 10, 0.5)) #way out of the plot region
barplot(h2, width = 0.25, space = c(4,2,4), col='blue', add=T)
From this it seem as (correct me if I am wrong):
1. width is the width of each bar - recycled as necessary
2. space controls the space to the previous bar (to the left) or to 0 for the first bar, and is calculated as width*space for the current bar - recycled as necessary. So the first blue bar starts at (space to 0) 0.25*4 = 1 and its right side is at 1+0.25 = 1.25; the second bar starts at 1.25+0.25*2 = 1.75, and its right side is at 1.75+0.25 = 2. And so forth...
You can do this:
h1 <- c(10,5,1)
h2 <- c(8, 3, 1)
barplot(h1, width = 0.5, space = 2, col='red')
barplot(h2, width = 0.5, space = c(3,2,2), col='blue', add=T)
And this will be the output:

how to increase the radius in circlize plot

I have drawn the following plot using the circlizepackage. The red circle is the unit circle drawn afterwards, using plotrix. I want to plot the first track outside the red unit circle. For this reason I changed canvas.xlim and canvas.ylim to c(-1.2, 1.2). However, this does not work. Any ideas how to increase the circle radius for the circlize plot?
NOTE: Alternatively, it would be sufficient for me, if the tracks would be outside of the unit circle instead of inside.
library(circlize)
set.seed(2)
n = 10
a = data.frame(factor = "dummy",
x = rnorm(n, 100, sd=10))
circos.par(track.height = 0.2,
canvas.xlim=c(-1.2, 1.2), # bigger canvas?
canvas.ylim=c(-1.2, 1.2)) # bigger canvas?
circos.initialize(factors = a$factor,
x = a$x, xlim = c(0, 360))
lim <- c(-1.2, 1.2)
plot(NULL, asp=1, xlim=lim, ylim=lim)
circos.trackHist(a$factor, a$x, col = "blue", bg.col = grey(.95))
plotrix::draw.circle(0,0,1, border="red", lwd=2) # unit circle
I don't know how to adjust xlim and ylim to make two plots fit. But if you just want to put the red circle inside the track, you can use draw.sector() function directly:
circos.initialize(factors = a$factor,
x = a$x, xlim = c(0, 360))
circos.trackHist(a$factor, a$x, col = "blue", bg.col = grey(.95))
draw.sector(0, 360, rou1 = circlize:::get_most_inside_radius(),
border = "red")
Here circlize:::get_most_inside_radius() returns the distance between the bottom border of the last track to the center of the circle.

R legend issue, symbols of points are masked by lines

Is there a way to draw the lines in such a way that they would start on the side of the points, or allow the symbols to be in foreground?
My solution was to make the symbols bigger and more visible.
Edit 1: it's for plot {graphics} of the R program.
Edit 2: the code per popular request.
legend(2,.4,bty='n', c('sugar','citrus','none'), pch=c('s','c','u'), pt.bg='white',lty= c(1,2,3), lwd=1.5, title="Condition",pt.cex=c(1.5),cex=1.5)
Edit 3: This is solved for plot(type='b') but somehow not for legend.
Thanks for reading!
The only thing I can come up with is to manually finagle the dash lengths until they end up looking the way you want them. For instance, this:
> plot(1,1)
> legend(c("A", "B"), col = 1:2, x = 1, y = .8, lty="99", pch=1:2)
produces the image below.
The lty parameter allows you to specify the lengths of lines and dashes as hex characters. In this case, it's saying to create a line of length 9 then create a space of length 9 then repeat. It looks like 9 is about the best fit to space around a normal pch symbol.
Note that you'd probably need to adjust this depending on the size of the image, symbol, etc. My advice ultimately would be to export the image from R and touch up the image to meet your needs in graphic editing software.
Going with the suggestion by #JeffAllen, here is a way to get what I think you might want. It requires modifying the legend() function to return the position of the points (these are given by x1 and y1 in body(legend)[[46]]).
legend2 <- legend
body(legend2)[[49]] <- quote(
invisible(list(rect = list(w = w, h = h, left = left, top = top),
text = list(x = xt, y = yt), points = list(x = x1, y = y1)))
)
Make a plot:
plot(-100:100, -100:100, type = "b")
While drawing the legend, draw white circles (pch = 21 with pt.bg = 'white') over the lines, and assign the values invisibly returned by legend2() to an object. Note also the changes to pt.lwd and pt.cex.
myLegend <- legend2(1, .8, bty = 'n', c('sugar','citrus','none'), pch = 21,
pt.bg = 'white', pt.lwd = 0, lty = c(1, 2, 3), lwd = 1.5, title = "Condition",
pt.cex = c(1.8), cex = 1.5)
Finally, draw the characters you'd like to use in the legend using points(), supplying the x and y values from the object myLegend.
points(myLegend$points$x, myLegend$points$y, pch = c('s','c','u'), cex = 1.5)
And this should get you something like:
You could also use the filled points offered by R (pch=21:25) and specify the fill color using pc.bg which gets passed to the points call when creating a legend.
plot(1,1)
legend(c("A", "B"), col = 1:2, x = 1, y = .8, lty=1, pt.bg=1:2, pch=21:22)
generates the following:

Resources