R: tiff( ) won't compress or set resolution to 300 ppi - r

I am trying to save some graphs using R for publication. I want to have them compressed with lzw and have the resolution at 300. For some reason it won't allow me to do this. In fact, it seems like R is ignoring some of the variables I set.
For the code example,
tiff(file="file.tiff",
width=6.83, height=6.83, units="in",
pointsize="12", compression = "lzw",
bg="white", res=300, antialias = "none" )
outputs an uncompressed file of size 28 x 28 inches and a resolution of 72 ppi.
A reproducable example would be
hist(rnorm(1000))
dev.off()
Here is the output of ImageMagick for file.tiff
Image: file.tiff
Format: TIFF (Tagged Image File Format)
Class: DirectClass
Geometry: 2049x2049+0+0
Units: PixelsPerInch
Type: PaletteAlpha
Base type: TrueColor
Endianess: MSB
Colorspace: sRGB
...
Compression: None
...
Filesize: 16.8MB
I tested this on another Apple running 10.7 and get the same results. As can be seen, even when using the options to compress and set the resolution at 300 dpi, the output does not follow the options.

I verified your example with R 2.15.1 on GNU/Linux by appending
hist(rnorm(1000))
dev.off()
to your tiff() call and checked the resulting file "file.tiff" with ImageMagick's command line tool identify (most output omitted):
Image: file.tiff
Format: TIFF (Tagged Image File Format)
Class: DirectClass
Geometry: 2049x2049+0+0
Resolution: 300x300
Print size: 6.83x6.83
[...]
Compression: LZW
[...]
Filesize: 70KB
[...]
The R command seems to do exactly what you intend to do. I suspect that either you create the TIFF file not in the manner you describe or the tool you use to check the TIFF file's properties is faulty.

Related

Displaying tif files in jupyter notebook vie ipywidgets

I am trying to display .tif images using the ipywidgets in jupyter-notebooks. The below code works for .png and .jpg files
from ipywidgets import Image
png_image_path = r"C:\Users\xxxxxxxx\Work\Exercises\images\000000000.png"
file = open(png_image_path, "rb")
im = file.read()
Image(
value=im,
width=300,
height=400,
)
type(im) # <class 'bytes'>
The ipywidget from the above code renders the desired image. For reading a tif file I am using gdal.
img = gdal.Open(tif_img_path).ReadAsArray()
print(img.shape) # (3, 1024, 1024)
print(img.transpose(1,2, 0).shape) # (1024, 1024, 3)
type(img.transpose(1,2,0).tobytes()) # <class 'bytes'>
Image(
value=img.transpose(1,2,0).tobytes(),
width=300,
height=400,
)
I get the following output, the image is not properly displayed in the ipywidget
The fact that you just do file.read() on the PNG image implies to me that Jupyter widgets expect a PNG or JPEG-encoded image, with a header and compressed pixel data.
If you open your TIFF with GDAL you will have a Numpy array, so you will need to encode it into an "in-memory" PNG or JPEG before passing to Jupyter widgets. You can do that with OpenCV like this:
import cv2
# Open TIFF image into Numpy array
img = gdal.Open(tif_img_path).ReadAsArray()
# Encode into in-memory PNG for Jupyter
_, PNG = cv2.imencode('.png', img)
As you rightly note in the comments, OpenCV uses BGR ordering so you would need to reverse the order of the colour channels with:
RGBimage = cv2.cvtColor(BGRimage, cv2.COLOR_BGR2RGB)
As an alternative to introducing the OpenCV dependency and its weird channel ordering, you could use PIL/Pillow which uses regular RGB ordering. In that case, you would convert a Numpy array you got from GDAL into a PNG with:
from io import BytesIO
im = ... read from GDAL ...
# Write Numpy array to in-memory PNG
membuf = BytesIO()
Image.fromarray(im).save(membuf, format="png")
... you can now use membuf.getvalue()
Note also, that in general TIFFs may contain float or float64 values that cannot be expressed in an 8-bit JPEG, so you may need to re-scale your data to fit the smaller range.

How to set the resolution of a png in R on a Mac

How to create a png with a 100 dpi resolution in R, on a Mac, by the png function?
I try:
png("1.png", res = 100)
plot(1)
dev.off()
On a Mac, the above code however produces a png with only 72 dpi, which can be checked e.g. on the command line by
sips -g dpiWidth 1.png
dpiWidth: 72.000
Running the above R code on Windows or Unix, both results in a png with indeed the expected resolution of 100 dpi. I am aware of workarounds (using sips or ggplot), but I'd prefer the above command to work as expected on a Mac too. Am I missing something? Is there a way to (re)set the resolution of a yet existing png using R?
Thanks!
It seems that type = "cairo" can do the trick!
png("1.png", res = 100, type = "cairo")
plot(1)
dev.off()
On Mac's command line one can check that the resulting resolution is indeed 100 dpi:
sips -g dpiWidth 1.png
dpiWidth: 100.000

