Individual axes labels in facet_wrap without scales="free" - r

My data looks like this:
df <- data.frame(Year = as.factor(c(rep(2015, 3), rep(2016, 3), rep(2017,3))),
Tax = as.factor(c(rep(c("A", "B", "C"), 3))),
Depth = as.factor(c(10, 30, 50, 20,30,50,10,30,40)),
values= c(0.5, 0.25, 0.25, 0.1, 0.4, 0.5, 0.2, 0.6, 0.2))
I want to plot it with gaps for missing data and individual axis labels.
library(ggplot2)
The scale argument of facet_wrap gives individual axes, but is not performing as desired, as missing data is not reflected.:
ggplot(df, aes(Depth, values, fill=Tax)) + geom_bar(stat="identity")+
facet_wrap(~Year, scale="free") +
coord_flip()
Without scales:
ggplot(df, aes(Depth, values, fill=Tax)) + geom_bar(stat="identity")+
facet_wrap(~Year) +
coord_flip()
The missing data is represented (which i want!), but it lacks axis labels (which i need).
is there anything i can do?

It looks like this can be done using the lemon package:
library(tidyverse)
library(lemon)
df <- data.frame(Year = as.factor(c(rep(2015, 3), rep(2016, 3), rep(2017,3))),
Tax = as.factor(c(rep(c("A", "B", "C"), 3))),
Depth = as.factor(c(10, 30, 50, 20,30,50,10,30,40)),
values= c(0.5, 0.25, 0.25, 0.1, 0.4, 0.5, 0.2, 0.6, 0.2))
ggplot(df, aes(Depth, values, fill=Tax)) + geom_bar(stat="identity")+
facet_rep_wrap(~Year,repeat.tick.labels = T) +
coord_flip()

Related

How can I format the axis tick labels for each ggplot panel separately?

I need to create a multi-panel figure where the tick labels for the y-axis (factor) are italicized for some panels and plain text for other panels.
Here is a reproducible example, using made up data, of one thing I've tried:
library(ggplot2)
## Example data
df <- data.frame(var = c("Grass cover", "River depth", "Canis familiaris", "Canis lupus", "Canis latrans"),
coef = c(0.6, 0.4, 0.8, 0.1, 0.5),
se = c(0.3, 0.4, 0.4, 0.05, 0.2),
panel = c(rep("Environment", 2), rep("Canid abundance", 3)))
## multi-panel plot
ggplot(df, aes(y = var, x = coef, xmin = coef - se, xmax = coef + se)) +
geom_pointrange() +
facet_wrap(~ panel, scales = "free_y", ncol = 1) +
labs(y = NULL) +
theme(axis.text.y = element_text(face = c(rep("plain", 2), rep("italic", 3))))
Notice that only "Canis lupus" is italicized in the top panel. The desired figure would have all scientific names (y-axis labels) in the first panel be italics but labels in the bottom panel should be plain. In the real data, I have 4 panels, 2 of which need italics.
It appears that a vectorized face argument in element_text() is recycled between panels. I've also tried axis.text.y = element_text(face = rep("italic", 3), c(rep("plain", 2))) which results in all 5 y-axis labels being italicized.
If possible, I'd prefer not to use multiple ggplot objects (i.e., grid_arrange() or cowplot()). Though, I'm open to any solution that allows me to tweak all visual formatting elements.
I think there must be a solution using expression(), but I haven't been able to work it out.
Here is another option.
library(tidyverse)
df <- tibble(var = c("Grass cover", "River depth", "Canis familiaris", "Canis lupus", "Canis latrans"),
coef = c(0.6, 0.4, 0.8, 0.1, 0.5),
se = c(0.3, 0.4, 0.4, 0.05, 0.2),
panel = c(rep("Environment", 2), rep("Canid abundance", 3)))
df %>%
mutate(lab = map2_chr(var, panel,
~ifelse(.y == "Canid abundance",
paste0('italic("', .x,'")'),
paste0('"', .x,'"')))) %>%
ggplot(aes(y = lab, x = coef, xmin = coef - se, xmax = coef + se)) +
geom_pointrange() +
facet_wrap(~ panel, scales = "free_y", ncol = 1) +
labs(y = NULL) +
scale_y_discrete(label = function(x) parse(text = x))
One option to achieve your desired result would be to make use of the ggtext package which allows for using markdown syntax and/or HTML/CSS to style labels and theme elements.
Making use of theme(axis.text.y = ggtext::element_markdown()) the y axis labels will be parsed as markdown code.
Wrap the labels to be shown in italic inside * ... *.
library(ggplot2)
library(ggtext)
df <- data.frame(var = c("Grass cover", "River depth", "Canis familiaris", "Canis lupus", "Canis latrans"),
coef = c(0.6, 0.4, 0.8, 0.1, 0.5),
se = c(0.3, 0.4, 0.4, 0.05, 0.2),
panel = c(rep("Environment", 2), rep("Canid abundance", 3)))
df$var <- ifelse(df$panel %in% "Canid abundance", paste0("*", df$var, "*"), df$var)
## multi-panel plot
ggplot(df, aes(y = var, x = coef, xmin = coef - se, xmax = coef + se)) +
geom_pointrange() +
facet_wrap(~ panel, scales = "free_y", ncol = 1) +
labs(y = NULL) +
theme(axis.text.y = ggtext::element_markdown())

