giving the following data:
data2 <- list(structure(list(super_group = c(1,1), Group.1 = structure(3:4, .Label = c("A","B", "C", "D", "E", "F"), class = "factor"), Pr1 = c(65, 75), Pr2 = c(54, 88), Prh = c(25, 5), SE = c(25, 75 )), row.names = c(NA, -2L), class = "data.frame"), NULL, structure(list(super_group = c(3,3), Group.1 = structure(3:4, .Label = c("A","B", "C", "D", "E", "F"), class = "factor"), Pr1 = c(81,4), Pr2 = c(66, 57),Prh = c(3,3), SE = c(8, 9)), row.names = c(NA,
-2L), class = "data.frame"))
to plot using ggplot2:
data2 %>%
bind_rows() %>%
ggplot(., aes(x = Group.1, y = Pr1, fill = Group.1)) +
geom_bar(stat = "identity") +
facet_grid(. ~ super_group)
-you see C and D labels in the x axis which are not necessary. So I want to remove them and reduce the width of the bars. any ideas?
-can we move 1 and 3 from x axis top to x axis bottom?
We could use switch argument to facet_grid to change the position of facet labels.
Arguments axis.text.x and axis.ticks.x control the text and tick on the x axis. To remove them declare them as element_blank().
library(tidyverse)
data2 %>%
bind_rows() %>%
ggplot(., aes(x = Group.1, y = Pr1, fill = Group.1)) +
geom_bar(stat = "identity") +
facet_grid(. ~ super_group, switch = "x") +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank()) -> p1
To change the proportions of the graph save it with different dimensions. Example:
ggsave("p1.pdf", plot = p1, device = "pdf", width = 3, height = 5)
Or if using knitr change the chunk options by defining:
fig.width=3, fig.height=5 for example:
```{r p1, fig.width=3, fig.height=5}
data2 %>%
bind_rows() %>%
ggplot(., aes(x = Group.1, y = Pr1, fill = Group.1)) +
geom_bar(stat = "identity") +
facet_grid(. ~ super_group, switch = "x") +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank())
```
and to change the width of the bars use argument width:
data2 %>%
bind_rows() %>%
ggplot(., aes(x = Group.1, y = Pr1, fill = Group.1)) +
geom_bar(stat = "identity", width = 0.5) +
facet_grid(. ~ super_group, switch = "x") +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank())
another option (based on the comments it seems to me this is the desired one) is to change expand:
data2 %>%
bind_rows() %>%
ggplot(., aes(x = Group.1, y = Pr1, fill = Group.1)) +
geom_bar(stat = "identity") +
facet_grid(. ~ super_group, switch = "x") +
scale_x_discrete(expand = c(1,1))+
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank())
Related
I have a dataframe where the first column has different types of bacteria, and the rest of the columns the samples, each sample belong to a specific time (T0, T1...) and the last 39 columns are the control group.
What I pretend is to plot each bacteria in one plot. And the plot must contain the different times in x-axis and the value in the y-axis (I was thinking in a bar plot or box plot with the errors coef.
Any idea about how can I group the data for different times and for different bacteria?
Here a small example of the data:
thanks!
structure(list(Bacteria = c("Methanobrevibacter", "Methanosphaera",
"Methanomassiliicoccus"), PIE2001_T0_TORUNDA = c(2.279974027,
0.670536115, -0.022611066), PIE2001_T1_TORUNDA = c(2.021643324,
-0.057798217, -0.057798217), PIE2001_T5_COMPL = c(2.788566988,
0.648500825, -0.044646356), PIE2006_T0_TORUNDA = c(0.07550014,
1.684938052, 0.07550014), PIE2007_T0_TORUNDA = c(2.072075243,
1.261145027, -0.125149334), PIE2007_T1_TORUNDA = c(2.601582257,
1.279826417, -0.106467944), PIE2007_T2 = c(2.81564899, 1.765826865,
-0.180083284), PIE2007_T3 = c(0.639040509, 3.081387545, -0.054106671
), PIE2013_T0_COMPLETA = c(2.683794403, -0.024255798, -0.024255798
), PIE2013_T1_COMPLETA = c(2.614756053, -0.024301277, -0.024301277
), PIE2013_T4_COMP = c(2.653056483, 0.013999154, 0.013999154),
PIE2013_T5_COMPL = c(1.861263144, -0.084647005, -0.084647005
), PIE2014_COMP = c(2.304771706, 1.005488722, -0.093123567
), PIE2016_T0_COMPLETA = c(-0.141271428, -0.141271428, -0.141271428
), PIE2016_T1_COMPLETA = c(-0.081696055, -0.081696055, -0.081696055
), PIE2016_T3 = c(-0.019385468, -0.019385468, -0.019385468
), PIE2016_T3_TOR = c(0.045856809, 0.045856809, 0.045856809
), PIE2017_T0_COMPLETA = c(4.493506636, 0.189441543, 0.189441543
), PIE2017_T1_COMPLETA = c(5.001671041, 0.71808448, 0.024937299
), PIE2017_T2_TOR = c(5.887191114, 0.672255357, -0.020891824
), PIE2017_T3 = c(3.306066839, 0.703377154, 0.010229973),
PIE2017_T4_COMP = c(5.560847286, 1.371192544, -0.015101817
), PIE2017_T5_COMPL = c(5.688626959, -0.025105846, -0.025105846
), PIE2018_T1 = c(0.158551089, 0.158551089, 0.158551089),
PIE2019_T1_COMPL = c(6.659430141, 0.833430034, 0.140282853
)), row.names = c(NA, 3L), class = "data.frame")
Script updated:
colnames(df)[363:401] <- gsub("T0", "T6", colnames(df)[363:401])
df %>%
pivot_longer(-Bacteria) %>%
mutate(group = gsub('_.*$', '', name),
time = gsub('^.*_(T\\d+).*$', '\\1', name)) %>%
filter(grepl('T\\d+', time)) %>%
ggplot(aes(time, value, fill = Bacteria)) +
geom_bar(stat = 'summary', fun = 'mean', position = 'dodge') +
stat_summary(fun.data = "mean_se", geom = "errorbar", width = 0.2, position = position_dodge(0.9)) +
theme_minimal() +
facet_grid(Bacteria ~ ., scale = 'free_y') +
scale_fill_brewer(palette = 'Set1') +
theme(panel.border = element_rect(fill = NA, color = 'gray75'))
You need to reshape your data. You can then do a comparative boxplot:
library(tidyverse)
df %>%
pivot_longer(-Bacteria) %>%
mutate(group = gsub('_.*$', '', name),
time = gsub('^.*_(T\\d+).*$', '\\1', name)) %>%
filter(grepl('T\\d+', time)) %>%
ggplot(aes(time, value, fill = Bacteria)) +
geom_boxplot() +
theme_minimal() +
facet_grid(Bacteria ~ ., scale = 'free_y') +
scale_fill_brewer(palette = 'Set2') +
theme(panel.border = element_rect(fill = NA, color = 'gray75'))
Pivot your data to long format, then facet by bacterium:
library(tidyr)
library(dplyr)
library(forcats)
library(ggplot2)
dat_long <- dat %>%
pivot_longer(!Bacteria, names_to = "sample") %>%
mutate(sample = fct_inorder(sample))
ggplot(dat_long, aes(sample, value)) +
geom_col() +
facet_wrap(vars(Bacteria), ncol = 1) +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
Or make a line graph with bacteria mapped to color:
ggplot(dat_long, aes(sample, value)) +
geom_line(aes(color = Bacteria, group = Bacteria)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
Hi supposed I have the following pie info.
df=structure(list(Var1 = c("a", "b"), Freq = c(306L, 1064L), per = c(0.223357664233577,
0.776642335766423)), row.names = c(NA, -2L), class = "data.frame")
and I plot this pie chart with direction -1
ggplot(data = df,
aes(x = "", y = per, fill = Var1)) +
geom_col() +
geom_text(aes(label = scales::percent(per, accuracy = 1)),
position = position_stack(vjust = 0.5),
color = "grey20", size = pietext ) +
coord_polar(theta = "y", direction =-1 ) +
theme_void ()
However what I would like is to label with with the frequency rather than the percentage.
Var1 Freq per
1 a 306 0.2233577
2 b 1064 0.7766423
Is this possible with this method? I tried replacing per with Freq but that just gave some really strange text.
thank you.
aes(label = Freq) is the way to go:
ggplot(data = df,
aes(x = "", y = per, fill = Var1)) +
geom_col() +
geom_text(aes(label = Freq),
position = position_stack(vjust = 0.5),
color = "grey20", size=12) +
coord_polar(theta = "y", direction =-1) +
theme_void ()
Just change geom_text(aes(label =Freq)
ggplot(data = df, aes(x = "", y = per, fill = Var1)) +
geom_col() +
geom_text(aes(label =Freq),
position = position_stack(vjust = 0.5),
color = "black", size = 10 ) +
labs( x="", y="", fill="")+
scale_fill_manual(values=c("#4E79A7", "#fc7d0b"))+
coord_polar(theta = "y", direction =-1 ) +
theme_no_axes()
Plot:
or something that is better than a pie chart
Sample code:
library(waffle)
library(ggthemes)
vals <- c(306,1064)
val_names <- sprintf("%s (%s)", c("a","b"), label=vals)
names(vals) <- val_names
waffle::waffle(vals) +
ggthemes::scale_fill_tableau(name=NULL)
Plot:
Sample code:
df=structure(list(Var1 = c("a", "b"), Freq = c(306L, 1064L), per = c(0.223357664233577, 0.776642335766423)), row.names = c(NA, -2L), class = "data.frame")
I am trying to get my mean and totals to the left of my bar chart like in the example above.
I have my bar charts created in ggplot. Picture and code below. Any advice on how to get the means and totals to display in the right place? Possibly custom_annotations?
Thanks
percentData = stotal %>% #stotal = survey data frame
group_by(qtext, div, response) %>% #qtext is my question text
summarise(N = n()) %>%
mutate(prop = N/sum(N))
percentData$prop = label_percent(accuracy = 1)(percentData$prop) #make percent from decimal
percentData
#colors
myColors <- c("green4","springgreen2","yellow1","orange1","red1","black", "black", "black")
ggplot(stotal)+
geom_bar(aes(x = div, fill = response), position = 'fill', width = 0.5)+
facet_grid(rows = vars(qtext))+
scale_fill_manual (values = myColors)+
coord_flip()+
ylab('')+
xlab('')+
scale_y_continuous(labels = percent)+
ggtitle(i)+
geom_text(data = percentData, aes(fill = response, y = N, label = prop, x = div),
position=position_fill(vjust=0.5))+
theme(strip.text.y = element_text(size = 12, angle = 0, family = "serif"))
One approach to achieve this is by making the table via a second ggplot which can be glued to the main plot by e.g. patchwork. Basically the table plot replicates the main plot with only one category, uses facetting to get the colum layout with the mean and the totals and gets rids of axis, grid, background colors, ...
Using some random example data try this:
library(ggplot2)
library(dplyr)
library(scales)
library(patchwork)
# Random example data
set.seed(42)
stotal <- data.frame(
qtext = rep(c("A", "B"), 50),
div = sample(c("University", "KSAS-HUM"), 100, replace = TRUE),
response = sample(c("Poor", "Fair", "Good", "Very good", "Excellent"), 100, replace = TRUE)
)
stotal$response <- factor(stotal$response, levels = c("Poor", "Fair", "Good", "Very good", "Excellent"))
percentData = stotal %>% #stotal = survey data frame
group_by(qtext, div, response) %>% #qtext is my question text
summarise(N = n()) %>%
mutate(prop = N/sum(N))
#> `summarise()` regrouping output by 'qtext', 'div' (override with `.groups` argument)
percentData$prop = label_percent(accuracy = 1)(percentData$prop) #make percent from decimal
#colors
myColors <- c("green4","springgreen2","yellow1","orange1","red1","black", "black", "black")
p1 <- ggplot(stotal)+
geom_bar(aes(x = div, fill = response), position = 'fill', width = 0.5)+
facet_grid(rows = vars(qtext))+
scale_fill_manual (values = myColors)+
coord_flip()+
ylab('')+
xlab('')+
scale_y_continuous(labels = percent)+
#ggtitle(i)+
geom_text(data = percentData, aes(fill = response, y = N, label = prop, x = div),
position=position_fill(vjust=0.5))+
theme(strip.text.y = element_text(size = 12, angle = 0, family = "serif"))
#> Warning: Ignoring unknown aesthetics: fill
# Table plot
table_data <- stotal %>%
mutate(response = as.numeric(response)) %>%
group_by(qtext, div) %>%
summarise(Mean = mean(response), "Total N" = n()) %>%
mutate(Mean = round(Mean, 1)) %>%
tidyr::pivot_longer(-c(qtext, div), names_to = "var")
#> `summarise()` regrouping output by 'qtext' (override with `.groups` argument)
p2 <- ggplot(table_data, aes(x = div)) +
geom_bar(color = "white", fill = "white", position = 'fill', width = .5)+
#geom_vline(color = "grey", xintercept = c(.5, 1.5, 2.5)) +
geom_text(aes(y = 1, label = value), position=position_fill(vjust=0.5), size = 0.8 * 11 /.pt) +
facet_grid(qtext ~ var, switch = "y") +
coord_flip() +
labs(x = NULL, y = NULL) +
theme_minimal() +
theme(strip.text.y = element_blank()) +
theme(axis.ticks.y = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(color = "transparent"),
axis.ticks.x = element_line(color = "transparent"),
axis.title = element_blank(),
panel.grid = element_blank(), panel.spacing.x = unit(0, "pt"))
# Glue together
p2 + p1 + plot_layout(widths = c(1, 3))
This is what is the output.I have a data set which contains unit, weight of each unit and compliance score for each unit in year 2016.
I was not able to add the table but here is the screenshot for the data in csv
I have named the columns in the data as unit, weight and year(which is compliance score) .
I want to create a sunburst chart where the first ring will be the unit divided based on weight and the second ring will be the same but will have labels compliance score.
The colour for each ring will be different.
I was able to do some code with the help from an online blog and the output I have gotten is similar to what I want but I am facing difficulty in positioning of the labels and also the colour coding for each ring
#using ggplot
library(ggplot2) # Visualisation
library(dplyr) # data wrangling
library(scales) # formatting
#read file
weight.eg = read.csv("Dummy Data.csv", header = FALSE, sep =
";",encoding = "UTF-8")
#change column names
colnames(weight.eg) <- c ("unit","weight","year")
#as weight column is factor change into integer
weight.eg$weight = as.numeric(levels(weight.eg$weight))
[as.integer(weight.eg$weight)]
weight.eg$year = as.numeric(levels(weight.eg$year))
[as.integer(weight.eg$year)]
#Nas are introduced, remove
weight.eg <- na.omit(weight.eg)
#Sum of the total weight
sum_total_weight = sum(weight.eg$weight)
#First layer
firstLevel = weight.eg %>% summarize(total_weight=sum(weight))
sunburst_0 = ggplot(firstLevel) # Just a foundation
#this will generate a bar chart
sunburst_1 =
sunburst_0 +
geom_bar(data=firstLevel, aes(x=1, y=total_weight),
fill='darkgrey', stat='identity') +
geom_text(aes(x=1, y=sum_total_weight/2, label=paste("Total
Weight", comma(total_weight))), color='black')
#View
sunburst_1
#this argument is used to rotate the plot around the y-axis which
the total weight
sunburst_1 + coord_polar(theta = "y")
sunburst_2=
sunburst_1 +
geom_bar(data=weight.eg,
aes(x=2, y=weight.eg$weight, fill=weight.eg$weight),
color='white', position='stack', stat='identity', size=0.6)
+
geom_text(data=weight.eg, aes(label=paste(weight.eg$unit,
weight.eg$weight), x=2, y=weight.eg$weight), position='stack')
sunburst_2 + coord_polar(theta = "y")
sunburst_3 =
sunburst_2 +
geom_bar(data=weight.eg,
aes(x=3, y=weight.eg$weight,fill=weight.eg$weight),
color='white', position='stack', stat='identity',
size=0.6)+
geom_text(data = weight.eg,
aes(label=paste(weight.eg$year),x=3,y=weight.eg$weight),position =
'stack')
sunburst_3 + coord_polar(theta = "y")
sunburst_3 + scale_y_continuous(labels=comma) +
scale_fill_continuous(low='white', high='darkred') +
coord_polar('y') + theme_minimal()
Output for dput(weight.eg)
structure(list(unit = structure(2:7, .Label = c("", "A", "B",
"C", "D", "E", "F", "Unit"), class = "factor"), weight = c(30,
25, 10, 17, 5, 13), year = c(70, 80, 50, 30, 60, 40)), .Names =
c("unit",
"weight", "year"), row.names = 2:7, class = "data.frame", na.action
= structure(c(1L,
8L), .Names = c("1", "8"), class = "omit"))
output for dput(firstLevel)
structure(list(total_weight = 100), .Names = "total_weight", row.names
= c(NA,
-1L), na.action = structure(c(1L, 8L), .Names = c("1", "8"), class =
"omit"), class = "data.frame")
So I think I might have some sort of solution for you. I wasn't sure what you wanted to color-code on the outer ring; from your code it seems you wanted it to be the weight again, but it was not obvious to me. For different colour scales per ring, you could use the ggnewscale package:
library(ggnewscale)
For the centering of the labels you could write a function:
cs_fun <- function(x){(cumsum(x) + c(0, cumsum(head(x , -1))))/ 2}
Now the plotting code could look something like this:
ggplot(weight.eg) +
# Note: geom_col is equivalent to geom_bar(stat = "identity")
geom_col(data = firstLevel,
aes(x = 1, y = total_weight)) +
geom_text(data = firstLevel,
aes(x = 1, y = total_weight / 2,
label = paste("Total Weight:", total_weight)),
colour = "black") +
geom_col(aes(x = 2,
y = weight, fill = weight),
colour = "white", size = 0.6) +
scale_fill_gradient(name = "Weight",
low = "white", high = "darkred") +
# Open up new fill scale for next ring
new_scale_fill() +
geom_text(aes(x = 2, y = cs_fun(weight),
label = paste(unit, weight))) +
geom_col(aes(x = 3, y = weight, fill = weight),
size = 0.6, colour = "white") +
scale_fill_gradient(name = "Another Weight?",
low = "forestgreen", high = "white") +
geom_text(aes(label = paste0(year), x = 3,
y = cs_fun(weight))) +
coord_polar(theta = "y")
Which looks like this:
I'm making a plot with two different geoms, both use fill. I'd like one geom to have a legend, but the other to not. However adding show.legend=F to the required geom doesn't switch off the legend for that geom.
Example:
library(tidyverse)
library(ggalluvial)
x = tibble(qms = c("grass", "cereal", "cereal"),
move1 = "Birth",
move2 = c("Direct", "Market", "Slaughter"),
move3 = c("Slaughter", "Slaughter", NA),
freq = c(10, 5, 7))
x %>%
mutate(id = qms) %>%
to_lodes_form(axis = 2:4, id = id) %>%
na.omit() %>%
ggplot(aes(x = x, stratum = stratum, alluvium = id,
y = freq, label = stratum)) +
scale_x_discrete(expand = c(.1, .1)) +
geom_flow(aes(fill = qms)) +
geom_stratum(aes(fill = stratum), show.legend=F) +
geom_text(stat = "stratum", size = 3) +
theme_void() +
labs(fill="")
Output:
Desired output:
Question:
How do I turn off the fill legend for one geom, but not the other? I can (if I have to) do this in inkscape/gimp, but would prefer a solution I can version control.
Have a look at the final line of code:
scale_fill_discrete(breaks = c("grass", "cereal"))
That defines the breaks for the fills to only include cereal and grass, as required.
library(tidyverse)
library(ggalluvial)
x = tibble(qms = c("grass", "cereal", "cereal"),
move1 = "Birth",
move2 = c("Direct", "Market", "Slaughter"),
move3 = c("Slaughter", "Slaughter", NA),
freq = c(10, 5, 7))
x %>%
mutate(id = qms) %>%
to_lodes_form(axis = 2:4, id = id) %>%
na.omit() %>%
ggplot(aes(x = x, stratum = stratum, alluvium = id,
y = freq, label = stratum)) +
scale_x_discrete(expand = c(.1, .1)) +
geom_flow(aes(fill = qms)) +
geom_stratum(aes(fill = stratum), show.legend=FALSE) +
geom_text(stat = "stratum", size = 3) +
theme_void() +
labs(fill="") +
scale_fill_discrete(breaks = c("grass", "cereal")) #<- This line!
Created on 2019-03-18 by the reprex package (v0.2.1)