Construction of multi-bar graph - r

How to construct a graph like on the attached link
I have no idea how to put and move the bars in ggplot2
Thank you in advance for your help
For ease of data transfer
data <- data.frame(klm=c(1L,2L,3L),
year=c(rep(2000,3),rep(2016,3)),
Category1=c(c(1313,1057,981),c(1456,1200,1124)),
Category2=c(c(1661,1057,981),c(1827,1444,1400)))
data$klm <- factor(data$klm, levels=1:3, labels=c("Belgium", "Netherlands","Germany"))
data$rok <- factor(data$year,levels=c(2000,2016))
ggplot(data, aes(x = klm))
+ geom_bar(aes(y = Category1[1:3]))
+ geom_bar(aes(y = Category1[4:6]),position = "dodge")
+ geom_bar(aes(y = Category2[1:3]))
+ geom_bar(aes(y = Category2[4:6]),position = "dodge")
I'm starting, I do not know ggplot well

Will help someone improve it visually
data <- data.frame(klm=c(1L,2L,3L),
year=c(rep(2000,3),rep(2016,3)),
Category1=c(c(1313,1057,981),c(1456,1200,1124)),
Category2=c(c(1661,1257,1301),c(1827,1444,1600)))
data$klm <- factor(data$klm, levels=1:3, labels=c("Belgium", "Netherlands","Germany"))
data$year <- factor(data$year,levels=c(2000,2016))
Średnia=
ggplot(data=data, aes(x=klm, y=Category2, fill=year)) +
geom_bar(stat="identity", position=position_dodge(),colour="black")+
scale_fill_manual(values = c("blue", "red"))+
geom_text(aes(y = Category2,label = format(Category2,big.mark = " ")),position = position_dodge(width = 1),vjust = -0.5, hjust = 0.5, cex = 3)
Średnia+
geom_bar(data=data, aes(x=klm, y=Category1, fill=year),stat="identity", width = 0.5,position=position_dodge(), colour="black")+
geom_text(aes(y = Category1,label = format(Category1,big.mark = " ")),position = position_dodge(width = 1),vjust = -0.5, hjust = 0.5, cex = 3)
I do not know how to change the colors of the second bars and how to make the right legend
Thank you for the tips

Related

How do you create this gauge chart using ggplot?

