naming facets in facet_wrap - r

I am having issues trying to name a set of plots created with the facet_wrap feature. I am specifically trying to wrap the titles onto multiple lines. I have looked into this issue extensively within stack overflow and cannot find the error that I am generating. The code is below. a2$variable is a column of character strings (for grouping purposes), a2$ma_3 and a2$ma_12 are moving averages that I am trying to plot. The error that is generated is:
Error in as.integer(n) :
cannot coerce type 'closure' to vector of type 'integer'
p1=a2 %>%
ggplot(aes(x = date, color = variable)) +
geom_line(aes(y = ma_12), color = "aquamarine3", alpha = 0.5,size=.7) +
geom_line(aes(y = ma_3), color = "gray40", alpha = 0.5,size=.7) +
facet_wrap(~ variable, ncol = 3, scale = "free_y",label_wrap_gen(width=10))
Thanks in advance.

You're close. To modify the facet_wrap labels, we use the labeller argument:
library(tibble)
library(ggplot2)
mtcars %>%
rownames_to_column() %>%
head() %>%
ggplot(aes(x = mpg, color = cly)) +
geom_point(aes(y = wt), color = "aquamarine3", alpha = 0.5,size=5) +
geom_point(aes(y = qsec), color = "gray40", alpha = 0.5,size=5) +
facet_wrap(~ rowname, ncol = 3, scale = "free_y",
labeller = label_wrap_gen(width = 10))
Output:

I'd suggest formatting the variable before you send it to ggplot, like this:
library(tidyverse)
mtcars %>%
rownames_to_column() %>%
head() %>%
mutate(carname = stringr::str_wrap(rowname, 10)) %>%
ggplot(aes(x = mpg, color = cly)) +
geom_point(aes(y = wt), color = "aquamarine3", alpha = 0.5,size=5) +
geom_point(aes(y = qsec), color = "gray40", alpha = 0.5,size=5) +
facet_wrap(~ carname, ncol = 3, scale = "free_y")

Related

How to have sum of values sum to 1 in geom_freqpoly()?

As an example, we can use geom_freqpoly() to examine how hp varies by cyl in the mtcars data.
library(tidyverse)
mtcars %>%
mutate(cyl = as.factor(cyl)) %>%
ggplot() +
aes(x=hp, color=cyl) +
geom_freqpoly(mapping = aes(y = after_stat(ncount)), bins=5)
Using after_stat(ncount), I can make each line be normalized between 0 and 1. However, is there a way to have it so that the sum of all the lines at any point is equal to 1? i.e., at any value of hp, the red, green, and blue lines add to one -- representing the estimated proportion of each cyl type at that value of hp.
This can be achieved with position = "fill", though it looks confusing with lines and is better represented as a filled geom using the same statistical transformation as geom_freqpoly
library(tidyverse)
mtcars %>%
mutate(cyl = as.factor(cyl)) %>%
ggplot() +
aes(x = hp, fill =c yl) +
stat_bin(bins = 5, position = "fill", geom = "area")
Compare this to the same result using an unfilled geom_freqpoly
mtcars %>%
mutate(cyl = as.factor(cyl)) %>%
ggplot() +
aes(x = hp, color = cyl) +
geom_freqpoly(position = "fill", bins = 5)
I think this is harder to follow.
Another alternative to geom_freqpoly would be geom_density, which permits more visually appealing representations of similar information:
mtcars %>%
mutate(cyl = as.factor(cyl)) %>%
ggplot() +
aes(x = hp, fill = cyl) +
geom_density(position = "fill", alpha = 0.5, color = "white", lwd = 2) +
coord_cartesian(xlim = c(50, 200)) +
scale_fill_brewer(palette = "Set2") +
theme_minimal(base_size = 20) +
labs(y = "Relative density")
Created on 2022-09-05 with reprex v2.0.2

How to create scaled and faceted clustered bargraphs of a summarized dataframe in ggplot2?

