When I switched from working primarily with statisticians to working primarily with biologists, one of the hardest lessons I learned was the extent to which biologists value their figures. This was a long and painful lesson: while R is great for statistical analysis and simulation, I remain unaware of a nice internal R GUI for touching up graphics. Pair that tragedy with the fact that journal specifications for graphical displays vary far and wide, and you have yourself a lot of time spent fiddling with figures.
I’m aware of two nice and widely used GUIs for manipulating graphics by hand. One is Adobe Illustrator, which is fabulous but proprietary (and spendy). The other is Inkscape, which is open-source and freely available. Becoming comfortable working with Inkscape has saved me a lot of time.
Inkscape is a vector graphics editor, available for OS X, Windows, and Linux download. It is primarily designed for manipulation and construction of a scalable vector graphic (“svgs“) file, which is an open standard vector graphics format. I use Inkscape for assembling multipanel figures (like the one shown below), touching up single-panel graphics to comply with journal-specific graphic specifications, and building graphical displays that aren’t readily output by R (like the S-I-R compartment diagram shown in the upper-right hand corner of panel C below).
For me, the first step in constructing almost all graphics is designing the figure, and plotting the various pieces that comprise it in R. I do a fair amount of manipulation in R directly, using the
plot functions, and the
ggplot2 library. When I’ve got a panel constructed so that all the desired datastreams are displayed the way I want, I write the plot out as an svg file. Here’s an example R code snippet.
x <- 1:100 y <- rnorm(100, x^2, 500) par(oma = c(0, 0, 0, 0)) plot(y ~ x, pch = 16, col = "grey20") lines(lowess(y ~ x), lty = 2, lwd = 3, col = "grey60")
To write this plot as an svg, I need to add three lines. In one, I specify the path along which I'll write the file (this could be embedded directly in the
svg function, however I prefer to keep my paths written outside of functions so they're more readily accessible for manipulation; more on this in future posts). The second thing I do is call R's
svg function, which constructs the svg file and writes it to my specified path. Last (and this is important), I have to turn the graphical device off after plot construction is over (that's the
dev.off() bit). My revised code file looks like this:
x <- 1:100 y <- rnorm(100, x^2, 500) write.path <- "~/work/Kezia/Research/BlogPosts/Inkscape1/test.svg" svg(write.path, width = 6, height = 5) par(oma = c(0, 0, 0, 0)) plot(y ~ x, pch = 16, col = "grey20") lines(lowess(y ~ x), lty = 2, lwd = 3, col = "grey60") dev.off()
To open the figure in Inkscape, navigate to the directory containing your newly-minted svg file, and open the svg in Inkscape. For good measure, I always rename svg files that I've manipulated in Inkscape to _inkscape.svg. There are two reasons for doing this:
- It protects me from inadvertently overwriting my Inkscape edits if I rerun the file output commands in R.
- I have a good record of exactly what I've manipulated by hand in Inkscape, as opposed to what R generated for me.
I tend to write svgs smaller than I actually want to view them, so the first thing I typically do in Inkscape is resize the figure to dimensions I like. View -> Zoom -> 1:1 is usually a good first step. To resize the artboard (that is, to respecify the dimensions of the whole file, so that your figure occupies the whole file and not just a corner of it), go to File -> Document Properties. In the resulting dialogue box, adjust the height and width to fit your specifications.
To edit a particular element within the figure, select that element with the pointer tool (you may have to click through a few layers of selections to get to the particular object you want), and then manipulate it as desired. For example, suppose you want to first delete the default bounding box that surrounds the plot in the test.svg object created above, and then extend the x and y axes so that they intersect. To do this, select the bounding box by using the pointer tool and double-clicking at the top of the box. Once the box is selected, hit delete, and Inkscape will remove it. Next, select the y-axis with the pointer tool. When the axis is selected, it will show an arrow at each side and each corner. Selecting one of these arrows and dragging changes the width or length of an object. In this case, drag the left-pointing axis arrow leftward until it's approximately parallel to the x-axis. Repeat with the x-axis and adjust each axis so that they intersect.
To modify the appearance of an object, select the desired object (for example, the x-axis). Then, under the Object menu, select Fill and Stroke. A dialogue box opens on the right-hand side of the Inkscape window. The tabs in this dialogue box allow for modification of line width (useful for publication-quality figures), color, line type, addition of endpoint markings, etc. Similar dialogues are available for objects of other types.
To construct a multi-paneled figure, output the component plots from R. I vacillate between building the multipaneled figures in R directly using
par(mfrow = c(x, y)) and writing them as a single svg file, and exporting each piece separately. The latter is particularly useful when working with default plot functions associated with particular packages that don't allow for easy manipulation of the plot layout using R's
Once all the necessary svgs are written out of R, open each in its own Inkscape session. Use <Ctrl-a> to select all, and then group all elements of that particular plot together using the "Group selected objects" button midway across the top of the Inkscape window (this is the icon of a blue box overlaid with the blue circle). Copy and paste the grouped plot panel into a new Inkscape session, and bring in all other plots one at a time via the same steps. Grouping all elements of a given plot ahead of time ensures that all plot elements can be resized and moved as a unit.
Inkscape has the capacity to do all sorts of other things, including text manipulation, image creation, etc. It has a well-documented wiki, an active user community, and (best of all) it's free! Hopefully I've provided enough information here to get you started. Enjoy!