Adding a centred overlaid title to a ggplot2 doughnut graph - r

I'm hoping to create a ggplot2 title overlaying a doughnut graph, with my reprex adapted this example from https://www.r-graph-gallery.com/128-ring-or-donut-plot.html.
# load library
library(ggplot2)
# Create test data.
data <- data.frame(
category=c("A", "B", "C"),
count=c(10, 60, 30)
)
# Compute percentages
data$fraction <- data$count / sum(data$count)
# Compute the cumulative percentages (top of each rectangle)
data$ymax <- cumsum(data$fraction)
# Compute the bottom of each rectangle
data$ymin <- c(0, head(data$ymax, n=-1))
# Compute label position
data$labelPosition <- (data$ymax + data$ymin) / 2
# Compute a good label
data$label <- paste0(data$count)
# Make the plot
ggplot(data, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=category)) +
geom_rect() +
coord_polar(theta="y") + # Try to remove that to understand how the chart is built initially
xlim(c(2, 4))+ # Try to remove that to see how to make a pie chart
theme_void()+
scale_fill_brewer(palette = 1)+
geom_label( x=3.5, aes(y=labelPosition, label=label), size=6)+
theme(legend.position = "top",
plot.title = element_text(hjust=0.5))+
ggtitle("My title")
This is what I have currently:
And this is what I want:
I haven't been able to find any documentation demonstrating how to do this in ggplot2. Any suggestions are appreciated.

You can add an annotation layer :
library(ggplot2)
ggplot(data, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=category)) +
geom_rect() +
coord_polar(theta="y") +
xlim(c(2, 4))+
theme_void()+
scale_fill_brewer(palette = 1)+
geom_label( x=3.5, aes(y=labelPosition, label=label), size=6)+
theme(legend.position = "top") +
annotate('text', x = 2, y = 0.5, label = 'My title', color = 'blue', size = 5)

Related

Add horizontal lines outside plot area in ggplot2

I've tried finding an answer but nothing seems to work. The first image below is a scatterplot drawn in ggplot2, which has been post-processed by a specific LaTeX journal template on Overleaf. I would like to re-create the chart without having to use the template.
Unfortunately, I haven't been able to figure out how to draw the horizontal lines that separate the title area, and note area (respectively) from the main plot region (see red arrows.
How can I do this?
Oh, the second image is the one that is produced from the code below.
Thanks!
library(ggplot2)
theme_set(theme_bw()) # pre-set the bw theme.
data("midwest", package = "ggplot2")
# Scatterplot
gg <- ggplot(midwest, aes(x=area, y=poptotal)) +
geom_point(aes(col=state, size=popdensity)) +
geom_smooth(method="loess", se=F) +
xlim(c(0, 0.1)) +
ylim(c(0, 500000)) +
labs(y="Population",
x="Area",
title="Figure 4: Scatterplot",
caption = "Source: midwest") +
theme(plot.background = element_rect(colour="black",size=1))
plot(gg)
You can set coord_cartesian(clip = "off") and add a couple of annotation_customcalls. This allows plotting relative to the panel without having to specify co-ordinates relative to your data:
ggplot(midwest, aes(x=area, y=poptotal)) +
geom_point(aes(col=state, size=popdensity)) +
geom_smooth(method="loess", se=F) +
xlim(c(0, 0.1)) +
ylim(c(0, 500000)) +
labs(y="Population",
x="Area",
title="FIGURE 4: Scatterplot",
caption = "Source: midwest") +
coord_cartesian(clip = "off") +
annotation_custom(grid::linesGrob(x = c(-0.12, 1.19), y = c(1.03, 1.03))) +
annotation_custom(grid::linesGrob(x = c(-0.12, 1.19), y = c(-.07, -.07))) +
theme(plot.background = element_rect(colour="black", size = 1),
plot.title = element_text(size = 16, face = 2, vjust = 5, hjust = -0.2),
plot.margin = margin(20, 20, 20, 20))

How to visualize the group and subgroup frequency?