I am trying to create a grid of bargraphs that show the average for different species. I am using the iris dataset for this question.
I summarised the data, melted it into long form long, and tried to use facet_wrap.
iris %>%
group_by(Species) %>%
summarise(M.Sepal.Length=mean(Sepal.Length),
M.Sepal.Width=mean(Sepal.Width),
M.Petal.Length= mean(Petal.Length),
M.Petal.Width=mean(Petal.Width)) %>%
gather(key = Part, value = Value, M.Sepal.Length:M.Petal.Width) %>%
ggplot(., aes(Part, Value, group = Species, fill=Species)) +
geom_col(position = "dodge") +
facet_grid(cols=vars(Part)) +
facet_grid(cols = vars(Part))
However, the graph I am getting has x.axis labels that are strung across each facet grid. Additionally the clustered graphs are not centered within each facet box. Instead they appear at the location of their respective x-axis label. I'd like to get rid of the x-axis labels, center the graphs, and scale the graphs within each facet.
Here is an image of the resulting graph marked up with my expected output:
Perhaps this is what you're looking for?
The key changes are:
Remove Part as the variable mapped to x, that way the data is plotted in the same location in every facet
Switch to facet_wrap so you can use scales = "free_y"
Use labs to manually add the x title
Add theme to get rid of the x-axis ticks and tick labels.
library(ggplot2)
library(dplyr) # Version >= 1.0.0
iris %>%
group_by(Species) %>%
summarise(across(1:4, mean, .names = "M.{col}")) %>%
gather(key = Part, value = Value, M.Sepal.Length:M.Petal.Width) %>%
ggplot(., aes(x = 1, y = Value, group = Species, fill=Species)) +
geom_col(position = "dodge") +
facet_wrap(.~Part, nrow = 1, scales = "free_y") +
labs(x = "Part") +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank())
I also took the liberty of switching out your manual call to summarise with the new across functionality.
Here's how you might also calculate error bars:
library(tidyr)
iris %>%
group_by(Species) %>%
summarise(across(1:4, list(M = mean, SE = ~ sd(.)/sqrt(length(.))),
.names = "{fn}_{col}")) %>%
pivot_longer(-Species, names_to = c(".value","Part"),
names_pattern = "([SEM]+)_(.+)") %>%
ggplot(., aes(x = 1, y = M, group = Species, fill=Species)) +
geom_col(position = "dodge") +
geom_errorbar(aes(ymin = M - SE, ymax = M + SE), width = 0.5,
position = position_dodge(0.9)) +
facet_wrap(.~Part, nrow = 1, scales = "free_y") +
labs(x = "Part", y = "Value") +
theme(axis.ticks.x = element_blank(),
axis.text.x = element_blank())

How to plot an area figure for a category variable

Here are two reproducible minimal examples for my request.
In the first one, the x variable is a factor variable, I find the function geom_area does not work, works like a geom_segment output.
In the second one, I transfer the x variable from factor into interger, the function geom_area works but I find the axis.text.y labels are not what I want.
Anyone know fix it?
suppressMessages(library(tidyverse))
mtcars %>%
rownames_to_column('index1') %>%
mutate(index1 = index1 %>% as.factor) %>%
mutate(index2 = index1 %>% as.integer) -> df
df %>%
ggplot() +
geom_area(aes(x = index1, y = mpg), color = 'black', fill = 'black') +
coord_flip()
df %>%
ggplot() +
geom_area(aes(x = index2, y = mpg), color = 'black', fill = 'black') +
coord_flip()
Check this solution:
library(tidyverse)
library(wrapr)
df %.>%
ggplot(data = .) +
geom_area(aes(x = index2, y = mpg), color = 'black', fill = 'black') +
coord_flip() +
scale_x_continuous(
breaks = .$index2,
labels = .$index1
)

ggplot2 add sum to chart

