How to align caption text with left bar in a bar chart? - r

I am trying to align the caption text in a bar chart, so that it will start at the same vertical margin as the left bar.
library(ggplot2)
library(tibble)
my_df <-
tibble::tribble(~response, ~estimate,
"little_bit", 0.353477,
"no", 0.307639,
"very", 0.338883)
ggplot(my_df, aes(x = reorder(response, -estimate), y = estimate)) +
geom_bar(stat = "identity", width = 0.9, fill = "royalblue") +
ggtitle("do you like swimming with fish?") +
ylab("") +
labs(caption = "this is my caption") +
theme_minimal() +
theme(
axis.line.x = element_blank(),
axis.line.y = element_blank(),
axis.text.y = element_blank(),
panel.grid = element_blank(),
panel.grid.major=element_blank(),
plot.title = element_text(hjust = 0.5, size = 26),
axis.text.x = element_text(angle = 0, size = 14, margin = margin(t = 0, r = 20, b = 0, l = 0)),
axis.title.x = element_blank(),
legend.title = element_blank(),
plot.caption = element_text(hjust = 0, size = 8),
plot.caption.position = "plot") ## <-- I thought this would help, but no...
Is there a way to align the caption such as the following?

To get your desired result set the caption position to "panel" and remove the expansion of the x-scale:
library(ggplot2)
library(tibble)
my_df <-
tibble::tribble(~response, ~estimate,
"little_bit", 0.353477,
"no", 0.307639,
"very", 0.338883)
ggplot(my_df, aes(x = reorder(response, -estimate), y = estimate)) +
geom_bar(stat = "identity", width = 0.9, fill = "royalblue") +
ggtitle("do you like swimming with fish?") +
scale_x_discrete(expand = c(0, 0)) +
labs(caption = "this is my caption", y = NULL) +
theme_minimal() +
theme(
axis.line.x = element_blank(),
axis.line.y = element_blank(),
axis.text.y = element_blank(),
panel.grid = element_blank(),
panel.grid.major=element_blank(),
plot.title = element_text(hjust = 0.5, size = 26),
axis.text.x = element_text(angle = 0, size = 14, margin = margin(t = 0, r = 20, b = 0, l = 0)),
axis.title.x = element_blank(),
legend.title = element_blank(),
plot.caption = element_text(hjust = 0, size = 8),
plot.caption.position = "panel")

Or, a very common workaround for those cases would be to annotate outside of the plot area. (I am using annotate(geom = "text",...) - you could also use geom_text, but you would only need a data frame for it.)
I personally prefer the annotate option as it is more versatile and generalisable for other purposes as well.
library(ggplot2)
my_df <-
tibble::tribble( ~response, ~estimate, "little_bit", 0.353477, "no", 0.307639, "very", 0.338883)
barwidth <- 0.9
ggplot(my_df, aes(x = reorder(response, -estimate), y = estimate)) +
geom_bar(stat = "identity", width = barwidth, fill = "royalblue") +
annotate(
geom = "text",
x = 1 - barwidth / 2, hjust = 0, # that's the trick
y = -0.1, # play around with y. you could also set it relativ to your bar heights
label = "this is my caption"
) +
coord_cartesian(clip = "off", ylim = c(0, NA)) + # necessary to set axis limits and clip off to annotate beyond
ggtitle("do you like swimming with fish?") +
theme_minimal() +
theme(plot.margin = margin(b = 1, unit = "inch")) # margin randomly chosen. unfortunately also necessary

Related

Align the legend and the title in the center of plot in r