I have to plot the frequency data using a group variable As and subgroup variable ADs. What is the best way to visualize the frequency ie., pie chart or mosaic? Is there any function available in ggplot2?
df <- data.frame(As=c('GeA','GeA','GeA', 'GA'),
ADs=c('A44','A33','A37','A141'),
freq=c(501,65,50,103))
# As ADs freq
# 1 GeA A44 501
# 2 GeA A33 65
# 3 GeA A37 50
# 4 GA A141 103
Some thoughts are like below:
However, is there any way to differentiate both group and subgroup in a single plot?
Out of the proposed solutions, below two charts looked promising.
Pie Chart & Tile Graph
I have used the following code suggested by M--.
df.2 <- df
df.2$ymax <- with(df.2, ave(freq, As, FUN=cumsum))
df.2$ymin <- lag(df.2$ymax, default = 0)
df.2$ymin <- ifelse(lag(as.character(df.2$As), default = 0) != df.2$As, 0, df.2$ymin)
df.legend <- df.2[with(df.2, order(As)), ]
library(ggplot2)
# Pie Chart
ggplot(df.2) +
geom_rect(aes(fill=As, ymax=ymax, ymin=ymin, xmax=4, xmin=3)) +
geom_rect(aes(fill=ADs, ymax=ymax, ymin=ymin, xmax=3, xmin=0)) +
xlim(c(0, 4)) +
theme(aspect.ratio=1) +
coord_polar(theta="y") +
scale_x_continuous(breaks=c(0,3), labels=c("ADs", "As")) +
annotate("text", x=rep(1.5,4), y=c(50, 350,530,590),
label= as.character(df.legend$ADs)) +
annotate("text", x=rep(3.5,2), y=c(50, 350),
label= as.character(unique(df.legend$As))) +
theme(legend.position="none", axis.title.x=element_blank(),
axis.title.y=element_blank())
# Tile Graph
ggplot(df.2) +
geom_rect(aes(fill=As, ymax=ymax, ymin=ymin, xmax=4, xmin=3)) +
geom_rect(aes(fill=ADs, ymax=ymax, ymin=ymin, xmax=3, xmin=0)) +
xlim(c(0, 4)) + theme(aspect.ratio=1) +
scale_x_continuous(breaks=c(1.5,3.5), labels=c("ADs", "As")) +
annotate("text", x=rep(1.5,4), y=c(50, 350,530,590),
label= paste(as.character(df.legend$ADs), df.legend$freq,sep= " = ")) +
annotate("text", x=rep(3.5,2), y=c(50, 350),
label= as.character(unique(df.legend$As))) +
theme(legend.position="none", axis.title.x=element_blank(),
axis.title.y=element_blank())
However, I didn't get the same output
Pie Chart & Tile Graph
Message: Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
Could you please advise what would be the issue? Is there any difference in the version of the package(s) used?
Stacked Barplot:
You can use stacked barplots:
library(ggplot2)
ggplot(data = df, aes(x = As, y = freq, fill = ADs)) +
geom_bar(stat = "identity")
you can add this and get labels on the plot:
p + geom_text(aes(label = paste(ADs, freq, sep=": ")),
position = position_stack(vjust = 0.5), size = 3) + #subgroups
stat_summary(fun.y = sum, aes(label = ..y.., group = As), geom = "text") + #groups
theme(legend.position="none")
Next two answers are in reference to this post.
Tile Graph:
For this we need to tweak the data:
df.2 <- df
df.2$ymax <- with(df.2, ave(freq, As, FUN=cumsum))
df.2 <- df.2[with(df.2, order(As)), ]
#for some reason lag function does not work properly in R 3.3.3
library(data.table)
setDT(df.2)[, ymin:=c(0,ymax[-.N])]
df.legend <- df.2[with(df.2, order(As)), ]
Then we can use ggplot again:
ggplot(df.2) +
geom_rect(aes(fill=As, ymax=ymax, ymin=ymin, xmax=4, xmin=3)) +
geom_rect(aes(fill=ADs, ymax=ymax, ymin=ymin, xmax=3, xmin=0)) +
xlim(c(0, 4)) + theme(aspect.ratio=1) +
scale_x_continuous(breaks=c(1.5,3.5), labels=c("ADs", "As")) +
annotate("text", x=rep(1.5,4), y=c(50, 350,530,590),
label= paste(as.character(df.legend$ADs), df.legend$freq,sep= " = ")) +
annotate("text", x=rep(3.5,2), y=c(50, 350),
label= as.character(unique(df.legend$As))) +
theme(legend.position="none", axis.title.x=element_blank(),
axis.title.y=element_blank())
Pie Chart:
ggplot(df.2) +
geom_rect(aes(fill=As, ymax=ymax, ymin=ymin, xmax=4, xmin=3)) +
geom_rect(aes(fill=ADs, ymax=ymax, ymin=ymin, xmax=3, xmin=0)) +
xlim(c(0, 4)) +
theme(aspect.ratio=1) +
coord_polar(theta="y") +
scale_x_continuous(breaks=c(0,3), labels=c("ADs", "As")) +
annotate("text", x=rep(1.5,4), y=c(50, 350,530,590),
label= as.character(df.legend$ADs)) +
annotate("text", x=rep(3.5,2), y=c(50, 350),
label= as.character(unique(df.legend$As))) +
theme(legend.position="none", axis.title.x=element_blank(),
axis.title.y=element_blank())

