I'm trying to fill slices (x-axis) of the area under a curve in different colors using ggplot's geom_area. But I somehow can't get the sides of the areas to be vertical. Here's a minimal reproducible example:
library(ggplot2)
x = 1:10
pdat = data.frame(y = log(x), x = x)
ggplot(pdat, aes(x=x, y=y)) +
geom_area(aes(y = ifelse(y > 2 & y < 5, y, 0)),
fill = "red", alpha = 0.5) +
geom_line()
Thanks for your suggestions!
The problem is that for x = 7 the y-value is now 0 but for x = 8 the y-value is 2.0794415 and so the area in between is interpolated.
You can instead use a subset of pdat for geom_area:
ggplot() +
geom_area(data = pdat[pdat$y > 2 & pdat$y < 5,], aes(x = x, y = y),
fill = "red", alpha = 0.5) +
geom_line(data = pdat, aes(x = x, y = y))
Related
I'd like to make a geom_area plot with the fill colour based on the y (or any other) value, similar to the geom_density_ridges_gradient function of the ggridges package. I could achieve this with multiple geom_cols but I want to have the nice smooth geom_area style. Do you have any idea?
This code illustrates what I want to do:
data <- data.frame(x = 1:100,
y = rnorm(100, 20,3))
#I'd like to have an area plot with the fill colour based on the y values
ggplot(data = data, aes(x = x, y = y))+
geom_area(aes(fill = y))
#As in a bar plot, but with a smooth area, not a composite of rectangles
ggplot(data = data, aes(x = x, y = y))+
geom_col(aes(fill = y))
Thanks a lot!
You can use approx to get a huge number of interpolated values and plot them as very thin vertical geom_segments
data2 <- as.data.frame(approx(data$x, data$y, seq(1, 100, len = 5000)))
ggplot(data = data2, aes(x = x, y = y))+
geom_segment(aes(xend = x, yend = 0, colour = y), linewidth = 0.1) +
geom_area(fill = NA, color = "black") +
scale_color_viridis_c() +
theme_minimal(base_size = 20)
I am trying to plot lines representing observations from two groups, y1 and y2 in a way that:
the two groups have different line color (marked on legend)
the two groups have different linetype (marked on legend)
the plot has errorbar, and error bar is solid line in both groups
Code generating some data:
## generate data
x.grid <- seq(0, 1, length.out = 6)
y1.func <- function(x) 1/(x+1)
y2.func <- function(x) 2/(x+3)
set.seed(1)
x.vec <- numeric()
y.vec <- numeric()
group.vec <- numeric()
for (x in x.grid){
x.vec <- c(x.vec, rep(x, 2*10))
y.vec <- c(y.vec,
rep(y1.func(x), 10) + rnorm(10, sd = 0.1),
rep(y2.func(x), 10) + rnorm(10, sd = 0.1))
group.vec <- c(group.vec, rep("y1", 10), rep("y2", 10))
}
plt.df <- data.frame(x = x.vec, y = y.vec, group = group.vec)
## summarize data
plt.df.se <- Rmisc::summarySE(plt.df, measurevar = "y", groupvars=c("x", "group"))
Approach 1:
ggplot2::ggplot(plt.df.se,
aes(x = x,
y = y,
color = group,
linetype = group)) +
geom_line(position=pd, size = 0.5) +
geom_errorbar(aes(ymin=y-se, ymax=y+se), width=.05,
position=position_dodge(0.05), linetype = 1)
bad: legend blue not dashed
Approach 2:
ggplot2::ggplot(plt.df.se,
aes(x = x,
y = y,
color = group,
linetype = group)) +
geom_line(position=pd, size = 0.5) +
geom_errorbar(aes(ymin=y-se, ymax=y+se), width=.05,
position=position_dodge(0.05))
bad: blue error bars are dashed (I want them solid)
First off, you only want the linetype aesthetic to apply to your lines, so don't include it in the top-level aesthetic mapping, only in geom_line(). Then use show.legend = FALSE in geom_errorbar() so it won't affect the legends:
ggplot(plt.df.se,
aes(x = x,
y = y,
color = group)) +
geom_line(aes(linetype = group), position=position_dodge(0.05), size = 0.5) +
geom_errorbar(aes(ymin=y-se, ymax=y+se), width=.05,
position=position_dodge(0.05),
show.legend = FALSE)
Result:
I created a plot with several geom_area according to the following code :
library(ggplot2)
set.seed(1)
dat <- data.frame(matrix(rnorm(100, 10, 2), 100, 1))
dat_density <- data.frame(density(dat[, 1])[c("x", "y")])
quant <- quantile(dat[, 1], probs = seq(0, 1, 0.10))
library(RColorBrewer)
color_pal <- brewer.pal(length(quant)-1, "RdYlBu")
dens <- ggplot(data = dat_density, aes(x = x, y = y)) +
geom_line(size = 2)
for(i in 1:(length(color_pal))){
dens <- dens +
geom_area(data = subset(dat_density, x > quant[[i]] & x < quant[[i + 1]]), fill = color_pal[i])
}
dens
How can I add a common legend with each color of the color_pal vector (corresponding to all the 10% area of data) ?
The easiest way is to define the groups in your dataset
dat_density$quant <- cut(dat_density$x, breaks = c(-Inf, quant, Inf))
ggplot(data = dat_density, aes(x = x, y = y, fill = quant)) +
geom_line(size = 2) +
geom_area() +
scale_fill_brewer(palette = "RdYlBu")
If you look at this
ggplot(mtcars,aes(x=disp,y=mpg,colour=mpg))+geom_line()
you will see that the line colour varies according to the corresponding y value, which is what I want, but only section-by-section. I would like the colour to vary continuously according to the y value. Any easy way?
One possibility which comes to mind would be to use interpolation to create more x- and y-values, and thereby make the colours more continuous. I use approx to " linearly interpolate given data points". Here's an example on a simpler data set:
# original data and corresponding plot
df <- data.frame(x = 1:3, y = c(3, 1, 4))
library(ggplot2)
ggplot(data = df, aes(x = x, y = y, colour = y)) +
geom_line(size = 3)
# interpolation to make 'more values' and a smoother colour gradient
vals <- approx(x = df$x, y = df$y)
df2 <- data.frame(x = vals$x, y = vals$y)
ggplot(data = df2, aes(x = x, y = y, colour = y)) +
geom_line(size = 3)
If you wish the gradient to be even smoother, you may use the n argument in approx to adjust the number of points to be created ("interpolation takes place at n equally spaced points spanning the interval [min(x), max(x)]"). With a larger number of values, perhaps geom_point gives a smoother appearance:
vals <- approx(x = df$x, y = df$y, n = 500)
df2 <- data.frame(x = vals$x, y = vals$y)
ggplot(data = df2, aes(x = x, y = y, colour = y)) +
geom_point(size = 3)
Since ggplot2 v0.8.5 one can use geom_line or geom_path with different lineend options (right now there are three options: round, butt and square). Selection depends on the nature of the data.
round would work on sharp edges (like in given OPs data):
library(ggplot2)
ggplot(mtcars, aes(disp, mpg, color = mpg)) +
geom_line(size = 3, lineend = "round")
square would work on a more continuous variable:
df <- data.frame(x = seq(0, 100, 10), y = seq(0, 100, 10) ^ 2)
ggplot(data = df, aes(x = x, y = y, colour = y)) +
geom_path(size = 3, lineend = "square")
Maybe this will work for you:
library(dplyr)
library(ggplot2)
my_mtcars <-
mtcars %>%
mutate(my_colors = cut(disp, breaks = c(0, 130, 200, 400, Inf)))
ggplot(my_mtcars, aes(x = disp, y = mpg, col = mpg)) +
geom_line() + facet_wrap(~ my_colors, scales = 'free_x')
Is it possible to create great number of different kinds of "red" color. For better understanding I am expecting following, but instead of grey I desire to have "red" or "red-black".
mypalette <- rev(grey.colors(10000, start = 0.1, end = 0.5, gamma = 4))
plot(1:length(mypalette),1:length(mypalette), col=mypalette, pch=16)
The color packages I know have limited range of colors. Any idea will be appreciated.
If I understand what you want, try colorRampPalette. It returns a function that outputs the requested number of colours between the two you specified.
reds <- colorRampPalette(c("black","red"))
reds(5)
[1] "#000000" "#3F0000" "#7F0000" "#BF0000" "#FF0000"
Here are some ggplot alternatives
library(ggplot2)
df <- data.frame(x = rnorm(100), y = rnorm(100), z = rnorm(100), z2 = factor(1:5))
# colour set by continuous variable
ggplot(data = df, aes(x = x, y = y, colour = z)) +
geom_point() +
scale_colour_gradient(low = "red", high = "white")
library(RColorBrewer)
ggplot(data = df, aes(x = x, y = y, colour = z)) +
geom_point() +
scale_colour_gradientn(colours = brewer.pal(5, "Reds"))
# colour set by discrete variable
ggplot(data = df, aes(x = x, y = y, colour = z2)) +
geom_point() +
scale_colour_brewer(palette = "Reds")