Related
This question already has answers here:
Reorder bars in geom_bar ggplot2 by value
(3 answers)
Change bar plot colour in geom_bar with ggplot2 in r
(2 answers)
Closed last year.
How can I easily ad one color in each bar and make it descending?
QG4 %>%
filter(value=="Yes") %>%
ggplot(aes(y=Freq, x=variable))+
geom_bar(position = "dodge", stat = "identity")+
theme_bw()+
coord_flip()+
labs(x="Mode", y=NULL, title = "What is your usual (or most frequently used) mode of travel to work/place of study?")
I used dput(QG4) to avoid using a picture of the dataset:
structure(list(variable = structure(c(1L, 2L, 3L, 4L, 5L, 6L,
7L, 8L, 9L, 10L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L), .Label = c("Bicycle",
"Bicycle (Yélo)", "Bus", "Car", "Car (Yélo)", "Carpool", "Motorcycle/scooter",
"On foot", "Scooter (trottinette)", "Train"), class = "factor"),
value = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("No",
"Yes"), class = "factor"), Freq = c(1634L, 2143L, 1781L,
1532L, 2281L, 2202L, 2267L, 1331L, 2265L, 2172L, 655L, 146L,
508L, 757L, 8L, 87L, 22L, 958L, 24L, 117L)), class = "data.frame", row.names = c(NA,
-20L))
enter image description here
Seems that this topic has not been covered this since the ggplot2.2.2 update where old solutions like this one and this one no longer apply. Fortunately, the process is far simpler than before. One line of code and you have a secondary Y-axis (as shown here).
But I cannot get a secondary X-axis on my plots...
I am comparing a depth profile of metal concentrations along the sediment core. I would like to display carbon and phosphate concentrations as an geom_area behind the metal's concentration. The problem is that both carbon and phosphate concentrations are no on the same scale as the metal. Thus I need a second axis.
The theme is the following (taken from this website):
theme_new <- theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank(), axis.line = element_line(colour = "black"), strip.text.x = element_text(size=10, angle=0, vjust=0), strip.background = element_blank(), strip.text.y = element_text(angle = 0), legend.position="none",panel.border = element_blank(), axis.text.x=element_text(angle=45,hjust=1)) # Axis tick label angle
And this code gives me a second Y-axis even though I specify it under X-axis.
ggplot(MasterTable)+
geom_line(aes(Depth,Conc.nM))+
geom_area(aes(Depth,Conc.uM, fill=Variable))+
scale_x_continuous("Depth (cm)", sec.axis = sec_axis(~ . *100, name = "Carbon & Phosphate"))+
scale_y_continuous("Metal concentration (nM)")+
coord_flip()+
theme_new+
theme(legend.position = "right")+
facet_grid(. ~ Assay, scales = "free")
Can anyone help me place the secondary axis on the top of the figure?
Thanks!!
dput of my MasterTable is the following:
structure(list(Depth = c(15L, 5L, 2L, -1L, -3L, -5L, -7L, -9L,
-11L, -13L, -15L, -17L, -19L, -21L, -23L, -25L, -27L, -29L, -31L,
15L, 5L, 2L, -1L, -3L, -5L, -7L, -9L, -11L, -13L, -15L, -17L,
-19L, -21L, -23L, -25L, -27L, -29L, -31L), Conc.nM = c(24L, 24L,
24L, 100L, 100L, 75L, 75L, 85L, 85L, 120L, 300L, 1000L, 200L,
240L, 240L, 800L, 1100L, 1500L, 2300L, 0L, 10L, 0L, 50L, 200L,
200L, 50L, 50L, 200L, 15L, 0L, 0L, 10L, 120L, 200L, 1500L, 2100L,
2000L, 2000L), Assay = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("Instrument 1",
"Instrument 2"), class = "factor"), Conc.uM = c(0L, 0L, 0L, 1L,
4L, 10L, 10L, 10L, 5L, 7L, 10L, 14L, 14L, 14L, 14L, 13L, 12L,
12L, 12L, 1L, 1L, 1L, 4L, 6L, 9L, 11L, 11L, 8L, 8L, 8L, 20L,
10L, 9L, 9L, 9L, 10L, 10L, 10L), Variable = structure(c(2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L), .Label = c("Carbon", "Phosphate"), class = "factor")), .Names = c("Depth",
"Conc.nM", "Assay", "Conc.uM", "Variable"), class = "data.frame", row.names = c(NA,
-38L))
Thanks to Brian's answer, and modifying the theme proposed above, I got the following figure.
As he suggested, you have to first modify your data manually using something like this:
MasterTable$Conc.uM <- MasterTable$Conc.uM *100
Then, in the code, adjust your axis with the same correction factor as the one used above. Here is the code to make the figure.
ggplot(MasterTable)+
geom_line(aes(Depth,Conc.nM))+
geom_area(aes(Depth,Conc.uM, fill=Variable), alpha=0.6)+ #Area for second X-axis
geom_area(aes(Depth,Conc.nM), alpha=0.95)+
geom_point(aes(Depth,Conc.uM), size=1, shape=16, alpha=0.3)+ #Adding points for second X-axis
geom_point(aes(Depth,Conc.nM), size=1, shape=16, alpha=0.8)+
scale_fill_manual(values=colours) + scale_colour_manual(values=colours) +
labs(title="Sediment core", color="",fill="") + #Place legend title in both color="" and fill=""
scale_y_continuous("Metal concentration (nM)",
sec.axis = sec_axis(~ . /100, name = "[Pi] (uM) DOC (mg/L)"))+
scale_x_continuous("Depth (cm)", breaks=pretty_breaks(n=7))+
coord_flip()+ #Required to make a proper depth profile
theme_new+ #Reference to custom theme
facet_grid(. ~ Assay, scales = "free") #Scales makes that the axis size can change
Now I just have one problem left to solve. I would like for the tick marks and labels to be under the facet. Seems more logical and less busy than having it at the top of the figure.
From your code:
...
scale_x_continuous("Depth (cm)", sec.axis = sec_axis(~ . *100, name = "Carbon & Phosphate"))+
scale_y_continuous("Metal concentration (nM)") +
coord_flip() ...
Consider which primary axis you want "Carbon & Phosphate" to be parallel to. Also consider what "x-axis" and "y-axis" mean in the context of using coord_flip.
TL;DR: Just move your secondary axis into scale_y_continuous.
I am trying to manually reorder the x-axis labels within each facet.
The data are as follows:
df = structure(list(block = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L,
4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L, 5L, 5L), .Label = c("1",
"2", "3", "4", "5"), class = "factor"), item = structure(c(14L,
15L, 28L, 29L, 30L, 31L, 32L, 15L, 16L, 17L, 18L, 19L, 20L, 21L,
15L, 22L, 23L, 24L, 25L, 26L, 27L, 1L, 2L, 3L, 4L, 5L, 6L, 7L,
1L, 8L, 9L, 10L, 11L, 12L, 13L), .Label = c("p00e00d00", "p00e00d11",
"p00e00d12", "p00e00d13", "p00e00d21", "p00e00d22", "p00e00d23",
"p00e11d00", "p00e12d00", "p00e13d00", "p00e21d00", "p00e22d00",
"p00e23d00", "p01e00d00", "p11e00d00", "p11e00d11", "p11e00d12",
"p11e00d13", "p11e00d21", "p11e00d22", "p11e00d23", "p11e11d00",
"p11e12d00", "p11e13d00", "p11e21d00", "p11e22d00", "p11e23d00",
"p12e00d00", "p13e00d00", "p14e00d00", "p21e00d00", "p22e00d00"
), class = "factor"), response = structure(c(2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("2",
"1"), class = "factor"), n = c(345L, 511L, 583L, 613L, 612L,
222L, 142L, 531L, 546L, 589L, 636L, 478L, 364L, 313L, 502L, 533L,
587L, 603L, 385L, 298L, 263L, 518L, 546L, 563L, 593L, 435L, 351L,
310L, 478L, 579L, 629L, 646L, 357L, 307L, 230L), freq = c(0.408284023668639,
0.604733727810651, 0.689940828402367, 0.725443786982249, 0.724260355029586,
0.262721893491124, 0.168047337278107, 0.628402366863905, 0.646153846153846,
0.697041420118343, 0.752662721893491, 0.565680473372781, 0.430769230769231,
0.370414201183432, 0.594082840236686, 0.630769230769231, 0.694674556213018,
0.713609467455621, 0.455621301775148, 0.352662721893491, 0.311242603550296,
0.61301775147929, 0.646153846153846, 0.666272189349112, 0.701775147928994,
0.514792899408284, 0.415384615384615, 0.366863905325444, 0.565680473372781,
0.685207100591716, 0.744378698224852, 0.764497041420118, 0.422485207100592,
0.363313609467456, 0.272189349112426)), class = c("tbl_df", "tbl",
"data.frame"), row.names = c(NA, -35L), .Names = c("block", "item",
"response", "n", "freq"))
There are five blocks, each block contains 7 items, and some items have the same names across blocks. I can therefore facet by block as follows:
df %>%
ggplot(aes(x = item, y = freq)) +
geom_bar(stat = "identity", position = "dodge", color = "black") +
facet_grid(.~block, scales = "free") +
coord_cartesian(ylim = c(0, 1), expand = F) + # need to add expanse = F to prevent zooming away
scale_y_continuous(labels = scales::percent) +
theme(axis.text.x = element_text(angle=45, hjust=1, vjust=1))
I also have vectors which states for each block the order that items should appear in. For example:
block_3_order = c("p11e13d00","p11e12d00", "p11e11d00", "p11e00d00", "p11e21d00", "p11e22d00","p11e23d00")
)
block_4_order = c("p00e00d13", "p00e00d12", "p00e00d11", "p00e00d00", "p00e00d21","p00e00d22","p00e00d23")
)
I tried to reorder the "item" factor, but to get the desired effect I would need to split the dataframe into subsets representing blocks. Otherwise I am having trouble grasping how you can integrate the ordering of factors with the ggplot treatment of item as a single factor across facets.
Any help is greatly appreciated.
To get a different custom axis order in each facet, you can create each "facet" as a separate plot and then lay them out together as if they were a single faceted plot.
library(tidyverse)
#devtools::install_github("baptiste/egg")
library(egg)
library(gridExtra)
library(grid)
theme_set(theme_bw())
First, create the custom orderings. The ones that are NULL will just be sorted alphabetically in the final plot.
b.order = list(b1 = NULL,
b2 = NULL,
b3 = c("p11e13d00","p11e12d00", "p11e11d00", "p11e00d00", "p11e21d00", "p11e22d00","p11e23d00"),
b4 = c("p00e00d13", "p00e00d12", "p00e00d11", "p00e00d00", "p00e00d21","p00e00d22","p00e00d23"),
b5 = NULL)
Create a list of plots, one for each block. We do this by splitting df by block. To get the custom ordering, we use factor to set the custom order based on the list b.order.
plist = map2(split(df, df$block), b.order,
~ .x %>% group_by(block) %>%
mutate(item = factor(item, levels=if(is.null(.y)) sort(unique(item)) else .y)) %>%
ggplot(aes(x = item, y = freq)) +
geom_bar(stat = "identity", position = "dodge", color = "black") +
facet_grid(.~block, scales = "free") +
coord_cartesian(ylim = c(0, 1), expand = F) + # need to add expanse = F to prevent zooming away
scale_y_continuous(labels = scales::percent) +
theme(axis.text.x = element_text(angle=45, hjust=1, vjust=1),
plot.margin=margin(b=-5)) +
labs(x=""))
Remove y-axis labels, title, and ticks from all but the left-most plot:
plist[2:length(plist)] = plist[2:length(plist)] %>%
map(~ .x + theme(axis.text.y=element_blank(),
axis.title.y=element_blank(),
axis.ticks.y=element_blank()))
Arrange the plots. We use ggarrange from the egg package in order to ensure that the plot panels all have the same horizontal width. We also need to add the Item label beneath the plot. However, ggarrange prints the plot to the output device, even inside arrangeGrob. So we create the object p, clear the device and then redraw the final plot.
p = arrangeGrob(ggarrange(plots=plist, ncol=length(plist)),
textGrob("Item"), heights=c(20,1))
grid.newpage()
grid.draw(p)
I have the following dataframe (output of dput(df2)):
structure(list(angles = c(-0.701916320805404, 2.33367948606366,
0.364313791379516, -0.228918909875176, -2.77064550417737, 2.97776037032614,
-3.03604124258522, 2.10507549390108, 2.07708771915781, -0.0646656487453258,
-0.701916320805404, 2.33367948606366, 0.364313791379516, -0.228918909875176,
-2.77064550417737, 2.97776037032614, -3.03604124258522, 2.10507549390108,
2.07708771915781, -0.0646656487453258, -0.701916320805404, 2.33367948606366,
0.364313791379516, -0.228918909875176, -2.77064550417737, 2.97776037032614,
-3.03604124258522, 2.10507549390108, 2.07708771915781, -0.0646656487453258
), id = c(9L, 4L, 5L, 6L, 3L, 10L, 3L, 4L, 4L, 6L, 1L, 4L, 5L,
6L, 2L, 1L, 3L, 4L, 4L, 6L, 1L, 7L, 5L, 6L, 2L, 1L, 3L, 4L, 4L,
6L), method = structure(c(2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L), .Label = c("kd-clips", "QT-Clust", "True"
), class = "factor"), truid = structure(c(1L, 4L, 5L, 6L, 2L,
1L, 3L, 4L, 4L, 6L, 1L, 4L, 5L, 6L, 2L, 1L, 3L, 4L, 4L, 6L, 1L,
4L, 5L, 6L, 2L, 1L, 3L, 4L, 4L, 6L), .Label = c("1", "2", "3",
"4", "5", "6"), class = "factor")), .Names = c("angles", "id",
"method", "truid"), row.names = c(940L, 474L, 889L, 298L, 222L,
932L, 87L, 695L, 261L, 832L, 1940L, 1474L, 1889L, 1298L, 1222L,
1932L, 1087L, 1695L, 1261L, 1832L, 2940L, 2474L, 2889L, 2298L,
2222L, 2932L, 2087L, 2695L, 2261L, 2832L), class = "data.frame")
I run the following code to make the plot that follows:
df2$y <- as.numeric(as.factor(df2$method)) + 3
df2$yend <- df2$y + 1
library(ggplot2)
library(RColorBrewer)
cx <- ggplot(df2, aes(y = y, x = angles))
cx + geom_point(aes(color = as.factor(id))) + ylim(0,6) + theme_light() + scale_colour_brewer(palette = "Paired") +
scale_x_continuous(labels = NULL, breaks = df2$angles)+coord_polar() +
theme(legend.position="none", panel.border=element_blank(), axis.title =
element_blank(), axis.text = element_blank())
I get the following figure:
Almost there, but what I would like to get are two more things:
The radial lines to be colored according to the last column (true.id) of the df2 (which is the same color as the points in the third concentric circle -- same as that for id == "True").
I would like a radial scale also, marked at intervals of 30 (like at angles of 0, 30, 60, 90, ... 330. 0). However, I do not want the scale at the left (of the y's).
The above has 30 points, three replicates of each method at each angle. However, the figures only appears to plot 9 replicates, i.e. 27 points in total. (It is possible that two angles -- the one with 2.077 and the one with 2.105) are very close, so that they are really perhaps both there, but I can not tell because then what are the two points that are close to each other?
I have tried all day but could not get either of these to work, so I was wondering if anyone can help.
Thanks in advance!
I think this is probably what you wanted (I know, long time ago now...). Some of what you were getting wrong I actually couldn't quite tell, but it's nearly always a mistake to try to use the coordinate gridlines to show data - use geom_line or geom_segment for the data, and leave the gridlines to show the coordinates. This solves both your need to have the lines coloured, and makes it easier for the x gridlines (ie the radial ones) to have the labels you want (whether I understood you correctly on this, re degrees v. radians, I'm not sure).
library(ggplot2)
library(RColorBrewer)
# your "angle" looks to be in radians, not sure how you want these converted to degrees?
# but let's set where we want the axis marks to be
br <- seq(from = -pi, to = pi, length.out = 7)
ggplot(df2, aes(y = y, x = angles)) +
geom_point(aes(color = as.factor(id))) +
theme_light() +
scale_colour_brewer(palette = "Paired") +
geom_vline(aes(xintercept = angles, colour = truid)) +
coord_polar() +
scale_x_continuous(lim = c(-pi, pi), breaks = br, labels = 0:6 * 60) +
theme(legend.position="none",
panel.border=element_blank(),
axis.title = element_blank(),
axis.text.y = element_blank())
I have created a stacked-bar plot with 'ggplot' to display my karyotype (molecular) results from a transplant experiment, with each panel representing a location, and the x-axis is the various substrates, while the y-axis is the percentage of each of the three karyotypes.
I have looked over several examples of questions and answers from Stack Overflow and cannot figure out how to do the following:
centre the values (should be rounded to two decimal places) within each section of the stacked bars, right now I just have them offset from the top.
how to change my legend text from "BB" to the Greek "lower alpha, lower alpha", "BD" to Greek "lower alpha, lower beta", and "DD" to Greek "lower beta, lower beta".
Here is some sample data and code with a copy of the plot it generates.
Karotype.Data <- structure(list(Location = structure(c(1L, 1L, 3L, 3L, 1L, 1L, 1L, 1L, 1L, 1L, 4L, 4L, 1L, 1L, 1L, 4L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 2L, 2L), .Label = c("Kampinge", "Kaseberga", "Molle", "Steninge"), class = "factor"), Substrate = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 3L, 4L, 2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 3L, 2L, 1L, 4L, 2L), .Label = c("Kampinge", "Kaseberga", "Molle", "Steninge"), class = "factor"), Karyotype = structure(c(1L, 3L, 4L, 1L, 3L, 3L, 4L, 4L, 4L, 3L, 1L, 4L, 3L, 4L, 2L, 3L, 1L, 4L, 3L, 2L, 4L, 3L, 4L, 2L, 3L), .Label = c("", "BB", "BD", "DD"), class = "factor")), .Names = c("Location", "Substrate", "Karyotype"), row.names = c(135L, 136L, 137L, 138L, 139L, 165L, 166L, 167L, 168L, 169L, 236L, 237L, 238L, 239L, 240L, 326L, 327L, 328L, 329L, 330L, 426L, 427L, 428L, 429L, 430L), class = "data.frame")
z.counts <- Karotype.Data %>%
group_by(Location,Substrate,Karyotype) %>%
summarise(Frequency=n())
z.freq <- z.counts %>% filter(Karyotype != '') %>%
group_by(Location,Substrate) %>%
mutate(Percent=Frequency/sum(Frequency))
z.freq
ggplot(z.freq, aes(x=Substrate, y=Percent, fill=Karyotype )) +
geom_bar(stat="identity") +
geom_text(aes(label = Percent), size = 5, vjust = 1, position = "stack") +
facet_wrap(~ Location, ncol=2) +
scale_y_continuous(name="Percentage") +
theme(strip.text.x = element_text(colour="black", size=20, face="bold"),
axis.title.x = element_text(colour="black", size=20, face="bold", vjust=-0.5),
axis.text.x = element_text(colour="black", size=18),
axis.title.y = element_text(colour="black", size=20,face="bold", vjust=1),
axis.text.y = element_text(colour="black", size=18),
legend.title = element_text(colour="black", size=20, face="bold"),
legend.text = element_text(colour="black", size = 18),
legend.position="bottom")
To add greek letters to the legend, you can change the colour scale with scale_colour_manual():
test = data.frame(x=1:30,y=1:30,label=rep(c("BB","BD","DD"),each=10))
ggplot(test) + geom_point(aes(x=x,y=y,color=label)) + scale_colour_manual(values=c(1,2,3),breaks = c("BB","BD","DD"),labels = list(bquote(alpha~alpha),bquote(alpha~beta),bquote(beta~beta)))
argument values sets the colour, breaks sets your breakpoints (BB, BD and DD) and labels sets the greek letters you want.
To round the legend, you can add another column to your dataframe, setting values to round(Percent,digits=3), and use this column in the geom_text.
Informations concerning greek letters in ggplot2 can be found here