Get the plot I am looking at as a 300px TIFF for publication

I'm trying to solve a common problem for me. Once I have a plot (usually made using ggplot) then I need the output in a high res (300 or sometimes 600 dpi) TIFF image (in OSX).
I figure I could make a simple function for this, but it seems not to work the way I expected.
dev.copy2tiff <- function(filename,res=300,compression="lzw",...){
sizes <- dev.size(units="px")
cop <-dev.copy(tiff,filename=filename,width=sizes[[1]],height=sizes[[2]],units="px",res=res,compression=compression,pointsize = 3,...)
dev.flush()
dev.off()
return(cop)
}
Output:
Screenshot of what the plot should look like:
Why are the output in the TIFF not like what is on the screen, and what can I do about it?
EDIT:
Just realized: the size of the device should of course be specified as width and height, not pixels. This revised code:
dev.copy2tiff <- function(filename,res=300,compression="lzw",...){
sizes <- dev.size(units="cm")
cop <- dev.copy(tiff,filename=filename,width=(sizes[[1]]),height=(sizes[[2]]),units="cm",res=res,compression=compression,...)
dev.flush()
dev.off()
return(cop)
}
Produces a nicely looking TIFF image that looks like the one presented on the screen (in RStudio), but in 72 DPI (according to OS X Preview).
How come it's not 300 dpi?
The solution to this seems to be to go through the EPS file format.
dev.copy2eps(file="filename.eps")
is now my friend. Once opened in Preview (OSX) it can be exported to TIFF (or submitted as is).

Export image from R to word with alpha channel (transparency)

I am wanting to export an R produced figure to Word. The figure contains transparency (alpha channel). Below is some example code - when exported to Windows metafile it throws an error:
Warning message:
In plot.xy(xy, type, ...) :
semi-transparency is not supported on this device: reported only once per page
Exporting to SVG produces the desired result, but this image format is not supported by MS Office. Is there a way around this? What image type could I use while retaining the alpha channel? PNG is possible, but this doesn't produce very crisp graphics - it loses the clear vectorized image.
# Get some colours with transparency (alpha = 0.6)
col.dot <- rainbow(5, alpha = .6)
# Save to svg file - OK
svg("test_fig.svg")
plot(1:5,col = col.dot, pch=15)
dev.off()
# Save to wmf - warning "semi-transparency is not supported on this device..."
win.metafile("test_fig.wmf")
plot(1:5,col = col.dot, pch=15)
dev.off()
I should add, this is on a Windows system (Windows 8 64 bit, with Word 2013)
I just made a new package export to easily export R graphs to Office (Word, Powerpoint), see
https://cran.r-project.org/web/packages/export/index.html and
for demo https://github.com/tomwenseleers/export.
Typical syntax is very easy, e.g.:
install.packages("export")
library(export)
library(ggplot2)
qplot(Sepal.Length, Petal.Length, data = iris, color = Species,
size = Petal.Width, alpha = I(0.7))
graph2ppt(file="ggplot2_plot.pptx", width=6, height=5)
Output is vector format and so fully editable after you ungroup your graph in Powerpoint. You can also use it to export to Word, Excel, Latex or HTML and you can also use it to export statistical output of various R stats objects.
This results in a fully editable, high quality Powerpoint graph in native Office vector-based DrawingML format, which you can also readily copy & paste as enhanced metafile if you like, and which unlike the EMFs exported from R also fully supports transparency.
From the help of win.metafile:
There is support for semi-transparent colours of lines, fills and text
on the screen devices. These work for saving (from the ‘File’ menu) to
PDF, PNG, BMP, JPEG and TIFF, but will be ignored if saving to
Metafile and PostScript.
So you cannot use transparency in a metafile. You can try saving as png and increasing the resolution of the output.

Convert pdf to png in R

I'm trying to convert a pdf plot to a png or jpeg file.
The reason is that I want to use the images for presentations and I need both formats, having exactly the same dimensions/scaling.
I tried the function im.convert() in the animation package, but the output looks really bad, in both png and jpeg.
To be able to run the following code you need the "animation" package and the ImageMagick software (http://www.imagemagick.org/script/convert.php)
library("animation")
ani.options(outdir = getwd())
pdf("bm.pdf")
plot(1:10)
dev.off()
im.convert("bm.pdf", output = "bm.jpeg")
im.convert("bm.pdf", output = "bm.png")
The result of im.convert is probably not satisfactory because it uses the default resolution, which is 74 dpi. You can increase the resolution by passing an extra parameter:
im.convert("bm.pdf", output = "bm.png", extra.opts="-density 150")
-density 150 will double the resolution and your PNGs and JPEGs will look nicer.
But in general it is probably better to use png() and jpeg() to generate the plots and use appropiate parameters to get the same results as with pdf(). For example:
pdf(width=5, height=5)
plot(1:10)
dev.off()
png(width=5, height=5, units="in", res=150)
plot(1:10)
dev.off()

Resources