small plot with no margins - border with line width (lwd) equal to 1 not visible - r

I've been trying to make some very tiny line graphs using base plotting functions, but am coming unstuck when trying to add a thin border.
This is via RGui on Windows 7, saving a png from the plot window.
Here's my code:
dev.new(width=1.3,height=0.3)
par(mar=c(0,0,0,0))
set.seed(13)
x <- 1:10
y <- runif(10)
plot(x,y,type="n",xaxs="i",yaxs="i",ylim=c(0,1))
polygon( c(1,x,max(x),0), c(0,y,0,0), col="lightblue", border=NA)
lines(x,y,lwd=1)
Everything is fine until I try to add a box with a line width of 1, giving:
box(lwd=1)
Now I can solve this by increasing the line width to 2, but this seems a bit of a hack.
box(lwd=2)
Using rect like rect(1,0,10,1) doesn't seem to give me an appropriate solution either, with the bottom and right borders not being visible.

Have you considered giving mar a small non-zero value:
dev.new(width=0.3,height=0.3)
par(mar=c(0.01,0.01,0.01,0.01))
set.seed(13)
x <- 1:10
y <- runif(10)
plot(x,y,type="n",xaxs="i",yaxs="i",ylim=c(0,1))
polygon( c(1,x,max(x),0), c(0,y,0,0), col="lightblue", border=NA)
lines(x,y,lwd=1)
box(lwd=1)
I admit I haven't quite figured out what the end-game might be, but when I do an interactive "stretch" of that very small screen-object, it does result in an all-around border.
I do recognize that I am on a Mac and saving this to a pdf file and converting it to a png file for SO-inclusion may not be precisely reproducible on a Linux or Windows device.

Another solution base in grid and gridBase package. The idea is to replace the box by grid.rect.
Use gridBase to get the base viewport
Introduce some offset (viewport y ) to show the bottom line
Reduce the width of the viewport to show the right line.
Here my code:
library(gridBase)
sp <- baseViewports()
vp <- sp$plot
vp$width <- unit(0.999,'npc')
vp$y <- unit(0.001,'npc')
pushViewport(vp)
grid.rect(gp=gpar(fill=NA))
upViewport(1)
EDIT thanks to #baptiste, you can simply get the same result using only grid.rect:
library(grid)
grid.rect(width = unit(0.999,'npc'),
y = unit(0.5001, "npc"),
gp=gpar(fill=NA))

To answer my own question thanks to #baptiste's tip-off, this is a device dependent issue due to RGui. If the image is saved directly out to file using png everything works as intended. E.g.:
dev.new(width=1.3,height=0.3)
# repeat from here onwards only for png call below
par(mar=c(0,0,0,0))
set.seed(13)
x <- 1:10
y <- runif(10)
plot(x,y,type="n",xaxs="i",yaxs="i",ylim=c(0,1),bty="n")
polygon( c(1,x,max(x),0), c(0,y,0,0), col="lightblue", border=NA)
lines(x,y,lwd=1)
box(lwd=1)
Saving out to png from the "R Graphics" window gives my original stuffed up image:
Going directly to file using png like:
png("textbox_direct.png",width=116,height=27)
# take code block from above
dev.off()
...gives the correct result:

Related

Is it possible to plot images in a ggplot2 plot, that don't get distorted when you save to any non-standard aspect ratio?