I'm pretty new to R, and the answers to similar questions I've found out there are going way over my head.
I have a data frame res of survey responses. There is a row for each respondent and a column for each question. I want to visualise responses to a particular question res$Q13 as a gauge chart showing the proportion of respondents who answered "Yes".
The closest thing to what I'm aiming to produce is this: https://pomvlad.files.wordpress.com/2018/05/pomvlad-dials.png
I want a gauge chart that looks just like that one, but I obviously don't need the facet layer, I just need a single gauge chart. I've pared the code (source: https://pomvlad.blog/2018/05/03/gauges-ggplot2/ credit: https://pomvlad.blog/author/pomvlad/) back to the bits I think I need, commenting out the lines I think are unnecessary, and added in some random colours to help me identify which lines of code produce which bits of the chart:
ggplot(res, aes(fill = "violet", ymax = 100, ymin = 0, xmax = 2, xmin = 1)) +
geom_rect(aes(ymax=1, ymin=0, xmax=2, xmin=1), fill = "#ece8bd") +
geom_rect() +
coord_polar(theta = "y", start = -pi/2) + xlim(c(0, 2)) + ylim(c(0, 2)) +
geom_text(aes(x = 0, y = 0, label = "title1", colour = "blue"), size = 6.5) +
geom_text(aes(x = 1.5, y = 1.5, label = "title2"), size = 4.2) +
#facet_wrap(~title, ncol = 5) +
theme_void() +
#scale_fill_manual(values = c("red" = "#C9146C", "orange" = "#DA9112", "green" = "#129188")) +
#scale_colour_manual(values = c("red" = "#C9146C", "orange" = "#DA9112", "green" = "#129188")) +
theme(strip.background = element_blank(),
strip.text.x = element_blank()) +
guides(fill = FALSE) +
guides(colour = FALSE)
All I get is the yellow background of the gauge and the titles. I'm confused about how to make the gauge chart show the percentage of respondents who answered "Yes". Can anyone help? Thank you in advance!
Got it, thanks for the help!
Q13.GaugeChart <- ggplot(res, aes(fill = rag(round(nrow(res[res$Q13 == "Yes",])/nrow(res),2)), ymax = nrow(res[res$Q13 == "Yes",])/nrow(res), ymin = 0, xmax = 2, xmin = 1)) +
geom_rect(aes(ymax=1, ymin=0, xmax=2, xmin=1), fill = "#ece8bd") +
geom_rect() +
coord_polar(theta = "y", start = -pi/2) + xlim(c(0, 2)) + ylim(c(0, 2)) +
geom_text(aes(x = 0, y = 0, label = paste(round(100*nrow(res[res$Q13 == "Yes",])/nrow(res),0),"%", sep = ""), colour = rag(round(nrow(res[res$Q13 == "Yes",])/nrow(res),2)), size = 6.5)) +
geom_text(aes(x = 1, y = 1.5, label = "TITLE"), size = 4.2) +
theme_void() +
theme(legend.position = "none") +
scale_fill_manual(values = c("red" = "#C9146C", "orange" = "#DA9112", "green" = "#129188")) +
scale_colour_manual(values = c("red" = "#C9146C", "orange" = "#DA9112", "green" = "#129188")) +
theme(strip.background = element_blank(),
strip.text.x = element_blank()) +
guides(fill = FALSE) +
guides(colour = FALSE)

How to scale a Geom_bar to be in line with an overlaid line graph in R ggplot

I am trying to overlay a bar chart with a line graph on a single plot with ggplot in R. My line graph works fine but the data are much larger than the data for the bar chart component.
How could I use an additional scale for this bar chart or do something that will get this to look nice all in one graph.
Here is my plot code thus far:
chart <- data.frame("QuantileName" = 1:5, "AvgLoss" = c(100, 500, 1000, 2500, 3000), "AvgFactor" = c(1.0, 1.1, 1.3, 1.4, 1.5))
Plot <- ggplot(chart, aes(x = 1:5)) +
scale_x_continuous(name = "Quintile", limits = c(0, 5 + .5), breaks = seq(1, 5)) +
geom_line(aes(y = AvgLoss, colour = "AvgLoss")) +
geom_bar(aes(y = AvgFactor, colour = "AvgFactor" ), stat = "identity") +
geom_text(aes(y = AvgLoss, label = round(AvgLoss)), position = position_nudge(x = .3)) +
geom_point(aes(y = AvgLoss)) +
ylab("AvgLoss") +
scale_colour_manual("",breaks = c("AvgLoss","AvgFactor"), values = c("AvgLoss" = "red", "AvgFactor" = "grey")) +
ggtitle("Quintile Plot") +
theme(plot.title = element_text(hjust=0.5))
Plot
Thank you for any help!
Essentialy, multiply your AvgFactor variable by a number
+ geom_bar(aes(y = AvgFactor*1000, colour = "AvgFactor" ), stat = "identity")
and set
+ scale_y_continuous(sec.axis = sec_axis(~ ./1000, name = "AvgFactor"))
so your plot code would look like
Plot <- ggplot(chart, aes(x = 1:5)) +
scale_x_continuous(name = "Quintile", limits = c(0, 5 + .5),
breaks = seq(1, 5)) +
geom_bar(aes(y = AvgFactor*1000, colour = "AvgFactor" ),
stat = "identity") +
geom_line(aes(y = AvgLoss, colour = "AvgLoss")) +
geom_text(aes(y = AvgLoss,
label = round(AvgLoss)),
position = position_nudge(x = .3)) +
geom_point(aes(y = AvgLoss)) +
ylab("AvgLoss") +
scale_colour_manual("",breaks = c("AvgLoss","AvgFactor"),
values = c("AvgLoss" = "red", "AvgFactor" = "grey")) +
ggtitle("Quintile Plot") +
theme(plot.title = element_text(hjust=0.5)) +
scale_y_continuous(sec.axis = sec_axis(~ ./1000, name = "AvgFactor"))
However, I think it is probably more elegant to avoid secondary axes whenever possible.
It may be useful to know that geom_col(...) is shorthand for geom_bar(..., stat = 'identity')

Aesthetics must be either length 1 or the same as the data (1): x, y, label

I'm working on some data on party polarization (something like this) and used geom_dumbbell from ggalt and ggplot2. I keep getting the same aes error and other solutions in the forum did not address this as effectively. This is my sample data.
df <- data_frame(policy=c("Not enough restrictions on gun ownership", "Climate change is an immediate threat", "Abortion should be illegal"),
Democrats=c(0.54, 0.82, 0.30),
Republicans=c(0.23, 0.38, 0.40),
diff=sprintf("+%d", as.integer((Democrats-Republicans)*100)))
I wanted to keep order of the plot, so converted policy to factor and wanted % to be shown only on the first line.
df <- arrange(df, desc(diff))
df$policy <- factor(df$policy, levels=rev(df$policy))
percent_first <- function(x) {
x <- sprintf("%d%%", round(x*100))
x[2:length(x)] <- sub("%$", "", x[2:length(x)])
x
}
Then I used ggplot that rendered something close to what I wanted.
gg2 <- ggplot()
gg2 <- gg + geom_segment(data = df, aes(y=country, yend=country, x=0, xend=1), color = "#b2b2b2", size = 0.15)
# making the dumbbell
gg2 <- gg + geom_dumbbell(data=df, aes(y=country, x=Democrats, xend=Republicans),
size=1.5, color = "#B2B2B2", point.size.l=3, point.size.r=3,
point.color.l = "#9FB059", point.color.r = "#EDAE52")
I then wanted the dumbbell to read Democrat and Republican on top to label the two points (like this). This is where I get the error.
gg2 <- gg + geom_text(data=filter(df, country=="Government will not control gun violence"),
aes(x=Democrats, y=country, label="Democrats"),
color="#9fb059", size=3, vjust=-2, fontface="bold", family="Calibri")
gg2 <- gg + geom_text(data=filter(df, country=="Government will not control gun violence"),
aes(x=Republicans, y=country, label="Republicans"),
color="#edae52", size=3, vjust=-2, fontface="bold", family="Calibri")
Any thoughts on what I might be doing wrong?
I think it would be easier to build your own "dumbbells" with geom_segment() and geom_point(). Working with your df and changing the variable refences "country" to "policy":
library(tidyverse)
# gather data into long form to make ggplot happy
df2 <- gather(df,"party", "value", Democrats:Republicans)
ggplot(data = df2, aes(y = policy, x = value, color = party)) +
# our dumbell
geom_path(aes(group = policy), color = "#b2b2b2", size = 2) +
geom_point(size = 7, show.legend = FALSE) +
# the text labels
geom_text(aes(label = party), vjust = -1.5) + # use vjust to shift text up to no overlap
scale_color_manual(values = c("Democrats" = "blue", "Republicans" = "red")) + # named vector to map colors to values in df2
scale_x_continuous(limits = c(0,1), labels = scales::percent) # use library(scales) nice math instead of pasting
Produces this plot:
Which has some overlapping labels. I think you could avoid that if you use just the first letter of party like this:
ggplot(data = df2, aes(y = policy, x = value, color = party)) +
geom_path(aes(group = policy), color = "#b2b2b2", size = 2) +
geom_point(size = 7, show.legend = FALSE) +
geom_text(aes(label = gsub("^(\\D).*", "\\1", party)), vjust = -1.5) + # just the first letter instead
scale_color_manual(values = c("Democrats" = "blue", "Republicans" = "red"),
guide = "none") +
scale_x_continuous(limits = c(0,1), labels = scales::percent)
Only label the top issue with names:
ggplot(data = df2, aes(y = policy, x = value, color = party)) +
geom_path(aes(group = policy), color = "#b2b2b2", size = 2) +
geom_point(size = 7, show.legend = FALSE) +
geom_text(data = filter(df2, policy == "Not enough restrictions on gun ownership"),
aes(label = party), vjust = -1.5) +
scale_color_manual(values = c("Democrats" = "blue", "Republicans" = "red")) +
scale_x_continuous(limits = c(0,1), labels = scales::percent)

How to align text on clustered bar chart in ggplot2?

I'm trying to align the percent frequency of each bar in my clustered bar chart. Right now, my chart looks like this:
Here's the code as well:
ggplot(graph_data, aes(x, Freq)) +
geom_bar(aes(fill = Pref), position = 'dodge', stat = 'identity') +
geom_text(aes(label = sprintf("%.0f%%", round(Freq/sum(Freq) * 100))),
hjust = -0.25) +
labs(list(x = attr(graph_data, 'seg_label'),
y = 'Frequency',
title = paste('Q:', attr(graph_data, 'question')))) +
scale_y_continuous(limits = c(0, 1.2 * max(graph_data$Freq))) +
guides(fill = F) +
coord_flip() +
annotate("text", x = Inf, y = Inf,
label = paste0("N = ", sum(graph_data$Freq)),
hjust = 1.5, vjust = 1.5)
I think the issue can be solved on this snippet of code, but I'm not sure how:
geom_text(aes(label = sprintf("%.0f%%", round(Freq/sum(Freq) * 100))), hjust = -0.25)
Any help would be greatly appreciated!
Edit: Here's a sample of my data's structure as well:
df <- data.frame(x = rep(c('1824', '2534', '3544'), 3),
Pref = rep(c('low', 'neutral', 'high')),
Freq = 1:9 * 10)
As mentioned in the comments I think this is a duplicate of Position geom_text on dodged barplot.
But I did it now, so I'll include the code.
ggplot(df, aes(x, Freq, fill = Pref)) +
geom_bar(position = 'dodge', stat = 'identity') +
geom_text(aes(label = sprintf("%.0f%%", round(Freq/sum(Freq) * 100))),
position = position_dodge(width = 0.9), hjust = -0.25) +
labs(list(x = attr(df, 'seg_label'),
y = 'Frequency',
title = paste('Q:', attr(df, 'question')))) +
scale_y_continuous(limits = c(0, 1.2 * max(df$Freq))) +
guides(fill = F) +
coord_flip()
You need to put fill in the original aes so the that geom_text knows which label to dodge by which amount.

How to label a barplot on the opposite side of a bar of -ve and +ve values with ggplot?

May I please seek your help to Label a barplot with ggplot2 like the following graph:
I am using the following code to obtain the attached plot:
library(ggplot2)
test <- data.frame(x = c("Moderately Poor", "Deeply Poor", "Deeply & Intensely Poor", "Intensely Poor", "Overall Poverty"), y = c(0.024, -0.046, -0.025, -0.037, -0.083))
test$colour <- ifelse(test$y < 0, "firebrick1", "steelblue")
test$hjust <- ifelse(test$y > 0, 1.03, -0.03)
ggplot(test, aes(x, y, label = x, hjust = hjust)) +
geom_text(aes(y = 0, colour = colour)) +
geom_bar(stat = "identity", aes(fill = colour))
last_plot() + coord_flip() + labs(x = "", y = "") +
scale_x_discrete(breaks = NA) + theme_bw() +
opts(legend.position = "none")
I was just wondering how can I get the second numeric label on each bar?
Thanks,
R graphics, including ggplot2, are pen-on-paper, i.e layers (each geom_...) will be drawn in order.
So, if you want to have a geom_text on top of a geom_bar, the geom_text will need to come after the geom_bar.
Updating for ggplot2 0.9.3 (the current version)
ggplot(test, aes(x, y)) +
geom_text(aes(y = 0, colour = colour, hjust =hjust, label = x), size=4.5) +
geom_bar(stat = "identity", aes(fill = colour)) +
geom_text(colour ='black',
aes(label = paste( formatC( round(y*100, 2 ), format='f', digits=2 ),'%'),
hjust = ifelse(y>0,1,0))) +
coord_flip() + labs(x = "", y = "") +
scale_x_discrete(breaks = NULL) + theme_bw() +
theme(legend.position = "none")
produces

Resources