raster images in r graphics - the r journal because plots are typically made up of data symbols...

7
48 CONTRIBUTED RESEARCH ARTICLES Raster Images in R Graphics by Paul Murrell Abstract The R graphics engine has new sup- port for rendering raster images via the func- tions rasterImage() and grid.raster(). This leads to better scaling of raster images, faster rendering to screen, and smaller graphics files. Several examples of possible applications of these new features are described. Prior to version 2.11.0, the core R graphics engine was entirely vector based. In other words, R was only capable of drawing mathematical shapes, such as lines, rectangles, and polygons (and text). This works well for most examples of statistical graphics because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure 1). Sepal.Length 2.0 3.0 4.0 ●● ●● ●● 0.5 1.5 2.5 4.5 5.5 6.5 7.5 ●● ●● ●● 2.0 3.0 4.0 ●● ●● Sepal.Width ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● Petal.Length 1 2 3 4 5 6 7 ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● 4.5 5.5 6.5 7.5 0.5 1.5 2.5 ●● ●● ●● ●● ●● ●● ●● 1 2 3 4 5 6 7 ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● ●● Petal.Width Figure 1: A typical statistical plot that is well- described by vector elements: polygons, rectangles, lines, and text. However, some displays of data are inherently raster . In other words, what is drawn is simply an array of values, where each value is visualized as a square or rectangular region of colour (see Figure 2). It is possible to draw such raster elements using vector primitives—a small rectangle can be drawn for each data value—but this approach leads to at least two problems: it can be very slow to draw lots of small rectangles when drawing to the screen; and it can lead to very large files if output is saved in a vector file format such as PDF (and viewing the re- sulting PDF file can be very slow). 26008 04006 63001 28028 28032 31007 24005 19005 16004 15004 22010 24001 28019 30001 28021 15005 09008 11005 28036 62001 27003 26003 62002 65005 84004 03002 20002 12012 22013 37013 14016 27004 49006 24011 08011 62003 12026 31011 43001 24017 68003 12006 24010 24022 08001 12007 01005 37039_at 41237_at 37383_f_at 37420_i_at 1461_at 31508_at 41745_at 676_g_at 35016_at 38833_at 38095_i_at 1389_at 675_at 36795_at 38096_f_at 41215_s_at 37043_at 32378_at 37967_at 40369_f_at 36398_at 36798_g_at 39717_g_at 37320_at 34210_at 38968_at 32977_at 41723_s_at 36878_f_at 36773_f_at 41266_at 40570_at 40088_at 41193_at 36650_at 34362_at 38032_at 33774_at 35769_at 39327_at 35260_at 1134_at 35816_at 40480_s_at 2039_s_at 32116_at 39424_at 37413_at 38056_at 37225_at 873_at 40763_at 41448_at 32215_i_at 36092_at 1929_at 33405_at 39716_at 33193_at 40393_at 35663_at 33528_at 34098_f_at 1500_at 36149_at 34247_at 32475_at 205_g_at 31605_at 41348_at 37558_at 33936_at 38223_at 39635_at 37809_at 36873_at 1914_at 931_at 41191_at 39315_at 33358_at 35665_at 31615_i_at 34106_at 36897_at 177_at 38004_at 36777_at 37810_at 1947_g_at 41470_at 37251_s_at 34961_at 39135_at 41071_at 41401_at 38385_at 37724_at 176_at 35831_at 41478_at 1140_at 919_at 39210_at 37479_at 37193_at 33412_at 41779_at 40493_at 35256_at 37184_at 31472_s_at 1126_s_at 2036_s_at 38413_at 1973_s_at 37099_at 37978_at 40785_g_at 40784_at 1674_at 41743_i_at 41742_s_at 40504_at 1307_at 1928_s_at 1308_g_at 40953_at 33809_at 36275_at 33440_at 34699_at 32872_at 40167_s_at 33244_at 1992_at 35714_at 40692_at 41346_at 41397_at 37006_at 36536_at 37280_at 38631_at 34850_at 34789_at 41744_at 39556_at 2057_g_at 1463_at 1911_s_at 37539_at 38408_at 307_at 266_s_at 39781_at 40215_at 1039_s_at 36643_at 1007_s_at 37600_at 32562_at 402_s_at 1267_at 39837_s_at Figure 2: An example of an inherently raster graph- ical image: a heatmap used to represent microarray data. This image is based on Cock (2010); the data are from Chiaretti et al. (2004). Another minor problem is that some PDF view- ers have trouble reconciling their anti-aliasing algo- rithms with a large number of rectangles drawn side by side and may end up producing an ugly thin line between the rectangles. To avoid these problems, from R version 2.11.0 on, the R graphics engine supports rendering raster elements as part of a statistical plot. Raster graphics functions The low-level R language interface to the new raster facility is provided by two new func- tions: rasterImage() in the graphics package and grid.raster() in the grid package. For both functions, the first argument provides the raster image that is to be drawn. This argument should be a "raster" object, but both functions will accept any object for which there is an as.raster() method. This means that it is possible to simply spec- ify a vector, matrix, or array to describe the raster image. For example, the following code produces a simple greyscale image (see Figure 3). > library(grid) > grid.raster(1:10/11) The R Journal Vol. 3/1, June 2011 ISSN 2073-4859