I'm looking for any solution to this problem, regardless of packages used.
The problem at hand is that plotted images get distorted when you save them using ggsave. Let me give an example:
image_links = data.frame(id = c(1,2,3,4,5),
image = c("https://cdn.shopify.com/s/files/1/1061/1924/products/Smiling_Emoji_with_Eyes_Opened_large.png",
"https://cdn.shopify.com/s/files/1/1061/1924/products/Smiling_Emoji_with_Smiling_Eyes_large.png",
"https://cdn.shopify.com/s/files/1/1061/1924/products/Hushed_Face_Emoji_large.png",
"https://cdn.shopify.com/s/files/1/1061/1924/products/Disappointed_but_Relieved_Face_Emoji_large.png",
"https://cdn.shopify.com/s/files/1/1061/1924/products/Expressionless_Face_Emoji_large.png"))
mydata = data.frame(x = rnorm(100, mean = 50, sd = 20),
y = rnorm(100, mean = 50, sd = 5),
id = rep(c(1,2,3,4,5), 20))
mydata$y = mydata$y - 10*mydata$id
mydata = mydata %>% left_join(image_links, by='id')
g <- ggplot(mydata) + geom_image(aes(x=x, y=y, image=image), size=0.05)
ggsave(g, filename='[INSERT PATH HERE].png', width=width, height=height, dpi=300)
This works fine:
The problem arises when you adjust the width and height parameters of ggsave, for instance because you want the x and y-axis to be in the correct proportion:
width = (max(mydata$x) - min(mydata$x))/10
height = (max(mydata$y) - min(mydata$y))/10
ggsave(g, filename='[INSERT PATH HERE].png', width = width, height=height, dpi=300)
The x and y-axis are now fine, but the images are distorted:
This happens in ANY situation where you plot an image but the width/height aspect ratio is different than what was the original aspect ratio of the image you want to add.
I'm looking for any solution to this problem, not necessarily restricted to ggimage. It seems very weird to me that you can't properly add images to a ggplot, as I image it's very common for people to want to do that.
I don't know a lot about ggsave, but this seems like an issue related to relative versus absolute units. Probably the geom_image() calculates positions relative to the axes, which get distorted when the axes get resized (such as within ggsave). For example:
ggplot(mydata) + geom_image(aes(x=x, y=y, image=image), size=0.05)
Can look like:
Or can look like:
Depending on the device window that I can resize at will.
There are two ways I can see this getting fixed, both of which will involve re-calculating the sizes of the rasters at drawtime. The easier fix will be the one below.
# Get plot
g <- ggplot(mydata) + geom_image(aes(x=x, y=y, image=image), size=0.05)
# Convert to gtable
gt <- ggplotGrob(g)
# Get the imagegrobs, correct slots found by trial and error
imagegrobs <- gt$grobs[[6]]$children[[3]]$children
# Re-class them to a custom, made-up class
imagegrobs <- lapply(imagegrobs, function(image) {
class(image) <- c("fixasp_raster", class(image))
image
})
# Put them back into the gtable
gt$grobs[[6]]$children[[3]]$children <- imagegrobs
So now that we have a custom class for these images, we can write a piece of code that gets executed at the time of drawing by writing a method for our class using the S3 generic makeContent from the grid package.
library(grid)
makeContent.fixasp_raster <- function(x) {
# Convert from relative units to absolute units
h <- convertHeight(x$height, "cm", valueOnly = TRUE)
w <- convertWidth(x$width, "cm", valueOnly = TRUE)
# Decide how the units should be equal
x$height <- x$width <- unit(sqrt(h * w), "cm")
x
}
Note that taking the square root of the product is improvised, I don't know if this is the optimal procedure.
When we plot the data now, we'll have a consistent size of the images, regardless of the aspect ratio:
grid.newpage(); grid.draw(gt)
The second way to fix this is to file an issue in the github page of the ggimage package, motivating your use case and convice them to implement something that adresses your concerns. If they want, they could make a fix at the ggproto level, so that you don't have dabble with gtables.
#teunbrand's answer has been implemented in dev version 0.2.4 of ggimage. You can install the latest dev version like this:
setRepositories(ind=1:2)
## install.packages("devtools")
devtools::install_github("GuangchuangYu/ggimage")
This should fix the aspect ratio issues.

Define margins of PDF used for boxplot rendering