Rolling mean function similar to pandas in zoo

I want to create a rolling mean of some geochemical data. Currently, I have data for every 1 mm from 0mm to 45.7 mm and I want to average every 10 mm to create 1 cm averages.
This is the data at the moment but it still is not giving me 1 cm averages. Can someone tell me where I am going wrong? Thanks
wapPbTa<-read.csv("wappbta.csv",header=TRUE)
wapPbTa<-wapPbTa[-c(251:458), ]
library(ggplot2)
library(tidypaleo)
library(zoo)
width <- 10
RM<-rollmean(x = wapPbTa$PbTa, k = width,fill=NA)
##Averaged data
ggplot(wapPbTa, aes(x =RM , y = Depth))+
labs(y = "Depth (cm)")+
geom_lineh(size=1)+
geom_point(size=2)+
theme_classic()+
scale_y_reverse()
## Unaveraged data
ggplot(wapPbTa, aes(x =PbTa , y = Depth))+
labs(y = "Depth (cm)")+
geom_lineh(size=1)+
geom_point(size=2)+
theme_classic()+
scale_y_reverse()
structure(list(Depth = c(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7,
0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9), PbTa = c(0.163857678,
0.161569533, 0.086305592, 0, 0.006086142, 0, 0, 0.044096031,
0.050739958, 0.088385995, 0.104100946, 0.133012821, 0, 0.127524872,
0.046368715, 0.02514558, 0.109383676, 0.081979695, 0.0766503,
0.064679583)), row.names = c(NA, 20L), class = "data.frame")
This type of problems generally has to do with reshaping the data. The format should be the long format and the data is in wide format. See this post on how to reshape the data from wide to long format.
library(ggplot2)
library(dplyr)
library(tidyr)
library(tidypaleo)
library(zoo)
width <- 10
wapPbTa$RM <- rollmeanr(x = wapPbTa$PbTa, k = width, fill = NA)
wapPbTa %>%
pivot_longer(cols = -Depth) %>%
ggplot(aes(x = value, y = Depth, colour = name)) +
geom_lineh(size = 1) +
geom_point(size = 2) +
scale_y_reverse() +
scale_colour_manual(
breaks = c("PbTa", "RM"),
values = c("black", "blue")
) +
labs(y = "Depth (cm)") +
theme_classic()

manipulate scale_y_log in geom_bar ggplot2

I have the following df as example:
sites <- c('s1','s1','s2', "s2", "s3", "s3")
conc <- c(15, 12, 0.5, 0.05, 3, 0.005)
trop <- c("pp", "pt")
df <- data.frame(sites, conc, trop)
df$trop<- factor(df$trop, levels = c("pp", "pt"))
ggplot(df, aes(x= sites, y= conc))+
geom_bar(stat = "identity", colour="black")+
scale_y_log10()+
facet_grid(.~trop)+
theme_bw()
which gives as results the following figure, which is quite helpful for my data analysis since I want to highlight sites with values above 1.
However, under another assumption, I need to highlight sites above 1 and 0.1 using facet_grid, ending up with something like this (I edited this figure as desire output):
Do you know any option in scale_y_log10 in order to get the second figure under facet_grid?
One option is to reparameterise the bars as rectangles and plot that instead.
library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.0.3
sites <- c('s1','s1','s2', "s2", "s3", "s3")
conc <- c(15, 12, 0.5, 0.05, 3, 0.005)
trop <- c("pp", "pt")
df <- data.frame(sites, conc, trop)
df$trop<- factor(df$trop, levels = c("pp", "pt"))
char2num <- function(x){match(x, sort(unique(x)))}
ggplot(df) +
geom_rect(
aes(
xmin = char2num(sites) - 0.4,
xmax = char2num(sites) + 0.4,
ymin = ifelse(trop == "pt", 0.1, 1),
ymax = conc
),
colour = 'black'
) +
scale_y_log10() +
# Fake discrete axis
scale_x_continuous(labels = sort(unique(df$sites)),
breaks = 1:3) +
facet_grid(. ~ trop) +
theme_bw()
Created on 2021-02-26 by the reprex package (v1.0.0)