I have a dataset and I want to plot the heat map for them. my problem is: I want a vertical legend and also I want to put the title of legend in the middle of legend.
My data is a text file with is like the attached figure.
Here is the code that I am using( when I change the horizontal to the vertical, the legend moves up and also the title is not in the center of legend).
# Heatmap
ggplot(heat, aes(Samples, Gene, fill= log(Folded_Change_of_Expression))) +
geom_tile()+
theme(axis.text.x = element_text(angle = 90))+ theme(axis.text.y =
element_text(size = 12)) +
coord_fixed(ratio = 4)+theme(panel.background = element_blank()) +
theme(axis.title = element_text(size = 16)) +
guides(fill = guide_colourbar(barwidth = 5, barheight = 1, title = "log(Folded
Change of Expression)",
title.position = "top", direction = "horizontal"))
However, the output figure for me is not the thing that I want. Could you please help me with that?
Thank you
Legend that I want is same as this:
Here is one suggestion:
New added last 3 lines remove existent guides lines:
library(tidyverse)
ggplot(heat, aes(Samples, Gene, fill= log(Folded_Change_of_Expression))) +
geom_tile()+
theme(axis.text.x = element_text(angle = 90))+
theme(axis.text.y = element_text(size = 12)) +
coord_fixed(ratio = 4)+
theme(panel.background = element_blank()) +
theme(axis.title = element_text(size = 16)) +
scale_fill_continuous(guide = "colourbar") +
theme(legend.title = element_text(angle = 90, hjust = 0.5, vjust = 0.5)) +
guides(fill = guide_legend(title.position = "right",
title = "log(Folded Change \n of Expression)"))
Perhaps the only way to 'center' the colourbar and title is for the colourbar to be larger than the legend title, e.g.
library(tidyverse)
heat <- data.frame(Samples = rep(c(paste("Control", 1:10, sep = "_"),
paste("Treat", 1:10, sep = "_")), each = 2),
Gene = c("Occludin", "Claudin"),
Folded_Change_of_Expression = runif(20, -4, 4))
ggplot(heat, aes(x = Samples, y = Gene, fill = log(abs(Folded_Change_of_Expression)))) +
geom_tile() +
coord_fixed(ratio = 4) +
theme(axis.text.x = element_text(angle = 90),
axis.text.y = element_text(size = 12),
panel.background = element_blank(),
axis.title = element_text(size = 16),
legend.direction = "vertical",
legend.box = "vertical",
legend.title = element_text(angle = 90,
hjust = 0.5,
vjust = 0.5),
legend.justification = c(0.5, 0.5)) +
guides(fill = guide_colourbar(title = "log(Fold Change in Gene Expression)",
title.position = "right",
title.hjust = 0.5,
title.vjust = 0.5,
legend.title.align = 0.5,
barheight = 14))
When the legend title is longer than the colourbar it appears to 'fall back' on a default justification. I've had a look at the source code for guide_colourbar (https://rdrr.io/github/SahaRahul/ggplot2/src/R/guide-colorbar.r) but it's not clear to me why this is the case. If you make the legend title smaller, it is positioned as expected:
library(tidyverse)
heat <- data.frame(Samples = rep(c(paste("Control", 1:10, sep = "_"),
paste("Treat", 1:10, sep = "_")), each = 2),
Gene = c("Occludin", "Claudin"),
Folded_Change_of_Expression = runif(20, -4, 4))
ggplot(heat, aes(x = Samples, y = Gene, fill = log(abs(Folded_Change_of_Expression)))) +
geom_tile() +
coord_fixed(ratio = 4) +
theme(axis.text.x = element_text(angle = 90),
axis.text.y = element_text(size = 12),
panel.background = element_blank(),
axis.title = element_text(size = 16),
legend.direction = "vertical",
legend.box = "vertical",
legend.title = element_text(angle = 90,
hjust = 0,
vjust = 0,
size = 8),
legend.justification = c(0, 0.5)) +
guides(fill = guide_colourbar(title = "log(Fold Change in Gene Expression)",
title.position = "right",
title.vjust = 0.5,
barheight = 10))
Created on 2022-06-30 by the reprex package (v2.0.1)

How to highlight (bold or italic) specific labels using geom_label()

