Add coloured underline in the text in bar-chart - r

Let say I have below bar chart
require(ggplot2)
require(dplyr)
df <- data.frame (Origin = c("Canada", "Canada","USA","USA"),
Year = c("2021", "2022","2021","2022"),
Sales = c(103, 192, 144, 210),
diff = c(89, " ",66," "),
perdiff = c(86.4, " ",45.83," "))
df <- df %>% mutate(label= ifelse(diff!=" ",paste0(diff,", ",perdiff,'%'),NA))
ggplot(df, aes(fill=Year, y=Origin, x=Sales)) +
geom_bar(position="dodge", stat="identity")+
geom_text(aes(label=label, x=200), fontface='bold') +
scale_x_continuous(breaks=seq(0,200,25))+
theme()
While this is fine, I want to add coloured underline under the figures (e.g. 89, 86.4%) which are displayed at the right side of each bar. I should also be able to control the width of such an underline.
Is there any way to achieve this programmatically?
Any pointer will be really helpful

Not sure what you mean by "control the width of such an underline". But one option to add colored underlines to your labels would to add your colored underlines a second geom_text where I use plotmath's underline and phantom to just add the underlines.
library(ggplot2)
library(dplyr)
df <- df %>%
mutate(label = ifelse(diff != " ", paste0(diff, ", ", perdiff, "%"), NA)) %>%
mutate(label1 = ifelse(diff != " ", paste0("underline(bold(phantom(\"", diff, ", ", perdiff, "%", "\")))"), NA))
ggplot(df, aes(fill = Year, y = Origin, x = Sales)) +
geom_bar(position = "dodge", stat = "identity") +
geom_text(aes(label = label, x = 200), fontface = "bold") +
geom_text(aes(label = label1, x = 200), color = "red", parse = TRUE) +
scale_x_continuous(breaks = seq(0, 200, 25))
#> Warning: Removed 2 rows containing missing values (geom_text).
#> Removed 2 rows containing missing values (geom_text).
EDIT To add some padding between the label and the line you could increase the vjust in the second geom_text, e.g.:
ggplot(df, aes(fill = Year, y = Origin, x = Sales)) +
geom_bar(position = "dodge", stat = "identity") +
geom_text(aes(label = label, x = 200), fontface = "bold") +
geom_text(aes(label = label1, x = 200), color = "red", parse = TRUE, vjust = 1) +
scale_x_continuous(breaks = seq(0, 200, 25))

Related

put legend of area chart inside the figure

here is my data and my area chart:
df<- data.frame(age=15:40,h1= 25:50,h2=35:60,h3=45:70)
data1<- df %>% gather(timeuse, minute, -age)
ggplot(data1, aes(x = age, y = minute, fill = timeuse)) +
geom_area() +
scale_fill_brewer(palette = "Gray")+
scale_x_continuous(breaks = seq(15, 90, by = 5))+
scale_y_continuous(breaks = seq(0, 1500, by = 100))+
theme_classic()
I want to put legend inside the area chart like this picture:
In general that could be easily achieved using geom_text with position = position_stack(vjust = 0.5). Depending on your real data the tricky part would be to select the x positions where you want to place the labels. In my code below I use dplyr::case_when to set different positions for each category of timeuse. Additionally depending on your real data it might be worthwhile to have a look at ggrepel::geom_text_repel.
library(ggplot2)
library(dplyr)
data1 <- data1 %>%
mutate(label = case_when(
timeuse == "h3" & age == 20 ~ timeuse,
timeuse == "h2" & age == 27 ~ timeuse,
timeuse == "h1" & age == 35 ~ timeuse,
TRUE ~ ""
))
p <- ggplot(data1, aes(x = age, y = minute, fill = timeuse)) +
geom_area() +
scale_fill_brewer(palette = "Greys")+
scale_x_continuous(breaks = seq(15, 90, by = 5))+
scale_y_continuous(breaks = seq(0, 1500, by = 100))+
theme_classic()
p +
geom_text(aes(label = label), position = position_stack(vjust = 0.5)) +
guides(fill = "none")
You can do it manually with annotate
annotate("text", x=50, y=2, label= "market work")
or more automated, something like this (play with the selection of rows where you want to place them):
geom_text(data = df%>% group_by(timeuse) %>% sample_n(1),
aes(x = Age, y = minute,
label = rev(timeuse), color = rev(timeuse)),
position = position_stack(vjust = 0.5))

Why am I unable to put text in my stacked bar chart (ggplot using geom_bar) without losing all of my data?