Upload: duongdung

Post on 11-Mar-2018

226 views

Category:

Documents


8 download

TRANSCRIPT

Page 1: Raster Images in R Graphics - The R Journal because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure1)

48 CONTRIBUTED RESEARCH ARTICLES

Raster Images in R Graphicsby Paul Murrell

Abstract The R graphics engine has new sup-port for rendering raster images via the func-tions rasterImage() and grid.raster(). Thisleads to better scaling of raster images, fasterrendering to screen, and smaller graphics files.Several examples of possible applications ofthese new features are described.

Prior to version 2.11.0, the core R graphics enginewas entirely vector based. In other words, R wasonly capable of drawing mathematical shapes, suchas lines, rectangles, and polygons (and text).

This works well for most examples of statisticalgraphics because plots are typically made up of datasymbols (polygons) or bars (rectangles), with axes(lines and text) alongside (see Figure 1).

Sepal.Length

2.0 3.0 4.0

●●

●●

●●

● ●

●● ●

●●

●●

●●

●●

●●

● ●

● ●

●●

●● ●

●●

●●

●●

●●

● ●

●●●

●●

●●●

● ●●

●●

●●

● ●

●●

●●

● ●

●●

●●●

●●

●●●

●●●

●●

●●●●

●●

●●

●●●●●

●●

●●

●●

●●

●●

●●

●●

●● ●

●●

●●

●●

●●

●●

●●●

●●

●● ●

●●●

●●

●●

●●

●●

●●

●●

●●

●●●

●●

●●

●●●

●●

0.5 1.5 2.5

4.5

5.5

6.5

7.5

●●●●

●●

● ●

●● ●●●

●●

●●

●●

●●

●●

●●

●●

●● ●

●●

●●

●●

●●● ●

●●●

●●

●●●

●●●

●●

●●

● ●

●●

●●

●●

●●

●●●

●●

●●

● ●●

●●

2.0

3.0

4.0

●●

● ●

●●

●●

●●

●●

●●●

●●

●●

●●

●●

●●

●●●

●●

●●

●●

●●

●●

●●

●●

●●

●● ●

●●

● ●

● ●●

●●

●●

●●

●●●

●●

Sepal.Width●

●●

●●

●●

●●

●●

●●

●●●

●●

●●

●●

●●

●●

●●●●

●●

●●

●●

●●●

●●

●●

● ●

●●

●●●

●●● ●

● ●●

●●

●●

●●

●●●

●●

●●

●●

●●

●●

●●

●●

●●●

●●

●●

●●

●●

●●

●●●

●●

●●

●●

●●

●●

●●

● ●

●●

●●●

●●

●●

●●●

●●

●●

●●

● ●●

●●

●●●● ●

●● ●● ● ●●

●● ●

●●●

●●

●●

●●

●●●●●● ●● ●●

