I'm trying to plot an area with two different set of points with ggplot2 but I get always two different legends. I've read this and this but I still have two legends.
Below the code and the chart.
Thank you very much
library(ggplot2)
library(dplyr)
set.seed(1)
df <- data.frame(x = letters,
y = 1:26 +runif(26),
z = 2*(1:26) + runif(26),
jj = 1:26,
hh = 1:26*2,
x1 = 1:26)
some_names <- df %>%
filter(row_number() %% 10 == 1) %>%
select(x,x1)
p <- df %>%
ggplot(aes(x1)) +
geom_ribbon(aes(ymin = y, ymax = z, fill = "area")) +
geom_point(aes(y = jj, colour = "points1")) +
geom_point(aes(y = hh, colour = "points2")) +
scale_x_continuous(breaks = some_names %>% select(x1) %>% unlist %>% unname,
labels = some_names %>% select(x) %>% unlist %>% unname )
p + scale_fill_manual(name = "legend",
values = c("area" = "red","points1" = NA,"points2" = NA)) +
scale_colour_manual(name = "legend",
values = c("area" = NA ,"points1" = "blue","points2" = "purple"))
You could do something in the veins of
library(tidyverse)
packageVersion("ggplot2")
# [1] ‘2.2.1’
df %>%
gather(var, val, jj, hh) %>%
ggplot(aes(x1, val, ymin=y, ymax=z, color=var, fill=var)) +
geom_ribbon(color=NA) +
geom_point() +
scale_color_manual(values=c("blue","purple"), name="leg", labels = c("lab1","lab2")) +
scale_fill_manual(values = rep("red", 2), name="leg", labels= c("lab1","lab2"))
or
library(tidyverse)
df %>%
gather(var, val, jj, hh) %>%
bind_rows(data.frame(x=NA,y=NA,z=NA,x1=NA,var="_dummy",val=NA)) %>%
ggplot(aes(x1, val, ymin=y, ymax=z, color=var, fill=var)) +
geom_ribbon(color=NA) +
geom_ribbon(color=NA, fill="red") +
geom_point() +
scale_color_manual(
values=c("#FFFFFF00", "blue","purple"), name="leg", labels = c("lab1","lab2","lab3")) +
scale_fill_manual(
values = c("red", rep(NA, 2)), name="leg", labels= c("lab1","lab2","lab3"))
One option is to use an interior fill for each element. There may be a way to use override.aes to get the points to be a point in the legend, but I wasn't able to get that with any quick experimentation.
p <- df %>%
ggplot(aes(x1)) +
geom_ribbon(aes(ymin = y, ymax = z, fill = "area")) +
geom_point(aes(y = jj, fill = "points1"), shape=21, colour="blue") +
geom_point(aes(y = hh, fill = "points2"), shape=21, colour="purple") +
scale_x_continuous(breaks = some_names %>% select(x1) %>% unlist %>% unname,
labels = some_names %>% select(x) %>% unlist %>% unname ) +
scale_fill_manual(name = "legend",
values = c("area" = "red","points1" = "blue","points2" = "purple"),
guide = guide_legend(override.aes=aes(colour=NA)))
p
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))
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 trying to create two plots which should display frequency in a decreasing order.
#preparing the data to resemble actual data
test <- data.frame(HairEyeColor) %>%
mutate(combi = paste(Hair,Eye)) %>%
group_by(Sex) %>%
mutate(prop = Freq / sum(Freq)) %>%
ungroup()
test$combi <- factor(test$combi)
freq_test_count <- test %>%
setorder(Freq)
#creating the plot
freq_test_plot <- freq_test_count %>%
ggplot(aes(x = reorder(combi,prop),y = prop, label = Freq)) +
geom_col(show.legend = FALSE) +
geom_text(check_overlap = TRUE, nudge_y = 0.005, size = 3) +
facet_wrap(~Sex, scales = "free") +
labs(y = "Proportion",
x = NULL) +
coord_flip()
When i plot freq_test_plot, it shows the plot but the output is not in decreasing order
I am not sure what should I do so that I can see terms in decreasing order of frequency.
A workaround is to create two different plots and arrange them in grid. But you should be cautious because, like Gregor mentioned, it could definitely be misleading.
library(grid)
p1 = freq_test_count[freq_test_count$Sex == "Male",] %>%
ggplot(aes(x = reorder(combi,prop),y = prop, label = Freq)) +
geom_col(show.legend = FALSE) +
geom_text(check_overlap = TRUE, nudge_y = 0.005, size = 3) +
facet_wrap(~Sex, scales = "free") +
labs(y = "Proportion",
x = NULL) +
coord_flip()
p2 = freq_test_count[freq_test_count$Sex == "Female",] %>%
ggplot(aes(x = reorder(combi,prop),y = prop, label = Freq)) +
geom_col(show.legend = FALSE) +
geom_text(check_overlap = TRUE, nudge_y = 0.005, size = 3) +
facet_wrap(~Sex, scales = "free") +
labs(y = "Proportion",
x = NULL) +
coord_flip()
graphics.off()
grid.newpage()
grid.draw(ggarrange(p1, p2, ncol = 2))
Another work-around is to make male and female specific levels for the factor. Here I add a space " " to the front of the Male Hair/Eye labels. This lets you define an ordering that takes sex into account:
test <- data.frame(HairEyeColor) %>%
mutate(combi = paste(Hair,Eye)) %>%
group_by(Sex) %>%
mutate(prop = Freq / sum(Freq)) %>%
ungroup() %>%
mutate(combi = factor(test$combi),
sex_combi = factor(paste(ifelse(Sex == "Male", " ", ""), Hair, Eye)),
sex_combi = reorder(sex_combi, prop))
#creating the plot
ggplot(test, aes(x = sex_combi,y = prop, label = Freq)) +
geom_col(show.legend = FALSE) +
geom_text(check_overlap = TRUE, nudge_y = 0.005, size = 3) +
facet_wrap(~Sex, scales = "free") +
labs(y = "Proportion",
x = NULL) +
coord_flip()
But as I mentioned in the comments, I think this is a misleading plot.
Are you wanting the values to be sorted on male or female?
library(tidyverse)
#preparing the data to resemble actual data
test <- data.frame(HairEyeColor) %>%
mutate(combi = paste(Hair,Eye)) %>%
group_by(Sex) %>%
mutate(prop = Freq / sum(Freq)) %>%
ungroup()
test$combi <- factor(test$combi)
test$combi<- factor(test$combi, levels = unique(test$combi)[order(test$Freq)],)
#creating the plot
ggplot(test,aes(x = combi,y = prop, label = Freq))+
geom_col(show.legend = FALSE)+
geom_text(check_overlap = TRUE, nudge_y = 0.005, size = 3) +
facet_wrap(~Sex, scales = "free")+
labs(y = "Proportion",
x = NULL) +
coord_flip()
updated to include full code from question.
I have a plot i wish to add another layer to
Th plot is below. I want to overlay another polar plot on it to see that the numbers "match up"
In the example below I have create the plot for one species of the iris dataset. I would like to overlay another plot of a different species
Thank you for your time
library(ggplot2)
library(dplyr)
mydf <- iris
plot.data <- tidyr::gather(mydf,key = attribute ,value = avg_score, Sepal.Length:Petal.Width)
plot.data <- plot.data %>%
filter(Species == 'setosa') %>%
group_by(attribute) %>%
summarise(attr_mean = mean(avg_score))
ggplot(plot.data, aes(x=attribute, y = attr_mean, col = attribute)) +
geom_bar(stat = "identity", fill = 'white') +
coord_polar(theta = "x") +
theme_bw()
This is quite the pedestrian way of doing things.
plot.setosa <- plot.data %>%
filter(Species == 'setosa') %>%
group_by(attribute) %>%
summarise(attr_mean = mean(avg_score))
plot.virginica <- plot.data %>%
filter(Species == 'virginica') %>%
group_by(attribute) %>%
summarise(attr_mean = mean(avg_score))
ggplot(plot.setosa, aes(x=attribute, y = attr_mean, col = attribute)) +
geom_bar(stat = "identity", fill = 'blue', alpha = 0.25) +
geom_bar(data = plot.virginica, stat = "identity", fill= "green", alpha = 0.25,
aes(x = attribute, y = attr_mean, col = attribute)) +
coord_polar(theta = "x") +
theme_bw()
And a slightly less pedestrian.
xy <- plot.data %>%
group_by(Species, attribute) %>%
summarise(attr_mean = mean(avg_score))
ggplot(xy, aes(x = attribute, y = attr_mean, color = attribute, fill = Species)) +
theme_bw() +
geom_bar(stat = "identity", alpha = 0.25) +
coord_polar(theta = "x")