I have a plot that looks at 2 quarts worth of data. I also included a target value (dashed line) and a YTD section (which is the cumsum(count).
I am having an issue trying to show the # in that section added for YTD but only for 1 of the quarters (since Q1 should already have a value inside the bar plot). Currently it is showing 0 and 2 in the plot below but I only want to show everything > Q1 values.
Current plot
I have tried with this current approach but does not seem to work:
**geom_text(aes(label = ifelse((quarter_2022= "Q1"), total_attainment, ifelse(quarter_2022="Q2",total_attainment+2)),
position = position_stack(vjust = 1))) +**
Plot Code
ggplot(df1, aes(x=quarter_2022, y=total_attainment)) +
geom_col(aes(y = YTD_TOTAL), fill = c("green1", "green2"), color = "black") +
geom_text(aes(y = YTD_TOTAL, label = scales::percent(YTD_PERCENT_ATTAINMENT)),
vjust = -0.5) +
geom_col(fill = "gray70", color = "gray20") +
geom_text(aes(label = YTD_TOTAL - total_attainment),
position = position_stack(vjust = 1.25))+
geom_text(aes(label = total_attainment),
position = position_stack(vjust = 0.5))+
geom_segment(aes(x = as.numeric(as.factor(quarter_2022)) - 0.4,
xend = as.numeric(as.factor(quarter_2022)) + 0.4,
y = attainment_target, yend = attainment_target),
linetype = "dashed") +
geom_text(aes(label = attainment_target),
position = position_stack(vjust = 4))
Here is the data:
structure(list(attainment_target = c(7.5, 15), quarter_2022 = c("Q1",
"Q2"), year = structure(c(1640995200, 1640995200), class = c("POSIXct",
"POSIXt"), tzone = ""), total_attainment = c(2, 4), percent_attainment_by_quarter = c(0.2666,
0.2666), ytd = c(2, 6), YTD_TOTAL = c(2, 6), YTD_PERCENT_ATTAINMENT = c(0.266666666666667,
0.4)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", "data.frame"
))
Create a logical column in your dataset that indicates whether the label is 0. In the geom_text that creates the label, set the color aesthetic to the logical column. Use scale_color_manual(values = c(NA, "black"), na.value = NA) to assign no color to the labels that were 0s.
Related
Hi supposed I have the following pie info.
df=structure(list(Var1 = c("a", "b"), Freq = c(306L, 1064L), per = c(0.223357664233577,
0.776642335766423)), row.names = c(NA, -2L), class = "data.frame")
and I plot this pie chart with direction -1
ggplot(data = df,
aes(x = "", y = per, fill = Var1)) +
geom_col() +
geom_text(aes(label = scales::percent(per, accuracy = 1)),
position = position_stack(vjust = 0.5),
color = "grey20", size = pietext ) +
coord_polar(theta = "y", direction =-1 ) +
theme_void ()
However what I would like is to label with with the frequency rather than the percentage.
Var1 Freq per
1 a 306 0.2233577
2 b 1064 0.7766423
Is this possible with this method? I tried replacing per with Freq but that just gave some really strange text.
thank you.
aes(label = Freq) is the way to go:
ggplot(data = df,
aes(x = "", y = per, fill = Var1)) +
geom_col() +
geom_text(aes(label = Freq),
position = position_stack(vjust = 0.5),
color = "grey20", size=12) +
coord_polar(theta = "y", direction =-1) +
theme_void ()
Just change geom_text(aes(label =Freq)
ggplot(data = df, aes(x = "", y = per, fill = Var1)) +
geom_col() +
geom_text(aes(label =Freq),
position = position_stack(vjust = 0.5),
color = "black", size = 10 ) +
labs( x="", y="", fill="")+
scale_fill_manual(values=c("#4E79A7", "#fc7d0b"))+
coord_polar(theta = "y", direction =-1 ) +
theme_no_axes()
Plot:
or something that is better than a pie chart
Sample code:
library(waffle)
library(ggthemes)
vals <- c(306,1064)
val_names <- sprintf("%s (%s)", c("a","b"), label=vals)
names(vals) <- val_names
waffle::waffle(vals) +
ggthemes::scale_fill_tableau(name=NULL)
Plot:
Sample code:
df=structure(list(Var1 = c("a", "b"), Freq = c(306L, 1064L), per = c(0.223357664233577, 0.776642335766423)), row.names = c(NA, -2L), class = "data.frame")
I'm having difficulty modifying the legends on my ggplot to plot to my liking.
The correct fill is not showing (the circles are all black atm, so I can't tel which group the points refer to)
The position is incorrect (position = "bottom" is not working)
Ideally, I would like the legends to use squares (the same as the shape used in my plot) rather than circles, but I'm not sure how to achieve this.
My data:
ors_fi = structure(list(col.x = c("Pre-frail", "Frail", "Pre-frail", "Frail",
"Pre-frail", "Frail"), col.estimate = c(0.865018872113144, 1.63924006466768,
0.972589483876898, 1.74300310363782, 0.836325226050668, 1.51301774619739
), col.stderr = c(0.0865502520576455, 0.0991158308454572, 0.0933472713471928,
0.109413945850029, 0.0901760485538073, 0.109136014040399), col.group = c("Wave 1",
"Wave 1", "Wave 2", "Wave 2", "Mean", "Mean")), row.names = c(NA,
-6L), class = c("tbl_df", "tbl", "data.frame"))
My code:
plot_ors_fi = ggplot(data = ors_fi,
aes(x = `col.x`, y = exp(`col.estimate`), group = as.factor(`col.group`))) +
# Plot the point estimates
geom_point(aes(size = 1,
shape = 22,
fill = as.factor(`col.group`)),
stroke = 0.5,
position = position_dodge(width = 0.4)) +
# Plot point estimates text
geom_text(aes(y = exp(`col.estimate`+1.96*`col.stderr`),
label = format(round(exp(`col.estimate`), 2), nsmall = 2)),
vjust = -0.8,
size = 3,
position = position_dodge(width = 0.4)) +
# Set the scale for the size of boxes
scale_radius(guide = "none",
limits = c(0, NA_real_),
range = c(0, 3)) +
# Plot the CIs
geom_linerange(aes(ymin = exp(`col.estimate`-1.96*`col.stderr`),
ymax = exp(`col.estimate`+1.96*`col.stderr`),
colour = "black"),
lwd = 0.5,
position = position_dodge(width = 0.4)) +
# Use identity for aesthetic scales
scale_shape_identity() +
scale_colour_identity() +
# Set the scale for fill colours
scale_fill_grey(start = 0,
end = 1,
limits=c("Wave 1", "Wave 2", "Mean"),
guide="legend",
position = "bottom", ## NOT WORKING?
name=NULL) +
# Set the y-axis scale
scale_y_continuous(trans = "log", breaks = c(1, 2, 4, 8)) +
# Set the x-axis scale
scale_x_discrete(limits = c("Pre-frail", "Frail")) +
# Add titles
xlab("Frailty Index") +
ylab("OR (95% CI)") +
ggtitle("")
This produces:
As you can see the legend at present is not very useful. I couldn't find a similar question in SO where the legend fill colour does not show at all?
I'd appreciate some advice and thanks in advance.
Shape needs to come out of the aes tag:
ggplot(data = ors_fi,
aes(x = `col.x`, y = exp(`col.estimate`), group = as.factor(`col.group`))) +
# Plot the point estimates
geom_point(aes(size = 1,
fill = as.factor(`col.group`)),
shape = 22,
stroke = 0.5,
position = position_dodge(width = 0.4))
# etc.
And legend position can be set by theme:
# Add titles
xlab("Frailty Index") +
ylab("OR (95% CI)") +
ggtitle("") +
theme(legend.position = "bottom")
Which is hopefully what you're looking for?
This is what is the output.I have a data set which contains unit, weight of each unit and compliance score for each unit in year 2016.
I was not able to add the table but here is the screenshot for the data in csv
I have named the columns in the data as unit, weight and year(which is compliance score) .
I want to create a sunburst chart where the first ring will be the unit divided based on weight and the second ring will be the same but will have labels compliance score.
The colour for each ring will be different.
I was able to do some code with the help from an online blog and the output I have gotten is similar to what I want but I am facing difficulty in positioning of the labels and also the colour coding for each ring
#using ggplot
library(ggplot2) # Visualisation
library(dplyr) # data wrangling
library(scales) # formatting
#read file
weight.eg = read.csv("Dummy Data.csv", header = FALSE, sep =
";",encoding = "UTF-8")
#change column names
colnames(weight.eg) <- c ("unit","weight","year")
#as weight column is factor change into integer
weight.eg$weight = as.numeric(levels(weight.eg$weight))
[as.integer(weight.eg$weight)]
weight.eg$year = as.numeric(levels(weight.eg$year))
[as.integer(weight.eg$year)]
#Nas are introduced, remove
weight.eg <- na.omit(weight.eg)
#Sum of the total weight
sum_total_weight = sum(weight.eg$weight)
#First layer
firstLevel = weight.eg %>% summarize(total_weight=sum(weight))
sunburst_0 = ggplot(firstLevel) # Just a foundation
#this will generate a bar chart
sunburst_1 =
sunburst_0 +
geom_bar(data=firstLevel, aes(x=1, y=total_weight),
fill='darkgrey', stat='identity') +
geom_text(aes(x=1, y=sum_total_weight/2, label=paste("Total
Weight", comma(total_weight))), color='black')
#View
sunburst_1
#this argument is used to rotate the plot around the y-axis which
the total weight
sunburst_1 + coord_polar(theta = "y")
sunburst_2=
sunburst_1 +
geom_bar(data=weight.eg,
aes(x=2, y=weight.eg$weight, fill=weight.eg$weight),
color='white', position='stack', stat='identity', size=0.6)
+
geom_text(data=weight.eg, aes(label=paste(weight.eg$unit,
weight.eg$weight), x=2, y=weight.eg$weight), position='stack')
sunburst_2 + coord_polar(theta = "y")
sunburst_3 =
sunburst_2 +
geom_bar(data=weight.eg,
aes(x=3, y=weight.eg$weight,fill=weight.eg$weight),
color='white', position='stack', stat='identity',
size=0.6)+
geom_text(data = weight.eg,
aes(label=paste(weight.eg$year),x=3,y=weight.eg$weight),position =
'stack')
sunburst_3 + coord_polar(theta = "y")
sunburst_3 + scale_y_continuous(labels=comma) +
scale_fill_continuous(low='white', high='darkred') +
coord_polar('y') + theme_minimal()
Output for dput(weight.eg)
structure(list(unit = structure(2:7, .Label = c("", "A", "B",
"C", "D", "E", "F", "Unit"), class = "factor"), weight = c(30,
25, 10, 17, 5, 13), year = c(70, 80, 50, 30, 60, 40)), .Names =
c("unit",
"weight", "year"), row.names = 2:7, class = "data.frame", na.action
= structure(c(1L,
8L), .Names = c("1", "8"), class = "omit"))
output for dput(firstLevel)
structure(list(total_weight = 100), .Names = "total_weight", row.names
= c(NA,
-1L), na.action = structure(c(1L, 8L), .Names = c("1", "8"), class =
"omit"), class = "data.frame")
So I think I might have some sort of solution for you. I wasn't sure what you wanted to color-code on the outer ring; from your code it seems you wanted it to be the weight again, but it was not obvious to me. For different colour scales per ring, you could use the ggnewscale package:
library(ggnewscale)
For the centering of the labels you could write a function:
cs_fun <- function(x){(cumsum(x) + c(0, cumsum(head(x , -1))))/ 2}
Now the plotting code could look something like this:
ggplot(weight.eg) +
# Note: geom_col is equivalent to geom_bar(stat = "identity")
geom_col(data = firstLevel,
aes(x = 1, y = total_weight)) +
geom_text(data = firstLevel,
aes(x = 1, y = total_weight / 2,
label = paste("Total Weight:", total_weight)),
colour = "black") +
geom_col(aes(x = 2,
y = weight, fill = weight),
colour = "white", size = 0.6) +
scale_fill_gradient(name = "Weight",
low = "white", high = "darkred") +
# Open up new fill scale for next ring
new_scale_fill() +
geom_text(aes(x = 2, y = cs_fun(weight),
label = paste(unit, weight))) +
geom_col(aes(x = 3, y = weight, fill = weight),
size = 0.6, colour = "white") +
scale_fill_gradient(name = "Another Weight?",
low = "forestgreen", high = "white") +
geom_text(aes(label = paste0(year), x = 3,
y = cs_fun(weight))) +
coord_polar(theta = "y")
Which looks like this:
I have a stacked bar plot, with highly unequal heights of bars. I would like to show the percentages on top of each bar.
What I have done so far is the following
df = structure(list(Type = c("Bronchoscopy", "Bronchoscopy", "Endoscopy",
"Endoscopy"), Bacteremia = structure(c(1L, 2L, 1L, 2L), .Label = c("False",
"True"), class = "factor"), count = c(2710L, 64L, 13065L, 103L
), perc = c(97.6928622927181, 2.3071377072819, 99.2178007290401,
0.782199270959903)), class = c("grouped_df", "tbl_df", "tbl",
"data.frame"), row.names = c(NA, -4L), groups = structure(list(
Type = c("Bronchoscopy", "Endoscopy"), .rows = list(1:2,
3:4)), row.names = c(NA, -2L), class = c("tbl_df", "tbl",
"data.frame"), .drop = TRUE))
ggplot(df, aes(x = Type, y = perc, fill = Bacteremia)) +
geom_bar(stat = "identity") +
ylab("percent") +
geom_text(aes(label = paste0(round(perc, 2), "%")), position =
position_stack(vjust = -0.1), color = "black", fontface = "bold")
I can't seem to get the vjust right. It seems like it's not behaving in the same way for the bottom versus the top bar.
What I would like to achieve is to place the percentages slightly higher than the top edge of each bar.
Any ideas?
Here's a possible approach:
ggplot(df, aes(x = Type, y = perc, fill = Bacteremia)) +
geom_bar(stat = "identity") +
ylab("percent") +
geom_text(aes(label = paste0("", round(perc, 2), "%\n"), y = perc),
color = "black", fontface = "bold", nudge_y = 2)
I should elaborate that ggplot2 is going to try to place the geom_text() relative to the data. If you are trying to align horizontally the text labels, you will need to either use annotate() or supply a labelling dataset with type, percent and Bacteremia and call that in geom_text() as below.
labdf <- cbind(df, ypos = c(103, 5, 103, 5))
ggplot(df, aes(x = Type, y = perc, fill = Bacteremia)) +
geom_bar(stat = "identity") +
ylab("percent") +
geom_text(data = labdf,
aes(label = paste0("", round(perc, 2), "%"), y = ypos, x = Type),
color = "black", fontface = "bold")
Here's one way to do it:
df <-
tibble(
Type = c("Bronchoscopy", "Bronchoscopy", "Endoscopy", "Endoscopy"),
Bacteremia = c("False", "True", "False", "True"),
count = c(2710L, 64L, 13065L, 103L)
) %>%
group_by(Type) %>%
mutate(Percent = round((count / sum(count) * 100), 1))
df %>%
ggplot(aes(x = Type, y = Percent, fill = Bacteremia)) +
geom_col() +
geom_label(
data = . %>% filter(Bacteremia == "True"),
aes(y = Percent + 5, label = str_c(Percent, "%")),
show.legend = FALSE
) +
geom_label(
data = . %>% filter(Bacteremia == "False"),
aes(y = 105, label = str_c(Percent, "%")),
show.legend = FALSE
)
The choices of 5 and 105 work on my computer, but may need to be tweaked a bit based on your specific settings and aspect ratio. The first geom_label call sets the y-axis based on the precise percentage, while the second one sets it at a constant level above the bars.
You might also want to play around with using geom_text vs. geom_label to experiment with different color and label settings. The nice thing about geom_label is that it will make it very clear which group is being labeled.
Here is a data frame:
library(tidyverse)
example_df <- structure(list(Funnel = c("Sessions", "AddToCart", "Registrations", "ShippingDetails", "Checkout", "Transactions"), Sum = c(1437574, 385281, 148181, 56989, 35613, 29671), End = c(NA, 1437574, 385281, 148181, 56989, 35613), xpos = c(0.5, 1.5, 2.5, 3.5, 4.5, 5.5), Diff = c(NA, 1052293, 237100, 91192, 21376, 5942), Percent = c("NA %", "73.2 %", "61.5 %", "61.5 %", "37.5 %", "16.7 %")), .Names = c("Funnel", "Sum", "End", "xpos", "Diff", "Percent"), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -6L))
And here is a ggplot2:
ggplot(example_df, aes(x = reorder(Funnel, -Sum), y = Sum)) +
geom_col(alpha = 0.6, fill = "#008080") +
stat_summary(aes(label = scales::comma(..y..)), fun.y = 'sum',
geom = 'text', col = 'white', vjust = 1.5) +
geom_segment(aes(x=xpos, y = End, xend = xpos, yend = Sum)) +
geom_text(aes(x=xpos,y = End-Diff / 2, label=Percent), hjust = -0.2) +
theme(axis.title.x = element_blank(),
axis.title.y = element_blank()) +
scale_y_continuous(labels = function(l) {l = l / 1000; paste0(l, "K")}) +
Here's what it looks like:
The values on the plot from Shipping Details: Transactions are tricky to read because the bars are smaller.
I wondered if there was a good approach to dealing with this. I tried extending the range with:
+ expand_limits(y = -100000)
But that just lowers the y axis.
Is there a sensible solution to visualizing the data points in a way they are not squished? If I could somehow lower the green bars into the minus region without impacting the proportions?
Very dirty solution, but works. Add dummy geom_bar's bellow each segment (ie., extend original segment by adding negative bar) with the same color and alpha.
Bars to add:
geom_bar(data = data.frame(x = example_df$Funnel, y = -2e4),
aes(x, y),
stat = "identity", position = "dodge",
alpha = 0.6, fill = "#008080")
Final code:
# Using OPs data
library(ggplot2)
ggplot(example_df, aes(x = reorder(Funnel, -Sum), y = Sum)) +
geom_col(alpha = 0.6, fill = "#008080") +
geom_segment(aes(x=xpos, y = End, xend = xpos, yend = Sum)) +
geom_text(aes(x=xpos,y = End-Diff / 2, label=Percent), hjust = -0.2) +
theme(axis.title.x = element_blank(),
axis.title.y = element_blank()) +
scale_y_continuous(labels = function(l) {l = l / 1000; paste0(l, "K")}) +
geom_bar(data = data.frame(x = example_df$Funnel, y = -2e4),
aes(x, y),
stat = "identity", position = "dodge",
alpha = 0.6, fill = "#008080") +
stat_summary(aes(label = scales::comma(..y..)), fun.y = 'sum',
geom = 'text', col = 'white', vjust = 1.5) +
theme_classic()
Plot:
PS:
You have to add stat_summary after geom_bar