● ●●●●

●●●●●

●●

● ●●

●●

●●●

●●

●●

●●●

●●

●●●

●●●

● ●●

●●●

●●

●●● ●

●●

●●

●●

●●●●

●●

●●

●●

●●

●●

●●

●●

●●

●●

●●

●●

●● ●● ●

●●●● ● ●●

●● ●

●●●

●●

●●

●●

● ●●●●● ● ●●●● ●●●

●●● ●●

●●

● ●●

●●

●●●

●●

●●

●●●

●●

●●●

●●●

● ●●

●●●

●●

● ●●●

●●

●●

●●

● ●●

●●

●●

● ●

●●

●●

●●

●●

●●

●●

●●

●●

Petal.Length

12

34

56

7

●●●●●

●●●●●●●●

●●●●●

●●

●●

●●● ●●●●● ●●●●●●

●●●

●●●●

●●●●●

●●●

●●●

●●

●●

●●●

●●

●●●

●●●

●●●

●●●

●●

●●●●

●●

●●

●●

● ●●

●●

●●

●●

●●

●●

●●

●●

●●

●●

●●

●●

4.5 5.5 6.5 7.5

0.5

1.5

2.5

●●●● ●

●●

●●●

●●●●

●●● ●●

●●

●●●●

●●●● ●

●● ●

●●●

●●

●● ●●

●● ●

●●

●●

●●

●●

●●

●●●

●●

●●

●●●●

●●● ●

●●

●●●

●●

●●

●●

●●

● ●

●●●

●●

●●

●●

●●

●●

●●

●● ●● ●

●●●●

●●●

●●●

●●● ●●

●●

●●●●

●●●● ●

●● ●

●●●

●●

●● ●●

●●●

●●

●●

●●

●●

●●

●●●

●●

●●

● ●●●

●●

●●

●●

●●●

●●

●●

●●

●●

●●

●● ●

●●

●●

●●

●●

●●

●●

1 2 3 4 5 6 7

●●●●●

●●●●●●●●●

●●●●●

●●

●●●●

●●●●●●●●●●●

●●●●●●

●● ●

●●

●●

●●

●●● ●

●●●

●●●●

●●●●

●●●●

●●

●●●

●●

●●

●●

●●

● ●

●●●

●●

●●

●●

●●

●●

●●

Petal.Width

Figure 1: A typical statistical plot that is well-described by vector elements: polygons, rectangles,lines, and text.

However, some displays of data are inherentlyraster . In other words, what is drawn is simply anarray of values, where each value is visualized as asquare or rectangular region of colour (see Figure 2).

It is possible to draw such raster elements usingvector primitives—a small rectangle can be drawnfor each data value—but this approach leads to atleast two problems: it can be very slow to draw lotsof small rectangles when drawing to the screen; andit can lead to very large files if output is saved in avector file format such as PDF (and viewing the re-sulting PDF file can be very slow).

2600

804

006

6300

128

028

2803

231

007

2400

519

005

1600

415

004

2201

024

001

2801

930

001

2802

115

005

0900

811

005

2803

662

001

2700

326

003

6200

265

005

8400

403

002

2000

212

012

2201

337

013

1401

627

004

4900

624

011

0801

162

003

1202

631

011

4300

124

017

6800

312

006

2401

024

022

0800

112

007

0100

5