Repel geom label and text in ggplot. And ordering geom points based on size

I have 2 data frames such as these:
df1 <- data.frame(
party = c("Blue Party", "Red Party"),
dim1 = c(0.03, -0.04),
dim2 = c(-0.05, 0.02),
sz = c(34, 42)
)
df2 <- data.frame(
var = c("Economic", "Gov trust", "Inst trust", "Nationalism", "Religiosity"),
dim1 = c(0.1, -0.5, 0, 0.6, 0.4),
dim2 = c(0.1, 0.6, 0, 0, 0.3)
)
I want to plot the parties from df1 as points defined by size and include arrows based on df2 on the same graph. I've used ggplot to do this:
ggplot(df1, aes(x = dim1, y = dim2, color = party)) +
geom_point(size = df1$sz) +
scale_size_area() +
scale_x_continuous(limits = c(-1.5, 1.5)) +
scale_y_continuous(limits = c(-1.5, 1.5)) +
geom_label_repel(aes(label = party),
box.padding = 1,
point.padding = 1.5,
force = 1) +
geom_segment(aes(xend=0, yend=0, x=dim1, y=dim2), data=df2,
arrow=arrow(length=unit(0.20,"cm"), ends="first", type = "closed"), color="black") +
geom_text_repel(aes(x=dim1, y=dim2, label=var),
data = df2, color = "black", size = 3, force = 1)
Resulting in this:
The functions geom_label_repel and geom_text_repel prevent the party labels and the texts from overlapping, but how can I repel the labels and texts from each other?
My second problem is that I want to order the points, with the smallest in the front and the largest at the back. How could this be done?
Appreciate the help!

Adjust size of pie charts

I've made these pie charts:
df <- expand.grid(log.var = c(TRUE, FALSE), zone = 1:4)
df$proportion <- c(0.3, 0.7, 0.4, 0.6, 0.2, 0.8, 0.5, 0.5)
df$size = sample(1:20, 8)
library(ggplot2)
ggplot(df, aes(factor(1), proportion, fill = log.var)) +
geom_bar(stat = "identity") + coord_polar(theta = "y") + facet_grid(.~zone)
Is there any way of adjusting the size of each pie chart according to the sum of size in each zone?
#lukeA's suggestion is sensible but doesn't quite work:
library("ggplot2"); theme_set(theme_bw())
library("dplyr") ## for mutate()
set.seed(101)
df <- expand.grid(log.var = c(TRUE, FALSE), zone = 1:4)
df <- mutate(df,
proportion=c(0.3, 0.7, 0.4, 0.6, 0.2, 0.8, 0.5, 0.5),
size = sample(1:20, 8),
totsize=ave(size, zone,FUN=sum))
g0 <- ggplot(df, aes(x=factor(1), y=proportion, fill = log.var))
g0 + geom_bar(stat="identity",aes(width=totsize))+facet_grid(.~zone)+
coord_polar(theta = "y")
The problem here is that the bars are drawn (in rectangular coordinates) in the middle of the x-axis; we'd like them to be drawn with their x-coordinates running from 0 to the full width, but I'm not sure how to do that. The alternative would be to do a bunch of the cumulative proportion/stacking computations by hand (or at least outside ggplot2), then use geom_rect() ...
Here's how:
df <- df %>% group_by(zone) %>%
mutate(cp1=c(0,head(cumsum(proportion),-1)),
cp2=cumsum(proportion))
ggplot(df) + geom_rect(aes(xmin=0,xmax=totsize,ymin=cp1,ymax=cp2,
fill=log.var)) + facet_grid(.~zone)+
coord_polar(theta = "y")

Resources