How to manually change text color of ggplot2 legend in R?

There might be a simple way to do this, but I am not sure what it is. I am trying to make it so that the text in the legend matches up with the color box next to it. I have been trying to do this for a while and have not found a way to use the element_text function to add multiple colors to the legend. I've had no problem making every label the same color, but is there a way to make each legend label a different color?
data<-data.frame(count=c(39,36,19,6), category=c("a","b","c","d"))
data$fraction = data$count / sum(data$count)
data = data[order(data$fraction), ]
data$ymax = cumsum(data$fraction)
data$ymin = c(0, head(data$ymax, n=-1))
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Create Plot
fill <- c("blue3","cyan3","darkgrey","forestgreen")
library(ggplot2)
p1 = ggplot(data, aes(fill=category, ymax=ymax, ymin=ymin, xmax=4, xmin=3.5)) +
geom_rect(colour="White") +
coord_polar(theta="y") +
scale_fill_manual(values=fill)+
theme_bw()+
geom_label(aes(label=paste(data$fraction*100,"%"),x=4,y=
(ymin+ymax)/2),inherit.aes = F)+
theme(panel.grid=element_blank())+
theme(axis.ticks=element_blank()) +
xlim(c(0, 4)) +
theme(axis.text=element_blank()) +
theme(legend.text=element_text(color=fill,size=12))+
theme(legend.key.size=unit(2,'lines'))+
theme(legend.key=element_rect(size=5))+
labs(title="donut plot")
print(p1)
With a couple of modifications to this answer, match-legend-text-color-in-geom-text-to-symbol, you get what you want. But note, the answer uses grid's editing functions.
# Your data and plot
data<-data.frame(count=c(39,36,19,6), category=c("a","b","c","d"))
data$fraction = data$count / sum(data$count)
data = data[order(data$fraction), ]
data$ymax = cumsum(data$fraction)
data$ymin = c(0, head(data$ymax, n=-1))
fill <- c("blue3","cyan3","darkgrey","forestgreen")
library(ggplot2)
p1 = ggplot(data, aes(fill=category, ymax=ymax, ymin=ymin, xmax=4, xmin=3.5)) +
geom_rect(colour="White") +
coord_polar(theta="y") +
scale_fill_manual(values=fill)+
theme_bw()+
geom_label(aes(label=paste(data$fraction*100,"%"),x=4,y=
(ymin+ymax)/2),inherit.aes = F)+
theme(panel.grid=element_blank())+
theme(axis.ticks=element_blank()) +
xlim(c(0, 4)) +
theme(axis.text=element_blank()) +
theme(legend.text=element_text(color=fill,size=12))+
theme(legend.key.size=unit(2,'lines'))+
theme(legend.key=element_rect(size=5))+
labs(title="donut plot")
# Get the ggplot grob
g <- ggplotGrob(p1)
# Check out the grobs
library(grid)
grid.ls(grid.force(g))
Look through the list of grobs. The grobs you want to edit are towards the bottom of the list, in the 'guide-box' set of grobs - with names that begin with "label". There are four grobs:
label-3-3.4-4-4-4
label-4-3.5-4-5-4
label-5-3.6-4-6-4
label-6-3.7-4-7-4
# Get names of 'label' grobs.
names.grobs <- grid.ls(grid.force(g))$name
labels <- names.grobs[which(grepl("^label", names.grobs))]
# Edit the 'label' grobs - change their colours
# Use the `editGrob` function
for(i in seq_along(labels)) {
g <- editGrob(grid.force(g), gPath(labels[i]), grep = TRUE,
gp = gpar(col = fill[i]))
}
# Draw it
grid.newpage()
grid.draw(g)
It's possible to achieve this without editing grobs, by using the ggtext package. Specify the legend text labels as element_markdown and wrap them in <span> tags that use the colors you want.
data<-data.frame(count=c(39,36,19,6), category=c("a","b","c","d"))
data$fraction = data$count / sum(data$count)
data = data[order(data$fraction), ]
data$ymax = cumsum(data$fraction)
data$ymin = c(0, head(data$ymax, n=-1))
fill <- c("blue3","cyan3","darkgrey","forestgreen")
library(ggplot2)
library(ggtext)
ggplot(data, aes(fill=category, ymax=ymax, ymin=ymin, xmax=4, xmin=3.5)) +
geom_rect(colour="White") +
coord_polar(theta="y") +
scale_fill_manual(labels = paste("<span style='color:",
fill,
"'>",
unique(data$category),
"</span>"),
values = fill)+
theme_bw()+
geom_label(aes(label=paste(data$fraction*100,"%"),x=4,y=
(ymin+ymax)/2),inherit.aes = F)+
theme(panel.grid=element_blank())+
theme(axis.ticks=element_blank()) +
xlim(c(0, 4)) +
theme(axis.text=element_blank()) +
theme(legend.text=element_markdown(size=12))+
theme(legend.key.size=unit(2,'lines'))+
theme(legend.key=element_rect(size=5))+
labs(title="donut plot")

