space images in PDF using R - r

I'm using R to generate PDFs that contain QR code images. The images have to be arranged in a 4x6 pattern like this mockup that i made in Word:
I've written a loader that i plan to write into a loop later on (i've got over 2000 images). However, i can't quite get the spacing right. This is my current result:
It's not a bad thing that the images are smaller, but the large margins on top and bottom and right are a problem. I've been trying to set par(mar = c(4,0,0,0) in the loop to see if the images would get a bottom margin, but that doesn't happen. Also, i think i need to use padding instead of margin, but i haven't found a parameter for padding.
Is there a way to do this? The code i've written so far:
# import libraries
library(qrcode)
library(imager)
# clear workspace
rm(list = ls())
filenames <- list.files(path = "./QR/2/")
im <- load.image(paste0("./QR/2/",filenames[1]))
im <- list()
for(i in 1:24){
im[[i]] <- load.image(paste0("./QR/2/",filenames[i]))
}
pdf("./QR/2/stickervellen/1.pdf", paper = "a4")
par(mfrow = c(6,4), mar=c(0,0,0,0))
for(i in 1:24){
par(mar = c(4,0,0,0))
plot(im[[i]], axes = F)
}
dev.off()
the images i'm using can be found here: https://easyupload.io/v4gmbf

You have to specify the size of your graphics region with width and height. If you don't do that, default values (7 inch) are used and for an A4 paper which has a height of 11.7 inch you won't get full coverage.
pdf("./QR/2/stickervellen/1.pdf", paper="a4", width=8.3, height=11.7)
par(mfrow=c(6, 4), mar=rep(0, 4))
for(i in 1:24){
plot(im[[i]], axes=F)
box()
}
dev.off()
Please note that I added box() in your code so that the extent of the individual plots and the margins around them are visible.
In ?pdf you may also find that if you specify the paper argument
if either width or height is less than 0.1 or too large to give a total margin of 0.5 inch, it is reset to the corresponding paper dimension minus 0.5.
That's why there will always be a small margin around the whole page when you specify paper. If you don't want that margin, just leave out paper="a4" and you will get this:

Related

Control how much space legend.only takes from a raster plot in r

I am trying to simply plot a raster map and a legend barr, but i cannot seem to get it at the right distance from the raster. Is either over it or too far. Also, despite i indicate a fixed width and height to the SVG printing function, the final size does not look similar. Would it be a way to control the exact position of the legend barr when plotting legend.only=T? By the way, stack overflow does not allow me to upload an SVG image, so i am uploading a screen capture that looks similar.
here is how i see it in R
Here is how i get it from the file generated
Here is the script used to generate that image, region and range are polygons, and hill and tmax are rasters. The plotting in R works fine-I just want to know how avoid the changes in the image from the R window to the file. There seems to be something in the exporting function that is creating a high white space between the map and the barr, and it express only when exporting the graph.
svg(paste("/Users/",spp[i],"filename", ".svg",sep=""),
bg="transparent", width = 5,height=5)
plot(region)
plot(hill,col=grey(0:100/100), add=T, legend=F)
plot(range,add=T, border="turquoise")
plot(Tmaxc>tmaxsp,col=heat.colors(100),add=T,legend=F)
plot(Tmaxc>tmaxsp,col=heat.colors(100),legend.only=TRUE, horizontal = TRUE,
legend.args = list(text='Warming tolerance\u00B0C', side = 1, line = 2))
dev.off()

Change size and aspect ratio without distortion

i'm searching for a way in R to make 400x400px images (.jpg/.png) out of a larger images of different size and aspect size without distorting it. The new image should have most of the content of the original one but can be cut off a bit on the left and right so that it becomes a square without distortion.
How far I got (with distortion):
library(magick)
pics <- list.files("./")
for(i in 1:length(pics)){
a <- image_read((paste0("./", pics[i], sep="")))
b<-image_resize(a, "300x300!")
image_write(b, path = paste0("./", pics[i], sep=""), format = "jpg")
}
Thanks in advance!
Dominik.
You can add these lines right before the resize line b<-image_resize(a, "300x300!") to crop a so it is square.
newdim <- min(image_info(a)[c('width', 'height')])
a <- image_crop(a, geometry = geometry_area(newdim, newdim))

Color gradients in R in PDF and bitmap output

I am struggling to get a visually acceptable color gradient in R (see here for a detailed description of my particular case). The problem, in short, is that while output in the R window looks OK, PDFs show thin, white lines between segments used to generate the gradient.
n <- 100
cc <- colorRampPalette(c("red", "blue"))(n)
plot.new()
par(mar=rep(0,4))
sapply(1:n, function(i) rect((i-1)/n, 0, i/n, 1, col=cc[i], border=NA))
dev.copy2pdf(file="test.pdf")
Here is the result:
You can see the thin, white lines. Their positioning depends on the zoom, so I assume that they are an artifact of how the PDF is displayed. Here the same in another zoom:
Unfortunately, these lines are also visible on a printout. I guess the problem may be with how the coordinates in the PDF get rounded when the vector graphics is rendered to bitmap for display or printing.
A possible solution would be to use segments which overlap with each other. This is acceptable only for solid colors; unfortunately, I would like to use transparent colors in the gradients as well.
What can I do to make my output in PDF better?
This seems to be an issue purely due to the renderer. E.g.:
I don't believe there's anything you can change about the PDF to fundamentally fix the issue. In my case, Adobe Acrobat looked good at any zoom level except at very high zoom (I had to go to 3200% zoom to see white lines).
Also, Chrome and Microsoft Edge seemed to work well.
Have you tried this solution? The first rectangle will take a bigger space and the second will be plotted on the first one thus eliminating the white lines behind it. The pdf that Ive got does not show white lines
n <- 100
cc <- colorRampPalette(c("red", "blue"))(n)
plot.new()
par(mar=rep(0,4))
sapply(1:n, function(i) rect((i-1)/n, 0, (i + 1)/n, 1, col=cc[i], border=NA))
dev.copy2pdf(file="test.pdf")
This is zoomed in at 6400 percent

Usage of layout in R

I'm trying to create this layout for this plot:
layout(matrix(c(1,1,1,1,1,1,
2,2,2,3,3,3,
2,2,2,3,3,3,
2,2,2,3,3,3), nrow=4,ncol=6,byrow = TRUE))
# Set up the top chart that keeps track of the current frame/iteration
# Dress it up a little just for fun
plot(-5, xlim = c(1997,2011), ylim = c(0, .3), xlab = "", ylab = "", main = "Time",axes=F)
abline(v=1995, lwd=5, col = rgb(0, 0, 255, 255, maxColorValue=255))
# Bring back the X axis
xticks <- 1997:2011
axis(side=1, at=xticks, labels=xticks)
# Plot
plot(1:100,1:100)
plot(1:100,1:100)
Obviously the last two plot aren't plot(1:100,1:100)in my real code, but I have a question on usage of layout. Why i get this error on the first plot?
Error in plot.new() : figure margins too large
I want the first picture to have a little height
It might sound silly, but the reason is indeed that the figure margins are too large!
Let me elaborate on this. In R, there are several kind of margins to let your pictures breath:
In your particular case, the margins are eating all the space available, as you try to cram too many figures in the same plot.
To solve this, I would advise to set all the margins to 0:
par(mai=c(0,0,0,0), oma=c(0,0,0,0), mar=c(0,0,0,0))
Which will likely result in your plot to at least be rendered. At the same time, all the subplots will be way too close to each other, so you then have to increase the margins little by little, with similar calls to par(...) until the results looks fine.
Hope this helps :)
The margins are measured in multiples of line-heights via the parameters par(mar), par(oma), and par(mai), as described in this passage in ?par
MAR
A numerical vector of the form c(bottom, left, top, right) which gives the number of lines of margin to be specified on the four sides of the plot. The default is c(5, 4, 4, 2) + 0.1.
There are two solutions, you can (a) reduce the margins by setting one of the previous 'par()' settings or (b) you can increase the size of the device, either by re-sizing the device using the mouse if it's a visible device, or if you are printing to PDF, for example, you can set the device size to be larger by setting height and width parameters when you set up the device, as in:
pdf( <<FileNameHere>> , width = par('din')[1],height = par('din')[2] )
I by setting width to par('din')[1] and height to par('din')[2], you get a PDF with the same dimensions as the current device, which lets you make adjustments to the visible device with the mouse. (This is handy for one-off plots and poor practice for a production environment)
If you do reduce the margins, I recommend not setting mar=c(0,0,0,0), as that will result in not having visible axis labels.