Using mtcars as an example, I've produced some violin plots. I wanted to add two things to this chart:
for each group, list n
for each group, sum a third variable (e.g. wt)
I can do (1) with the geom_text code below although (n) is actually plotted on the x axis rather than off to the side.
But I can't work out how to do (2).
Any help much appreciated!
library(ggplot2)
library(gridExtra)
library(ggthemes)
result <- mtcars
ggplot(result, aes(x = gear, y = drat, , group=gear)) +
theme_tufte(base_size = 15) + theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(stat = "count", aes(label = ..count.., y = ..count..))
You can add both of these annotations by creating them in your dataframe temporarily prior to graphing. Using the dplyr package, you can create two new columns, one with the count for each group, and one with the sum of wt for each group. This can then be piped directly into your ggplot using %>% (alternatively, you could save the new dataset and insert it into ggplot the way you have it). Then with some minor edits to your geom_text call and adding a second one, we can create the plot you want. The code looks like this:
library(ggplot2)
library(gridExtra)
library(ggthemes)
library(magrittr)
library(dplyr)
result <- mtcars
result %>%
group_by(gear) %>%
mutate(count = n(), sum_wt = sum(wt)) %>%
ggplot(aes(x = gear, y = drat, , group=gear)) +
theme_tufte(base_size = 15) + theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(aes(label = paste0("n = ", count),
x = (gear + 0.25),
y = 4.75)) +
geom_text(aes(label = paste0("sum wt = ", sum_wt),
x = (gear - 0.25),
y = 4.75))
The new graph looks like this:
Alternatively, if you create a summary data frame named result_sum, then you can manually add that into the geom_text calls.
result <- mtcars %>%
mutate(gear = factor(as.character(gear)))
result_sum <- result %>%
group_by(gear) %>%
summarise(count = n(), sum_wt = sum(wt))
ggplot(result, aes(x = gear, y = drat, , group=gear)) +
theme_tufte(base_size = 15) +
theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(data = result_sum, aes(label = paste0("n = ", count),
x = (as.numeric(gear) + 0.25),
y = 4.75)) +
geom_text(data = result_sum, aes(label = paste0("sum wt = ", sum_wt),
x = (as.numeric(gear) - 0.25),
y = 4.75))
This gives you this:
The benefit to this second method is that the text isn't bold like in the first graph. The bold effect occurs in the first graph due to the text being printed over itself for all observations in the dataframe.
Thanks to those who helped.... I used this in the end which plots the calculated values, one set of classes being text based so using vjust to position the vertical offset.
thanks again!
library(ggplot2)
library(gridExtra)
library(ggthemes)
results <- mtcars
results$gear <- as.factor(as.character(results$gear)) #Turn 'gear' to text to simulate classes, then factorise
result_sum <- results %>%
group_by(gear) %>%
summarise(count = n(), sum_wt = sum(wt))
ggplot(results, aes(x = gear, y = drat, group=gear)) +
theme_tufte(base_size = 15) + theme(line=element_blank()) +
geom_violin(fill = "white") +
geom_boxplot(fill = "black", alpha = 0.3, width = 0.1) +
ylab("drat") +
xlab("gear") +
coord_flip()+
geom_text(data = result_sum, aes(label = paste0("n = ", count), x = (gear), vjust= 0, y = 5.25)) +
geom_text(data = result_sum, aes(label = paste0("sum wt = ", round(sum_wt,0)), x = (gear), vjust= -2, y = 5.25))

Maintaining a scale of a histogram when using ..ncount

Using the code below, I'm generating a set of simple histogram:
data(mtcars); Vectorize(require)(package = c("ggplot2", "ggthemes", "dplyr"))
mtcars %>%
add_rownames(var = "model") %>%
gather(var, value, -model, -am) %>%
filter(var %in% c("hp")) %>%
# Define chart
ggplot(aes(value)) +
geom_histogram(aes(y = ..ncount..), colour = "black", fill = "gray58",
binwidth = 15) +
geom_density(aes(y = ..scaled..), colour = "red") +
facet_wrap( ~am, ncol = 3, scales = "free")
I would like to maintain scale that is produced when generating a histogram without the ..ncount.. special variable, as in the example:
mtcars %>%
add_rownames(var = "model") %>%
gather(var, value, -model, -am) %>%
filter(var %in% c("hp")) %>%
# Define chart
ggplot(aes(value)) +
geom_histogram(colour = "black", fill = "gray58",
binwidth = 15) +
geom_density(aes(y = ..scaled..), colour = "red") +
facet_wrap( ~am, ncol = 3, scales = "free")
But it makes the geom_density look poor.
Task
So what I want boils down to:
keep scale of y axis from the second one
keep graphics from the first one

Resources