I am trying to highlight (either bold or italic) specific labels in a graph.
I am using geom_label but I don't know how to specify which groups should be highlighted.
Here is the data to build the table.
library(ggplot2)
library(dplyr)
library(ggalt)
library(cowplot)
library(tibble)
library(lubridate)
dates <- tribble( ~start_date, ~event, ~displ, ~model,
ymd(19680101), "No bold", 1, 'SP',
ymd(19820101), "Bold", 1, 'SP',
ymd(19800101), "No bold", 0.8, 'RCC',
ymd(20010101), "Bold", 0.8, 'RCC',
ymd(19740101), "No bold", -0.8,'OM',
ymd(19940101), "Bold", -0.8,'OM',
ymd(19560101), "No bold", -1,'SM',
ymd(20090101), "Bold", -1,'SM',
ymd(20010101), "No bold", 0.5,'US',
ymd(20090101), "Bold", 0.5,'US',
ymd(19890101), "Bold", -0.5,'LA')
Here is the function to plot the timeline.
shift_axis <- function(p, xmin, xmax, y=0){
g <- ggplotGrob(p)
dummy <- data.frame(y=y)
ax <- g[["grobs"]][g$layout$name == "axis-b"][[1]]
p + annotation_custom(grid::grobTree(ax, vp = grid::viewport(y=1, height=sum(ax$height))),
ymax=y, ymin=y) +
annotate("segment", y = 0, yend = 0, x = xmin, xend = xmax, size = 0.5,
arrow = arrow(length = unit(0.1, "inches"))) +
theme(axis.text.x = element_blank(),
axis.ticks.x=element_blank())
}
Finally, the graph where the labels go together in pairs (color coded).
vjust = ifelse(dates$displ > 0, -1.5, 1.5)
p1 <- dates %>%
ggplot(aes(start_date, displ)) +
geom_lollipop(point.size =1 ) +
#geom_text(aes(x = start_date, y = displ, label = event), data = data,
# hjust = 0, vjust = vjust, size = 4) +
geom_label(aes(x = start_date, y = displ, label = event, color=factor(model)),
data = data, hjust = 0, vjust = 0, size = 4) +
geom_point(aes(colour = factor(model)), size = 2) +
theme(axis.title = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.line = element_blank(),
axis.text.x = element_text(size = 12)) +
theme(axis.line = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank()) +
expand_limits(x = c(ymd(19500101), ymd(20210101)), y = 1.2) +
scale_x_date(breaks = scales::pretty_breaks(n = 9)) +
theme(legend.position = "none")
timeline <- shift_axis(p1, ymd(19500101), ymd(20210101))
timeline
So, I am trying to highlight the labels in "Bold" (either bold or italic) and the "No bold" leave them as they appear in the plot.
Thanks in advance.

Aligning text on horizontal bar chart

I've come across several threads pointing out how to annotate bar charts, but I've tried a number of iterations of this code and can't seem to get the text left justified, starting at 0% on the x axis. I've tried to change hjust to "left", 0.95, and progressively larger numbers - none of them have the text tethered to the x origin.
dummy_data <- tibble(Proportion = c(0.87, 1),
`Person of Interest` = c("Person B", "Person A"))
dummy_data %>%
ggplot(aes(x = Proportion, y = `Person of Interest`,
fill = `Person of Interest`,
label = paste0(`Person of Interest`, "~", scales::percent(Proportion))))+
geom_col(width = 0.5) +
geom_text(position = position_dodge(width = .9), # move to center of bars
vjust = 0, # nudge above top of bar
hjust = "top",
size = 4.5,
colour = "white",
fontface = "bold") +
scale_x_continuous(labels = scales::percent,
limits = c(0, 1.01),
expand = c(0, 0)) +
ggthemes::theme_economist(horizontal = F) +
scale_fill_manual(values = alpha(c("black", "#002D62"), .5)) +
ggtitle("Lack of Skill") +
theme(title = element_text("Lack of Skill"),
plot.title = element_text(hjust = 0.5, face = "italic"),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.x = element_blank(),
axis.text.x = element_text(hjust = 0.25),
legend.position="none",
aspect.ratio = 1/3)
I've often found text data with ggplot maddening - a huge thanks to anyone willing to take a look.
Try this approach that is close to what you want. Your themes can be producing the issues with placing the labels:
#Code
dummy_data %>%
ggplot(aes(x=`Person of Interest`,
y=Proportion,
fill=`Person of Interest`,
label = paste0(`Person of Interest`, "~", scales::percent(Proportion))))+
geom_bar(stat = 'identity')+
geom_text(aes(y=0.13),
size = 4.5,
colour = "white",
fontface = "bold")+coord_flip()+
scale_y_continuous(labels = scales::percent,
limits = c(0, 1.01),
expand = c(0, 0)) +
ggthemes::theme_economist(horizontal = F) +
scale_fill_manual(values = alpha(c("black", "#002D62"), .5)) +
ggtitle("Lack of Skill") +
theme(title = element_text("Lack of Skill"),
plot.title = element_text(hjust = 0.5, face = "italic"),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.x = element_blank(),
axis.text.x = element_text(hjust = 0.25),
legend.position="none",
aspect.ratio = 1/3)
Output:

