I am having certain issues while converting ggplot2 plots to plotly plots.
Here is my code:
> dput(dat.c)
structure(list(Cell_Line = structure(1:15, .Label = c("NBLS",
"NBSD", "NGP", "NLF", "RPE1", "RPE1MYCN40HT", "RPE1MYCNWT", "RPE1WT40HT",
"SKNAS", "SKNDZ", "SKNFI", "SKNKAN", "SKNSH", "SMSSAN", "SY5Y"
), class = "factor"), A1CF = c(5.10772389542502, 5.04909249557583,
5.16367852798093, 5.14220860530212, 5.25310652067225, 5.26436607107436,
5.230991944454, 5.4310065318786, 5.18630235564568, 5.02696275142877,
5.04518295317946, 5.15650800484188, 5.18630235564568, 5.18630235564568,
5.04905014785891), A2M = c(5.95668979157631, 5.59054925920344,
5.87084903365957, 5.85359773104682, 5.94551823960579, 5.82444459419149,
5.69488212149351, 5.70563676209623, 5.81016207843128, 5.66186721932247,
5.62134775395947, 5.62471305571508, 5.67165736680416, 5.76130826308792,
5.88006576048066), A2ML1 = c(5.56172395998964, 5.50076886952901,
5.7884753846352, 5.86613223339835, 5.82836474266047, 5.62750510524894,
5.76666636363946, 5.95103526370421, 5.58407662670697, 5.44780492507868,
5.35529657578242, 5.58813057293296, 5.67254168845041, 5.68685275370324,
5.6859273460443), A4GALT = c(6.73058652581215, 6.57480531818191,
6.70607981578649, 6.97173508307211, 7.0975112557987, 6.8286006127757,
6.56835917368749, 7.07629253436335, 6.66209247382635, 6.5876785423068,
6.59571996076717, 6.46673750407667, 6.70110916967979, 6.85058340238055,
6.59506833206593), A4GNT = c(4.87275116647384, 4.60002647258705,
4.99494601675408, 4.69477600401491, 4.7985530619801, 4.8349540959233,
4.77659739577691, 4.95071744980212, 4.77868342368918, 4.8025955817638,
4.87887068068956, 4.84258505663777, 4.84258505663777, 4.84616620572434,
4.66050997534254)), .Names = c("Cell_Line", "A1CF", "A2M", "A2ML1",
"A4GALT", "A4GNT"), row.names = c(NA, -15L), class = "data.frame")
gene1 <- 'A2M'
# modify gene name, dashes present in most of them
gene1.mut <- paste('`',gene1,'`',sep='')
# ggplot
p <- ggplot(dat.c, aes_string(x='Cell_Line', y=gene1.mut, fill='Cell_Line')) + geom_bar(stat="identity") + theme(axis.text.x = element_text(angle=90)) + ggtitle(gene1)
ggplotly(p)
This generates a figure like this:
As you can see, the one bar with X label RPE1MYCN40HT is not shown completely. Also the X and Y axis titles are clipped. How do I adjust the X axis labels and title so that they are not clipped? I do want to stick with ggplotly() instead of plot_ly() if that is possible.
Try to adjust plot.margins:
# ggplot
ggplot(dat.c, aes_string(x='Cell_Line', y=gene1.mut, fill='Cell_Line')) +
geom_bar(stat = "identity") +
theme(axis.text.x = element_text(angle=90),
plot.margin = unit(c(3, 3, 3, 3), "cm")) +
ggtitle(gene1)
When window is small then Xaxis label is overlapped with X labels, but when window is big it doesn't.
Related
I want to reproduce the following graph:
And my data is the following, where the blue line is complete_preds_means and the orange line is contrafact:
structure(list(dias = structure(c(19052, 19053, 19054, 19055,
19056, 19057, 19058, 19059, 19060, 19061, 19062, 19063, 19064,
19065, 19066, 19067, 19068, 19069, 19070, 19071), class = "Date"),
complete_preds_means = c(341.07434, 381.59167, 455.47815,
485.05597, 527.60876, 562.63965, 602.48975, 624.663, 626.5637,
527.2239, 420.71643, 389.30804, 378.74396, 366.61548, 361.36566,
363.37253, 319.31824, 314.39688, 303.60342, 294.8934), contrafact = c(364.5,
358.89, 466.64, 470.11, 464.25, 487.27, 591.2, 715.33, 628.02,
505.98, 402.9, 316.81, 323.35, 358.61, 354.26, 369.5, 317.01,
336.5, 285.33, 270.91), complete_preds_lower = c(320.6368042,
361.7870895, 432.4487762, 461.2275833, 503.2255051, 535.7108551,
576.3850006, 597.9762146, 601.4407013, 504.0448837, 398.7777023,
368.0046799, 356.3603165, 345.5847885, 339.9679932, 342.7514801,
298.3247482, 293.4419693, 282.5286865, 275.4635284), complete_preds_upper = c(359.9897186,
402.5708664, 477.4746765, 508.7775711, 550.3326447, 587.6521027,
628.5320251, 649.9691833, 649.4831665, 547.9886108, 442.046402,
410.8121475, 399.0208908, 389.8615128, 387.4929993, 386.2935928,
340.140834, 336.3622116, 324.793483, 315.4606934)), row.names = c(NA,
-20L), class = c("tbl_df", "tbl", "data.frame"))
So far I have tried this:
plot_fig4 <- ggplot()+
geom_line(data=fig4, aes(x=dias, y=complete_preds_means), colour="blue")+
geom_line(data=fig4, aes(x=dias, y=contrafact), colour="red") +
geom_ribbon(aes(ymin=fig4$complete_preds_lower, ymax=fig4$complete_preds_upper))+
labs(y="Clase ($)",
x="") +
scale_y_continuous(breaks=seq(from=100, to=800, by=100))+
scale_x_date(expand = c(0, 0), date_breaks="1 month", date_labels = "%b\n%Y")
But I only get this error: Error: geom_ribbon requires the following missing aesthetics: x or y, xmin and xmax
You haven't told geom_ribbon what variable should be on the x axis. You could just add x=fig4$dias inside the aes of geom_ribbon, but this isn't the best way to use ggplot. Better to use ggplot's inheritance of data and aesthetic mappings to avoid repeating yourself and making mistakes along the way. If you change your first line to ggplot(fig4, aes(x = dias)) you don't need to do data=fig4 and x=dias in every geom call.
A couple of other issues are that you should map the color aesthetic to produce a legend, and make the alpha low on your ribbon so that it is semi-transparent. The ordering of layers is also important.
Finally, I have added some theme tweaks to make the plot more like the desired output.
ggplot(fig4, aes(x = dias)) +
geom_line(aes(y = contrafact, color = "Contrafact"), linewidth = 1) +
geom_ribbon(aes(ymin = complete_preds_lower, ymax = complete_preds_upper),
fill = "deepskyblue4", alpha = 0.2) +
geom_line(aes(y = complete_preds_means, color = "Predicted"), linewidth = 1) +
geom_vline(xintercept = as.Date("2022-03-13"),
linetype = 4, colour = "green4") +
labs(y = "Clase ($)", x = NULL) +
scale_color_manual(NULL, values = c("orange", "deepskyblue4")) +
scale_y_continuous(breaks = 1:8 * 100) +
scale_x_date(expand = c(0, 0), date_breaks = "1 month",
date_labels = "%b\n%Y") +
theme_classic(base_size = 16)
I was trying to use ggplot2 to creat a percentage barplot.
An example dataframe
sample mapped(%) unmapped(%) reads
sample1 96.5 3.5 1320
sample2 97.4 2.6 1451
sample3 92.1 7.9 1824
sample4 98.7 1.3 1563
and I used following code to create the barplot
df <- algin %>% gather(col,reads,mapped:reads)
ggplot(df,aes(x=sample, y=reads, fill=col)) + geom_col(position = position_stack()) + coord_flip() + scale_fill_manual("legend", values = c("mapped" = "darkred", "unmapped" = "red", "reads"="darkblue"))
Although the created barplot here is close to what I desired to display, it doesn't seem like correct, e.g. legend should be "mapped" with darkblue color, "unmapped" with darkred color.
I set above values as I tried different settings, and only above one gave me the desired visual effect.
For example, I also tried
ggplot(df, aes(x = sample, y = reads, fill = col)) +
geom_col(position = position_stack()) +
coord_flip() +
scale_fill_manual(
"legend",
values = c("mapped" = "darkblue", "unmapped" = "darkred", "reads" = "red")
)
Then the plot looks like...
What I want to see is
bar length represents reads (sequencing reads) of each sample, and add every x-axis values with M unit, e.g. 500M, 1000M, etc;
darkblue color corresponds to the percentage of reads that were aligned (i.e. mapped) to the reference genome;
darkred color corresponds to the percentage of reads that were not aligned (i.e. unmapped) to the reference genome;
legend: mapped, unmapped, and better to remove reads (as is no necessary to be there)
An example of the desired plot as follows
Solutions appreciated!
Thanks!
Assuming these data:
algin <- tribble(
~sample, ~mapped, ~unmapped, ~reads,
"sample1", 96.5, 3.5, 1320,
"sample2", 97.4, 2.6, 1451,
"sample3", 92.1, 7.9, 1824,
"sample4", 98.7, 1.3, 1563
)
We can create the plotting df like this:
df <- algin %>%
transmute(
sample,
mapped = reads * mapped / 100,
unmapped = reads * unmapped / 100
) %>%
gather(mapping, n, -sample)
And then plot what is pretty close to what you showed:
df %>%
ggplot(
aes(sample, n,
# Factor levels control the order of the colors
fill = factor(mapping, levels = c( "unmapped","mapped")))
) +
geom_col() +
scale_fill_manual(
# Control the shade with the colors of your example
values = c("mapped" = "#427BB0", "unmapped" = "#B0064C"),
# Control what the colors look like in the legend
# We could have directly named the new columns wit CamelCase too
labels = c("mapped" = "Mapped", "unmapped" = "Unmapped"),
# Control the order in the legend
breaks = c("mapped", "unmapped")
) +
# Flip sideways
coord_flip() +
# To not have the grey background
theme_minimal() +
theme(
# Your example didn't have horizontal lines
panel.grid.major.y = element_blank(),
# Self explanatory
legend.position = "bottom"
) +
# Add M to everything except 0
scale_y_continuous(labels = as_mapper(~ifelse(. == 0, "0",paste0(., "M")))) +
labs(
# Your example has no x axis label
x = NULL,
y = "# Reads",
# The values are self explanatory
fill = NULL
)
Your table:
df <- structure(list(sample = structure(1:4, .Label = c("sample1",
"sample2", "sample3", "sample4"), class = "factor"), `mapped(%)` = c(96.5,
97.4, 92.1, 98.7), `unmapped(%)` = c(3.5, 2.6, 7.9, 1.3), reads = c(1320L,
1451L, 1824L, 1563L)), class = "data.frame", row.names = c(NA,
-4L))
You need to calculate the number of mapped and unmapped reads, and we make it into a long format using pivot_longer which is similar to gather() which you used. We keep only the columns we need.
library(tidyverse)
plotdf <- df %>%
mutate(mapped=`mapped(%)`*reads/100,
unmapped=`unmapped(%)`*reads/100) %>%
select(sample,mapped,unmapped) %>%
pivot_longer(-sample) %>%
mutate(name = factor(name, levels = c("unmapped","mapped")))
Then we set colors like you said, and also defined the breaks. And plot basically using something you already have:
COLS <- alpha(c("mapped" = "darkred", "unmapped" = "darkblue"),0.7)
BR <- seq(0,1750,by=250)
ggplot(plotdf,aes(x=sample,y=value,fill=name)) +
scale_y_continuous(breaks=BR,labels=paste(BR,"M",sep=""))+
geom_col() + coord_flip() + scale_fill_manual("legend", values = COLS)+
theme_light()+
theme(legend.position = "bottom")+
ylab("#Reads")+xlab("")
I am trying to create a bar chart in ggplot where the widths of the bars are associated with a variable Cost$Sum.of.FS_P_Reduction_Kg. I am using the argument width=Sum.of.FS_P_Reduction_Kg to set the width of the bars according to a variable.
I want to add direct labels to the chart to label each bar, similar to the image documented below. I am also seeking to add in x axis labels corresponding to the argument width=Sum.of.FS_P_Reduction_Kg. Any help would be greatly appreciated. I am aware of ggrepel but haven't been able to get the desired effect so far.
I have used the following code:
# Plot the data
P1 <- ggplot(Cost,
aes(x = Row.Labels,
y = Average.of.Cost_Per_Kg_P_Removal.undiscounted..LOW_Oncost,
width = Average.of.FS_Annual_P_Reduction_Kg, label = Row.Labels)) +
geom_col(fill = "grey", colour = "black") +
geom_label_repel(
arrow = arrow(length = unit(0.03, "npc"), type = "closed", ends = "first"),
force = 10,
xlim = NA) +
facet_grid(~reorder(Row.Labels,
Average.of.Cost_Per_Kg_P_Removal.undiscounted..LOW_Oncost),
scales = "free_x", space = "free_x") +
labs(x = "Measure code and average P reduction (kg/P/yr)",
y = "Mean annual TOTEX (£/kg) of P removal (thousands)") +
coord_cartesian(expand = FALSE) + # remove spacing within each facet
theme_classic() +
theme(strip.text = element_blank(), # hide facet title (since it's same as x label anyway)
panel.spacing = unit(0, "pt"), # remove spacing between facets
plot.margin = unit(c(rep(5.5, 3), 10), "pt"), # more space on left for axis label
axis.title=element_text(size=14),
axis.text.y = element_text(size=12),
axis.text.x = element_text(size=12, angle=45, vjust=0.2, hjust=0.1)) +
scale_x_discrete(labels = function(x) str_wrap(x, width = 10))
P1 = P1 + scale_y_continuous(labels = function(x) format(x/1000))
P1
The example data table can be reproduced with the following code:
> dput(Cost)
structure(list(Row.Labels = structure(c(1L, 2L, 6L, 9L, 4L, 3L,
5L, 7L, 8L), .Label = c("Change the way P is applied", "Improve management of manure",
"In channel measures to slow flow", "Keep stock away from watercourses",
"No till trial ", "Reduce runoff from tracks and gateways", "Reversion to different vegetation",
"Using buffer strips to intercept pollutants", "Water features to intercept pollutants"
), class = "factor"), Average.of.FS_Annual_P_Reduction_Kg = c(0.11,
1.5425, 1.943, 3.560408144, 1.239230769, 18.49, 0.091238043,
1.117113762, 0.11033263), Average.of.FS_._Change = c(0.07, 0.975555556,
1.442, 1.071692763, 1.212307692, 8.82, 0.069972352, 0.545940711,
0.098636339), Average.of.Cost_Per_Kg_P_Removal.undiscounted..LOW_Oncost = c(2792.929621,
2550.611429, 964.061346, 9966.056875, 2087.021801, 57.77580744,
165099.0425, 20682.62962, 97764.80805), Sum.of.Total_._Cost = c(358.33,
114310.49, 19508.2, 84655, 47154.23, 7072, 21210, 106780.34,
17757.89), Average.of.STW_Treatment_Cost_BASIC = c(155.1394461,
155.1394461, 155.1394461, 155.1394461, 155.1394461, 155.1394461,
155.1394461, 155.1394461, 155.1394461), Average.of.STW_Treatment_Cost_HIGH = c(236.4912345,
236.4912345, 236.4912345, 236.4912345, 236.4912345, 236.4912345,
236.4912345, 236.4912345, 236.4912345), Average.of.STW_Treatment_Cost_INTENSIVE = c(1023.192673,
1023.192673, 1023.192673, 1023.192673, 1023.192673, 1023.192673,
1023.192673, 1023.192673, 1023.192673)), class = "data.frame", row.names = c(NA,
-9L))
I think it will be easier to do a bit of data prep so you can put all the boxes in one facet with a shared x-axis. For instance, we can calc the cumulative sum of reduction Kg, and use that to define the starting x for each box.
EDIT -- added ylim = c(0, NA), xlim = c(0, NA), to keep ggrepel::geom_text_repel text within positive range of plot.
library(ggplot2)
library(ggrepel)
library(stringr)
library(dplyr)
Cost %>%
arrange(desc(Average.of.Cost_Per_Kg_P_Removal.undiscounted..LOW_Oncost)) %>%
mutate(Row.Labels = forcats::fct_inorder(Row.Labels),
cuml_reduc = cumsum(Average.of.FS_Annual_P_Reduction_Kg),
bar_start = cuml_reduc - Average.of.FS_Annual_P_Reduction_Kg,
bar_center = cuml_reduc - 0.5*Average.of.FS_Annual_P_Reduction_Kg) %>%
ggplot(aes(xmin = bar_start, xmax = cuml_reduc,
ymin = 0, ymax = Average.of.Cost_Per_Kg_P_Removal.undiscounted..LOW_Oncost)) +
geom_rect(fill = "grey", colour = "black") +
geom_text_repel(aes(x = bar_center,
y = Average.of.Cost_Per_Kg_P_Removal.undiscounted..LOW_Oncost,
label = str_wrap(Row.Labels, 15)),
ylim = c(0, NA), xlim = c(0, NA), ## EDIT
size = 3, nudge_y = 1E4, nudge_x = 2, lineheight = 0.7,
segment.alpha = 0.3) +
scale_y_continuous(labels = scales::comma) +
labs(x = "Measure code and average P reduction (kg/P/yr)",
y = "Mean annual TOTEX (£/kg) of P removal (thousands)")
You could experiment with scaling the values a little bit, e.g. using logarithmization. Since I prefer baseplots over gglplot2 I show you a base solution using barplot accordingly.
First, we transform the firs column into rownames and delete it.
cost <- `rownames<-`(Cost[-1], Cost[,1])
Defining widths in barplot is quite straightforward, since it has an option width= where we put in the logarithmized values of the according variable. For the bar-labels we need to calculate the positions and use text; to achieve line-wraps we may use strwrap. A label can conveniently left out if it's a hardship case (as #6 in the example). Finally we use (headless) arrows .
# logarithmize values
w <- log(w1 <- cost$Average.of.Cost_Per_Kg_P_Removal.undiscounted..LOW_Oncost)
# define vector labels inside / outside, at best by hand
inside <- as.logical(c(0, 1, 0, 1, 1, 0, 1, 1, 1))
# calculate `x0` values of labels
x0 <- w / 2 + c(0, cumsum(w)[- length(w)])
# define y values o. labels
y0 <- ifelse(inside, colSums(t(cost)) / 2, 1.5e5)
# make labels using 'strwrap'
labs <- mapply(paste, strwrap(rownames(cost), 15, simplify=F), collapse="\n")
# define nine colors
colores <- hcl.colors(9, "Spectral", alpha=.7)
# the actual plot
b <- barplot(cs <- colSums(t(cost)), width=w, space=0, ylim=c(1, 2e5),
xlim=c(-1, 80), xaxt="n", xaxs="i", col=colores, border=NA,
xlab="Measure code and average P reduction (kg/P/yr)",
ylab="Mean annual TOTEX (£/kg) of P removal (thousands)")
# place lables, leave out # 6
text(x0[-6], y0[-6], labels=labs[-6], cex=.7)
# arrows
arrows(x0[c(1, 3)], 1.35e5, x0[c(1, 3)], cs[c(1, 3)], length=0)
# label # 6
text(40, 1e5, labs[6], cex=.7)
# arrow # 6
arrows(40, 8.4e4, x0[6], cs[6], length=0)
# make x axis
axis(1, c(0, cumsum(log(seq(0, 1e5, 1e4)[-1]))),
labels=format(c(0, cumsum(seq(0, 1e5, 1e4)[-1])), format="d"), tck=-.02)
# put it in a box
box()
Result
I hope I got the x axis values right.
You probably have to figure out a little how the probably new functions work, but it's quite easy using the help files, e.g. type ?barplot.
I am new to R and ggplot2.I have searched a lot regarding this but I could not find the solution.
Sample observation1 observation2 observation3 percentage
sample1_A 163453473 131232689 61984186 30.6236955883
Sample1_B 170151351 137202212 59242536 26.8866816109
sample2_A 194102849 162112484 89158170 40.4183031852
sample2_B 170642240 141888123 79925652 41.7493687378
sample3_A 192858504 161227348 90532447 41.8068248626
sample3_B 177174787 147412720 81523935 40.5463120438
sample4_A 199232380 174656081 118115358 55.6409038531
sample4_B 211128931 186848929 123552556 54.7201927527
sample5_A 186039420 152618196 87012356 40.9656544833
sample5_B 145855252 118225865 66265976 39.5744515254
sample6_A 211165202 186625116 112710053 48.5457722338
sample6_B 220522502 193191927 114882014 47.238670909
I am planning to plot a bar plot with ggplot2. I want to plot the first three columns as a bar plot "dodge" and label the observation3 bar with the percentage. I could plot the bars as below but I could not use geom_text() to add the label.
data1 <- read.table("readStats.txt", header=T)
data1.long <- melt(data1)
ggplot(data1.long[1:36,], aes(data1.long$Sample[1:36],y=data1.long$value[1:36], fill=data1.long$variable[1:36])) + geom_bar(stat="identity", width=0.5, position="dodge")
Transform data1 to long form with the observation columns as the measure variables and the Sample and percentage columns as the id variables. Compute the maximum value, mx, to be used to place the percentages. Then perform the plot. Note that geom_bar uses data1.long but geom_text uses data1. We have colored the text giving the percentages the same color as the observation3 bars. (See this post for how to specify default colors.) Both inherit aes(x = Sample) but use different y and other aesthetics. We clean up the X axis labels by removing all lower case letters and underscores from the data1$Sample (optional).
library(ggplot2)
library(reshape2)
data1.long <- melt(data1, measure = 2:4) # cols 2:4 are observation1, ..., observation3
mx <- max(data1.long$value) # maximum observation value
ggplot(data1.long, aes(x = Sample, y = value)) +
geom_bar(aes(fill = variable), stat = "identity", width = 0.5, position = "dodge") +
geom_text(aes(y = mx, label = paste0(round(percentage), "%")), data = data1,
col = "#619CFF", vjust = -0.5) +
scale_x_discrete(labels = gsub("[a-z_]", "", data1$Sample))
(click on chart to enlarge)
Note: We used this data. Note that one occurrence of Sample was changed to sample with a lower case s:
Lines <- "Sample observation1 observation2 observation3 percentage
sample1_A 163453473 131232689 61984186 30.6236955883
sample1_B 170151351 137202212 59242536 26.8866816109
sample2_A 194102849 162112484 89158170 40.4183031852
sample2_B 170642240 141888123 79925652 41.7493687378
sample3_A 192858504 161227348 90532447 41.8068248626
sample3_B 177174787 147412720 81523935 40.5463120438
sample4_A 199232380 174656081 118115358 55.6409038531
sample4_B 211128931 186848929 123552556 54.7201927527
sample5_A 186039420 152618196 87012356 40.9656544833
sample5_B 145855252 118225865 66265976 39.5744515254
sample6_A 211165202 186625116 112710053 48.5457722338
sample6_B 220522502 193191927 114882014 47.238670909"
data1 <- read.table(text = Lines, header = TRUE)
UPDATE: minor improvements
It might be that G. Grothendieck's answer is a better solution, but here's my suggestion (code below)
# install.packages("ggplot2", dependencies = TRUE)
require(ggplot2)
df <- structure(list(Sample = structure(1:12, .Label = c("sample1_A",
"Sample1_B", "sample2_A", "sample2_B", "sample3_A", "sample3_B",
"sample4_A", "sample4_B", "sample5_A", "sample5_B", "sample6_A",
"sample6_B"), class = "factor"), observation1 = c(163453473L,
170151351L, 194102849L, 170642240L, 192858504L, 177174787L, 199232380L,
211128931L, 186039420L, 145855252L, 211165202L, 220522502L),
observation2 = c(131232689L, 137202212L, 162112484L, 141888123L,
161227348L, 147412720L, 174656081L, 186848929L, 152618196L,
118225865L, 186625116L, 193191927L), observation3 = c(61984186L,
59242536L, 89158170L, 79925652L, 90532447L, 81523935L, 118115358L,
123552556L, 87012356L, 66265976L, 112710053L, 114882014L),
percentage = c(30.6236955883, 26.8866816109, 40.4183031852,
41.7493687378, 41.8068248626, 40.5463120438, 55.6409038531,
54.7201927527, 40.9656544833, 39.5744515254, 48.5457722338,
47.238670909)), .Names = c("Sample", "observation1", "observation2",
"observation3", "percentage"), class = "data.frame", row.names = c(NA,
-12L))
# install.packages("reshape2", dependencies = TRUE)
require(reshape2)
data1.long <- melt(df, id=c("Sample"), measure.var = c("observation1", "observation2", "observation3"))
data1.long$percentage <- paste(round(data1.long$percentage, 2), "%", sep="")
data1.long[data1.long$variable == "observation1" | data1.long$variable == "observation2" ,2] <- ""
ggplot(data1.long, aes(x = Sample, y = value, fill=variable)) +
geom_bar(, stat="identity", width=0.5, position="dodge") +
geom_text(aes(label = percentage), vjust=2.10, size=2, hjust=-.06, angle = 90)
I am making a plot in ggplot2 that contains a geom_pointrange and a geom_line. I see that when I change the order of the geoms, either the points are plotted on top of the line, or vice versa. The legend also changes which geom is plotted on top of the other based on the same ordering of the geoms. However, I would like for the line to plot first, then the pointrange on top, in the plot itself, with the opposite in the legend. Is this possible? I would greatly appreciate any input.
Here is the code I used to make the figure.
md.figd2 <- structure(list(date = c("2013-05-28", "2013-07-11", "2013-09-22",
"2013-05-28", "2013-07-11", "2013-09-22", "2013-05-28", "2013-07-11",
"2013-09-22"), trt = structure(c(3L, 3L, 3L, 1L, 1L, 1L, 2L,
2L, 2L), .Label = c("- Fescue", "- Random", "Control"), class = "factor"),
means = c(1, 0.921865257043089, 0.793438250521971, 1, 0.878305313846414,
0.85698797555687, 1, 0.840679145697309, 0.798547331410388
), mins = c(1, 0.87709562979756, 0.72278951032918, 1, 0.816185624483356,
0.763720265496049, 1, 0.780804129401513, 0.717089626439849
), maxes = c(1, 0.966634884288619, 0.864086990714762, 1,
0.940425003209472, 0.950255685617691, 1, 0.900554161993105,
0.880005036380927)), .Names = c("date", "trt", "means", "mins",
"maxes"), row.names = c(NA, 9L), class = "data.frame")
library(ggplot2)
dplot1.ysc <- scale_y_continuous(limits=c(0,1), breaks=seq(0,1,.2), name='Proportion mass lost')
dplot1.xsc <- scale_x_date(limits=as.Date(c('2013-05-23', '2013-10-03')), labels=c('May 28', 'July 11', 'Sep 22'), breaks=md.figdata$date, name='Date')
dplot1.csc <- scale_color_manual(values=c('grey20','grey50','grey80'))
dplot1.lsc <- scale_linetype_manual(values=c('solid','dotted','dashed'))
djitter <- rep(c(0,-1,1), each=3)
# This one produces the plot with the legend I want.
dplot1b <- ggplot(md.figd2, aes(x=date + djitter, y=means, group=trt)) + geom_pointrange(aes(ymin=mins, ymax=maxes, color=trt), size=2) + geom_line(aes(linetype=trt), size=1)
# This one produces the plot with the points on the main plot that I want.
dplot1b <- ggplot(md.figd2, aes(x=date + djitter, y=means, group=trt)) + geom_line(aes(linetype=trt), size=1) + geom_pointrange(aes(ymin=mins, ymax=maxes, color=trt), size=2)
dplot1b + dplot1.xsc + dplot1.ysc + dplot1.csc + dplot1.lsc
You can use gtable::gtable_filter to extract the legend from the plot you want, and then gridExtra::grid.arrange to recreate the plot you want
# the legend I want
plot1a <- ggplot(md.figd2, aes(x=date , y=means, group=trt)) +
geom_pointrange(aes(ymin=mins, ymax=maxes, color=trt), size=2,
position = position_dodge(width=1)) +
geom_line(aes(linetype=trt), size=1)
# This one produces the plot with the points on the main plot that I want.
dplot1b <- ggplot(md.figd2, aes(x=date, y=means, group=trt)) +
geom_line(aes(linetype=trt), size=1) +
geom_pointrange(aes(ymin=mins, ymax=maxes, color=trt), size=2)
w <- dplot1b + dplot1.xsc + dplot1.ysc + dplot1.csc + dplot1.lsc
# legend
l <- dplot1a + dplot1.xsc + dplot1.ysc + dplot1.csc + dplot1.lsc
library(gtable)
library(gridExtra)
# extract legend ("guide-box" element)
leg <- gtable_filter(ggplot_gtable(ggplot_build(l)), 'guide-box')
# plot the two components, adjusting the widths as you see fit.
grid.arrange(w + theme(legend.position='none'),leg,ncol=2, widths = c(3,1))
An alternative is to simply replace the legend in the plot you want with the legend you want that you have extracted (using gtable_filter)
# create ggplotGrob of plot you want
wGrob <- ggplotGrob(w)
# replace the legend
wGrob$grobs[wGrob$layout$name == "guide-box"][[1]] <- leg
grid.draw(wGrob)
Quick and dirty. To get the correct plotting order in both figure and legend, add the layers like this: (1) geom_pointrange, (2) geom_line, and then (3) a second geom_pointrange without legend (show.legend = FALSE).
ggplot(md.figd2, aes(x = date, y = means, group = trt)) +
geom_pointrange(aes(ymin = mins, ymax = maxes, color = trt),
position = position_dodge(width = 5), size = 2) +
geom_line(aes(linetype = trt), size = 1) +
geom_pointrange(aes(ymin = mins, ymax = maxes, color = trt),
position = position_dodge(width = 5), size = 2,
show.legend = FALSE) +
scale_y_continuous(limits = c(0,1), breaks = seq(0,1, 0.2), name = 'Proportion mass lost') +
scale_x_date(limits = as.Date(c('2013-05-23', '2013-10-03')), name = 'Date') +
scale_color_manual(values = c('grey20', 'grey50', 'grey80')) +
scale_linetype_manual(values = c('solid', 'dotted', 'dashed'))