37039_at41237_at37383_f_at37420_i_at1461_at31508_at41745_at676_g_at35016_at38833_at38095_i_at1389_at675_at36795_at38096_f_at41215_s_at37043_at32378_at37967_at40369_f_at36398_at36798_g_at39717_g_at37320_at34210_at38968_at32977_at41723_s_at36878_f_at36773_f_at41266_at40570_at40088_at41193_at36650_at34362_at38032_at33774_at35769_at39327_at35260_at1134_at35816_at40480_s_at2039_s_at32116_at39424_at37413_at38056_at37225_at873_at40763_at41448_at32215_i_at36092_at1929_at33405_at39716_at33193_at40393_at35663_at33528_at34098_f_at1500_at36149_at34247_at32475_at205_g_at31605_at41348_at37558_at33936_at38223_at39635_at37809_at36873_at1914_at931_at41191_at39315_at33358_at35665_at31615_i_at34106_at36897_at177_at38004_at36777_at37810_at1947_g_at41470_at37251_s_at34961_at39135_at41071_at41401_at38385_at37724_at176_at35831_at41478_at1140_at919_at39210_at37479_at37193_at33412_at41779_at40493_at35256_at37184_at31472_s_at1126_s_at2036_s_at38413_at1973_s_at37099_at37978_at40785_g_at40784_at1674_at41743_i_at41742_s_at40504_at1307_at1928_s_at1308_g_at40953_at33809_at36275_at33440_at34699_at32872_at40167_s_at33244_at1992_at35714_at40692_at41346_at41397_at37006_at36536_at37280_at38631_at34850_at34789_at41744_at39556_at2057_g_at1463_at1911_s_at37539_at38408_at307_at266_s_at39781_at40215_at1039_s_at36643_at1007_s_at37600_at32562_at402_s_at1267_at39837_s_at

Figure 2: An example of an inherently raster graph-ical image: a heatmap used to represent microarraydata. This image is based on Cock (2010); the dataare from Chiaretti et al. (2004).

Another minor problem is that some PDF view-ers have trouble reconciling their anti-aliasing algo-rithms with a large number of rectangles drawn sideby side and may end up producing an ugly thin linebetween the rectangles.

To avoid these problems, from R version 2.11.0on, the R graphics engine supports rendering rasterelements as part of a statistical plot.

Raster graphics functions

The low-level R language interface to the newraster facility is provided by two new func-tions: rasterImage() in the graphics package andgrid.raster() in the grid package.

For both functions, the first argument providesthe raster image that is to be drawn. This argumentshould be a "raster" object, but both functions willaccept any object for which there is an as.raster()method. This means that it is possible to simply spec-ify a vector, matrix, or array to describe the rasterimage. For example, the following code produces asimple greyscale image (see Figure 3).

> library(grid)

> grid.raster(1:10/11)

The R Journal Vol. 3/1, June 2011 ISSN 2073-4859

Page 2: Raster Images in R Graphics - The R Journal because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure1)

CONTRIBUTED RESEARCH ARTICLES 49

Figure 3: A simple greyscale raster image generatedfrom a numeric vector.

As the previous example demonstrates, a nu-meric vector is interpreted as a greyscale image, with0 corresponding to black and 1 corresponding towhite. Other possibilities are logical vectors, whichare interpreted as black-and-white images, and char-acter vectors, which are assumed to contain eithercolour names or RGB strings of the form "#RRGGBB".

The previous example also demonstrates that avector is treated as a matrix of pixels with a singlecolumn. More usefully, the image to draw can bespecified by an explicit matrix (numeric, logical, orcharacter). For example, the following code shows asimple way to visualize the first 100 named coloursin R.

> grid.raster(matrix(colors()[1:100], ncol=10),+ interpolate=FALSE)

Figure 4: A raster image generated from a charactermatrix (of the first 100 values in colors()).

It is also possible to specify the raster image as anumeric array: either three-planes of red, green, andblue channels, or four-planes where the fourth planeprovides an “alpha” (transparency) channel.

Greater control over the conversion to a "raster"object is possible by directly calling the as.raster()function, as shown below.

> grid.raster(as.raster(1:10, max=11))

Interpolation

The simple image matrix example above demon-strates another important argument in both of the

new raster functions—the interpolate argument.

In most cases, a raster image is not going to berendered at its “natural” size (using exactly one de-vice pixel for each pixel in the image), which meansthat the image has to be resized. The interpolateargument is used to control how that resizing occurs.

By default, the interpolate argument is TRUE,which means that what is actually drawn by R is alinear interpolation of the pixels in the original im-age. Setting interpolate to FALSE means that whatgets drawn is essentially a sample from the pixels inthe original image. The former case was used in Fig-ure 3 and it produces a smoother result, while the lat-ter case was used in Figure 4 and the result is more“blocky.” Figure 5 shows the images from Figures 3and 4 with their interpolation settings reversed.