How to save an image in R exactly as it is 'stored'?

I generated a random example plot with ggplot2 and multiple facets. I am interested in the exact positions of the individual panels and want to export the relative start and end coordinates of those panels as well as the picture of the plot (basically for point identification via mouseover events in a javascript context).
To get the information i need for the relative coordinates i use the grid package. Suppose p to be the variable which stores my plot (after p <- ggplot(...)).
With
pb <- ggplot_build(p)
pta <- ggplot_gtable(pb)
heights <- pta$heights
and analogously for the widths I get that information.
For example, in this case I get for heigths
[1] 1lines 0cm+0lines 1null
[4] 0.25lines 1null 0.25lines
[7] 1null 0.532222222222222cm 1grobheight+0.5lines
[10] 0.5lines
where the entries with unit null represent the panels. To be able to compare these I have to convert them into the same unit. null I cannot convert but the remaining ones. Using that the viewport is 1npc (npc is a unit too) in width and length I can solve an equation which allows me to create the following image (screenshot from the RStudio Plots window) with the lines drawn with grid.lines():
So everything seems to work. Now if I rescale the Plot window in RStudio the lines are drawn at the wrong places. The reason is that some units like grobheight are dependent on the current viewport. Hence, if I want to save the image (say 600 x 600 pixel) i have to do
png(fn, width = 600, height = 600)
pushViewport(viewport(width=0.5, height=0.5, xscale=c(0, 600), yscale=c(0, 600)))
print(p)
... #draw the lines
dev.off()
But.
Despite that, no matter how I save the image, say ggsave() or png() (the latter either with print(p) oder grid.draw(pta)) the actual proportions differ from the computed ones which were correct in the R environment.
A certain amount of the plotmargins seems to get cut off, and additional scaling is done apparently.
A png export looks like this for example:
The difference seems to be small, but that doesn't help. So, is there a way to save the image exactly as it is described in the gtable object pta? Is it a matter of dpi or pointsize?
Many thanks for your help,
Mika
Everything I've encountered with this exact issue stems back to the height and width call in the png() or pdf() or anything output call. Play with the height and width in order to best determine what it will look like.
If you want to know what it will look like when you export use x11(height= width= ), note the units here are "in" so you will want to mimic that in your output function.

Resources