I've used ggplot to create a number of diverging bar charts, using the following data and code:
library(ggplot)
library(gridExtra)
# Import percentage change dataset
LC_Pct_Change <- read.csv("LC_%_Change_SA.csv", header=T)
# Create plots for relevant periods
PC_1930_1960 <- ggplot(LC_Pct_Change, aes(x=Land_Cover_Category, y=Change_1930_1960))
geom_bar(stat="identity", fill=ifelse(LC_Pct_Change$Change_1930_1960<0,"darksalmon", "darkseagreen2"), show.legend = FALSE)
geom_text(aes(label = round(Change_1930_1960, 1), hjust = 0.5, vjust = ifelse(Change_1930_1960 < 0, 1.5, -1)), size = 2.5)
ggtitle("1930-1960")
xlab("Land Cover")
ylab("% Change")
theme_bw()
scale_x_discrete(limits = c("W", "R", "G", "A", "U"))
# Repeated the above for each period
# Then combine into a single plot to export
PC_All <- grid.arrange(PC_1930_1960, PC_1960_1990, PC_1990_2000, PC_2000_2007,
PC_2007_2015, PC_2015_2020, PC_1930_2020, ncol=3)
The code I've got adds labels above and below the bars in the geom_text
line, as below:
Instead, I'd like them to be in the centre (horizontally and vertically) of the bars. All the examples online I've found have been for bar charts with positive values only - even so I've tried several methods, but the most common way I've seen online is to add in something along the lines of position = position_stack(vjust = .5)
into geom_text
. But I can't get it to work.
Edit: Adding dataset:
LC_Pct_Change <- structure(list(
Land_Cover_Category = c("W", "R", "G", "A", "U"),
Change_1930_1960 = c(1.984932164, -3.628139858, -1.446064637, 2.20879849, 0.880473841),
Change_1960_1990 = c(1.56838857, -7.920867205, -1.967420952, 6.078769876, 2.241129711),
Change_1990_2000 = c(
1.54170708,
0.909136716, -7.092356282, -2.215064057, 6.856576543
),
Change_2000_2007 = c(-1.244727434, 5.104227969, -0.328826854, 3.025170368, -6.555844049),
Change_2007_2015 = c(1.254510492, -6.750375486, 5.846903583, -2.837464028, 2.486425439),
Change_2015_2020 = c(0.998194067, -0.084741498, -0.2985041, -1.250054436, 0.635105966),
Change_1990_2020 = c(2.549684204, -0.821752298, -1.872783653, -3.277412153, 3.4222639),
Change_1930_2020 = c(6.103004939, -12.37075936, -5.286269243, 5.010156213, 6.543867451)
), class = "data.frame", row.names = c(NA, -5L))
CodePudding user response:
Besides the option to place the labels in the middle of the bars via the y
aesthetic as outlined by @lab_rat_kid you could achieve your desired using position_stack
like so.
Using some fake example data:
library(ggplot2)
LC_Pct_Change <- data.frame(
Land_Cover_Category = c("W", "R", "G", "A", "U"),
Change_1930_1960 = seq(-2, 2, length.out = 5)
)
ggplot(LC_Pct_Change, aes(x = Land_Cover_Category, y = Change_1930_1960))
geom_bar(stat = "identity", fill = ifelse(LC_Pct_Change$Change_1930_1960 < 0, "darksalmon", "darkseagreen2"), show.legend = FALSE)
geom_text(aes(label = round(Change_1930_1960, 1)),
position = position_stack(vjust = .5), size = 2.5)
ggtitle("1930-1960")
xlab("Land Cover")
ylab("% Change")
theme_bw()
scale_x_discrete(limits = c("W", "R", "G", "A", "U"))
UPDATE Not sure what's the issue when using my code above with your real data. But based on your real data I simplified your code a bit, e.g. instead of copy and paste the same code which IMHO is error prone I have put the plotting code inside a function. Afterwards I use lapply
to loop over the columns to be plotted to create a list of plots. This list could then be plotted via grid.arrange
to create the final chart. Unfortunately grid.arrange
does not allow to pass the plots as a list. That's why I had to use do.call
to achieve this.
Note: Of course could you go on without lapply
and do.call
, e.g. you could do PC_1930_1960 <- plot_fun("Change_1930_1960")
to create your plots one by one.
Additionally, instead of providing the fill colors as argument I use the fill
aes and set the colors via scale_fill_manual
. Once more doing so is in general less error prone.
library(ggplot2)
plot_fun <- function(col) {
title <- gsub("^Change_", "", col)
title <- gsub("_", "-", title)
ggplot(LC_Pct_Change, aes(x = Land_Cover_Category, y = .data[[col]]))
geom_col(aes(fill = .data[[col]] < 0))
scale_fill_manual(values = c("FALSE" = "darkseagreen2", "TRUE" = "darksalmon"), guide = "none")
geom_text(aes(label = round(.data[[col]], 1)),
position = position_stack(vjust = .5), size = 2.5)
ggtitle(title)
xlab("Land Cover")
ylab("% Change")
theme_bw()
scale_x_discrete(limits = c("W", "R", "G", "A", "U"))
}
cols_to_plot <- names(LC_Pct_Change)[grepl("^Change", names(LC_Pct_Change))]
plot_list <- lapply(cols_to_plot, plot_fun)
names(plot_list) <- cols_to_plot
library(gridExtra)
do.call("grid.arrange", c(plot_list, ncol = 3))
CodePudding user response:
geom_text(aes(label = round(Change_1930_1960, 1), hjust = 0.5, y= (Change_1930_1960/2)), size = 2.5)
This should work, but you haven't supplied your data in a usable form (don't do pictures please), so I can't test.