> grid.raster(1:10/11, interpolate=FALSE)

> grid.raster(matrix(colors()[1:100], ncol=10))

Figure 5: The raster images from Figures 3 and 4 withtheir interpolation settings reversed.

The ability to use linear interpolation providesanother advantage over the old behaviour of draw-ing a rectangle per pixel. For example, Figure 6shows a greyscale version of the R logo image drawnusing both the old behaviour and with the new rastersupport. The latter version of the image is smootherthanks to linear interpolation.

> download.file("http://cran.r-project.org/Rlogo.jpg",+ "Rlogo.jpg")> library(ReadImages)> logo <- read.jpeg("Rlogo.jpg")

> par(mar=rep(0, 4))> plot(logo)

> grid.raster(logo)

The R Journal Vol. 3/1, June 2011 ISSN 2073-4859

Page 3: Raster Images in R Graphics - The R Journal because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure1)

50 CONTRIBUTED RESEARCH ARTICLES

Figure 6: The R logo drawn using the old behaviourof drawing a small rectangle for each pixel (left) andusing the new raster support with linear interpola-tion (right), which produces a smoother result.

In situations where the raster image representsactual data (e.g., microarray data), it is important topreserve each individual “pixel” of data. If an imageis viewed at a reduced size, so that there are fewerscreen pixels used to display the image than there arepixels in the image, then some pixels in the originalimage will be lost (though this is true whether theimage is rendered as pixels or as small rectangles).

What has been described so far applies equally tothe rasterImage() function and the grid.raster()function. The next few sections look at each of thesefunctions separately to describe their individual fea-tures.

The rasterImage() function

The rasterImage() function is analogous to otherlow-level graphics functions, such as lines() andrect(); it is designed to add a raster image to the cur-rent plot.

The image is positioned by specifying the loca-tion of the bottom-left and top-right corners of theimage in user coordinates (i.e., relative to the axisscales in the current plot).

To provide an example, the following code setsup a matrix of normalized values based on a mathe-matical function (taken from the first example on theimage() help page).

> x <- y <- seq(-4*pi, 4*pi, len=27)> r <- sqrt(outer(x^2, y^2, "+"))> z <- cos(r^2)*exp(-r/6)> image <- (z - min(z))/diff(range(z))>

The following code draws a raster image from thismatrix that occupies the entire plot region (see Fig-ure 7). Notice that some work needs to be done tocorrectly align the raster cells with axis scales whenthe pixel coordinates in the image represent data val-ues.

> step <- diff(x)[1]> xrange <- range(x) + c(-step/2, step/2)> yrange <- range(y) + c(-step/2, step/2)

> plot(x, y, ann=FALSE,+ xlim=xrange, ylim=yrange,+ xaxs="i", yaxs="i")> rasterImage(image,+ xrange[1], yrange[1],+ xrange[2], yrange[2],+ interpolate=FALSE)

−10 −5 0 5 10

−10

−5

05

10

Figure 7: An image drawn from a matrix of normal-ized values using rasterImage().

It is also possible to rotate the image (about thebottom-left corner) via the angle argument.

To avoid distorting an image, some calculationsusing functions like xinch(), yinch(), and dim() (toget the dimensions of the image) may be required.More sophisticated support for positioning and siz-ing the image is provided by grid.raster().

The grid.raster() function

The grid.raster() function works like any othergrid graphical primitive; it draws a raster imagewithin the current grid viewport.

By default, the image is drawn as large as possiblewhile still respecting its native aspect ratio (Figure 3shows an example of this behaviour). Otherwise, theimage is positioned according to the arguments x andy (justified by just, hjust, and vjust) and sized viawidth and height. If only one of width or height isgiven, then the aspect ratio of the image is preserved(and the image may extend beyond the current view-port).

Any of x, y, width, and height can be vectors, inwhich case multiple copies of the image are drawn.For example, the following code uses grid.raster()to draw the R logo within each bar of a lattice bar-chart.

