-
Notifications
You must be signed in to change notification settings - Fork 0
/
Noam_Ross_20131122_Formatting_Plots_for_Pubs.R
171 lines (165 loc) · 8.29 KB
/
Noam_Ross_20131122_Formatting_Plots_for_Pubs.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#'% How to format plots for publication using `ggplot2` (with some help from Inkscape)
#'% Rosemary Hartman
#'% 13-11-20 19:51:47
#'
#' ***The following is the code from a presentation made by Rosemary Hartman to
#' the [Davis R Users' Group](http://www.noamross.net/davis-r-users-group.html).
#' I've run the code through the `spin` function in `knitr` to produce this post.
#' Download the script to walk through [here](https://gist.github.com/noamross/7576436)***
#'
#' First, make your plot. I am going to use the data already in R
#' about sleep habits of different animals. It's the same one Noam used for
#' [his intro to ggplot.](http://www.noamross.net/blog/2012/10/5/ggplot-introduction.html)
library(ggplot2)
str(msleep)
#' Let's say we have written a groundbreaking paper on the relationship
#' between body size and sleep time. Therefore, we
#'want to present a plot of the log of body weight by the total sleep time
sleepplot = ggplot(data = msleep, aes(x = log(bodywt), y = sleep_total))+geom_point(aes(color=vore))
sleepplot
#' We made a beautiful model of this relationship
slp = lm(sleep_total ~ log(bodywt), data=msleep)
summary(slp)
#'Let's put the model on the plot
sleepplot = sleepplot + geom_abline(intercept=coef(slp)[1], slope=coef(slp)[2])
sleepplot
#'It's beautiful! I love it! Unfortunately, you want to submit to Science
#' (you might as well aim high), and this is what they say about figures:
#' <http://www.sciencemag.org/site/feature/contribinfo/prep/prep_subfigs.xhtml>
#'
#' So we have several problems:
#'
#' - gray background
#' - Poor labels (need units, capital letters, larger font on axes)
#' - Poor legend
#' - Poor color scheme (avoid red and green together, more contrast needed)
#' - Not correct file format or resolution (want a PDF with at least 600dpi)
#'
#' First make the labels a little more useful.
sleepplot = sleepplot + labs(x="Log body weight (Kg)", y="Time asleep (hrs/day)")
sleepplot
#' Now let's fix the legend.
#' You would think you do this with some sort of "legend" command, but *no*,
#' what you are looking for is "scale".
sleepplot + scale_color_discrete(name="Functional\n feeding group",
labels = c("carnivore", "herbivore", "insectivore", "omnivore"))
#' If you haven't figured it out yet, putting "`\n`" in a text string gives
#' you a line break. It took me WAY to long to discover that.
#'
#' `ggplot` automatically gives you evenly spaced hues for color variations,
#' but this is not necessarily the best way to get a good contrasting color
#' scheme. You may want to try `scale_color_brewer` for better contrasts.
#' See <http://colorbrewer2.org> for more information.
sleepplot + scale_color_brewer(name="Functional \n feeding group",
labels = c("carnivore", "herbivore", "insectivore", "omnivore"),
type = "qual", palette = 1)
#' Oh, crap! Color figures cost an extra $700 on top of the normal page charges!
#' Let's try something else:
sleepplot2 = ggplot(data = msleep, aes(x = log(bodywt), y = sleep_total)) +
geom_point(aes(shape=vore), size=3) + #' This time we will vary the feeding groups by shapes instead of colors
geom_abline(intercept=coef(slp)[1], slope=coef(slp)[2])
sleepplot2
#' Now to fix the labels and legend again:
sleepplot2 = sleepplot2 + labs(x="Log body weight (Kg)", y="Time asleep (hrs/day)") +
#' we will use scale_shape_discrete instead of scale_color_discrete
scale_shape_discrete(name="Functional \n feeding group",
labels = c("carnivore", "herbivore", "insectivore", "omnivore"))
sleepplot2
#' Now, let's work on how the plot looks overall.
#'
#' ggplot uses "themes" to adjust plot appearence without changes the actual presentation of the data.
sleepplot2 + theme_bw(base_size=12, base_family = "Helvetica")
#' `theme_bw()` will get rid of the background, and gives you options to
#' change the font. Science recomends Helvetica, wich happens to be R's
#' default, but we will specify it here anyway.
#'
#' Check out the other fonts out here:
#'
#' ??postscriptFonts
#'
#' For even more fonts, see the `extrafont` package.
#'
#' Other pre-set themes can change the look of your plot
sleepplot2 + theme_minimal()
sleepplot2 + theme_classic()
#'
#' For more themes,
library(ggthemes)
#' If you want to publish in the Wall Street Journal...
sleepplot2 + theme_wsj()
#' But we want to publish in Science, not the Wall Street Journal, so let's get back to our black and white theme.
sleepplot2 = sleepplot2 + theme_bw(base_size=12, base_family = "Helvetica")
sleepplot2
#' You can't really see the gridlines with the `bw` theme, so we are going to tweak the
#' pre-set theme using the `theme` function.
#'`theme` allows you to do all kinds of stuff involved with how the plot looks.
#'
#' ?theme
sleepplot2 +
#increase size of gridlines
theme(panel.grid.major = element_line(size = .5, color = "grey"),
#increase size of axis lines
axis.line = element_line(size=.7, color = "black"),
#Adjust legend position to maximize space, use a vector of proportion
#across the plot and up the plot where you want the legend.
#You can also use "left", "right", "top", "bottom", for legends on t
#he side of the plot
legend.position = c(.85,.7),
#increase the font size
text = element_text(size=14))
#' You can save this theme for later use
science_theme = theme(panel.grid.major = element_line(size = .5, color = "grey"),
axis.line = element_line(size=.7, color = "black"),
legend.position = c(.85,.7),
text = element_text(size=14))
sleepplot2 = sleepplot2 + science_theme
sleepplot2
#' That looks pretty good. Now we need to get it exported properly.
#' The instructions say the figure should be sized
#' to fit in one or two columns (2.3 or 4.6 inches),
#' so we want them to look good at that resolution.
pdf(file = "sleepplot.pdf", width= 6, height = 4, #' see how it looks at this size
useDingbats=F) #I have had trouble when uploading figures with digbats before, so I don't use them
sleepplot2 #print our plot
dev.off() #stop making pdfs
#'
#' ### A few other tricks to improve the look of your plots:
#'
#' Let's say we are grouping things by categories instead of a regression
sleepcat = ggplot(msleep, aes(x=vore, y=sleep_total,color=conservation))
sleepcat + geom_point()
#' It's hard to see what's going on there, so we can jitter the points to make
#'them more visible.
sleepcat + geom_point(position = position_jitter(w=0.1))
#' Maybe this would be better with averages and error bars instead of every point:
library(plyr)
msleepave = ddply(msleep, .(vore, conservation), summarize, meansleep = mean(sleep_total), sdsleep = sd(sleep_total)/sqrt(22))
sleepmean = ggplot(msleepave, aes(x=vore, y = meansleep, color=conservation))
#' Plot it with means and error bars +/- 1 stadard deviation
sleepmean + geom_point() + geom_errorbar(aes(ymax = meansleep + sdsleep, ymin=meansleep + sdsleep),
width = 0.2)
#' Spread them out, but in an orderly fashion this time, with position_dodge rather than jitter
sleepmean + geom_point(position = position_dodge(width=.5, height=0), size=2) +
geom_errorbar(aes(ymax = meansleep + sdsleep, ymin=meansleep - sdsleep),
position = position_dodge(width=.5, height=0), width = .5)
#' Note that dodging the points gives the conservation status in the same order for each
#' feeding type category. A little more organized.
#'
#' ### Some other things you might want to do with formatting:
#'
#' Add annotation to the plot
sleepplot2 + annotate("text", label = "R2 = 0.999", x=-4, y=17)
#' Let's put that annotation in italics
sleepplot2 + annotate("text", label = "R2 = 0.999", x=-4, y=17, fontface=3)
#' NOW. Let's put half that annotation in italics, the other half plain,
#' then insert five greek characters and rotate it 90 degrees!
#'
#' OR we can beat our head against a wall until it explodes and
#' export our plot into an actual graphics program.
#'
#' Not everything has to be done in R. 'SVG' files are vector graphic files that can be easily edited in the
#' FREE GUI-based program [Inkscape](http://inkscape.org/). Make and SVG and you can edit it by hand for final tweaks.
#' Inkscape can also edit and export PDFs.
svg(filename = "sleepplot.svg", width=6, height=4)
sleepplot2
dev.off()