I'm trying to avoid the bottom annotation being clipped. It's the descender on the "p" that gets chopped off. I've used the "inward" option on vjust.
df <- data.frame(x=c(as.Date("2020-01-01"),as.Date("2022-01-01"))
,y=c(0,1))
df
ggplot(df) +
geom_point(mapping=aes(x=x,y=y)) +
annotate("text",x=mean(df$x),y=-Inf,label="Clipped",hjust=0.5,vjust="inward",size=12,colour="red") +
annotate("text",x=mean(df$x),y=Inf,label="Not Clipped",hjust=0.5,vjust="inward",size=12,colour="blue")
A possible approach would be to use the min and max y values:
library(tidyverse)
df <- data.frame(
x = c(as.Date("2020-01-01"), as.Date("2022-01-01")),
y = c(0, 1)
)
ggplot(df) +
geom_point(aes(x, y)) +
annotate("text", x = mean(df$x), y = min(df$y), label = "Clipped", hjust = 0.5, vjust = "inward", size = 12, colour = "red") +
annotate("text", x = mean(df$x), y = max(df$y), label = "Not Clipped", hjust = 0.5, vjust = "inward", size = 12, colour = "blue")
Created on 2022-07-02 by the reprex package (v2.0.1)
Interesting. Looks like this issue is related to what is chosen as the base line to align the text labels. This could be seen clearly when switching to geom_label where we see that for the clipped label the base line chosen for the alignment is not the end of the "p". Hence the "p"s get clipped off:
ggplot(df) +
geom_point(mapping = aes(x = x, y = y)) +
annotate("label", x = mean(df$x), y = -Inf, label = "Clipped",
hjust = 0.5, vjust = "inward", size = 12, colour = "red", label.padding = unit(0, "lines")) +
annotate("label", x = mean(df$x), y = Inf, label = "Not Clipped",
hjust = 0.5, vjust = "inward", size = 12, colour = "blue", label.padding = unit(0, "lines"))
One possible fix would be to switch to ggtext::GeomRichtext:
library(ggplot2)
library(ggtext)
ggplot(df) +
geom_point(mapping = aes(x = x, y = y)) +
annotate(ggtext::GeomRichtext, x = mean(df$x), y = -Inf, label = "Clipped",
hjust = 0.5, vjust = "inward", size = 12, colour = "red",
label.size = 0, fill = NA, label.padding = unit(0, "lines")) +
annotate(ggtext::GeomRichtext, x = mean(df$x), y = Inf, label = "Not Clipped",
hjust = 0.5, vjust = "inward", size = 12, colour = "blue",
label.size = 0, fill = NA, label.padding = unit(0, "lines"))
If you don't want it to be clipped on the same position, you can use coord_cartesian(clip = "off"):
df <- data.frame(x=c(as.Date("2020-01-01"),as.Date("2022-01-01"))
,y=c(0,1))
library(ggplot2)
ggplot(df) +
geom_point(mapping=aes(x=x,y=y)) +
annotate("text",x=mean(df$x),y=-Inf,label="Clipped",hjust=0.5,vjust="inward",size=12,colour="red") +
annotate("text",x=mean(df$x),y=Inf,label="Not Clipped",hjust=0.5,vjust="inward",size=12,colour="blue") +
coord_cartesian(clip = 'off')
Created on 2022-07-02 by the reprex package (v2.0.1)
Related
I am trying to label the series of concentric circles below with the labels from C in the data frame
I am aware that I could use something like geom_text_repel but I cannot seem to get it to work.
In addition, I cannot seem to get rid of the tick marks on the upper left.
df <- data.frame(C=c(rep("The macro-environment",4),rep("The industry",4),rep("Competitors",4),rep("The organisation",4)))
ggplot(df, aes(factor(1), fill = C)) +
geom_bar(width = 1, colour = NA, show.legend = FALSE, alpha = .8) +
coord_polar() +
labs(
x = "",
y = ""
) +
scale_fill_manual(values = c("#289045", "#beddc7", "#d4dfe9", "#286291")) +
theme(axis.ticks.x = element_blank(),
axis.ticks.y = element_blank()) +
theme_minimal()
A second option would be to add your labels as curved labels using the geomtextpath package:
library(ggplot2)
library(geomtextpath)
ggplot(df, aes(factor(1), fill = C)) +
geom_bar(width = 1, colour = NA, show.legend = FALSE, alpha = .8) +
geom_textpath(aes(x = .5, label = C, group = C),
stat = "count", position = position_stack(vjust = .5),
vjust = 1
) +
coord_polar() +
labs(
x = "",
y = ""
) +
scale_fill_manual(values = c("#289045", "#beddc7", "#d4dfe9", "#286291")) +
theme_void()
You could do:
ggplot(df, aes(factor(1), fill = C)) +
geom_bar(width = 1, colour = NA, show.legend = FALSE, alpha = .8) +
geom_text(stat = 'count', aes(label = C), size = 6,
position = position_stack(vjust = 0.5),
vjust = c(0.5, 0.5, 0.5, 2)) +
coord_polar(start = pi) +
labs(x = NULL, y = NULL ) +
scale_fill_manual(values = c("#289045", "#beddc7", "#d4dfe9", "#286291")) +
theme_void()
Is there a way to create a figure similar to the one below without having any data on this?
You could do something like this. You could add another geom_curve and a couple of geom_vlines.
library(tidyverse)
ggplot() +
geom_abline() +
geom_curve(aes(x = 0, y = 0, xend = 1, yend = 1), curvature = -0.4) +
annotate("text", x = 0.5, y = 0.5, label = "Line of Equality", angle = 35, vjust = 2) +
labs(x = "Individuals Neighbourhoods\nAcross Space", y = "Scoioeconomic Position") +
theme_minimal() +
theme(axis.text = element_blank())
Created on 2022-04-27 by the reprex package (v2.0.1)
For the arrows you can use this code: arrow = arrow(length = unit(0.5, "cm")) in a geom_segment. It is a bit tricky without any numbers, but maybe you want something like this:
library(ggplot2)
ggplot() +
geom_abline(slope = 1) +
geom_curve(aes(x = 0, y = 0, xend = 1, yend = 1), curvature = -0.4) +
geom_curve(aes(x = 0, y = 1, xend = 1, yend = 0.1), curvature = 0.4, linetype = "dashed") +
geom_segment(aes(x=0.9,y=0.98,xend=0.9,yend=0.12), arrow = arrow(length = unit(0.5, "cm"))) +
geom_segment(aes(x=0.02,y=0.85,xend=0.02,yend=0.23), arrow = arrow(length = unit(0.5, "cm"))) +
annotate("text", x = 0.5, y = 0.5, label = "Line of Equality", angle = 45, vjust = 2) +
annotate("text", x = 0.25, y = 0.75, label = "Income (etc.)", angle = 45, vjust = 2) +
annotate("text", x = 1.2, y = 0.1, label = "Corresponding\nExposure", angle = 0) +
labs(x = "Individuals Neighbourhoods\nAcross Space", y = "Scoioeconomic Position") +
scale_x_continuous(limits = c(0, 1.3)) +
theme_minimal() +
theme(axis.text = element_blank())
Output:
I have my labels roughly aligned to each side of my stacked bar chart. The problem is that they look like a mess because they aren't right and left justified on either side of the bar. How do I fix this so that they look professional?
df3 <- data.frame(
Label = c("Dasher", "Dancer", "Comet", "Cupid", "Prancer", "Blitzen", "Rudolph"),
Amount = c(650.01, 601.01, 340.05, 330.20, 260.01, 250.80, 10.10)
)
# Sort order
level_order <- df3 %>%
arrange(desc(Amount))
ggplot(level_order, aes(fill=fct_inorder(Label), y=Amount, x="")) +
geom_bar(position="stack", stat="identity", width = 0.55) +
scale_fill_brewer(palette = "Blues", direction = -1) +
theme_void() +
geom_text(aes(label = paste0("$", Amount)),
position = position_stack(vjust = 0.5),
hjust = -3.1,
size = 5) +
geom_text(aes(label = Label),
position = position_stack(vjust = 0.5),
hjust = 5,
size = 5) +
theme(legend.position = "none") +
theme(plot.title = element_text(size = 50, hjust = .5, vjust = 0)) +
ggtitle("Food Costs by Reindeer")
hjust determines the text alignment (with 0 being left-aligned, and 1 right-aligned). The x co-ordinate of your geom_text at the moment is defaulted to 1, so changing this will change the position of the text.
ggplot(level_order, aes(fill=fct_inorder(Label), y=Amount, x="")) +
geom_bar(position="stack", stat="identity", width = 0.55) +
scale_fill_brewer(palette = "Blues", direction = -1) +
theme_void() +
geom_text(aes(x=0.6, label = paste0("$", Amount)),
position = position_stack(vjust = 0.5),
hjust = 0.5,
size = 5) +
geom_text(aes(x=1.4, label = Label),
position = position_stack(vjust = 0.5),
hjust = 0.5,
size = 5) +
theme(legend.position = "none") +
theme(plot.title = element_text(size = 50, hjust = .5, vjust = 0)) +
ggtitle("Food Costs by Reindeer")
You can also pass hjust as an aesthetic. In order to do that, you will need to prepare the labelling as a separate data frame. Then, you only need to call geom_text once. I don't say this is necessarily better, but just pointing out that this is possible. A few more comments in the code, also regarding a few common pitfalls.
library(tidyverse)
df3 <- data.frame(
Label = c("Dasher", "Dancer", "Comet", "Cupid", "Prancer", "Blitzen", "Rudolph"),
Amount = c(650.01, 601.01, 340.05, 330.20, 260.01, 250.80, 10.10)
) %>%
## arrange step here
arrange(desc(Amount))
## I like to prepare the data outside ggplot
label_df <- df3 %>%
mutate(Amount_lab = paste0("$", Amount)) %>%
pivot_longer(-Amount) %>%
## this adds a column for your adjustment, and the x position compared with the central column
mutate(hjust = rep(0:1, nrow(.)/2),
x = rep(c(1.21, .79), nrow(.)/2))
ggplot(mapping = aes(y = Amount)) +
## geom_col is geom_bar(stat = "identity"), stack is default, so you can omit it
## call data in the geom layers
## set x to 1
## width = .4 so it matches your selected x from above
geom_col(data = df3, aes(x = 1, fill=fct_inorder(Label)), width = .4) +
scale_fill_brewer(palette = "Blues", direction = -1) +
## need to reverse both y and value, weirdly
geom_text(data = label_df, aes(x, y = rev(Amount), label = rev(value),
## this is the main trick
hjust = hjust),
position = position_stack(vjust = 0.5) ) +
## sadly, need to turn clip off
coord_cartesian(clip = "off") +
theme_void() +
## call theme only once!!
theme(legend.position = "none",
plot.title = element_text(size = 20, hjust = .5, vjust = 0),
## you need to add a margin
plot.margin = margin(r = .6, l = .6, unit = "in")) +
ggtitle("Food Costs by Reindeer")
Created on 2021-12-20 by the reprex package (v2.0.1)
Try fixing the x co-ordinate in the call to geom_text and managing alignment with hjust...
df3 <- data.frame(
Label = c("Dasher", "Dancer", "Comet", "Cupid", "Prancer", "Blitzen", "Rudolph"),
Amount = c(650.01, 601.01, 340.05, 330.20, 260.01, 250.80, 10.10)
)
library(ggplot2)
library(dplyr)
library(forcats)
level_order <- df3 %>%
arrange(desc(Amount))
ggplot(level_order, aes(fill=fct_inorder(Label), y=Amount, x="")) +
geom_bar(position="stack", stat="identity", width = 0.55) +
scale_fill_brewer(palette = "Blues", direction = -1) +
theme_void() +
geom_text(aes(x = 1.3, label = paste0("$", Amount)),
position = position_stack(vjust = 0.5),
hjust = 0,
size = 5) +
geom_text(aes(x = 0.6, label = Label),
position = position_stack(vjust = 0.5),
hjust = 0,
size = 5) +
theme(legend.position = "none") +
theme(plot.title = element_text(size = 50, hjust = .5, vjust = 0)) +
ggtitle("Food Costs by Reindeer")
Created on 2021-12-19 by the reprex package (v2.0.1)
Using Peter's answer above (reminding me of the "x" position argument I forgot existed), this was the final fix that got what I was looking for. hjust = 0 is left-justification and hjust = 1 is right justification.
library(tidyverse)
library(grid)
df3 <- data.frame(
Label = c("Dasher", "Dancer", "Comet", "Cupid", "Prancer", "Blitzen", "Rudolph"),
Amount = c(650.01, 601.01, 340.05, 330.20, 260.01, 250.80, 10.10)
)
# Sort order
level_order <- df3 %>%
arrange(desc(Amount))
ggplot(level_order, aes(fill=fct_inorder(Label), y=Amount, x="")) +
geom_bar(position="stack", stat="identity", width = 0.55) +
scale_fill_brewer(palette = "Blues", direction = -1) +
theme_void() +
geom_text(aes(x = 1.3, label = paste0("$", Amount)),
position = position_stack(vjust = 0.5),
hjust = 0,
size = 5) +
geom_text(aes(x = 0.7, label = Label),
position = position_stack(vjust = 0.5),
hjust = 1,
size = 5) +
theme(legend.position = "none",
plot.margin = unit(c(0,0,2,0), "cm"))
grid.text("Food Costs by Reindeer", x = unit(0.5, "npc"), y = unit(0, "npc"),
vjust = -0.5, gp = gpar(cex=4))
I'm trying to make a world map with a custom legend on the right side. The legend should be with the prepared text on the left and the generated numbers on the right. I tried but to no avail. I need help My code is as follows:
library(dplyr)
library(ggplot2)
library(ggrepel)
library(rworldmap)
world_map_without_antarctica <- getMap()[-which(getMap()$ADMIN=='Antarctica'),] #get data from web
world_map_without_antarctica_t <- fortify(world_map_without_antarctica)
Data <- data.frame( "lon"=c(17.816883, 38.544239,20.895352,20.819651,35.392102,99.060241,
43.756911, 10.288485, 16.566191, 14.076159,8.118301,16.596266,
121.544442,-73.077732,14.938152),
"lat"=c(44.1807678, 35.0126143, 42.5793648, 44.2330372, 38.9907297,
39.5015541, 33.0368223, 51.1337227, 45.0162344, 47.6139488,
46.7917377, 62.8114850, 15.7509443, 3.9272139, 46.1254221),
"NAME"=c("Bosnia and Herzegovina", "Syria", "Kosovo","Republic of Serbia",
"Turkey","United States of America","Iraq","Germany","Croatia",
"Austria","Switzerland","Sweden","Philippines","Colombia","Slovenia"),
"Count"=c(65800,32636,15005,9276,6979,6528,6449,
5830,4862,3109,2959,2777,2577,2315,1394))
Data$label <- paste0(Data$NAME,': ',Data$Count)
word_data_merged <- merge(world_map_without_antarctica_t, Data[ , c("NAME","Count")], by.x="id", by.y="NAME", all.x=T)
word_data_merged <- word_data_merged %>% arrange(id, order)
country_shapes <- geom_polygon(data = world_map_without_antarctica_t, aes(x = long, y = lat, group = group),fill = NA)
maptheme <-
theme(panel.grid = element_blank())+
theme(axis.text = element_blank())+
theme(axis.ticks = element_blank())+
theme(axis.title = element_blank())+
theme(legend.position = "bottom")+
theme(panel.grid = element_blank())+
theme(plot.margin = unit(c(0, 0, 0.5, 0), 'cm'))
guide = guide_colorbar(
title="legend_title",
label = TRUE,
draw.ulim = TRUE,
draw.llim = TRUE,
frame.colour = "black",
ticks = TRUE,
nbin = 10,
label.position = "bottom",
barwidth = 13,
barheight = 1.3,
direction = 'horizontal')
ggplot(word_data_merged) +
labs(title = "plot_title", subtitle = "plot_subtitle") +
country_shapes +
scale_fill_gradient(high = "#381802", low = "#fccaa7", guide = guide) +
geom_polygon(aes(long, lat, group = group, fill=Count),alpha=1) +
geom_point(data=Data[Data$label !="",],aes(x = lon, y = lat), shape = 21,fill= "#275083", color = "#275083", size = 1.5,alpha=0.5) +
geom_path(aes(x=long,y=lat, group = group), color="#c7c9c9", size= 0.5, alpha=0.4) +
geom_label_repel(data=Data,aes(x= lon,y= lat,label = label),
size = 5,
show.legend= F,
fontface = "bold",
point.padding = unit(0.2, "lines") ) +
maptheme +
theme(panel.background = element_rect(fill = "#ebf2f7"))
After running the code, the following world map is obtained:
How can I add a legend with free text entry? I would like the map to look like in this picture:
This might help:
a) changing plot.margin,
b) adding geom_text for the annotation (updated with #Tung's suggestion to use check_overlap = TRUE to sharpen up the text), and
c) coord_cartesian(clip = 'off') to allow drawing outside of the plot area
ggplot(word_data_merged) +
labs(title = "plot_title", subtitle = "plot_subtitle") +
country_shapes +
scale_fill_gradient(high = "#381802", low = "#fccaa7", guide = guide) +
geom_polygon(aes(long, lat, group = group, fill=Count),alpha=1) +
geom_point(data=Data[Data$label !="",],aes(x = lon, y = lat), shape = 21,fill= "#275083", color = "#275083", size = 1.5,alpha=0.5) +
geom_path(aes(x=long,y=lat, group = group), color="#c7c9c9", size= 0.5, alpha=0.4) +
geom_label_repel(data=Data,aes(x= lon,y= lat,label = label),
size = 5,
show.legend= F,
fontface = "bold",
point.padding = unit(0.2, "lines") ) +
geom_text(aes(label = "Statistics", x = 180, y = 80),
fontface = "bold",
hjust = -0.5,
size = 5,
check_overlap = TRUE) +
geom_text(aes(label = "Total unique countries = #", x = 180, y = 70),
hjust = -0.35,
size = 3,
check_overlap = TRUE) +
coord_cartesian(clip = 'off')+
maptheme +
theme(panel.background = element_rect(fill = "#ebf2f7"),
plot.margin = unit(c(0, 4, 0.5, 0), 'cm'))
#> Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider
#> increasing max.overlaps
Based on: ggplot2 - annotate outside of plot
Created on 2021-01-16 by the reprex package (v0.3.0)
I can't see, to figure out how to add labels to this plot:
ggplot(input_cleaned, aes(x =DAYS_TO_FA, y = fct_rev(DATE_TEXT), group = fct_rev(DATE_TEXT))) +
geom_density_ridges2(stat="binline", bins = 75, scale = 0.95, draw_baseline = FALSE) +
labs(title = 'Monthly Plots of Time to First Nose Pickin', y='Month Tracked', x = 'Days to First Pickin Action') +
theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5)) +
scale_x_continuous(breaks=seq(0,130,5)) +
geom_segment(aes(x=50, xend = 50, y=1,yend=5),
linetype = "dashed", size = 1.5,
color = "black") +
geom_segment(aes(x=75, xend = 75, y=5,yend=30),
linetype = "dashed", size = 1.5,
color = "black")
which produces:
I have tried this:
ggplot(input_cleaned, aes(x =DAYS_TO_FA, y = fct_rev(DATE_TEXT), group = fct_rev(DATE_TEXT))) +
geom_density_ridges2(stat="binline", bins = 75, scale = 0.95, draw_baseline = FALSE) +
geom_text(stat = "bin",
aes(y = fct_rev(input_cleaned$DATE_TEXT) + 0.95*(..count../max(..count..)), label = ifelse(..count..>0, ..count.., "")),
vjust = 1.4, size = 3, color = "white", binwidth = 1) +
labs(title = 'Monthly Plots of Time to First Nose Pickin', y='Month Tracked', x = 'Days to First Pickin Action') +
theme(plot.title = element_text(hjust = 0.5), plot.subtitle = element_text(hjust = 0.5)) +
scale_x_continuous(breaks=seq(0,130,5)) +
geom_segment(aes(x=50, xend = 50, y=1,yend=5),
linetype = "dashed", size = 1.5,
color = "black") +
geom_segment(aes(x=75, xend = 75, y=5,yend=30),
linetype = "dashed", size = 1.5,
color = "black")
based on the example found here:
Visualization of Groups of Poisson random samples using ggridges
but I can't get it to work. Nothing changes.
I know it may not be a good idea for this graph, but I am interested in seeing how it looks and more or less learning how to apply it.