I am using a dataframe to create facet plot by months to view highest covid CFR states for each month (Issue shown in point 3).
DF:
df_ind_stacked_cum <- read.csv(url("https://raw.githubusercontent.com/johnsnow09/covid19-df_stack-code/main/df_ind_stacked_cum.csv"))
When I create a plot this is what I get:
2.1
2.2 code:
df_ind_stacked_cum %>%
filter(!State.UnionTerritory %in%
c("Maharashtra***","Punjab***","Chandigarh***","Telangana***", "Cases being reassigned to states")) %>%
mutate(month = lubridate::month(Date, label = TRUE, abbr = TRUE)) %>%
filter(Cases_type == "Confirmed") %>%
group_by(State.UnionTerritory, month) %>%
summarise(CFR = max(CFR, na.rm = TRUE)) %>%
group_by(month) %>%
top_n(n = 7, wt = CFR) %>%
ungroup() %>%
mutate(State.UnionTerritory = fct_reorder(State.UnionTerritory, CFR, max)) %>%
ggplot(aes(x = CFR, y = State.UnionTerritory,
fill = State.UnionTerritory, group = State.UnionTerritory )) +
geom_col() +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90),
legend.position = "none") +
facet_wrap(~month) +
# coord_cartesian(clip = "off") +
# scale_fill_tableau() +
labs(title = "Top 7 CFR States based on each month")
Issue: When I add scale_fill_brewer() then plot looks changed ?
3.1
3.2 Code:
df_ind_stacked_cum %>%
filter(!State.UnionTerritory %in%
c("Maharashtra***","Punjab***","Chandigarh***","Telangana***", "Cases being reassigned to states")) %>%
mutate(month = lubridate::month(Date, label = TRUE, abbr = TRUE)) %>%
filter(Cases_type == "Confirmed") %>%
group_by(State.UnionTerritory, month) %>%
summarise(CFR = max(CFR, na.rm = TRUE)) %>%
group_by(month) %>%
top_n(n = 7, wt = CFR) %>%
ungroup() %>%
mutate(State.UnionTerritory = fct_reorder(State.UnionTerritory, CFR, max)) %>%
ggplot(aes(x = CFR, y = State.UnionTerritory,
fill = State.UnionTerritory, group = State.UnionTerritory )) +
geom_col() +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90),
legend.position = "none") +
facet_wrap(~month) +
# coord_cartesian(clip = "off") +
# scale_fill_tableau() +
labs(title = "Top 7 CFR States based on each month") +
scale_fill_brewer(palette = "Paired")
It gets changed based on palette I select:
scale_fill_brewer(palette = "Set2")
How can I change colors without changing the plot?
Related
I have a face_wrapped plot with free y axis in ggplot2. I was wondering if it is possible to reposition some of the flipped x-axis label based on the red arrows shown in the picture below?
library(tidyverse)
data <- read_csv('https://raw.githubusercontent.com/rnorouzian/e/master/surv.csv')
names(data)[2:5] <- c("Representation", "Solidification", "Application", "Confidence")
data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = str_wrap(value, 20)) %>%
ggplot() +
geom_bar(aes(value, fill = name), show.legend = FALSE) +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
We can reorder after creating the frequency with count
library(dplyr)
library(tidyr)
library(ggplot2)
data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = str_wrap(value, 20)) %>%
count(name, value) %>%
ggplot(aes(x = reorder(value, n), y = n, fill = name)) +
geom_bar(show.legend = FALSE, stat = 'identity') +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
-output
Or if it is a custom order, then have to create the custom order vector and use that to change the 'value' to a factor with levels specified in that order
data1 <- data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = str_wrap(value, 20))
lvls <- unique(data1$value)[c(3, 10, 1, 5, 9, 4, 8, 7, 6, 2)]
data1 %>%
mutate(value = factor(value, levels = lvls)) %>% # // change here
ggplot() +
geom_bar(aes(value, fill = name), show.legend = FALSE) +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
This code should get the exact picture you want, by reordering the factor after you have pivoted longer
data %>%
pivot_longer(cols = -id) %>%
mutate(name = name,
value = factor(str_wrap(value, 20))) %>%
mutate(value = forcats::fct_relevel(value, "Agree", after = 1)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\nhelped me solidify\nthe key concepts", after = Inf)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\nreflected the class\ninstructions", after = Inf)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\nhighly reflected the\nclass instructions", after = Inf)) %>%
mutate(value = forcats::fct_relevel(value, "The assignment\ngave me a great\nopportunity to apply\nwhat I learned", after = Inf)) %>%
ggplot() +
geom_bar(aes(value, fill = name), show.legend = FALSE) +
facet_wrap(.~name, scales = 'free_y') +
coord_flip() +
labs(y = "Students", x = "") +
theme(axis.text.y = element_text(size=8))
I am learning r and I have problem with sorting the double bar in ascending or descending order and I want to set the legend just on the top of the plot with two color represent respectively with one row and two columns like for example:
The title Time
box color Breakfast box color Dinner
And the plot here
Here is my dataframe:
dat <- data.frame(
time = factor(c("Breakfast","Breakfast","Breakfast","Breakfast","Breakfast","Lunch","Lunch","Lunch","Lunch","Lunch","Lunch","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner"), levels=c("Breakfast","Lunch","Dinner")),
class = c("a","a","b","b","c","a","b","b","c","c","c","a","a","b","b","b","c","c"))
And here is my code to make change:
dat %>%
filter(time %in% c("Breakfast", "Dinner")) %>%
droplevels %>%
count(time, class) %>%
group_by(time) %>%
mutate(prop = n/sum(n)) %>%
ggplot(aes(x = class, y = prop, fill = time, label = scales::percent(prop))) +
geom_col(position = 'dodge') +
geom_text(position = position_dodge(width = 0.9), vjust = 0.5, size = 3) +
scale_y_continuous(labels = scales::percent)+
coord_flip()
Any help would be appreciated.
Something like this should be close to what you are asking, feel free to ask more
Resources consulted during the answer: http://www.sthda.com/english/wiki/ggplot2-legend-easy-steps-to-change-the-position-and-the-appearance-of-a-graph-legend-in-r-software
Using part of the answer you can look further into https://ggplot2.tidyverse.org/reference/theme.html
library(tidyverse)
dat <- data.frame(
time = factor(c("Breakfast","Breakfast","Breakfast","Breakfast","Breakfast","Lunch","Lunch","Lunch","Lunch","Lunch","Lunch","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner","Dinner"), levels=c("Breakfast","Lunch","Dinner")),
class = c("a","a","b","b","c","a","b","b","c","c","c","a","a","b","b","b","c","c"))
dat %>%
filter(time %in% c("Breakfast", "Dinner")) %>%
droplevels %>%
count(time, class) %>%
group_by(time) %>%
mutate(prop = n/sum(n)) %>%
ggplot(aes(x = fct_reorder(class,prop), y = prop, fill = time, label = scales::percent(prop))) +
geom_col(position = 'dodge') +
geom_text(position = position_dodge(width = 0.9), vjust = 0.5, size = 3) +
scale_y_continuous(labels = scales::percent)+
coord_flip() +
labs(x = "class",fill = "Time") +
theme(legend.position = "top", legend.direction="vertical", legend.title=element_text(hjust = 0.5,face = "bold",size = 12))
Created on 2020-05-08 by the reprex package (v0.3.0)
To get the legend title above the legend key, requires a little additional adjustments to the theme and guides.
dat %>%
filter(time %in% c("Breakfast", "Dinner")) %>%
droplevels %>%
count(time, class) %>%
group_by(time) %>%
mutate(prop = n/sum(n)) %>%
ggplot(aes(x = class, y = prop, fill = time, label = scales::percent(prop))) +
geom_col(position = 'dodge') +
geom_text(position = position_dodge(width = 0.9), vjust = 0.5, size = 3) +
scale_y_continuous(labels = scales::percent)+
coord_flip() +
theme(legend.position="top", legend.direction="vertical", legend.title=element_text(hjust = 0.5))+
guides(fill = guide_legend(title = "Time", nrow = 1))
Sup,
Consider the following lines:
data
df=data.frame(
prod=sample(1:30, 1000, replace=TRUE),
mat=sample(c('yes', 'no'), 1000, replace=TRUE),
fj=sample(c(1,2), 1000, replace = TRUE)
)
plot
df %>%
group_by(mat, prod, fj) %>%
summarise(n = n()) %>%
arrange(desc(n)) %>%
slice(1:5) %>%
ggplot(aes(x = reorder(prod, n), y = n)) +
geom_col(fill = RColorBrewer::brewer.pal(3, 'Dark2')[2], colour = "grey", alpha = 0.8) +
labs(x = "Prod", y = "Qnt") +
scale_y_continuous(labels = scales::comma) +
coord_flip() +
facet_wrap(fj ~ mat, scale="free") +
theme_minimal()
which gives me
Now, if i drop fj variable, as in
df %>%
group_by(mat, prod) %>%
summarise(n = n()) %>%
arrange(desc(n)) %>%
slice(1:5) %>%
ggplot(aes(x = reorder(prod, n), y = n)) +
geom_col(fill = RColorBrewer::brewer.pal(3, 'Dark2')[2], colour = "grey", alpha = 0.8) +
labs(x = "Prod", y = "Qnt") +
scale_y_continuous(labels = scales::comma) +
coord_flip() +
facet_wrap(~ mat, scale="free") +
theme_minimal()
slice(1:5) does it's job and i've got:
Question
why slice and reorder doesn't seems to work properly when there's 3+ variables and what should i do to limit the first plot to 5 lines each?
When you call summarize you loose one level of grouping. In this case, you lost fj, so when you slice it's not included in the group divisions.
If you first ungroup then group_by mat and fj, I think you'll end up with what you are looking for.
df %>%
group_by(mat, prod, fj) %>%
summarise(n = n()) %>%
ungroup()%>%
group_by(mat, fj) %>%
arrange(desc(n)) %>%
slice(1:5) %>%
ggplot(aes(x = reorder(prod, n), y = n)) +
geom_col(fill = RColorBrewer::brewer.pal(3, 'Dark2')[2], colour = "grey", alpha = 0.8) +
labs(x = "Prod", y = "Qnt") +
scale_y_continuous(labels = scales::comma) +
coord_flip() +
facet_wrap(fj ~ mat, scale="free") +
theme_minimal()
This leaves the problem of reordering the prod variable within each facet. It doesn't work in the example above because you are ordering by the entire data frame, and some of the values of Prod are repeated in several of the facets. As discussed in this blog post by #drsimonj you need to create an order variable and plot based on that. This follows/blatently copies the method outlined in the blog post.
df %>%
group_by(mat, prod, fj) %>%
summarise(n = n()) %>%
group_by(mat, fj) %>%
arrange(desc(n)) %>%
slice(1:5) %>%
ungroup() %>%
arrange(fj,mat, n) %>% # arrange the entire table by the facets first, then by the n value
mutate(row.order = row_number()) %>% # create dummy variable
ggplot(aes(x = row.order, y = n)) + # plot by the dummy variable
geom_col(fill = RColorBrewer::brewer.pal(3, 'Dark2')[2], colour = "grey", alpha = 0.8, position = "dodge") +
labs(x = "Prod", y = "Qnt") +
scale_y_continuous(labels = scales::comma) +
scale_x_continuous( # add back in the Prod values
breaks = df2$row.order,
labels = df2$prod
)+
coord_flip() +
facet_wrap(fj ~ mat, scales = "free") +
theme_minimal()
I'm trying to rename faceted, ordered, x-axis tick marks in ggplot().
library(ggplot2)
library(dplyr)
set.seed(256)
myFun <- function(n = 5000) {
a <- do.call(paste0, replicate(5, sample(LETTERS, n, TRUE), FALSE))
paste0(a, sprintf("%04d", sample(9999, n, TRUE)), sample(LETTERS, n, TRUE))
}
n <- 15
dat <- data.frame(category = sample(letters[1:2], n, replace = T),
name = myFun(n),
perc = sample(seq(0, 1, by = 0.01), n, replace = TRUE))
to_plot <-
dat %>%
group_by(category) %>%
arrange(category, desc(perc)) %>%
top_n(5, perc)
Plotting this gets me
to_plot %>%
ggplot(aes(x = name, y = perc)) +
geom_bar(stat = "identity") +
facet_wrap(~category, scales = "free_y") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
which is unordered and not what I want at all, so I do some ordering by adding a "dummy" column of row_number()
to_plot %>%
mutate(row_number = row_number()) %>%
ungroup() %>%
mutate(row_number = row_number %>% as.factor()) %>%
ggplot(aes(x = row_number, y = perc)) +
geom_bar(stat = "identity") +
facet_wrap(~category, scales = "free_y") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
This gets me close, but I still need to change the names on the x-axis so I add:
scale_x_discrete(name = "name", labels = str_wrap(to_plot %>% pull(name), 3))
but this only repeats the first facet group across both facets, even though the data in each plot is correct
I've also tried just ordering everything sequentially and allowing both axes to be free in the facet_wrap() fx, but that doesn't seem to work either:
new_plot <-
dat %>%
group_by(category) %>%
arrange(category, desc(perc)) %>%
ungroup() %>%
mutate(row_number = row_number() %>% as.factor())
new_plot %>%
ggplot(aes(x = row_number, y = perc)) +
geom_bar(stat = "identity") +
scale_x_discrete(name = "name", labels = new_plot %>% pull(name)) +
facet_wrap(~category, scales = "free") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
How can I label the x-axis tick-marks in multiple facet_wrap() plots independently of one another? I feel like I'm missing something pretty basic here, but I can't figure out what it is.
to_plot %>%
ggplot(aes(x = name %>% forcats::fct_reorder(-perc), y = perc)) +
geom_bar(stat = "identity") +
facet_wrap(~category, scales = "free") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
I am working a making som nice plots that I can copy-paste when needed (that is why I have included so many options). So I have this plot:
library(tidyverse)
mtcars %>%
group_by(cyl) %>%
summarise(n=n()) %>%
ungroup() %>%
mutate(cars = "cars") %>%
ggplot(aes(x = as.factor(cars), y = n, fill=as.factor(cyl))) +
geom_bar(stat="identity", width = .3) +
geom_text(aes(label = paste0(round(n, digits = 0), "stk.")),
position = position_stack(vjust = 0.5)) +
labs(title = "Number of cars with cylinders in the data set",
subtitle= "If needed",
caption= "Fodnote",
x= "", y="Antal",
fill="# of cylinders") +
theme(#legend.position="none",
plot.caption = element_text(hjust = 0))
How can I reorder the stacks so e.g. the blue is at the bottom, then the red stack and the green stack on top.
Thanks. I think the solution involes forcats...
Is this what you're looking for? To change the fill color, use scale_fill_manual() or scale_fill_brewer()
library(tidyverse)
library(forcats)
mtcars %>%
group_by(cyl) %>%
summarise(n=n()) %>%
ungroup() %>%
mutate(cars = "cars",
cars = factor(cars),
cyl = factor(cyl)) %>%
# use fct_reorder here
mutate(cyl = fct_reorder(cyl, n)) %>%
ggplot(aes(x = cars, y = n, fill = cyl)) +
geom_col(width = .3) +
geom_text(aes(label = paste0(round(n, digits = 0), "stk.")),
position = position_stack(vjust = 0.5)) +
labs(title = "Number of cars with cylinders in the data set",
subtitle = "If needed",
caption = "Footnote",
x = "", y = "Antal",
fill = "# of cylinders") +
theme(#legend.position="none",
plot.caption = element_text(hjust = 0))
To define order, convert cyl to factor with desired levels.
df1 = mtcars
df1$cyl = factor(df1$cyl, levels = c(6, 4, 8))
df1 %>%
group_by(cyl) %>%
summarise(n=n()) %>%
ungroup() %>%
mutate(cars = "cars") %>%
ggplot(aes(x = as.factor(cars), y = n, fill=as.factor(cyl))) +
#scale_fill_manual(values=c("green", "red", "blue")) +
geom_bar(stat="identity", width = .3) +
geom_text(aes(label = paste0(round(n, digits = 0), "stk.")),
position = position_stack(vjust = 0.5)) +
labs(title = "Number of cars with cylinders in the data set",
subtitle= "If needed",
caption= "Fodnote",
x= "", y="Antal",
fill="# of cylinders") +
theme(#legend.position="none",
plot.caption = element_text(hjust = 0))