I am trying to include values in my stacked bar chart (eventually I would like to show the percentages, but right now I am struggling to get even the values already in the dataframe to show up) in the actual bars to show what the numbers are and make the graphic easier to read. When I add in "+ geom_text(aes(label = value))" the numbers appear, but cause all of the data (actual bars) to disappear. How can I add in the values but not have my bars disappear? And is there an easy way to put in other values to use (such as the percentages) and put them in the center? Thank you!
Here is my code:
library(ggplot2)
library(extrafont)
library(ggthemes)
Percentage <- c(rep("100%", 2), rep("80%", 2), rep("60%", 2), rep("40%", 2), rep("20%", 2), rep("0%", 2), rep("NA", 2))
case_control <- rep(c("Cases","Controls"), 7)
value <- c(6, 0, 78, 9, 88, 7, 181, 365, 230, 307, 691, 1501, 2, 358)
del_df <- data.frame(Percentage, case_control, value)
del_df$Percentage <- factor(del_df$Percentage, levels = c("NA", "0%", "20%", "40%", "60%", "80%", "100%"))
ggplot(del_df, aes(fill = case_control, y = value, x = Percentage)) + geom_bar(position = "fill", stat = "identity") + coord_flip() + theme_classic() + labs(x = "Gene Score Evidence Level", fill = "", y = "Cumulative Findings") + ggtitle("Deletions")
Here is what the graph looks like with the code above:
When I add in + geom_text(aes(label = value)) right after the geom_bar() information, this is what my graph looks like:
You just need a position argument in geom_text:
library(ggplot)
ggplot(del_df, aes(fill = case_control, y = value, x = Percentage)) +
geom_bar(position = "fill", stat = "identity") +
geom_text(position = "fill",label = value) +
coord_flip() +
theme_classic() +
labs(x = "Gene Score Evidence Level", fill = "", y = "Cumulative Findings") +
ggtitle("Deletions")
Or, if you prefer, you could use position_fill():
ggplot(del_df, aes(fill = case_control, y = value, x = Percentage)) +
geom_bar(position = "fill",
stat = "identity") +
geom_text(position = position_fill(vjust = .5),
label = value) +
coord_flip() +
theme_classic() +
labs(x = "Gene Score Evidence Level", fill = "", y = "Cumulative Findings") +
ggtitle("Deletions")

ggplot add text to the center of a donut chart in R

I am working on a donut chart using ggplot2, but I need the center of the plot to contain text.
Here's sample data (found from this site: https://www.datanovia.com/en/blog/how-to-create-a-pie-chart-in-r-using-ggplot2/):
library(dplyr)
count.data <- data.frame(
class = c("1st", "2nd", "3rd", "Crew"),
n = c(325, 285, 706, 885),
prop = c(14.8, 12.9, 32.1, 40.2)
)
count.data <- count.data %>%
arrange(desc(class)) %>%
mutate(lab.ypos = cumsum(prop) - 0.5*prop)
count.data
I then modified their code to get this donut chart:
library(ggplot2)
library(dplyr)
mycols <- c("#0073C2FF", "#EFC000FF", "#868686FF", "#CD534CFF")
ggplot(count.data, aes(x = 2, y = prop, fill = class)) +
geom_bar(stat = "identity", color = "white") +
coord_polar(theta = "y", start = 0)+
geom_text(aes(y = lab.ypos, label = paste0("n = ", n, ", \n", prop, "%")), color = "white")+
scale_fill_manual(values = mycols) +
theme_void() +
xlim(.5, 2.5)
The plot looks like this:
It is exactly what I want except I need the center of the donut to have the proportion from a variable. In this case, I want the center to say 40.2% (the prop of crew, in this example).
How do I do this?
Edit
Used annotate as suggested by #aosmith and made it a direct call to crew.
like this?
ggplot(count.data, aes(x = 2, y = prop, fill = class)) +
geom_bar(stat = "identity", color = "white") +
coord_polar(theta = "y", start = 0)+
geom_text(aes(y = lab.ypos, label = paste0("n = ", n, ", \n", prop, "%")), color = "white")+
scale_fill_manual(values = mycols) +
theme_void() +
xlim(.5, 2.5) +
annotate(geom = 'text', x = 0.5, y = 0, label = paste0(count.data$prop[count.data$class == 'Crew'], "%"))

How can I round values in geom_text that are contained within other text?

I have some code:
library(dplyr)
library(tidyr)
library(ggplot2)
eu_chats %>%
spread(type, count, fill = 0) %>% # Spread the count column in missed and completed
mutate(Total = Completed + Missed) %>% # Create the Total column
ggplot(aes(date, Total)) +
geom_col(aes(fill = "Total"),
colour = "black") + # total bar (with stat = "identity")
geom_col(aes(y = Missed, fill = "Missed"),
colour = "black") + # missed bar
geom_text(aes(label = paste("Total chats:", Total)), # add total label
hjust = -0.05, vjust = 1) +
geom_text(aes(label = paste("Missed chats:", Missed, "(", Missed/Total*100, "%)")), # add missed label and calculate percentage
hjust = -0.05, vjust = -0.5, color = "red") +
scale_fill_manual(name = "", # Manual fill scale
values = c("Total" = "forestgreen", "Missed" = "red")) +
facet_grid(retailer~.) + # Displayed per retailer
scale_y_continuous(limits = c(0, max(eu_chats$count) * 2))
Which produces this chart:
How can I round the values in the Missed chats: label to two decimal places?
Other solutions seem only to focus on those cases where no other text is present other than the value itself.
Can this be achieved in my case, whilst still preserving the label text?

