Purpose
Create a stacked area plot or a "stacked" circle plot (see picture). Pie chart is not desired.
Data and code of a bar plot
#Data set:
Numbers 16%
Frosts 2%
Doors 6%
Shelfs 10%
Earning -3%
par(mai=c(2, 1, 1, 1), lwd=2)
barplot(as.numeric(c(16, 2, 6, 10, -3)), col = c("lightblue"), main="Bar plot",
names.arg=c("Numbers","Frosts","Earning", "Doors","Shelfs"), xpd=TRUE, las=2, lwd=2,
axes=FALSE, axis.lty=1, cex.axis=1, cex.names=1, cex.main=1, ylim=c(-4, 18), xlim=c(0, 5))
Two output options
This should get you most of the way there
library(ggplot2)
df<- data.frame(value=as.numeric(c(16, 2, 6, 10, -3)),
cat=c("Numbers","Frosts","Earning","Doors","Shelfs"))
ggplot(df[order(df$value),], aes(x=1, y=abs(value), fill=factor(ifelse(value>0, 0, 1)))) +
geom_bar(stat="identity", colour="grey") +
geom_text(aes(label=paste(cat, value)), position = "stack", vjust = 3) +
scale_fill_manual(values=c("white", "red"))
ggplot(df[order(df$value),], aes(x=1, y=abs(value), fill=factor(ifelse(value>0, 0, 1)))) +
geom_bar(stat="identity", colour="grey") +
geom_text(aes(label=paste(cat, value)), position = "stack", vjust = -1) +
scale_fill_manual(values=c("white", "red")) +
coord_polar()
You may need to fiddle around with the vjust values to change the position of the labels, or calculate a custom y mapping for them, but it's a good start.
You can try to work with this:
library(ggplot2)
data<-data.frame(Name=c("Earning","Frosts","Doors","Shelfs","Numbers"),Val=c(1,2,6,10,16))
ggplot(data,aes(x=factor(1),y=Val,fill=Name))+
geom_bar(stat="identity",width=1)+coord_polar()
Just change color palette and add text wherever you want (and of course first value in Val column if it's too big on the plot - it corresponds to your negative value)
The topmost of the "Related" links to the right should give you most of the info you need to construct a stacked bar plot, but adapted for your use it would be something like this:
# A vertical matrix containing the values
md <- matrix(c(-3, 16, 2, 6, 10), ncol=1)
d <- barplot(md, col=c(2, rep(0, 4)))
# Finding the vertical position for the labels
ypos <- apply(md, 2, cumsum)
ypos <- ypos - md/2
ypos <- t(ypos)
# I haven't checked if the values and names match
text(d/3, ypos, adj=c(0, NA),
paste(c("Earning","Numbers","Frosts","Doors","Shelfs"), md, sep=": "))
Related
I'd like to make a plot using ggplot2 where some of the fill values are clipped, i.e. values above or below the limits of the color scale are displayed as the minimum/maximum color. I can get this to work like this, using a combination of limit and oob (out of bounds):
library(ggplot2)
library(scales)
ggplot() + ... + scale_fill_viridis(na.value="white", limit=c(0, 10), oob=squish)
But there is no information in the colorbar that indicates there are values present outside of the limits.
How can I reproduce this matplotlib example in ggplot: https://stackoverflow.com/a/32072348
Specifically, how to get the triangles at the end of the colorbar?
As far as I'm aware there is not a package that implements triangle ends for colourbars in ggplot2 (but please let me know if there is!). However, we can implement our own. We'd need a constructor for our custom guide and a way to draw it. Most of the stuff is already implemented in guide_colourbar() and methods for their class, so what we need to do is just tag on our own class and expand the guide_gengrob method. The code below should work for vertically oriented colourbars. You'd need to know some stuff about the grid package and gtable package to follow along.
library(ggplot2)
library(gtable)
library(grid)
my_triangle_colourbar <- function(...) {
guide <- guide_colourbar(...)
class(guide) <- c("my_triangle_colourbar", class(guide))
guide
}
guide_gengrob.my_triangle_colourbar <- function(...) {
# First draw normal colourbar
guide <- NextMethod()
# Extract bar / colours
is_bar <- grep("^bar$", guide$layout$name)
bar <- guide$grobs[[is_bar]]
extremes <- c(bar$raster[1], bar$raster[length(bar$raster)])
# Extract size
width <- guide$widths[guide$layout$l[is_bar]]
height <- guide$heights[guide$layout$t[is_bar]]
short <- min(convertUnit(width, "cm", valueOnly = TRUE),
convertUnit(height, "cm", valueOnly = TRUE))
# Make space for triangles
guide <- gtable_add_rows(guide, unit(short, "cm"),
guide$layout$t[is_bar] - 1)
guide <- gtable_add_rows(guide, unit(short, "cm"),
guide$layout$t[is_bar])
# Draw triangles
top <- polygonGrob(
x = unit(c(0, 0.5, 1), "npc"),
y = unit(c(0, 1, 0), "npc"),
gp = gpar(fill = extremes[1], col = NA)
)
bottom <- polygonGrob(
x = unit(c(0, 0.5, 1), "npc"),
y = unit(c(1, 0, 1), "npc"),
gp = gpar(fill = extremes[2], col = NA)
)
# Add triangles to guide
guide <- gtable_add_grob(
guide, top,
t = guide$layout$t[is_bar] - 1,
l = guide$layout$l[is_bar]
)
guide <- gtable_add_grob(
guide, bottom,
t = guide$layout$t[is_bar] + 1,
l = guide$layout$l[is_bar]
)
return(guide)
}
You can then use your custom guide as the guide argument in a scale.
g <- ggplot(mtcars, aes(mpg, wt)) +
geom_point(aes(colour = drat))
g + scale_colour_viridis_c(
limits = c(3, 4), oob = scales::oob_squish,
guide = my_triangle_colourbar()
)
There isn't really a natural way to colour out-of-bounds values differently, but you can make very small slices near the extremes a different colour.
g + scale_colour_gradientn(
colours = c("red", scales::viridis_pal()(255), "hotpink"),
limits = c(3, 4), oob = scales::oob_squish,
guide = my_triangle_colourbar()
)
Created on 2021-07-19 by the reprex package (v1.0.0)
library(gg.layers)
library(ggplot2)
library(rcolors)
brk <- c(-Inf, -1, 0, 1, 3, 6, 9, Inf)
nbrk <- length(brk) - 1
cols <- get_color(rcolors$amwg256, nbrk)
g <- make_colorbar(
at = brk, col = cols, height = 1,
tck = 0.4,
space = "right",
legend.text.location = c(0.3, 0.5),
legend.text.just = c(0.5, 0.5),
# legend.text = list(fontfamily = "Times", cex = 1.1),
hjust = 0.05
)
p <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
p + g
https://github.com/rpkgs/gg.layers
Triangles? No idea. Colors? You can set a gradient with custom values where your normal range is manually defined and your extremes are something else.
library(ggplot2)
# example taken from ?viridis::scale_colour_viridis, even if I don't use that function
dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
dsub$diff <- with(dsub, sqrt(abs(x-y))* sign(x-y))
d <- ggplot(dsub, aes(x, y, colour=diff)) + geom_point()
d +
scale_color_gradientn(
colours=c("red", "red", "blue", "green", "yellow", "red", "red"),
values = c(0, 0.1-1e-9, 0.1, 0.5, 0.9, 0.9+1e-9, 1),
breaks = c(-0.51, -.4, 0, .4, .62),
label = function(z) replace(z, c(1, length(z)), c("Min", "Max"))) +
theme_bw()
I doubled "red" on each end so that there would be no gradient transition with the neighboring colors. You can choose a different color for one end (while in this case it's clear if it's extreme-high or extreme-low).
I chose to manually control values= and labels= to include arbitrary points and labels for the extremes. This can be improved based on your preferences.
The disadvantage to this is that you have to define the viridis colors manually; should not be too difficult. I've hastily approximated it here, I'm confident you can choose better colors for the internal gradient portion.
I'd like to make a plot using ggplot2 where some of the fill values are clipped, i.e. values above or below the limits of the color scale are displayed as the minimum/maximum color. I can get this to work like this, using a combination of limit and oob (out of bounds):
library(ggplot2)
library(scales)
ggplot() + ... + scale_fill_viridis(na.value="white", limit=c(0, 10), oob=squish)
But there is no information in the colorbar that indicates there are values present outside of the limits.
How can I reproduce this matplotlib example in ggplot: https://stackoverflow.com/a/32072348
Specifically, how to get the triangles at the end of the colorbar?
As far as I'm aware there is not a package that implements triangle ends for colourbars in ggplot2 (but please let me know if there is!). However, we can implement our own. We'd need a constructor for our custom guide and a way to draw it. Most of the stuff is already implemented in guide_colourbar() and methods for their class, so what we need to do is just tag on our own class and expand the guide_gengrob method. The code below should work for vertically oriented colourbars. You'd need to know some stuff about the grid package and gtable package to follow along.
library(ggplot2)
library(gtable)
library(grid)
my_triangle_colourbar <- function(...) {
guide <- guide_colourbar(...)
class(guide) <- c("my_triangle_colourbar", class(guide))
guide
}
guide_gengrob.my_triangle_colourbar <- function(...) {
# First draw normal colourbar
guide <- NextMethod()
# Extract bar / colours
is_bar <- grep("^bar$", guide$layout$name)
bar <- guide$grobs[[is_bar]]
extremes <- c(bar$raster[1], bar$raster[length(bar$raster)])
# Extract size
width <- guide$widths[guide$layout$l[is_bar]]
height <- guide$heights[guide$layout$t[is_bar]]
short <- min(convertUnit(width, "cm", valueOnly = TRUE),
convertUnit(height, "cm", valueOnly = TRUE))
# Make space for triangles
guide <- gtable_add_rows(guide, unit(short, "cm"),
guide$layout$t[is_bar] - 1)
guide <- gtable_add_rows(guide, unit(short, "cm"),
guide$layout$t[is_bar])
# Draw triangles
top <- polygonGrob(
x = unit(c(0, 0.5, 1), "npc"),
y = unit(c(0, 1, 0), "npc"),
gp = gpar(fill = extremes[1], col = NA)
)
bottom <- polygonGrob(
x = unit(c(0, 0.5, 1), "npc"),
y = unit(c(1, 0, 1), "npc"),
gp = gpar(fill = extremes[2], col = NA)
)
# Add triangles to guide
guide <- gtable_add_grob(
guide, top,
t = guide$layout$t[is_bar] - 1,
l = guide$layout$l[is_bar]
)
guide <- gtable_add_grob(
guide, bottom,
t = guide$layout$t[is_bar] + 1,
l = guide$layout$l[is_bar]
)
return(guide)
}
You can then use your custom guide as the guide argument in a scale.
g <- ggplot(mtcars, aes(mpg, wt)) +
geom_point(aes(colour = drat))
g + scale_colour_viridis_c(
limits = c(3, 4), oob = scales::oob_squish,
guide = my_triangle_colourbar()
)
There isn't really a natural way to colour out-of-bounds values differently, but you can make very small slices near the extremes a different colour.
g + scale_colour_gradientn(
colours = c("red", scales::viridis_pal()(255), "hotpink"),
limits = c(3, 4), oob = scales::oob_squish,
guide = my_triangle_colourbar()
)
Created on 2021-07-19 by the reprex package (v1.0.0)
library(gg.layers)
library(ggplot2)
library(rcolors)
brk <- c(-Inf, -1, 0, 1, 3, 6, 9, Inf)
nbrk <- length(brk) - 1
cols <- get_color(rcolors$amwg256, nbrk)
g <- make_colorbar(
at = brk, col = cols, height = 1,
tck = 0.4,
space = "right",
legend.text.location = c(0.3, 0.5),
legend.text.just = c(0.5, 0.5),
# legend.text = list(fontfamily = "Times", cex = 1.1),
hjust = 0.05
)
p <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
p + g
https://github.com/rpkgs/gg.layers
Triangles? No idea. Colors? You can set a gradient with custom values where your normal range is manually defined and your extremes are something else.
library(ggplot2)
# example taken from ?viridis::scale_colour_viridis, even if I don't use that function
dsub <- subset(diamonds, x > 5 & x < 6 & y > 5 & y < 6)
dsub$diff <- with(dsub, sqrt(abs(x-y))* sign(x-y))
d <- ggplot(dsub, aes(x, y, colour=diff)) + geom_point()
d +
scale_color_gradientn(
colours=c("red", "red", "blue", "green", "yellow", "red", "red"),
values = c(0, 0.1-1e-9, 0.1, 0.5, 0.9, 0.9+1e-9, 1),
breaks = c(-0.51, -.4, 0, .4, .62),
label = function(z) replace(z, c(1, length(z)), c("Min", "Max"))) +
theme_bw()
I doubled "red" on each end so that there would be no gradient transition with the neighboring colors. You can choose a different color for one end (while in this case it's clear if it's extreme-high or extreme-low).
I chose to manually control values= and labels= to include arbitrary points and labels for the extremes. This can be improved based on your preferences.
The disadvantage to this is that you have to define the viridis colors manually; should not be too difficult. I've hastily approximated it here, I'm confident you can choose better colors for the internal gradient portion.
I have a simple plot below. I log scaled the x-axis and I want the graph to show 0.1, 1, 10. I can't figure out how to override the default of 0.1, 1.0, 10.0.
Is there a way I could change only two of the x-axis labels?
library(ggplot2)
x <- c(0.1, 1, 10)
y <- c(1, 5, 10)
ggplot()+
geom_point(aes(x,y)) +
scale_x_log10()
You could specify labels and breaks in scale_x_log10
library(ggplot2)
x <- c(0.1, 1, 10)
y <- c(1, 5, 10)
ggplot() + geom_point(aes(x,y)) + scale_x_log10(labels = x, breaks = x)
I would like to make geom_ribbon have gradation color.
For example, I have data.frame as below;
df <-data.frame(Day = c(rnorm(300, 3, 2.5), rnorm(150, 7, 2)), # create random data
Depth = c(rnorm(300, 6, 2.5), rnorm(150, 2, 2)),
group = c(rep('A', 300), rep('B', 150))) # add two groups
With this data.frame, I make ggplot using geom_ribbon as below
gg <-
ggplot(data=df,aes(x=Day))+
geom_ribbon(aes(ymin=Depth,ymax=max(Depth)),alpha = 0.25)+
ylim(max(df$Depth),0)+
facet_wrap(~group,scales = "free_x",ncol=2)+
labs(x="Days(d)",y="Depth (m)")
gg
, which makes a following plot;
Here, I would like to make the ribbon have gradation color by the value of y-axis (i.e. df$Depth, in this case). However, I do not how to do it.
I can do it by geom_point as below;
gg <- gg +
geom_point(aes(y=Depth,color=Depth),alpha = 1, shape = 20, size=5)+
scale_color_gradient2(midpoint = 5,
low = "red", mid="gray37", high = "black",
space ="Lab")
gg
But, I want the color gradation on ribbon by filling the ribbon area, not on each point.
Do you have any suggestion to do it with geom_ribbon?
I do not know this is perfect, but I found a solution for what I want as follows;
First, I prepare data.frame;
df <-data.frame(Day = c(rnorm(300, 7, 2), rnorm(150, 5, 1)), # create random data
Depth = c(rnorm(300, 10, 2.5), rnorm(150, 7, 2)),
group = c(rep('A', 300), rep('B', 150))) # add two groups
Second, prepare the gradation background by following the link; log background gradient ggplot
xlength <- ceiling(max(df$Day))
yseq <- seq(0,max(df$Depth), length=100)
bg <- expand.grid(x=0:xlength, y=yseq) # dataframe for all combinations
Third, plot by using ggplot2;
gg <- ggplot() +
geom_tile(data=bg,
aes(x=x, y=y, fill=y),
alpha = 0.75)+ # plot the gradation
scale_fill_gradient2(low='red', mid="gray37", high = "black",
space ="Lab",midpoint = mean(df$Depth)/2)+ #set the color
geom_ribbon(data=df,
aes(x=Day,ymin=0,ymax=Depth),
fill = "gray92")+ #default ggplot2 background color
ylim(max(df$Depth),0)+
scale_x_continuous()+
facet_wrap(~group,scales = "free_x",ncol=2)+
labs(x="Days(d)",y="Depth (m)")+
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank())
gg
I would like to use my own specific color in my image plot. I am very new in ggplot2 so had a look at its manual from here - the old link does not exist and now is here - and tried to repeat some of the stuff; but I couldn't figure out how to supply my colorbar as I did for the graphics plot.
library(reshape2)
library(ggplot2)
#my specific color list
mycol <- vector(length=512, mode = "numeric")
for (k in 1:256) mycol[k] <- rgb(255, k - 1, k - 1, maxColorValue=255)
for (k in 257:512) mycol[k] <- rgb(511 - (k - 1), 511 - (k - 1), 255, maxColorValue=255)
mycol <- rev(mycol)
ncolors <- length(mycol)
# graphics plot
par(mar = c(5, 13, 1, 6))
image(1:ncol(volcano), 1:nrow(volcano), t(volcano), zlim = c(0, ncolors), col=mycol, axes=FALSE, main="W Matrix", sub = "", xlab= "Components", ylab="Genes")
axis(2, at=1:nrow(volcano), labels=row.names(volcano), adj= 0.5, tick=FALSE, las = 1, cex.axis=0.25, font.axis=1, line=-1)
axis(1, at=1:ncol(volcano), labels=colnames(volcano), adj= 0.5, tick=FALSE,las = 3, cex=1, cex.axis=0.5, font.axis=1, line=-1)
# ggplot2
library(reshape2)
library(ggplot2)
library(ez)
ggplot(melt(volcano), aes(x=Var1, y=Var2, fill=value)) + geom_tile() + scale_color_gradient2(low = muted("red"), mid = "white", high = muted("blue"), midpoint = 0, space = "rgb", guide = "colourbar") # the code does not really use my color bar
Error in unit(tic_pos.c, "mm") : 'x' and 'units' must have length > 0
Just to clarify #Didzis' answer, which works but may not produce the gradient you're looking for...
'midpoint' refers to the numerical value at which you want the color specified by 'mid' to appear. So, instead of setting the 'midpoint' argument to 256 (which falls outside the range of value, which is the vector you're coloring by), it's wise to set it to a value somewhere in the middle of the range of values you are coloring by, otherwise you aren't using the entire gradient you specified with 'low' and 'high', which defeats the purpose of scale_color_gradient2. The exact value depends on what you are trying to communicate visually, but usually the mean or median is used. Here, I edited #Didzis' code with 'midpoint' set to the median of value
v <- melt(volcano)
ggplot(v, aes(x=Var1, y=Var2, fill=value)) +
geom_tile() +
scale_fill_gradient2(low = "#0000FF", mid = "#FFFFFF", high ="#FF0000",
midpoint = median(v$value), space = "rgb", guide = "colourbar")
This gives a plot with a much wider gradient:
I think that you should change values for low=, mid= and high= values in scale_fill_gradient2(). For low= I used first value of mycol, for high= last value of mycol and for mid= used 256. value (middle). Also changed midpoint= to 256 as this is midpoint of your number of colors.
ggplot(melt(volcano), aes(x=Var1, y=Var2, fill=value)) +
geom_tile() +
scale_fill_gradient2(low = "#0000FF", mid = "#FFFFFF", high ="#FF0000",
midpoint = 256.5, space = "rgb", guide = "colourbar")