I'm looking to make a radar plot for multivariate data, a task simple enough for excel.
The problem comes when I would like to also plot some error bars on this. From what I understand, I cannot do this in excel. Is this possible on R?
Or can someone suggest an alternative? I have 32 single value dimensions.
Thanks!
I don't much like radar charts but here are some ideas to get you going, drawing on this approach. I like the look of my option 1 best, but I'm not sure how to solve the gap between var32 and var1 (I have some ideas, but a bit awkward).
library(tidyverse)
library(ggplot2)
library(scales)
# make some mock data
mydata <- data.frame(variable = paste0("Var", 1:32),
midpoint = rnorm(32),
stderr = rnorm(32, 1, 0.1),
stringsAsFactors = FALSE) %>%
mutate(upper = midpoint + 1.96 * stderr,
lower = midpoint - 1.96 * stderr) %>%
mutate(variable = factor(variable, levels = variable))
# Option 1:
mydata %>%
ggplot(aes(x = variable, y = midpoint, group = 1)) +
geom_ribbon(aes(ymin = lower, ymax = upper), fill = "grey50", alpha = 0.5) +
geom_line(colour = "purple") +
theme_light() +
theme(panel.grid.minor = element_blank()) +
coord_polar() +
labs(x = "", y = "")
# Option 2:
mydata %>%
gather(measure, value, -variable, -stderr) %>%
ggplot(aes(x = variable, y = value, colour = measure, group = measure, linetype = measure)) +
geom_polygon(fill = NA) +
theme_light() +
theme(panel.grid.minor = element_blank()) +
coord_polar() +
scale_colour_manual(values = c("steelblue", "black", "steelblue")) +
scale_linetype_manual(values = c(2,1,2)) +
labs(x = "", y = "")
# Option 3:
mydata %>%
ggplot(aes(x = variable, y = midpoint, group = 1)) +
geom_polygon(fill = NA, colour = "purple") +
geom_segment(aes(xend = variable, y = lower, yend = upper), colour = "grey50") +
geom_point(colour = "purple") +
theme_light() +
theme(panel.grid.minor = element_blank()) +
theme(panel.grid.major.x = element_blank()) +
coord_polar() +
labs(x = "", y = "")
Edit / addition
I think I prefer this one:
# Option 4:
mydata %>%
ggplot(aes(x = variable, y = midpoint, group = 1)) +
geom_polygon(aes(y = upper), fill = "grey50", alpha = 0.5) +
geom_polygon(aes(y = lower), fill = "grey99", alpha = 0.7) +
geom_polygon(fill = NA, colour = "purple") +
theme_light() +
theme(panel.grid.minor = element_blank()) +
coord_polar() +
labs(x = "", y = "")
Related
using the data set airquality I have written the following code:
library("tidyverse")
data(airquality)
airquality <- na.omit(airquality)
airquality$date <- as.Date(paste("1973", airquality$Month, airquality$Day,
sep="-"))
p1 <- ggplot(airquality, aes(x= date, y = Ozone, col=factor(Month))) +
geom_point() +
geom_line()
p1
Now I would like to plot in the same graph the mean of ozone for each months. How can I do this?
You could add the mean as a dashed line. The easiest way to do this might be to simply pass the data you want to a geom_line layer:
ggplot(airquality, aes(x = date, y = Ozone, col = factor(Month))) +
geom_point() +
geom_line(alpha = 0.5) +
geom_line(data = airquality %>%
group_by(Month) %>%
summarise(Ozone = mean(Ozone),
date = c(first(date), last(date)),
Month = mean(Month)),
linetype = 2, size = 1) +
scale_color_brewer(palette = "Set1") +
theme_minimal(base_size = 16)
If you just want points showing the mean, you could simplify things with stat_mean from ggpubr
ggplot(airquality, aes(x = date, y = Ozone, col = factor(Month))) +
geom_point() +
geom_line(alpha = 0.5) +
ggpubr::stat_mean(size = 5, shape = 21,
aes(fill = factor(Month)), color = "black") +
scale_color_brewer(palette = "Set1") +
scale_fill_brewer(palette = "Set1") +
theme_minimal(base_size = 16)
To join these dots up, you could do:
ggplot(airquality, aes(x = date, y = Ozone, col = factor(Month))) +
geom_point() +
geom_line(alpha = 0.5) +
geom_line(data = airquality %>%
group_by(Month) %>%
summarise(Ozone = mean(Ozone), date = mean(date)),
color = "black", linetype = 2) +
ggpubr::stat_mean(size = 5, shape = 21,
aes(fill = factor(Month)), color = "black") +
scale_color_brewer(palette = "Set1") +
scale_fill_brewer(palette = "Set1") +
theme_minimal(base_size = 16)
In order to make a dynamic visualization, for example in a dashboard, I want to display the label colors (percentages or totals) depending on their real values in black or white.
As you can see from my reprex below, I changed the color of the label with the highest percentage manually to black, in order gain a better visability.
Is there a was, to automatically implement the label color? The label with the highest percentage corresponding should always be black, if data is changing over time.
library(ggplot2)
library(dplyr)
set.seed(3)
reviews <- data.frame(review_star = as.character(sample.int(5,400, replace = TRUE)),
stars = 1)
df <- reviews %>%
group_by(review_star) %>%
count() %>%
ungroup() %>%
mutate(perc = `n` / sum(`n`)) %>%
arrange(perc) %>%
mutate(labels = scales::percent(perc))
ggplot(df, aes(x = "", y = perc, fill = review_star)) +
geom_col(color = "black") +
geom_label(aes(label = labels), color = c( "white", "white","white",1,"white"),
position = position_stack(vjust = 0.5),
show.legend = FALSE) +
guides(fill = guide_legend(title = "Answer")) +
scale_fill_viridis_d() +
coord_polar(theta = "y") +
theme_void()
you can set the colors using replace(rep('white', nrow(df)), which.max(df$perc), 'black').
ggplot(df, aes(x = "", y = perc, fill = review_star)) +
geom_col(color = "black") +
geom_label(aes(label = labels),
color = replace(rep('white', nrow(df)), which.max(df$perc), 'black'),
position = position_stack(vjust = 0.5),
show.legend = FALSE) +
guides(fill = guide_legend(title = "Answer")) +
scale_fill_viridis_d() +
coord_polar(theta = "y") +
theme_void()
This question already has answers here:
Change stacked bar order when aesthetic fill is based on the interaction of two factors
(1 answer)
ggplot legends - change labels, order and title
(1 answer)
Closed 2 years ago.
Currently, I have a plot that looks like this:
library(ggplot2)
df <- ToothGrowth
df %>%
ggplot(aes(x = supp, y = len, fill = supp)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0),
alpha = .8) +
geom_point(aes(shape = supp),
position = position_jitter(width = .05),
size = 2, alpha = 0.8) +
geom_boxplot(width = .1, outlier.shape = NA, alpha = 0.5) +
coord_flip() +
labs(title = "ToothGrowth Length by Supplement",
y = "Length") +
theme_classic() +
raincloud_theme
I'd like to change the order so that OJ appears above VC. I've tried adding scale_x_discrete before coord_flip(), but that seems to mess up my plot as this is a raincloud plot -- I'd have to move not only the violin plot, but also the points and the box plot. I've also tried adding rev(), which also messed up my plot. What is the best way to reorder this?
EDIT
Thank you for the comment! How do I change the orders in an interaction plot?
df %>%
mutate(Supplement = ifelse(supp == "VC",
"VC",
"OJ"),
Dose = ifelse(dose == "0.5",
"0.5",
"1.0"),
Interaction = factor(str_replace(interaction(Supplement, Dose),
'\\.', '\n'),
ordered=TRUE)) %>%
ggplot(aes(x = Interaction, y = len, fill = Interaction)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0),
alpha = .8) +
geom_point(aes(shape = Dose),
position = position_jitter(width = .05),
size = 2, alpha = 0.8) +
geom_boxplot(width = .1, outlier.shape = NA, alpha = 0.5) +
coord_flip() +
labs(title = "Effect of Supplement and Dose on Length",
y = "Growth Length") +
scale_fill_discrete(guide = guide_legend(override.aes = list(shape = c(".", ".")))) +
scale_shape_discrete(guide = guide_legend(override.aes = list(size = 3))) +
theme_classic() +
raincloud_theme
ggplot2 will interpret the supp factor and the order in the plot correspond to the levels of the factor.
You will need to change the levels of the supp factor.
df <- ToothGrowth
df$supp
df$supp <- relevel(ToothGrowth$supp,ref = "VC")
df$supp
df %>%
ggplot(aes(x = supp, y = len, fill = supp)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0),
alpha = .8) +
geom_point(aes(shape = supp),
position = position_jitter(width = .05),
size = 2, alpha = 0.8) +
geom_boxplot(width = .1, outlier.shape = NA, alpha = 0.5) +
coord_flip() +
labs(title = "ToothGrowth Length by Supplement",
y = "Length") +
theme_classic() +
raincloud_theme
I would like to colour the dashed lines, which are the average values of the two respective categories, with the same colour of the default palette used by ggplot to fill the distributions:
Click here to view the distribution
This is the code used:
library(ggplot2)
print(ggplot(dati, aes(x=ECU_fuel_consumption_L_100Km_CF, fill=Model))
+ ggtitle("Fuel Consumption density histogram, by Model")
+ ylab("Density")
+ geom_density(alpha=.3)
+ scale_x_continuous(breaks=pretty(dati$ECU_fuel_consumption_L_100Km_CF, n=10))
+ geom_vline(aes(xintercept = mean(ECU_fuel_consumption_L_100Km_CF[dati$Model == "500X"])), linetype="dashed", size=1)
+ geom_vline(aes(xintercept = mean(ECU_fuel_consumption_L_100Km_CF[dati$Model == "Renegade"])), linetype="dashed", size=1)
)
Thank you all in advance!
No reproducible example, but you probably want to do something like this:
library(dplyr)
# make up some data
d <- data.frame(x = c(mtcars$mpg, mtcars$hp),
var = rep(c('mpg', 'hp'), each = nrow(mtcars)))
means <- d %>% group_by(var) %>% summarize(m = mean(x))
ggplot(d, aes(x, fill = var)) +
geom_density(alpha = 0.3) +
geom_vline(data = means, aes(xintercept = m, col = var),
linetype = "dashed", size = 1)
This approach is extendable to any number of groups.
An option that doesn't require pre-calculation, but is also a bit more hacky, is:
ggplot(d, aes(x, fill = var)) +
geom_density(alpha = 0.3) +
geom_vline(aes(col = 'hp', xintercept = x), linetype = "dashed", size = 1,
data = data.frame(x = mean(d$x[d$var == 'hp']))) +
geom_vline(aes(col = 'mpg', xintercept = x), linetype = "dashed", size = 1,
data = data.frame(x = mean(d$x[d$var == 'mpg'])))
I'm plotting a stacked bar graph and use geom_text to insert the value and name of each stack. The problem is some stacks are very small/narrow, so that the text of two stacks overlap each other and hence is not very readable. How can I modify the code to solve this issue.
Type<-c("ddddddddddd","ddddddddddd","bbbbbbbbbbbbb","ddddddddddd","eeeeeeeeeeeeee","bbbbbbbbbbbbb","ddddddddddd","bbbbbbbbbbbbb","ddddddddddd",
"eeeeeeeeeeeeee","mmmmmmmmmmmmmmmmmmm","bbbbbbbbbbbbb","ddddddddddd","bbbbbbbbbbbbb","eeeeeeeeeeeeee")
Category<-c("mmmmm","mmmmm","gggggggggggggggggg","ffffffffffff","ffffffffffff","ffffffffffff","sanddddddddd","sanddddddddd","yyyyyyyyyyy",
"yyyyyyyyyyy","yyyyyyyyyyy","sssssssssssssss","sssssssssssssss","sssssssssssssss","ttttttttttttt")
Frequency<-c(4,1,30,7,127,11,1,1,6,9,1,200,3,4,5)
Data <- data.frame(Type, Category, Frequency)
p <- ggplot(Data, aes(x = Type, y = Frequency)) +
geom_bar(aes(fill = Category), stat="identity", show.legend = FALSE) +
geom_text(aes(label = Frequency), size = 3) +
geom_text(aes(label = Category), size = 3)
Considering your data, a facetted plot might be a better approach:
# summarise your data
library(dplyr)
d1 <- Data %>%
mutate_each(funs(substr(.,1,2)),Type,Category) %>%
group_by(Type,Category) %>%
summarise(Freq = sum(Frequency)) %>%
mutate(lbl = paste(Category,Freq)) # create a label by pasting the 'Category' and the 'Freq' variables together
# plot
ggplot(d1, aes(x = Category, y = Freq, fill = Category)) +
geom_bar(stat="identity", width = 0.7, position = position_dodge(0.8)) +
geom_text(aes(label = lbl), angle = 90, size = 5, hjust = -0.1, position = position_dodge(0.8)) +
scale_y_continuous(limits = c(0,240)) +
guides(fill = FALSE) +
facet_grid(.~Type, scales = "free", space = "free") +
theme_bw(base_size = 14)
which gives:
In the above plot I shortened the labels on purpose. If you don't want to do that, you could consider this:
d2 <- Data %>%
group_by(Type,Category) %>%
summarise(Freq = sum(Frequency)) %>%
mutate(lbl = paste(Category,Freq))
ggplot(d2, aes(x = Category, y = Freq, fill = Category)) +
geom_bar(stat="identity", width = 0.7, position = position_dodge(0.8)) +
geom_text(aes(y = 5, label = lbl), alpha = 0.6, angle = 90, size = 5, hjust = 0, position = position_dodge(0.8)) +
scale_y_continuous(limits = c(0,240)) +
guides(fill = FALSE) +
facet_grid(.~Type, scales = "free", space = "free") +
theme_bw(base_size = 14) +
theme(axis.text.x = element_blank(),
axis.ticks.x = element_blank())
which gives: