ggplot annotation in fixed place in the chart - r

I am plotting the following data into a ggplot bar chart.
structure(list(MEDIATYPE = c("BACKLIT TOWER", "BILLBOARDS", "BRIDGE PANEL",
"BUILDING FACADES", "BUS SHELTER", "CANTILIVERS", "CYCLE SHELTER",
"FOB", "FREE STANDING PANEL", "GANTRIES"), RENTAL = c(197, 278363,
1423, 26, 35960, 6194, 70, 4845, 27, 9420)), .Names = c("MEDIATYPE",
"RENTAL"), row.names = c(NA, 10L), class = "data.frame")
I am using the following code to render the chart. It is working fine. However the problem is the yaxis values keeps changing and the annotation at the top of the chart sometimes disappears or in other instances appears in the middle of the chart.
library(ggplot2)
library(stringr) # str_wrap
ggplot(b, aes(x=reorder(MEDIATYPE,-RENTAL), y=RENTAL, fill=MEDIATYPE)) + geom_bar(stat = "identity", width = 0.8) +
theme(legend.position = "none") + xlab("MEDIATYPE") + ylab("SPENDS") +
scale_x_discrete(labels = function(x) str_wrap(x, width = 1)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
geom_text(aes(label=RENTAL), vjust = 0.5,hjust = 1, angle = 90, colour = "white",size = 3) +
ggtitle("MEDIAWISE SPENDS") +
theme(plot.title=element_text(size=rel(1.4), lineheight = 1, face = "bold")) +
theme(axis.text = element_text(size = 8, color = "black")) +
theme(axis.title = element_text(size=10, face = "bold")) +
theme(panel.background = element_rect(fill = "grey95")) +
ggplot2::annotate(geom = "text", label = "Source:ABC Monitors", x = Inf, y = -Inf, color = "blue",size = 3,fontface = "italic",hjust = 1, vjust = -30)
Is it possible to dynamically set the position of the annotation?

Extending #user20650's idea, textGrob allows the use relative coordinates, but use annotation_custom to restrict the grob to the plot panel.
b = structure(list(MEDIATYPE = c("BACKLIT TOWER", "BILLBOARDS", "BRIDGE PANEL",
"BUILDING FACADES", "BUS SHELTER", "CANTILIVERS", "CYCLE SHELTER",
"FOB", "FREE STANDING PANEL", "GANTRIES"), RENTAL = c(197, 278363,
1423, 26, 35960, 6194, 70, 4845, 27, 9420)), .Names = c("MEDIATYPE",
"RENTAL"), row.names = c(NA, 10L), class = "data.frame")
# Try a different y range
# b[2, 2] = 30000
library(ggplot2)
library(stringr) # str_wrap
library(grid)
label = textGrob(label = "Source:ABC Monitors", x = .95, y = 0.95,
just = c("right", "top"),
gp=gpar(fontface = "italic", col = "blue",size = 3))
p = ggplot(b, aes(x=reorder(MEDIATYPE,-RENTAL), y=RENTAL, fill=MEDIATYPE)) + geom_bar(stat = "identity", width = 0.8) +
theme(legend.position = "none") + xlab("MEDIATYPE") + ylab("SPENDS") +
scale_x_discrete(labels = function(x) str_wrap(x, width = 1)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
geom_text(aes(label=RENTAL), vjust = 0.5,hjust = 1, angle = 90, colour = "white",size = 3) +
ggtitle("MEDIAWISE SPENDS") +
theme(plot.title=element_text(size=rel(1.4), lineheight = 1, face = "bold")) +
theme(axis.text = element_text(size = 8, color = "black")) +
theme(axis.title = element_text(size=10, face = "bold")) +
theme(panel.background = element_rect(fill = "grey95")) +
annotation_custom(label, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf)

Instead of adjusting the position using hjust and vjust why not set the y-position to the tallest bar?
ggplot(b, aes(x=reorder(MEDIATYPE,-RENTAL), y=RENTAL, fill=MEDIATYPE)) + geom_bar(stat = "identity", width = 0.8) +
theme(legend.position = "none") + xlab("MEDIATYPE") + ylab("SPENDS") +
scale_x_discrete(labels = function(x) str_wrap(x, width = 1)) +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
geom_text(aes(label=RENTAL), vjust = 0.5,hjust = 1, angle = 90, colour = "white",size = 3) +
ggtitle("MEDIAWISE SPENDS") +
theme(plot.title=element_text(size=rel(1.4), lineheight = 1, face = "bold")) +
theme(axis.text = element_text(size = 8, color = "black")) +
theme(axis.title = element_text(size=10, face = "bold")) +
theme(panel.background = element_rect(fill = "grey95")) +
ggplot2::annotate(geom = "text", label = "Source:ABC Monitors",
x = Inf, y = max(b$RENTAL),
color = "blue",size = 3,fontface = "italic",hjust = 1, vjust = 1)

Related

can anyone tell me why my y-axis tick marks have disappeared? as well my legend has an a formatted into the boxes and I'm unsure of how to get rid of

p <- ggplot(data = JRdata, aes(x = reorder(tag,+occlusion19), y = occlusion19,
fill = IndividualSelectionMetagenomics,
colour = IndividualSelectionMetagenomics)) +
geom_bar(stat = "identity") +
scale_fill_manual(values = c("white","red")) +
scale_colour_manual(values = c("black", "black")) +
geom_col() +
geom_text_repel(aes(label=ifelse(IndividualSelectionMetagenomics=="Y",paste0(tag),"")),
angle = 90, size = 10, nudge_y = 1) +
theme_bw() + labs(x = "ID number", y = "Portion of Stomata Occluded /10") +
theme(axis.title.x = element_text(size = 40), axis.title.y = element_text(size = 40)) +
theme(legend.text = element_text(size = 20)) +
theme(legend.title = element_text(size = 40)) +
theme(legend.position = c(.95, .95), legend.justification = c("right", "top")) +
theme(element_blank()) +
theme(axis.text.x = element_blank()) +
ggsave(plot = p, width = 40, height = 20, dpi = 300, limitsize = FALSE, filename = "not squished axis.pdf")

how to put legend as a label in the middle of line in ggplot2

here is my data and code for chart line:
df<- data.frame(direct= 10:85, indirect= 55:130, age=15:90)
ggplot(data=df)+
geom_line(mapping=aes(y=direct,x= age,color="direct"),linetype="solid" ) +
geom_line(mapping=aes(y=indirect,x= age,color="indirect"),linetype="dashed") +
scale_color_manual(values = c(
'direct' = 'black',
'indirect' = 'black')) +
labs(color = NULL)+
scale_x_continuous(breaks = seq(15, 90, by = 5))+
labs(y= "Time Spent (in minutes)")+
guides(color = guide_legend(override.aes = list(linetype = c("solid","dashed"))))+
theme_classic()+
theme(plot.title = element_text(hjust = 0.5, size=9, face="bold"),legend.position=c(.90,.90))
I want to put legend in the middle of my each line as the picture:
You can add annotate to your lines. You can use the following code:
library(tidyverse)
df<- data.frame(direct= 10:85, indirect= 55:130, age=15:90)
ggplot(data=df)+
geom_line(mapping=aes(y=direct,x= age,color="direct"),linetype="dashed" ) +
geom_line(mapping=aes(y=indirect,x= age,color="indirect"),linetype="solid") +
scale_color_manual(values = c(
'direct' = 'black',
'indirect' = 'black')) +
labs(color = NULL)+
scale_x_continuous(breaks = seq(15, 90, by = 5))+
labs(y= "Time Spent (in minutes)")+
guides(color = guide_legend(override.aes = list(linetype = c("solid","dashed"))))+
theme_classic()+
theme(plot.title = element_text(hjust = 0.5, size=9, face="bold"), legend.position = "none") +
annotate('text', x=50, y=55, label = "direct")+
annotate('text', x=50, y=100, label = "indirect")
Output:
Not 100% what you desired. But one option would be the geomtextpath package which allows to easily add direct labels to lines or ...
library(ggplot2)
library(geomtextpath)
df <- data.frame(direct = 10:85, indirect = 55:130, age = 15:90)
ggplot(data = df) +
geom_textline(mapping = aes(y = direct, x = age, color = "direct",
label = "direct"), linetype = "solid", offset = unit(5, "pt"), gap = FALSE) +
geom_textline(mapping = aes(y = indirect, x = age, color = "indirect",
label = "indirect"), linetype = "dashed", offset = unit(5, "pt"), gap = FALSE) +
scale_color_manual(values = c(
"direct" = "black",
"indirect" = "black"
)) +
labs(color = NULL) +
scale_x_continuous(breaks = seq(15, 90, by = 5)) +
labs(y = "Time Spent (in minutes)") +
guides(color = guide_legend(override.aes = list(linetype = c("solid", "dashed")))) +
theme_classic() +
theme(plot.title = element_text(hjust = 0.5, size = 9, face = "bold"), legend.position = c(.90, .90)) +
guides(color = "none")

About ggplot2: Rotate geom_point shape & Show geom_text above the line

Good Morning.
I am trying to plot using a ggplot2 package but facing a problem below:
To make it more understandable, here is the target image that I want to make.
Just like the image, I want to do the followings:
1) Put a text 'median' above the dashed line so that it is ok to see the character clearly.
2) Rotate the degree of triangle (Not ^ ^ but < >) so that it makes sense.
To achieve the above, I've done so far with the codes:
# binding the data, defining the x and y aesthetics, title, labels
w_plot <- ggplot(
data = com_mal,
aes(x = reorder(name, -median_age), y = median_age)
)
labels = c('5 yrs old', 10, 15, 20, 25, 30)
w_plot +
geom_linerange(
aes(ymin = q1_age, ymax = q3_age),
color = "#76bde0",
size = 6,
alpha = 0.7
) +
geom_point(fill = "#ed3324", colour = "white", size = 4, shape = 21) +
geom_text(aes(y = 9, x = 15, label = '25th')) +
geom_text(aes(y = 20, x = 15, label = '75th percentile')) +
geom_text(aes(y = 30, x = 22, label = 'median')) +
geom_point(aes(y = 8.25, x = 15), shape = 17) +
geom_point(aes(y = 21.75, x = 15), shape = 17) +
geom_point(aes(y = 29, x = 21.9), fill = "#ed3324", colour = "white", size = 4, shape = 21) +
geom_hline(aes(yintercept = 5), linetype = 'dotted') +
geom_hline(aes(yintercept = 10), linetype = 'dotted') +
geom_hline(aes(yintercept = 15), linetype = 'dotted') +
geom_hline(aes(yintercept = 20), linetype = 'dotted') +
geom_hline(aes(yintercept = 25), linetype = 'dotted') +
geom_hline(aes(yintercept = 30), linetype = 'dotted') +
scale_y_continuous(breaks = seq(5, 30, by = 5), position = 'right', labels = labels) +
coord_flip() +
labs(title = 'Youngest Male Names',
subtitle = 'By estimated median age for Americans alive as of Jan 1. 2014',
x = NULL, y = NULL, caption = 'SOURCE: SOCIAL SECURITY ADMINISTRATION') +
theme(plot.title = element_text(face = 'bold', size = 16),
panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
axis.ticks = element_blank(), plot.caption = element_text(size = 10))
Thank you very much!
For the triangles, you could use geom_text() instead, setting the family argument to a font that supports the character, and for the label use geom_label():
geom_text(label = "▶", size = 3, family = "HiraKakuPro-W3")
geom_label(aes(y = 4, x = 10, label = 'median'), fill = "grey92", label.size = NA)
label.size removes the outline of the label, and "grey92" is (approximately?) the color of the background.
If you want the dotted line to be behind the label, you should add geom_label() to the plot after the line. (Also notice that you can add all the dotted lines in the same line of code.)
w_plot +
geom_linerange(
aes(ymin = q1_age, ymax = q3_age),
color = "#76bde0",
size = 6,
alpha = 0.7
) +
geom_point(fill = "#ed3324", colour = "white", size = 4, shape = 21) +
geom_text(aes(y = 9, x = 15, label = '25th')) +
geom_text(aes(y = 20, x = 15, label = '75th percentile')) +
geom_text(aes(y = 8.25, x = 15),label = "◀", size = 3,
family = "HiraKakuPro-W3") +
geom_text(aes(y = 21.75, x = 15),label = "▶", size = 3,
family = "HiraKakuPro-W3") +
geom_point(aes(y = 29, x = 21.9), fill = "#ed3324", colour = "white",
size = 4, shape = 21) +
geom_hline(yintercept = seq(5, 30, by = 5), linetype = 'dotted') +
geom_label(aes(y = 30, x = 22, label = 'median'),
fill = "grey92", label.size = NA) +
scale_y_continuous(breaks = seq(5, 30, by = 5),
position = 'right', labels = labels) +
coord_flip() +
labs(title = 'Youngest Male Names',
subtitle = 'By estimated median age for Americans alive as of Jan 1. 2014',
caption = 'SOURCE: SOCIAL SECURITY ADMINISTRATION') +
theme(plot.title = element_text(face = 'bold', size = 16),
panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
axis.ticks = element_blank(), plot.caption = element_text(size = 10))

Customized Line Break for ggplot

I can create quality control charts with the qicharts2 package.
library(tidyverse)
library(qicharts2)
(plot1 <- qic(age,
data = tail(cabg, 100),
chart = 'i',
ylab = 'Years',
xlab = 'Patient #'
)
)
p1 <- plot1$data
Then I can customize the charts.
(plot2 <- ggplot(p1, aes(x, y)) +
geom_ribbon(ymin = p1$lcl, ymax = p1$ucl, fill = "black", alpha = 0.05) +
geom_line(color = "black", size = 1) +
geom_line(aes(x, cl)) +
geom_point(color = "black" , fill = "black", size = 2) +
geom_point(data = p1 %>% filter(sigma.signal == TRUE), color = "red", size = 2) +
ggtitle(label = NULL) +
labs(x = NULL, y = NULL) +
scale_y_continuous(breaks = seq(0, 100, by = 10)) +
coord_cartesian(ylim = c(0, 100)) +
theme_bw() +
theme(
text = element_text(size = 18),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 0.6),
axis.text.y = NULL,
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
strip.text.x = element_text(size = 14, color = "black", angle = 0))
)
Using the part argument, in my qichart, causes it to split at the specified part point(s).
(plot3 <- qic(age,
data = tail(cabg, 100),
chart = 'i',
part = c(70, 85),
ylab = 'Years',
xlab = 'Patient #'
)
)
p3 <- plot3$data
What do I need to add to my customized ggplot2 syntax, below, to get it to part in the same manner? What I've got does everything, EXCEPT, it doesn't part like in the syntax directly above.
(plot4 <- ggplot(p3, aes(x, y)) +
geom_ribbon(ymin = p3$lcl, ymax = p3$ucl, fill = "black", alpha = 0.05) +
geom_line(color = "black", size = 1) +
geom_line(aes(x, cl)) +
geom_point(color = "black" , fill = "black", size = 2) +
geom_point(data = p3 %>% filter(sigma.signal == TRUE), color = "red", size = 2) +
ggtitle(label = NULL) +
labs(x = NULL, y = NULL) +
scale_y_continuous(breaks = seq(0, 100, by = 10)) +
coord_cartesian(ylim = c(0, 100)) +
theme_bw() +
theme(
text = element_text(size = 18),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 0.6),
axis.text.y = NULL,
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
strip.text.x = element_text(size = 14, color = "black", angle = 0))
)
Is the following plot what you are looking for?
If so, what I used is group= in the aesthetics of geom_ribbon and geom_line
(plot4 <- ggplot(p3, aes(x, y)) +
geom_ribbon(aes(group=cut(p3$x,c(0,70,85,max(p3$x)))),ymin = p3$lcl, ymax = p3$ucl, fill = "black", alpha = 0.05) +
geom_line(color = "black", size = 1, aes(group=cut(p3$x,c(0,70,85,max(p3$x))))) +
geom_line(aes(x, cl, group=cut(p3$x,c(0,70,85,max(p3$x))))) +
geom_point(color = "black" , fill = "black", size = 2) +
geom_point(data = p3 %>% filter(sigma.signal == TRUE), color = "red", size = 2) +
ggtitle(label = NULL) +
labs(x = NULL, y = NULL) +
scale_y_continuous(breaks = seq(0, 100, by = 10)) +
coord_cartesian(ylim = c(0, 100)) +
theme_bw() +
theme(
text = element_text(size = 18),
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 0.6),
axis.text.y = NULL,
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
strip.text.x = element_text(size = 14, color = "black", angle = 0)))