The R Journal Vol. 3/1, June 2011 ISSN 2073-4859

Page 4: Raster Images in R Graphics - The R Journal because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure1)

CONTRIBUTED RESEARCH ARTICLES 51

> x <- c(0.00, 0.40, 0.86, 0.85, 0.69, 0.48,+ 0.54, 1.09, 1.11, 1.73, 2.05, 2.02)> library(lattice)

> barchart(1:12 ~ x, origin=0, col="white",+ panel=function(x, y, ...) {+ panel.barchart(x, y, ...)+ grid.raster(logo, x=0, width=x, y=y,+ default.units="native",+ just="left",+ height=unit(2/37,+ "npc"))+ })

x

1:12

1

2

3

4

5

6

7

8

9

10

11

12

0.0 0.5 1.0 1.5 2.0

Figure 8: A lattice barchart of the change in the “levelof interest in R” during 1996 (see demo(graphics))with the R logo image used to annotate each bar(with apologies to Edward Tufte and all of his heirsand disciples).

In addition to grid.raster(), there is also arasterGrob() function to create a raster imagegraphical object.

Support for raster image packages

A common source of raster images is likely to be ex-ternal files, such as digital photos and medical scans.A number of R packages exist to read general rasterformats, such as JPEG or TIFF files, plus there aremany packages to support more domain-specific for-mats, such as NIFTI and ANALYZE.

Each of these packages creates its own sort ofdata structure to represent the image within R, so inorder to render an image from an external file, thedata structure must be converted to something thatrasterImage() or grid.raster() can handle.

Ideally, the package will provide a method for theas.raster() function to convert the package-specific

image data structure into a "raster" object. In theabsence of that, the simplest path is to convert thedata structure into a matrix or array, for which therealready exist as.raster() methods.

In the example that produced Figure 6, the Rlogo was loaded into R using the ReadImages pack-age, which created an "imagematrix" object calledlogo. This object could be passed directly to ei-ther rasterImage() or grid.raster() because an"imagematrix" is also an array, so the predefinedconversion for arrays did the job.

Profiling

This section briefly demonstrates that the claimedimprovements in terms of file size and speed of ren-dering are actually true. The following code gener-ates a simple random test case image (see Figure 9).The only important feature of this image is that it isa reasonably large image (in terms of number of pix-els).

> z <- matrix(runif(500*500), ncol=500)

Figure 9: A simple random test image.

The following code demonstrates that a PDF ver-sion of this image is more than three times larger ifdrawn using a rectangle per pixel (via the image()function) compared to a file that is generated usinggrid.raster().

> pdf("image.pdf")> image(z, col=grey(0:99/100))> dev.off()

> pdf("gridraster.pdf")> grid.raster(z, interp=FALSE)> dev.off()

> file.info("image.pdf", "gridraster.pdf")["size"]

sizeimage.pdf 14893004gridraster.pdf 1511027

The next piece of code can be used to demon-strate that rendering speed is also much slower whendrawing an image to screen as many small rectan-gles. The timings are from a run on a CentOS Linux

The R Journal Vol. 3/1, June 2011 ISSN 2073-4859

Page 5: Raster Images in R Graphics - The R Journal because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure1)

52 CONTRIBUTED RESEARCH ARTICLES

system with the Cairo-based X11 device. There arelikely to be significant differences to these results ifthis code is run on other systems.

> system.time({+ for (i in 1:10) {+ image(z, col=grey(0:99/100))+ }+ })

user system elapsed42.017 0.188 42.484

> system.time({+ for (i in 1:10) {+ grid.newpage()+ grid.raster(z, interpolate=FALSE)+ }+ })

user system elapsed2.013 0.081 2.372

This is not a completely fair comparison becausethere are different amounts of input checking andhousekeeping occurring inside the image() functionand the grid.raster() function, but more detailedprofiling (with Rprof()) was used to determine thatmost of the time was being spent by image() doingthe actual rendering.

Examples

This section demonstrates some possible applica-tions of the new raster support.