Add same gradient to each rectangle in ggplot

I am trying to display color gradient in below created ggplot2. So with using following data and code
vector <- c(9, 10, 6, 5, 5)
Names <- c("Leadership", "Management\n", "Problem Solving",
"Decision Making\n", "Social Skills")
# add \n
Names[seq(2, length(Names), 2)] <- paste0("\n" ,Names[seq(2, length(Names), 2)])
# data.frame, including a grouping vector
d <- data.frame(Names, vector, group=c(rep("Intra-capacity", 3), rep("Inter-capacity", 2)))
# correct order
d$Names <- factor(d$Names, levels= unique(d$Names))
d$group_f = factor(d$group, levels=c('Intra-capacity','Inter-capacity'))
# plot the bars
p <- ggplot(d, aes(x= Names, y= vector, group= group, fill=vector, order=vector)) +
geom_bar(stat= "identity") +
theme_bw()+
scale_fill_gradient(low="white",high="blue")
# use facet_grid for the groups
#p + facet_grid(.~group_f, scales= "free_x", space= "free_x")
p+ theme(text = element_text(size=23),plot.background = element_rect(fill = "white"),
strip.background = element_rect(fill="Dodger Blue")) +
facet_grid(.~group_f, scales= "free_x", space= "free_x") + xlab("") +ylab("") +
theme(strip.text.x = element_text(size = 18, colour = "white" )) +
geom_text(size=10, aes(label=vector))
My output is this:
But now I would like to insert color gradient so each rectangle would look like picture below (my desired output):
I've also looked at this:
R: gradient fill for geom_rect in ggplot2
create an arrow with gradient color
http://www.computerworld.com/article/2935394/business-intelligence/my-ggplot2-cheat-sheet-search-by-task.html
Color Gradients With ggplot
Label minimum and maximum of scale fill gradient legend with text: ggplot2
How can I apply a gradient fill to a geom_rect object in ggplot2?
And also tried using:
scale_fill_gradient(low="white",high="blue") or
scale_fill_gradientn(colours = c("blue","white","red"),
values = c(0,5,10),
guide = "colorbar", limits=c(0,10))
But I am clearly doing something wrong.
I'm with #RomanLustrik here. However, if you can't use Excel (= prly much easier), maybe just adding a white rectangle with an alpha-gradient is already enough:
ggplot(d, aes(x= Names, y= vector, group= group,order=vector)) +
geom_bar(stat= "identity", fill="blue") +
theme_bw() +
scale_fill_gradient(low="white",high="blue") +
annotation_custom(
grid::rasterGrob(paste0("#FFFFFF", as.hexmode(1:255)),
width=unit(1,"npc"),
height = unit(1,"npc"),
interpolate = TRUE),
xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=5
) +
geom_text(aes(label=vector), color="white", y=2, size=12)

