I am trying to plot a stacked barplot using ggplot2::geom_bar with backgroud shading (using ggplot2::geom_rect()) according to a categorical variable as follows:
shading <- data.frame(min = seq(from = 0.5, to = max(as.numeric(as.factor(diamonds$clarity))), by = 1),
max = seq(from = 1.5, to = max(as.numeric(as.factor(diamonds$clarity))) + 0.5, by = 1),
col = c(0,1))
ggplot() +
theme(panel.background = element_rect(fill = "transparent")) +
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
geom_rect(data = shading,
aes(xmin = min, xmax = max, ymin = -Inf, ymax = Inf,
fill = factor(col), alpha = 0.1)) +
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
guides(alpha = FALSE)
How to change the colours of the shading?
I have tried scale_fill_manual(values = c("white", "gray53")), but it seems that multiple scale aesthetics are not possible in ggplot2 (https://github.com/hadley/ggplot2/issues/578). Is there another way to get the desired result ?
Yes, instead of putting your colours in the aes(), put them outside (so they are used as-is). Since it's outside the aes() call you will have to use an explicit fill=shading$col rather than fill=col, and shading$col should have the colour name you are after (rather than a variable interpreted as a factor).
shading$col <- ifelse(shading$col, 'white', 'gray53')
ggplot() +
theme(panel.background = element_rect(fill = "transparent")) +
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
geom_rect(data = shading,
aes(xmin = min, xmax = max, ymin = -Inf, ymax = Inf, alpha = 0.1),
fill=shading$col) + # <-- here
geom_bar(data = diamonds, mapping = aes(clarity, fill=cut)) +
guides(alpha = FALSE)
Related
I created the following plot using ggplot:
y1 <- runif(20,-2,7)
y2 <- c(-0.30306664,0.14744265 , 0.43857131 ,-0.04536794 ,-1.41432016,0.51887010 , 6.34925495 , 2.82511601 , 2.84251791, 4.05300569,-2.34208042, -0.29278747 , 0.49661933 , 0.75099908 ,1.12097713,2.72244949 , 2.23933230 , 1.86667714 , 2.17540024 , 7.56568823)
x <- 2001:2020
ggplot() +
geom_rect(aes(xmin=2006.90, xmax=2009.15,ymin=-Inf,ymax=10, fill='blue'), alpha= 0.4)+geom_rect(aes(xmin=2019.80, xmax=Inf,ymin=-Inf,ymax=10, fill='orange'), alpha= 0.3)+geom_rect(aes(xmin=2009.90, xmax=2013.15,ymin=-Inf,ymax=10, fill="lightgreen"), alpha= 0.4)+
geom_line(aes(x=x,y = y1),colour="black")+geom_line(aes(x=x,y = y2),colour="red")+
geom_point(aes(x=x,y = y1),col="black")+
geom_point(aes(x=x,y = y2),col="red")+
theme_classic()+
scale_fill_manual(name="",values = c("lightblue","lightgreen","orange"),labels=c(" R","k","C"))+theme(legend.position = "bottom")+ theme(axis.text.x = element_text(angle = 90))+geom_hline(yintercept = 0, color="black", size=1)
I have one legend to explain the content of the rectangles of the graph, but I need to add another legend to explain the two lines which are black and red. I wondered how to add another legend with a different position than the one that already exists to explain the names of the lines?
Can anyone help?
Move color inside aes, add scale_color_identity to get the right colors and to set the labels for the legend:
library(ggplot2)
ggplot() +
geom_rect(aes(xmin = 2006.90, xmax = 2009.15, ymin = -Inf, ymax = 10, fill = "blue"), alpha = 0.4) +
geom_rect(aes(xmin = 2019.80, xmax = Inf, ymin = -Inf, ymax = 10, fill = "orange"), alpha = 0.3) +
geom_rect(aes(xmin = 2009.90, xmax = 2013.15, ymin = -Inf, ymax = 10, fill = "lightgreen"), alpha = 0.4) +
geom_line(aes(x = x, y = y1, colour = "black")) +
geom_line(aes(x = x, y = y2, colour = "red")) +
geom_point(aes(x = x, y = y1, col = "black")) +
geom_point(aes(x = x, y = y2, col = "red")) +
scale_color_identity(name = NULL, labels = c(black = "Label 1", red = "Label 2"), guide = "legend") +
theme_classic() +
scale_fill_manual(name = "", values = c("lightblue", "lightgreen", "orange"), labels = c(" Rezession", "krise", "Corona 2020-")) +
theme(legend.position = "bottom") +
theme(axis.text.x = element_text(angle = 90)) +
geom_hline(yintercept = 0, color = "black", size = 1)
I would like to create a raincloud plot. I have successfully done it. But I would like to know if instead of the density curve, I can put a histogram (it's better for my dataset).
This is my code if it can be usefull
ATSC <- ggplot(data = data, aes(y = atsc, x = numlecteur, fill = numlecteur)) +
geom_flat_violin(position = position_nudge(x = .2, y = 0), alpha = .5) +
geom_point(aes(y = atsc, color = numlecteur), position = position_jitter(width = .15), size = .5, alpha = 0.8) +
geom_point(data = sumld, aes(x = numlecteur, y = mean), position = position_nudge(x = 0.25), size = 2.5) +
geom_errorbar(data = sumld, aes(ymin = lower, ymax = upper, y = mean), position = position_nudge(x = 0.25), width = 0) +
guides(fill = FALSE) +
guides(color = FALSE) +
scale_color_brewer(palette = "Spectral") +
scale_y_continuous(breaks=c(0,2,4,6,8,10), labels=c("0","2","4","6","8","10"))+
scale_fill_brewer(palette = "Spectral") +
coord_flip() +
theme_bw() +
expand_limits(y=c(0, 10))+
xlab("Lecteur") + ylab("Age total sans check")+
raincloud_theme
I think we can maybe put the "geom_histogram()" but it doesn't work
Thank you in advance for your help !
(sources : https://peerj.com/preprints/27137v1.pdf
https://neuroconscience.wordpress.com/2018/03/15/introducing-raincloud-plots/)
This is actually not quite easy. There are a few challenges.
geom_histogram is "horizontal by nature", and the custom geom_flat_violin is vertical - as are boxplots. Therefore the final call to coord_flip in that tutorial. In order to combine both, I think best is switch x and y, forget about coord_flip, and use ggstance::geom_boxploth instead.
Creating separate histograms for each category is another challenge. My workaround to create facets and "merge them together".
The histograms are scaled way bigger than the width of the points/boxplots. My workaround scale via after_stat function.
How to nudge the histograms to the right position above Boxplot and points - I am converting the discrete scale to a continuous by mapping a constant numeric to the global y aesthetic, and then using the facet labels for discrete labels.
library(tidyverse)
my_data<-read.csv("https://data.bris.ac.uk/datasets/112g2vkxomjoo1l26vjmvnlexj/2016.08.14_AnxietyPaper_Data%20Sheet.csv")
my_datal <-
my_data %>%
pivot_longer(cols = c("AngerUH", "DisgustUH", "FearUH", "HappyUH"), names_to = "EmotionCondition", values_to = "Sensitivity")
# use y = -... to position boxplot and jitterplot below the histogram
ggplot(data = my_datal, aes(x = Sensitivity, y = -.5, fill = EmotionCondition)) +
# after_stat for scaling
geom_histogram(aes(y = after_stat(count/100)), binwidth = .05, alpha = .8) +
# from ggstance
ggstance::geom_boxploth( width = .1, outlier.shape = NA, alpha = 0.5) +
geom_point(aes(color = EmotionCondition), position = position_jitter(width = .15), size = .5, alpha = 0.8) +
# merged those calls to one
guides(fill = FALSE, color = FALSE) +
# scale_y_continuous(breaks = 1, labels = unique(my_datal$EmotionCondition))
scale_color_brewer(palette = "Spectral") +
scale_fill_brewer(palette = "Spectral") +
# facetting, because each histogram needs its own y
# strip position = left to fake discrete labels in continuous scale
facet_wrap(~EmotionCondition, nrow = 4, scales = "free_y" , strip.position = "left") +
# remove all continuous labels from the y axis
theme(axis.title.y = element_blank(), axis.text.y = element_blank(),
axis.ticks.y = element_blank())
Created on 2021-04-15 by the reprex package (v1.0.0)
I have been trying to build a bar chart for GDP growth in UK and overlay it with a recession bands. I can do what is necessary with the bar plot but the moment I overlay with the recession bands, i get an error that a variable cannot be found.
uk.recessions.df <- read.table(textConnection(
"Peak, Trough
1857-06-01, 1858-12-01
1867-06-01, 1869-12-01
1873-10-01, 1879-03-01
1882-03-01, 1885-05-01
1887-03-01, 1888-04-01
1890-07-01, 1891-05-01
1893-01-01, 1894-06-01
1895-12-01, 1897-06-01
1919-03-01, 1921-07-01
1930-01-01, 1931-12-01
1956-04-01, 1956-08-01
1961-07-01, 1962-01-01
1973-09-01, 1974-04-01
1975-04-01, 1975-10-01
1980-01-01, 1981-04-01
1990-07-01, 1991-09-01
2008-04-01, 2009-07-01
2020-01-01, 2020-07-01"), sep=',',
colClasses=c('Date', 'Date'), header=TRUE)
uk.recessions.trim.df <- subset(uk.recessions.df, Peak >= min(tbl.QQGDP$Date))
tbl.data <- tbl.QQGDP %>%
mutate(Value = GDPGrowth < 0)
p <- ggplot(data = tbl.data, aes(x = Date, y = GDPGrowth, fill = Value)) +
geom_col(position = "identity", colour = "black", size = 0.25) +
scale_fill_manual(values = c("#85225f","#dbab01"), guide = FALSE) +
theme_tq()
p <- p +
geom_rect(data = uk.recessions.trim.df,
aes(xmin = Peak, xmax = Trough, ymin = -Inf, ymax = Inf),
fill = "grey", alpha = 0.5)
p
The error i get is
Error in FUN(X[[i]], ...) : object 'GDPGrowth' not found
I am cannot figure out what i am doing wrong. Any help (even if to tell me off for a silly mistake!!) will be greatly appreciated.
By default, geom_*() elements inherit the aesthetic mappings from the top level of the plot (ggplot()). In your case, the geom_rect() call is inheriting aes(x = Date, y = GDPGrowth, fill = Value) but can't find those objects as you have a different data source (uk.recessions.trim.df instead of tbl.data).
If you add the option inherit.aes = FALSE to geom_rect() you'll get the desired plot.
p <- ggplot(data = tbl.data, aes(x = Date, y = GDPGrowth, fill = Value)) +
geom_col(position = "identity", colour = "black", size = 0.25) +
scale_fill_manual(values = c("#85225f","#dbab01"), guide = FALSE)
p <- p +
geom_rect(data = uk.recessions.trim.df,
aes(xmin = Peak, xmax = Trough, ymin = -Inf, ymax = Inf),
fill = "grey", alpha = 0.5,
inherit.aes = FALSE)
p
An alternative (and probably better method) is to define data and aes in each geom separately, instead of in the initial ggplot() call. Eg:
p <- ggplot() +
geom_col(data = tbl.data,
aes(x = Date, y = GDPGrowth, fill = Value),
position = "identity", colour = "black", size = 0.25) +
scale_fill_manual(values = c("#85225f","#dbab01"), guide = FALSE)
p <- p +
geom_rect(data = uk.recessions.trim.df,
aes(xmin = Peak, xmax = Trough, ymin = -Inf, ymax = Inf),
fill = "grey", alpha = 0.5)
p
I'm looking for a way to move every second x-axis tick downwards and have the tick line go down with it.
I can change the general margin and tick length for all ticks with:
#MWE
library(ggplot2)
ggplot(cars, aes(dist, speed))+
geom_point()+
theme(
axis.ticks.length.x = unit(15, "pt")
)
But, I would like the x-axis ticks 0, 50, and 100 (i.e., every second tick) to be without the added top margin.
A generalized answer is preferred as my x-axis is categorical and not numerical (and contains 430 ticks, so nothing I can set by hand).
Any ideas?
Edit:
Output should be:
Edit2:
A more intricate example would be:
#MWE
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge')+
theme(
axis.ticks.length.x = unit(15, "pt")
)
Edit -- added categorical approach at bottom.
Here's a hack. Hope there's a better way!
ticks <- data.frame(
x = 25*0:5,
y = rep(c(-0.2, -2), 3)
)
ggplot(cars, aes(dist, speed))+
geom_point()+
geom_rect(fill = "white", xmin = -Inf, xmax = Inf,
ymin = 0, ymax = -5) +
geom_segment(data = ticks,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks,
aes(x = x, y = y, label = x), vjust = 1.5) +
theme(axis.ticks.x = element_blank()) +
scale_x_continuous(breaks = 25*0:5, labels = NULL, name = "") +
coord_cartesian(clip = "off")
Here's a similar approach used with a categorical x.
cats <- sort(as.character(unique(diamonds$cut)))
ticks <- data.frame(x = cats)
ticks$y = ifelse(seq_along(cats) %% 2, -500, -2000)
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge') +
annotate("rect", fill = "white",
xmin = 0.4, xmax = length(cats) + 0.6,
ymin = 0, ymax = -3000) +
geom_segment(data = ticks, inherit.aes = F,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks, inherit.aes = F,
aes(x = x, y = y, label = x), vjust = 1.5) +
scale_x_discrete(labels = NULL, name = "cut") +
scale_y_continuous(expand = expand_scale(mult = c(0, 0.05))) +
theme(axis.ticks.x = element_blank()) +
coord_cartesian(clip = "off")
I have to create a figure with ggplot2 that has roughly this structure:
p <- ggplot() +
geom_rect(data = regions,aes(xmin = xmin, xmax = xmax, ymin = -Inf, ymax = Inf),
fill = "yellow",alpha = 0.1) +
geom_line(data = data, aes(x=dt, y = y, color = case)) +
geom_point(data = data, aes(x=dt, y = y, color = case)) +
facet_grid(groups ~ ., scale="free_y")
geom_vline(x=as.numeric(dates_start), color = "orange3",linetype="dashed") +
geom_vline(x=as.numeric(dates_end), color = "orange3",linetype="dashed")
p
Is there anyway I can avoid having to pass all the details in geom_point? since they are the same as the one used in geom_line?