The most obvious application is simply to use thenew functions wherever images are currently beingdrawn as many small rectangles using a function likeimage(). For example, Granovskaia et al. (2010) usedthe new raster graphics support in R in the produc-tion of gene expression profiles (see Figure 10).

Having raster images as a graphical primitivealso makes it easier to think about performing somegraphical tricks that were not necessarily obvious be-fore. An example is gradient fills, which are not ex-plicitly supported by the R graphics engine. The fol-lowing code shows a simple example where the barsof a barchart are filled with a greyscale gradient (seeFigure 11).

> barchart(1:12 ~ x, origin=0, col="white",+ panel=function(x, y, ...) {+ panel.barchart(x, y, ...)+ grid.raster(t(1:10/11), x=0,+ width=x, y=y,+ default.units="native",+ just="left",+ height=unit(2/37,+ "npc"))+ })

x1:

12

1

2

3

4

5

6

7

8

9

10

11

12

0.0 0.5 1.0 1.5 2.0

Figure 11: A lattice barchart of the change inthe “level of interest in R” during 1996 (seedemo(graphics)) with the a greyscale gradient usedto fill each bar (once again, begging the forgivenessof Edward Tufte).

Another example is non-rectangular clipping op-erations via raster “masks” (R’s graphics engine onlysupports clipping to rectangular regions). The codebelow is used to produce a map of Spain that is filledwith black (see Figure 12).

> library(maps)> par(mar=rep(0, 4))> map(region="Spain", col="black", fill=TRUE)

Having produced this image on screen, the functiongrid.cap() can be used to capture the current screenimage as a raster object.

> mask <- grid.cap()

An alternative approach would be produce a PNGfile and read that in, but grid.cap() is more conve-nient for interactive use.

The following code reads in a raster image ofthe Spanish flag from an external file (using the pngpackage), converting the image to a "raster" object.

> library(png)> espana <- readPNG("1000px-Flag_of_Spain.png")> espanaRaster <- as.raster(espana)

We now have two raster images in R. The follow-ing code trims the flag image on its right edge andtrims the map of Spain on its bottom edge so thatthe two images are the same size (demonstrating that"raster" objects can be subsetted like matrices).

> espanaRaster <- espanaRaster[, 1:dim(mask)[2]]> mask <- mask[1:dim(espanaRaster)[1], ]

The R Journal Vol. 3/1, June 2011 ISSN 2073-4859

Page 6: Raster Images in R Graphics - The R Journal because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure1)

CONTRIBUTED RESEARCH ARTICLES 5382cdc

82cdcrotcaf ahpla

rotcaf ahpla

0

50

100

150

2000

50

100

150

200

YJL156W−A

0

50

100

150

2000

50

100

150

200

FAR1 SSY5

124000 126000 128000

Chr 10(a)

82cdc82cdc

rotcaf ahplarotcaf ahpla

0

50

100

150

2000

50

100

150

200

0

50

100

150

2000

50

100

150

200

TAF2

000602000402000202

Chr 3(b)

82cdc82cdc

rotcaf ahplarotcaf ahpla

0

50

100

150

2000

50

100

150

200

TOM5 MSS18 CTF4

0

50

100

150

2000

50

100

150

200

000208000008000897

Chr 16(c)

82cdc82cdc

rotcaf ahplarotcaf ahpla

0

50

100

150

2000

50

100

150

200

YHR140W

0

50

100

150

2000

50

100

150

200

YHR138C SPS100 YHR139C−A

000083000873

Chr 8(d)

82cdc82cdc

rotcaf ahplarotcaf ahpla

0

50

100

150

2000

50

100

150

200

0

50

100

150

2000

50

100

150

200

YLR049C YLR050C YLR051C

244000 246000

Chr 12(e)CDS

CDS dubious

TF binding site

Segment boundary

0

1

2

3

4

5

6

7

log2(expression level)

Figure 10: An example of the use of raster images in an R graphic (reproduced from Figure 3 of Granovskaiaet al., 2010, which was published as an open access article by Biomed Central).