Wrong synchronization between the labels, the colors and the slices in a pie chart

By running this code :
g <- ggplot(results_table, aes(x = "", y = Pct*100,
fill = factor(results_table$Criteria, as.character(results_table$Criteria))),width = 0.5) +
geom_bar(stat = "identity") +
scale_color_manual(values = Palcolor) +
scale_fill_manual(values = Palcolor) +
coord_polar(theta = "y", start = 0, direction = -1) +
theme_minimal() +
theme(legend.position = "bottom", legend.title=element_blank(), axis.title.x = element_blank(),,
axis.title.y = element_blank(), panel.border = element_blank(), panel.grid = element_blank(),
axis.text = element_blank(), axis.ticks = element_blank(),
plot.title = element_text(size = 14, hjust = 0.5, vjust = 0)) +
guides(fill = guide_legend(nrow = 4, byrow = TRUE)) +
theme(
legend.key.height = unit(0.3, "lines"), #smaller squares
legend.key.width = unit(0.7, "lines"), #smaller squares
legend.margin=margin(l = 40, unit='pt'),
legend.text = element_text(margin = margin(r = 60, unit = "pt"))) +
xlab("") +
ylab("") +
geom_text(aes(x = 1.70, y =Pct*100/2 + c(0, cumsum(Pct*100)[-length(Pct*100)]),
label = paste0(sprintf("%0.1f", round(Pct*100, digits = 1)),"%")),
size = 3.2) +
labs(title = gTitle)
}
I get this pie chart :
As you can see, the slices and the color are right, but the labels are reversed. If I use
position = position_stack (vjust = 0.5, reverse = TRUE)
in geom_text, it reduces the whole pie to a small slice, then it doesn't fix my issue.
The solution is to substract the result of the formula for y in geom_text from 100 :
`geom_text(aes(x = 1.70, y = 100-(Pct*100/2 + c(0, cumsum(Pct*100)[-length(Pct*100)])),
label = paste0(sprintf("%0.1f", round(Pct*100, digits = 1)),"%")),
size = 3.2)'

Adjusting space between legend text and boxes after coord_flip() in ggplot

I am trying to move the legend text and legend boxes further apart (horizontally) on a box and jitter plot. The complicating factor is the coord_flip I used to make the boxplot horizontal. In theme I tried using both legend.spacing.x and legend.spacing.y but neither had any effect on the distance between legend text and legend boxes.
Here is the graph with fake data. More complex than necessary I know but I need to be able to make it work with all the complications.
library(dplyr)
library(ggplot2)
set.seed(01234)
# make some data
totDays <- data.frame(id = 1:80,
group = rep(c("Placebo", "Drug"), each = 40),
total84 = c(pmin(abs(round(rnorm(40, 55, 30))),84), pmin(abs(round(rnorm(40, 38, 30))),84)))
# get some descriptives
(groupDF <- totDays %>% group_by(group) %>%
dplyr::summarise(m = mean(total84, na.rm = T),
sd = sd(total84, na.rm = T),
count = n()) %>%
mutate(se = sd/sqrt(count)))
# now for the box and scatter plot
(g <- ggplot(totDays, aes(group, total84, colour = group)) +
geom_jitter(size = 1, width = 0.1) + # so points aren't overlaid, width controls how much jitter
geom_point(stat = "summary", fun.y = "mean", shape = 3, size = 3, colour = "black") + # crosses for mean
geom_boxplot(alpha = 0, width = 0.5, lwd = 1, size = 0.5) +
scale_color_manual(values = c("#00AFBB", "#E7B800")) +
scale_y_continuous(breaks = seq(0,84,14), minor_breaks = seq(0, 84, 14)) + # changes minor break line
coord_flip() +
labs(y = "Score") +
geom_hline(yintercept = c(groupDF$m), linetype = "dotted") +
geom_segment(x = 2.38, xend = 2.38, y = groupDF$m[2] + .1, yend = groupDF$m[1] - .1, size = .7, arrow = arrow(end = "both", type = "open", length = unit(0.15, "cm")), colour = "#696969") +
annotate("text", x = 2.46, y = mean(groupDF$m), label = paste0("italic(p) == ", 0.02), parse = T) +
theme_bw() +
theme(axis.title.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(size = 13),
axis.title.x = element_text(size = 13, face = "bold", margin = margin(t = 0, r = 0, b = 10, l = 0), vjust = -2), # note the use of margin to move the title away from the axis text
legend.title = element_blank(),
legend.position = "top",
legend.spacing.y = unit(.1, "cm"),
legend.box.spacing = unit(.1, "cm"), # adjusts distance of box from x-axis
legend.key.size = unit(1, "cm"),
legend.text = element_text(size = 13, face = "bold"),
strip.text = element_text(size = 13, face = "bold"),
panel.grid.major.y = element_blank(),
panel.grid.major.x = element_line(size=.4, color="#F7F7F7")))
Use either stringr::str_pad() or theme(legend.spacing.x = ...) or both
g <- ggplot(totDays, aes(group, total84, colour = group)) +
geom_jitter(size = 1, width = 0.1) + # so points aren't overlaid, width controls how much jitter
geom_point(stat = "summary", fun.y = "mean", shape = 3, size = 3, colour = "black") + # crosses for mean
geom_boxplot(alpha = 0, width = 0.5, lwd = 1, size = 0.5) +
scale_color_manual(values = c("#00AFBB", "#E7B800"),
### added
labels = stringr::str_pad(c("Drug", "Placebo"), 10, "right")) +
scale_y_continuous(breaks = seq(0,84,14), minor_breaks = seq(0, 84, 14)) + # changes minor break line
coord_flip() +
labs(y = "Score") +
geom_hline(yintercept = c(groupDF$m), linetype = "dotted") +
geom_segment(x = 2.38, xend = 2.38, y = groupDF$m[2] + .1, yend = groupDF$m[1] - .1, size = .7,
arrow = arrow(end = "both", type = "open", length = unit(0.15, "cm")), colour = "#696969") +
annotate("text", x = 2.46, y = mean(groupDF$m), label = paste0("italic(p) == ", 0.02), parse = T) +
theme_bw() +
theme(axis.title.y = element_blank(),
axis.ticks.y = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(size = 13),
axis.title.x = element_text(size = 13, face = "bold",
margin = margin(t = 0, r = 0, b = 10, l = 0), vjust = -2),
legend.title = element_blank(),
legend.position = "top",
### added
legend.spacing.x = unit(0.25, 'cm'),
legend.spacing.y = unit(.1, "cm"),
legend.box.spacing = unit(.1, "cm"), # adjusts distance of box from x-axis
legend.key.size = unit(1, "cm"),
legend.text = element_text(size = 13, face = "bold"),
strip.text = element_text(size = 13, face = "bold"),
panel.grid.major.y = element_blank(),
panel.grid.major.x = element_line(size=.4, color="#F7F7F7"))
Created on 2019-03-11 by the reprex package (v0.2.1.9000)

Resources