Draw lines between two facets in ggplot2

How can I draw several lines between two facets?
I attempted this by plotting points at the min value of the top graph but they are not between the two facets. See picture below.
This is my code so far:
t <- seq(1:1000)
y1 <- rexp(1000)
y2 <- cumsum(y1)
z <- rep(NA, length(t))
z[100:200] <- 1
df <- data.frame(t=t, values=c(y2,y1), type=rep(c("Bytes","Changes"), each=1000))
points <- data.frame(x=c(10:200,300:350), y=min(y2), type=rep("Bytes",242))
vline.data <- data.frame(type = c("Bytes","Bytes","Changes","Changes"), vl=c(1,5,20,5))
g <- ggplot(data=df, aes(x=t, y=values)) +
geom_line(colour=I("black")) +
facet_grid(type ~ ., scales="free") +
scale_y_continuous(trans="log10") +
ylab("Log values") +
theme(axis.text.x = element_text(angle = 90, hjust = 1), panel.margin = unit(0, "lines"))+
geom_point(data=points, aes(x = x, y = y), colour="green")
g
In order to achieve that, you have to set the margins inside the plot to zero. You can do that with expand=c(0,0). The changes I made to your code:
When you use scale_y_continuous, you can define the axis label inside that part and you don't need a seperarate ylab.
Changed colour=I("black") to colour="black" inside geom_line.
Added expand=c(0,0) to scale_x_continuous and scale_y_continuous.
The complete code:
ggplot(data=df, aes(x=t, y=values)) +
geom_line(colour="black") +
geom_point(data=points, aes(x = x, y = y), colour="green") +
facet_grid(type ~ ., scales="free") +
scale_x_continuous("t", expand=c(0,0)) +
scale_y_continuous("Log values", trans="log10", expand=c(0,0)) +
theme(axis.text.x=element_text(angle=90, vjust=0.5), panel.margin=unit(0, "lines"))
which gives:
Adding lines can also be done with geom_segment. Normally the lines (segments) will appear in both facets. If you want them to appear between the two facets, you will have to restrict that in data parameter:
ggplot(data=df, aes(x=t, y=values)) +
geom_line(colour="black") +
geom_segment(data=df[df$type=="Bytes",], aes(x=10, y=0, xend=200, yend=0), colour="green", size=2) +
geom_segment(data=df[df$type=="Bytes",], aes(x=300, y=0, xend=350, yend=0), colour="green", size=1) +
facet_grid(type ~ ., scales="free") +
scale_x_continuous("t", expand=c(0,0)) +
scale_y_continuous("Log values", trans="log10", expand=c(0,0)) +
theme(axis.text.x=element_text(angle=90, vjust=0.5), panel.margin=unit(0, "lines"))
which gives:

Resources