Using ggplot2; How to get position_dodge() to work with this example?

Background
I took the data from a Stephen Few Example and wanted to add labels to each of the bars to pull the legend from the side of the graphic.
The code in the "Hack Graphic" section got me there because I couldn't get the position_dodge() to work with the text labels.
Load Data
library(tidyverse)
library(forcats)
### Build data from his table
candidates <- tibble::tibble(`Rating Areas` = c("Experience",
"Communication", "Friendliness", "Subject matter knowledge", "Presentation",
"Education"), `Karen Fortou` = c(4,3.5, 4, 4, 3, 3.5), `Mike Rafun` = c(4.5,
2, 2, 5, 1.5, 4.5), `Jack Nymbul` = c(2.5, 5, 4.5, 2.5, 2.75, 2)) %>%
gather("Candidates", "Score", -`Rating Areas`)
# The totals for each candidate
totals <- candidates %>% group_by(Candidates) %>% summarise(Score =
sum(Score))
Hack Graphic
Notice how I used manually created x-axis values (x = c(seq(.6,1.35, by = .15), seq(1.6,2.35, by = .15), seq(2.6,3.35, by = .15))) to place the labels instead of using position = position_dodge() as described in this post.
candidates %>%
ggplot(aes(x = fct_reorder(Candidates, Score), y = Score)) +
geom_col(data = totals, alpha = .45) +
geom_col(aes(fill = `Rating Areas`), position = position_dodge(.9), color = "black",
show.legend = FALSE) +
geom_text(label = rep(c("Experience", "Communication", "Friendliness",
"Subject matter knowledge", "Presentation", "Education"),3),
x = c(seq(.6,1.35, by = .15), seq(1.6,2.35, by = .15),
seq(2.6,3.35, by = .15)), y = 5.1, angle = 90, color = "black",
hjust = "left", size = 4, fontface = "bold") +
scale_fill_brewer(type = "qual") +
scale_y_continuous(breaks = seq(0, 25, by = 2)) +
theme_bw() +
labs(x = "\nCandidates", y = "Rating Score") +
theme(axis.text.x = element_text(size = 14, color = "black"), legend.text = element_text(size = 14),
legend.title = element_text(size = 15), axis.title = element_text(size = 15))
Graphic Code that doesn't work
When I follow the example from the previous Stack answer using geom_text(aes(label =Rating Areas), position = position_dodge(width = 0.9), angle = 90, color = "black", hjust = "left", size = 4, fontface = "bold") it does not spread the labels out ever each bar.
I must be missing something obvious. Please help with how to get position_dodge() to work with this example?
candidates %>%
ggplot(aes(x = fct_reorder(Candidates, Score), y = Score)) +
geom_col(data = totals, alpha = .45) +
geom_col(aes(fill = `Rating Areas`), position = position_dodge(.9), color = "black", show.legend = FALSE) +
geom_text(aes(label = `Rating Areas`), position = position_dodge(width = 0.9), angle = 90, color = "black", hjust = "left", size = 4, fontface = "bold") +
scale_fill_brewer(type = "qual") +
scale_y_continuous(breaks = seq(0, 25, by = 2)) +
theme_bw() +
labs(x = "\nCandidates", y = "Rating Score") +
theme(axis.text.x = element_text(size = 14, color = "black"), legend.text = element_text(size = 14), legend.title = element_text(size = 15), axis.title = element_text(size = 15))
I think you need to have the same mapping for both geom_col and geom_text. You can add fill = Rating Areas to the aesthetics of geom_text. You will get a warning though.
candidates %>%
ggplot(aes(x = fct_reorder(Candidates, Score), y = Score)) +
geom_col(data = totals, alpha = .45) +
geom_col(aes(fill = `Rating Areas`), position = position_dodge(.9), color = "black", show.legend = FALSE) +
geom_text(aes(fill = `Rating Areas`, label = `Rating Areas`), position = position_dodge(width = 0.9), angle = 90, color = "black", hjust = "left", size = 4, fontface = "bold") +
scale_fill_brewer(type = "qual") +
scale_y_continuous(breaks = seq(0, 25, by = 2)) +
theme_bw() +
labs(x = "\nCandidates", y = "Rating Score") +
theme(axis.text.x = element_text(size = 14, color = "black"), legend.text = element_text(size = 14), legend.title = element_text(size = 15), axis.title = element_text(size = 15))
Edit: Here's a way to do it without the warning:
candidates %>%
ggplot(aes(x = fct_reorder(Candidates, Score), y = Score, fill = `Rating Areas`)) +
geom_col(data = totals, aes(x = fct_reorder(Candidates, Score), y = Score), alpha = .45, inherit.aes = FALSE) +
geom_col(position = position_dodge(.9), color = "black", show.legend = FALSE) +
geom_text(aes(label = `Rating Areas`), position = position_dodge(width = 0.9), angle = 90, color = "black", hjust = "left", size = 4, fontface = "bold") +
scale_fill_brewer(type = "qual") +
scale_y_continuous(breaks = seq(0, 25, by = 2)) +
theme_bw() +
labs(x = "\nCandidates", y = "Rating Score") +
theme(axis.text.x = element_text(size = 14, color = "black"), legend.text = element_text(size = 14), legend.title = element_text(size = 15), axis.title = element_text(size = 15))

Resources