When I render a boxplot on a PDF device in R there is a large white space besides the graph, especially at the top that i intent to reduce.
My script is basically just:
data <- read.csv("input.csv")
pdf(file="output.pdf", width=4, height=5)
boxplot(data, xlab="input graphs", ylab="vertex count")
This leads to something like:
where the grey outline indicates the end of the document.
I tried to use the par attributes "mar" and "mai" as described in https://stat.ethz.ch/R-manual/R-devel/library/graphics/html/par.html but it had no effect.
boxplot(data, mar=c(0,0,0,0=, mai=c(0,0,0,0))
Do you have an advice how I can gain whitespace control? I want to have zero outer whitespace as the generated graph will be used in a Latex environment that provides sufficient spacings on its own. I am using Ubuntu as OS.
Define mar right after pdf. Try this as an example
pdf(file = "test.pdf", width = 5, height = 5)
par(mar = c(5, 5, 0.05, 0.05))
set.seed(42)
plot(rnorm(20))
dev.off()

ggplot2 and TikzDevice - Removing White Space

I am using tikzDevice package to obtain Latex-friendly graphs in R. I am having trouble in removing excessive white spaces from top and bottom of the graph below:
I have tried using par(mar) but it does not seem to work with ggplot2. Also, theme(plot.margins) seems to unresponsive as well. The white space is introduced as I try to alter the aspect ratio of the figure with theme(aspect.ratio).
Any suggestions?
Thanks!
EDIT: Here is a MWE:
library(tikzDevice)
library(reshape2)
x = seq(0,1,0.1)
y1 = x^2+2*x+7
y2= x^+2*x+2
df = data.frame(x,y1,y2)
df <- melt(df, id.vars=c("x"))
names(df) <- c("x","$latex~Name$","value")
plot <- ggplot(df,aes(x=x,y=value,color=`$latex~Name$`,group=`$latex~Name$`)) + geom_line() +
theme(aspect.ratio = 0.4)
plot
tikzDevice(file="mweTex.tex")
plot
dev.off()
The problem seems to be caused by some tikz statements that affect the bounding box of the image. Since there doesn't seem to be any option in tikzDevice for minimizing whitespace, I had to think of something else. I managed to fix the generated tikz file by adding the following R code at the end of your MWE:
# remove all lines that invisibly mess up the bounding box
lines <- readLines(con="mweTex.tex")
lines <- lines[-which(grepl("\\path\\[clip\\]*", lines,perl=F))]
lines <- lines[-which(grepl("\\path\\[use as bounding box*", lines,perl=F))]
writeLines(lines,con="mweTex.tex")
I've tested it on your MWE:
The left image is without the fix, the right image is with the fix.

Inconsistent size pdf device

The pdf device in R seems to have an inconsistent output size.
For example:
library(grid)
pdf("myplot1.pdf", width=.51, height=.255)
grid.rect(width = 1, height=1, gp=gpar(col="red"))
dev.off()
results in an incomplete rectangle:
When the width and height are pretty rounded,
pdf("myplot2.pdf", width=.5, height=.25)
grid.rect(width = 1, height=1, gp=gpar(col="red"))
dev.off()
the rectangle is depicted well:
This problem does not occur with other devices such as png. It seems like the size of the pdf file is rounded down, while R still uses the original size to plot.
I've found got the solution.
Apparently, the pdf document is rounded down to the nearest 1/72 of an inch. Still don't know why.
Anyway, this wrapper will do the trick:
pdf2 <- function(file, width, height, ...) {
rnd <- function(x) x %/% (1/72) / 72
do.call("pdf", c(list(file=file, width=rnd(width), height=rnd(height)), list(...)))
}
Depending on the application, you can shorten the dimensions of the box:
pdf("myplot3.pdf", width=.51, height=.255)
grid.rect(height=0.95,width=0.95, gp=gpar(col="red"))
dev.off()
pdf("myplot4.pdf", width=.5, height=.25)
grid.rect(height=0.95,width=0.95, gp=gpar(col="red"))
dev.off()
It's an imperfect solution but may be functional.

Output Stem and Leaf Plot to Image

I'm trying to output a Stem and Leaf plot in R as an image. I'm not sure if there's a nice library which can accomplish this but below is some of the code I've tried.
jpeg(filename="stem.jpeg",width=480,height=480, units="px",pointsize=12)
plot.new()
tmp <- capture.output(stem(men, scale = 1, width = 40))
text( 0,1, paste(tmp, collapse='\n'), adj=c(0,1), family='mono' )
dev.off()
This above code resulted in the data being saved, but it looks very blurry and the plot gets cut off pretty badly. When adding a histogram to an image, R seems to do a good job to scale everything to fit in the size of the image.
jpeg(filename="stem.jpeg",width=480,height=480,
units="px",pointsize=12)
stem(men, scale = 1, width = 40)
dev.off()
This created the image but had no content within it.
Any ideas? Thanks!
That's because stem and leaf plots produce text not images. You can save the text as follows using the sink command: http://stat.ethz.ch/R-manual/R-devel/library/base/html/sink.html
sink(file=“Stem.txt”)
stem(men, scale = 1, width = 40)
sink(file=NULL)
unlink("stem.txt")
To export a stemplot as graphics, you can use a vector graphics format, such
as .eps, .pdf, or .emf. For example, a windows metafile:
win.metafile("stem.wmf", pointsize = 10)
plot.new()
tmp <- capture.output(stem(mtcars$mpg))
text(0,1,paste(tmp,collapse='\n'),family='mono',adj=c(0,1))
dev.off()

Resources