Now, we use the map as a “mask” to set all pixelsin the flag image to transparent wherever the mapimage is not black (demonstrating that assigning tosubsets also works for "raster" objects).

> espanaRaster[mask != "black"] <- "transparent"

The flag image can now be used to fill a map of Spain,as shown by the following code (see Figure 12).

> par(mar=rep(0, 4))> map(region="Spain")> grid.raster(espanaRaster, y=1, just="top")> map(region="Spain", add=TRUE)

Known issues

The raster image support has been implemented forthe primary screen graphics devices that are dis-tributed with R—Cairo (for Linux), Quartz (for Ma-cOS X), and Windows—plus the vector file formatdevices for PDF and PostScript. The screen devicesupport also covers support for standard raster fileformats (e.g., PNG) on each platform.

The X11 device has basic raster support, but ro-tated images can be problematic and there is no sup-port for transparent pixels in the image. The Win-

dows device does not support images with a differ-ent alpha level per pixel.1

There is no support for raster images for the XFigor PICTEX devices.

A web page on the R developer web site, http://developer.r-project.org/Raster/raster-RFC.html, will be maintained to show the ongoing stateof raster support.

Summary

The R graphics engine now has native support forrendering raster images. This will improve render-ing speed and memory efficiency for plots that con-tain large raster images. It also broadens the setof graphical effects that are possible (or convenient)with R.

Acknowledgements

Thanks to the editors and reviewers for helpful com-ments and suggestions that have significantly im-proved this article.

1However, Brian Ripley has added support in the development version of R.

The R Journal Vol. 3/1, June 2011 ISSN 2073-4859

Page 7: Raster Images in R Graphics - The R Journal because plots are typically made up of data symbols (polygons) or bars (rectangles), with axes (lines and text) alongside (see Figure1)

54 CONTRIBUTED RESEARCH ARTICLES

Figure 12: A raster image of the Spanish flag being used as a fill pattern for a map of Spain. On the left is a mapof spain filled in black (produced by the map() function from the maps package). In the middle is a PNG imageof Spanish flag (a public domain image from Wikimedia Commons, http://en.wikipedia.org/wiki/File:Flag_of_Spain.svg), and on the right is the result of clipping the Spanish flag image using the map as a mask.

Bibliography

R. Bivand, F. Leisch, and M. Maechler. pixmap: BitmapImages (“Pixel Maps”), 2009. URL http://CRAN.R-project.org/package=pixmap. R package ver-sion 0.4-10.

S. Chiaretti, X. Li, R. Gentleman, A. Vitale, M. Vi-gnetti, F. Mandelli, J. Ritz, and R. Foa. Geneexpression profile of adult T-cell acute lympho-cytic leukemia identifies distinct subsets of pa-tients with different response to therapy and sur-vival. Blood, 103(7):2771–2778, 2004.

P. Cock. Using R to draw a heatmap from microar-ray data, 2010. URL http://www2.warwick.ac.uk/fac/sci/moac/students/peter_cock/r/heatmap.

O. S. code by Richard A. Becker and A. R. W. R. ver-sion by Ray Brownrigg Enhancements by ThomasP Minka <[email protected]>. maps: DrawGeographical Maps, 2009. URL http://CRAN.R-project.org/package=maps. R package version2.1-0.

M. V. Granovskaia, L. M. Jensen, M. E. Ritchie,J. Toedling, Y. Ning, P. Bork, W. Huber, andL. M. Steinmetz. High-resolution transcriptionatlas of the mitotic cell cycle in budding yeast.Genome Biology, 11(3):R24, 2010. URL http://genomebiology.com/2010/11/3/R24.

M. Loecher. ReadImages: Image Reading Module for R,2009. URL http://CRAN.R-project.org/package=ReadImages. R package version 0.1.3.1.

D. Sarkar. lattice: Lattice Graphics, 2010. URL http://CRAN.R-project.org/package=lattice. R pack-age version 0.18-3.

Paul MurrellDepartment of StatisticsThe University of AucklandPrivate Bag 92019, AucklandNew [email protected]

The R Journal Vol. 3/1, June 2011 ISSN 2073-4859