Count and Percent Together using Stack Bar in R

I am trying to create stack bar with counts and percent in same graph. I took help from Showing data values on stacked bar chart in ggplot2 and add group total and plotted my as
By using code
### to plot stacked bar graph with total on the top and
### distribution of the frequency;
library(ggplot2);
library(plyr);
library(dplyr);
Year <- c(rep(c("2006-07", "2007-08", "2008-09", "2009-10"), each = 4))
Category <- c(rep(c("A", "B", "C", "D"), times = 4))
Frequency <- c(168, 259, 226, 340, 216, 431, 319, 368, 423, 645, 234, 685, 166, 467, 274, 251)
Data <- data.frame(Year, Category, Frequency);
sum_count <-
Data %>%
group_by(Year) %>%
summarise(max_pos = sum(Frequency));
sum_count;
Data <- ddply(Data, .(Year), transform, pos =
cumsum(Frequency) - (0.5 * Frequency));
Data;
# plot bars and add text
p <- ggplot(Data, aes(x = Year, y = Frequency)) +
geom_bar(aes(fill = Category), stat="identity") +
geom_text(aes(label=Frequency,y = pos), size = 3) +
geom_text(data = sum_count,
aes(y = max_pos, label = max_pos), size = 4,
vjust = -0.5);
print(p);
/Now I want to overlay percent of each group with counts This is my approach.merge data such a way that we can calculate
% for each of the group you are dealing with/
MergeData <- merge(Data,sum_count,by="Year");
MergeData <- transform(MergeData,
per_cent=round((pos/max_pos)*100,0));
MergeData<- ddply(MergeData, .(Year), transform, per_pos =
cumsum(per_cent) - (0.5 * per_cent));
# calculate percent and attach % sign;
MergeData <- transform(MergeData,
per_cent=paste(round((pos/max_pos)*100,0),"%"));
# Data only with percents
Percent_Data <- subset(MergeData,select
= c("Year","Category","per_cent","per_pos"));
/I am wondering if it is possible to overlay percent data to the image I created using previous code so that number and percent can be presented together./
I think you are almost there.
Use MergeData as the source for the data frame and add one more call to geom_text
p <- ggplot(MergeData, aes(x = Year, y = Frequency, group = Category)) +
geom_bar(aes(fill = Category), stat="identity") +
geom_text(aes(label=Frequency,y = pos), size = 3, vjust = 1) +
geom_text(
aes(y = max_pos, label = max_pos), size = 4,
vjust = -.5) +
geom_text(aes(x = Year, y = pos, label = per_cent), vjust = -1, size = 4)
print(p);
You may need to fiddle with hjust and vjust to get the text just how you like it.
Thank you for your response. I think it is very good.
p <- ggplot(MergeData, aes(x = Year, y = Frequency, group = Category)) +
geom_bar(aes(fill = Category), stat="identity") +
geom_text(aes(label=Frequency,y = pos), vjust = 1,size = 2,hjust = 0.5) +
geom_text(aes(y = max_pos, label = max_pos), size = 3,vjust = -.1) +
geom_text(aes(x = Year, y = pos, label = per_cent), vjust = -.4, size = 2)+
xlab("Year") + ylab(" Number of People") + # Set axis labels
ggtitle("Distribution by Category over Year") + # Set title
theme(panel.background =
element_rect(fill = 'white', colour = 'white'),
legend.position = "bottom" ,
legend.title = element_text(color="black",
size=7),
legend.key.width = unit(1,"inch") );
print(p);
now my % on top of number numbers,in other words, it is "17%" and "168" but I want "168" and "17%". I tried switching position of geom_text() but it did not work. I am wondering if you know how to fix it.
Yes it helped. I fixed number to make center of each stack. therefore i needed to make change in percent below code fixed my issue. Thank you so much for your help.
p <- ggplot(MergeData, aes(x = Year, y = Frequency, group = Category)) +
geom_bar(aes(fill = Category), stat="identity") +
geom_text(aes(label=Frequency,y = pos), vjust = 1,
size = 2,hjust = 0.5) +
geom_text(aes(y = max_pos, label = max_pos), size = 3,vjust = -.1) +
geom_text(aes(x = Year, y = pos, label = per_cent), vjust = 1.95,
size = 2,hjust=0.3)+
xlab("Year") + ylab(" Number of People") + # Set axis labels
ggtitle("Distribution by Category over Year") + # Set title;
theme(panel.background =
element_rect(fill = 'white', colour = 'white'),
legend.position = "bottom" ,
legend.title = element_text(color="black",
size=7) );
print(p);

Resources