I am trying to graph two different datasets, reconstructed temperatures (10-16) and charcoal data (0-140), with two different time series values, using ggplot. Is this possible?
I used this code (see below) but unfortunately it produced a plot (see below) that limits the variability of the temperature reconstruction. Is there a way to adjust the y axis so we can see more variability in the temperature record?
Thank you very much for your support.
R code
df <- data.frame(Charfiretempdata$AGETEMPS, Charfiretempdata$FIREAGE, Charfiretempdata$Comp2TEMPS,Charfiretempdata$Char.Acc.Rate..Char...cm.2.yr.1.)
ggplot(df) +
geom_col(mapping = aes(x = Charfiretempdata$FIREAGE,
y = Charfiretempdata$Char.Acc.Rate..Char...cm.2.yr.1. * 16/150), size = 2, color = "darkblue",
fill = "white") +
geom_line(mapping = aes(x = Charfiretempdata$AGETEMPS, y = Charfiretempdata$Comp2TEMPS)) +
geom_point(mapping = aes(x = Charfiretempdata$AGETEMPS, y = Charfiretempdata$Comp2TEMPS), size
= 3, shape = 21, fill = "white")+
scale_y_continuous(
name = expression("Temperature ("~degree~"C)"),
sec.axis = sec_axis(~ . * 150/16 , name = "Charcoal (mm)"))
R plot
I create a random sample data that would share similar characteristics to your data.
library(dplyr)
library(ggplot2)
set.seed(282930)
df <- tibble(x_axis = c(1400, 1500, 1600, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015, 2016, 2017),
y_axis_1 = runif(20, min = 10, max = 16),
y_axis_2 = runif(20, min = 0, max = 150))
Here is the df
> df
# A tibble: 20 x 3
x_axis y_axis_1 y_axis_2
<dbl> <dbl> <dbl>
1 1400 15.7 5.28
2 1500 11.8 141.
3 1600 14.5 149.
4 2000 11.6 121.
5 2001 15.6 37.3
6 2002 15.0 72.5
7 2003 10.7 130.
8 2004 15.4 84.7
9 2005 11.5 118.
10 2006 10.4 17.4
11 2007 11.3 124.
12 2008 13.6 22.6
13 2009 13.0 14.5
14 2010 15.9 142.
15 2011 12.3 103.
16 2012 10.3 131.
17 2013 12.6 93.6
18 2015 14.6 12.4
19 2016 11.4 27.9
20 2017 15.3 116.
Here is the ggplot similar to your but with the different Axis adjustment
ggplot(df,
# as they sharing same X-axis you can define share variable aes in the
# main call of ggplot
aes(x = x_axis)) +
geom_col(mapping =
# added 10 to 2nd axis value as will scale from 10 instead of 0
aes(y = (y_axis_2 * 10 / 150) + 10),
# the size here is size of the border - and due to the nature of
# your data, the col suppose to be very thin to match with that one
# tick on x-axis - so the inner fill is covered by dark blue border
size = 2, color = "darkblue",
# The fill is not really useful as you cannot see it.
fill = "white") +
geom_line(mapping = aes(y = y_axis_1)) +
geom_point(mapping = aes(y = y_axis_1), size
= 3, shape = 21, fill = "white") +
# Set the main Axis start at 10 instead of 0 so it would allow more zoom into it
coord_cartesian(ylim = c(10, 20), expand = c(0, 0)) +
scale_y_continuous(
name = expression("Temperature ("~degree~"C)"),
# The calculation of second axis lable is calculate base on 1st axis.
# and as the 1st axis start at 10, there fore the fomular need to minus 10
# before multiply back 15 - I keep 150 / 10 so it clear reverse of original
# transform of the 2nd axis value above.
sec.axis = sec_axis(~ (. - 10) * 150 / 10 , name = "Charcoal (mm)"))
Here is the sample output plot
And even with the adjsut y-axis we can hardly see the temperature at the end of the data because there are a lot more data points at the end. I think if you don't need all of data point at the end you may just take every 10 x as the data was on the range of 600 years so you don't need to graph so much details at the end. And if you need details just graph that time frame separately
Filter data at the end to only take every 10 year instead
ggplot(df %>% filter(x_axis <= 2000 | x_axis %% 10 == 0),
aes(x = x_axis)) +
# similar code to above but I use geom_bar instead
geom_bar(mapping =
aes(y = (y_axis_2 * 10 / 150) + 10),
stat = "identity", size = 2, color = "darkblue",
fill = "white") +
geom_line(mapping = aes(y = y_axis_1)) +
geom_point(mapping = aes(y = y_axis_1), size
= 3, shape = 21, fill = "white")+
scale_y_continuous(
name = expression("Temperature ("~degree~"C)"),
sec.axis = sec_axis(~ (. - 10) * 150/10 , name = "Charcoal (mm)")) +
coord_cartesian(ylim = c(10, 20), expand = c(0, 0))
(As you can see that with less data point, we started to see the fill as plot have more space)
Zoom in at the end of the data
ggplot(df %>% filter(x_axis >= 2000),
aes(x = x_axis)) +
# similar code to above but I use geom_bar instead
geom_bar(mapping =
aes(y = (y_axis_2 * 10 / 150) + 10),
stat = "identity", size = 2, color = "darkblue",
fill = "white") +
geom_line(mapping = aes(y = y_axis_1)) +
geom_point(mapping = aes(y = y_axis_1), size
= 3, shape = 21, fill = "white")+
scale_y_continuous(
name = expression("Temperature ("~degree~"C)"),
sec.axis = sec_axis(~ (. - 10) * 150/10 , name = "Charcoal (mm)")) +
coord_cartesian(ylim = c(10, 20), expand = c(0, 0))
(Now we can see both the darkblue border and the white fill inside)
Related
I have density plots for each shift and year. The means are plotted by grouping in a df called mu. I also add vertical reference lines which I can label without issue but I cannot seem to get the labels on the grouped vertical lines. You will see my latest attempt which throws an error "Aesthetics must be either length 1 or the same as the data (134): x"
My code
library(ggplot2)
library(dplyr)
df <- read.csv("f4_bna_no_cup.csv")
head(df)
ï..n yr s ys x
1 1 2021 1 2021-1 116.83
2 2 2021 1 2021-1 114.83
3 3 2021 1 2021-1 115.50
4 4 2021 1 2021-1 115.42
5 5 2021 1 2021-1 115.58
6 6 2021 1 2021-1 115.58
#summarize means by ys (year-shift)
mu <- df %>%
group_by(ys,s) %>%
summarise(grp.mean = mean(x))
mu
ys s grp.mean
<chr> <int> <dbl>
1 2021-1 1 116.
2 2021-2 2 117.
3 2022-1 1 114.
4 2022-2 2 115.
llab<-mu
shift <- c("Shift 1", "Shift 2")
#density charts on df
ggplot(data=df, aes(x=x,group =ys, fill = yr, color = yr)) +
geom_density(alpha = 0.4) +
scale_x_continuous(limits=c(112,120))+
geom_vline(aes(xintercept = grp.mean), data = mu, linetype = "dashed", size = 0.5) +
geom_text(aes(x=llab$grp.mean, y=.6), label = llab$ys) + #this throws the error
geom_vline(aes(xintercept=114.8), linetype="dashed", size=0.5, color = 'green3') +
geom_text(aes(x=114.8, y=.6), label = "Target", angle = 90, color="black",size=3) +
geom_vline(aes(xintercept=114.1), linetype="solid", size=0.5, color = 'limegreen') +
geom_text(aes(x=114.1, y=.55), label = "Potential", angle = 90, color="black",size=3 ) +
geom_vline(aes(xintercept=113.4), linetype="solid", size=0.5, color = 'firebrick3') +
geom_text(aes(x=113.4, y=.62), label = "Label wt", angle = 90,
color="black",size=3, family = "Times New Roman", vjust=0) +
facet_grid(
.~s,
labeller = labeller(
s = c(`1` = "Shift 1", `2` = "Shift 2")
))+
theme_light()+
theme(legend.position = "none")
Output so far...I'm so close.
Persistence pays off. I figured it out and thought I would share it in case someone else has a similar problem:
All code remains the same as in my question except a slight change to grouping for the mu df, AND replace the line that I noted as throwing the error as follows:
#small change to group_by, retaining yr
mu <- df %>%
group_by(yr,s,ys) %>%
summarise(grp.mean = mean(x))
Replace: geom_text(aes(x=llab$grp.mean, y=.6), label = llab$ys), with
geom_text(data = mu, aes(label = yr), x = mu$grp.mean, y = .60, color = "black", angle = 90, vjust = 0)
I am trying to plot weight of a fetus over time.
The y-axis is fetal weight in grams
The x-axis needs to be formatted as the following:
7 weeks 3 days == 27.3
29 weeks 6 days == 29.6
etc
My data (df) looks something like this
weight age
2013 22.4
2302 25.6
2804 27.2
3011 29.1
I have tried something like this... but not sure how to adjust the scale...
ggplot(df, aes(x = age, y = weight)) +
geom_point() +
scale_x_continuous()
If I get the actual numeric value for the age (i.e. 22.4 == 22weeks + 4/7days == 22.57),
Is it possible to label the corresponding age value with the label i want?
For example...
weight age.label age.value
2013 22.4 22.57
2302 25.6 25.86
2804 27.2 27.29
3011 29.1 29.14
When I call this:
df <- df %>% mutate(age.label = as.character(age.label))
ggplot(df, aes(x = age.value, y = weight)) +
geom_point() +
scale_x_continuous(label = "age.label")
I get the following...
Error in f(..., self = self) : Breaks and labels are different lengths
Any help much appreciated
I borrowed from this answer and this one, to create a variable ticks labels that uses formatting to seperate the days and the weeks.
I have supplied three different methods.
Simply places ticks at every day point but does not number them.
Numbers the days and the weeks correctly and distinguishes between them by making weeks bold and days light grey.
Same as 2 but uses size. This method doesn't work very well, as it creates a large gap between the labels and the plot. It has been included for completeness... and in the hope somebody says how to fix it.
The plot below is the second method.
I think the vertical tick lines could also be coloured so that some of them disappear if you want as well.
library(ggplot2)
library(tidyverse)
df<-read.table(header=TRUE, text="weight age.label age.value
2013 22.4 22.57
2302 25.6 25.86
2804 27.2 27.29
3011 29.1 29.14")
#have ticks for every day using 1/7 distance tick marks
ggplot(df, aes(x = age.value, y = weight)) +
geom_point() +
scale_x_continuous(limits=c(22, 30),
minor_breaks = seq(from = 1, to = 33, by = 1/7),
breaks = 1:30)
#create a df of tick marks labels containing day number and week number
breaks_labels_df <- data.frame(breaks = seq(from = 1, to = 33, by = 1/7)) %>%
mutate(minors= rep(0:6, length.out = nrow(.)),
break_label = ifelse(minors == 0, breaks, minors))
#plot both day number and week number differentiating between them by the label formatting.
#remove the minor tick lines to reduce the busyness of the plot
ggplot(df, aes(x = age.value, y = weight)) +
geom_point() +
scale_x_continuous(limits=c(22, 30),
breaks = seq(from = 1, to = 33, by = 1/7),
labels = breaks_labels_df$break_label) +
theme(axis.text.x = element_text(color = c("grey60","grey60","black",rep("grey60",4)),
size = 8, angle = 0,
hjust = .5, vjust = .5,
face = c("plain","plain","bold",rep("plain",4))),
panel.grid.minor.x = element_blank()) +
labs(title = "Baby weight in relation to age", x = "Age in weeks and days", y = "weight in grams")
#Changing the font size places a large gap between the tick labels and the axis
ggplot(df, aes(x = age.value, y = weight)) +
geom_point() +
scale_x_continuous(limits=c(22, 30),
breaks = seq(from = 1, to = 33, by = 1/7),
labels = breaks_labels_df$break_label) +
theme(axis.text.x = element_text(vjust = 0, size = c(8,8,12,rep(8,4)),
margin = margin(t = 0), lineheight = 0))
In order to add labels to the plot, use the geom_text function in the ggplot2 package. One can use the "hjust" and "vjust" to fine tune the placement.
df<-read.table(header=TRUE, text="weight age
2013 22.4
2302 25.6
2804 27.2
3011 29.1")
library(dplyr)
library(ggplot2)
#calculate the proper decimal value for axis
df<-df %>%mutate(age.value=floor(age)+ (age-floor(age))*10/7) %>% round(2)
ggplot(df, aes(x = age.value, y = weight)) +
geom_point() +
scale_x_continuous(limits=c(20, 30)) +
geom_text(aes(label = age), hjust = -.2, vjust=.1)
I am struggling to replicate the x-axis design of a figure I have seen. Is it possible to use ggplot2 to recreate the a-axis?
I have tried to use the lemon package, but this didn't quite replicate the axis as I wanted.
I want the x-axis to look like the image on the left in this
EDIT
Apologies for any confusion, I have now edited in some example data and code as requested.
tidy_data:
Replicate Group Time
1 Control 0.09997222
2 Control 0.04466667
3 Control 0.08608333
4 Control 0.10712500
5 Control 0.11410000
6 Control 0.69333333
7 Control 0.42383333
8 Control 0.06105556
9 Control 0.08676667
1 Treatment 0.13700000
2 Treatment 0.02983333
3 Treatment 0.49608333
4 Treatment 0.97858333
5 Treatment 0.70900000
6 Treatment 0.18683333
7 Treatment 0.45283333
8 Treatment 1.30220833
9 Treatment 1.39908333
results_tbl:
mean_time sem upper_sem lower_sem treatment
0.1534459 0.03681368 0.1902596 0.1166323 Control
0.8238021 0.15860139 0.9824035 0.6652007 Treatment
Plot Code:
figure = ggplot() +
geom_quasirandom(
data = tidy_data,
aes(x = Group, y = Time, colour = Replicate),
size = 5,
varwidth = TRUE
) +
geom_point(
data = results_tbl,
aes(x = treatment, y = mean_time),
colour = "black",
size = 4
) +
geom_errorbar(
data = results_tbl,
aes(x = treatment, ymin = lower_sem, ymax = upper_sem),
alpha = 1,
size = 0.1,
width = 0.1,
colour = "black"
) +
scale_y_continuous(breaks = scales::pretty_breaks()) +
labs(x = "", y = "Mean time spent in zone ± SE (mins)") +
theme_cowplot(font_size = 16, line_size = 1) +
theme(axis.title.y = element_text(vjust = 2))
I'm new to ggplot and have a problem with plotting errorbars in a barplot.
A minimal working example looks like this:
abun_all <- data.frame("Tree.genus" = c(rep("Acer", 5), rep("Betula", 5), rep("Larix", 5), rep("Picea", 5), rep("Pinus", 5), rep("Quercus", 5)),
"P.sampled" = c(sample(c(seq(from = 0.001, to = 0.06, by = 0.0005)), 30)),
"Insects.sampled" = c(sample(c(seq(from = 1.667, to = 533, by = 1.335)), 30)),
"Category" = as.factor(c(sample(c(seq(from = 1, to = 3, by = 1)), 30, replace = T))),
"P.sampled_mean" = c(sample(c(seq(from = 0.006, to = 0.178, by = 0.0005)), 30)),
"P.sampled_sd" = c(sample(c(seq(from = 0.004, to = 0.2137, by = 0.0005)), 30)))
ggplot(data = abun_all, aes(x = as.factor(Tree.genus), y = P.sampled , fill = Category)) +
geom_bar(stat = "identity", position = position_dodge(1)) +
geom_errorbar(aes(ymin = P.sampled - (P.sampled_mean+P.sampled_sd), ymax = P.sampled + (P.sampled_mean+P.sampled_sd)), width = 0.1, position = position_dodge(1)) + scale_fill_discrete(name = "Category",
breaks = c(1, 2, 3),
labels = c("NrAm in SSM", "NrAm in FR", "Eurp in FR")) +
xlab("Genus") + ylab("No. of Focus sp. per total insect abundance")
NOTE : The values are just random and do not represent the actual data but should suffice to demonstrate the problem !
The problem seems to be that errorbars are plotted for the number of entires of each Tree.genus per Category. How can I get this to work ?
Edit: I created another Df by hand with just the max values of each P.sampled combination and now the plot looks the way I want it (except for the two missing errorbars).
abun_plot <- data.frame("Tree.genus" = rep(genera, each = 3),
"P.sampled" = c(0.400000000, 0.100000000, 0.500000000, 0.200000000, 0.100000000, 0.042857143, 0.016666667, 0.0285714286, 0.0222222222, 0.020000000, 0, 0.010000000, 0.060000000, 0.025000000, 0.040000000, 0.250000000, 0.150000000, 0.600000000),
"Category" = as.factor(rep(c(1,2,3), 3)),
"P.sampled_SD" = as.numeric(c(0.08493057, 0.02804758, 0.19476489, 0.04533747, 0.02447665, 0.01308939, 0.004200168, "NA", 0.015356359, 0.005724859, "NA", "NA", 0.01633612, 0.01013794, 0.02045931, 0.07584737, 0.05760980, 0.21374053)),
"P.sampled_Mean" = as.numeric(c(0.07837134, 0.05133333, 0.14089286, 0.04537983, 0.02686200, 0.01680721, 0.005833333, 0.028571429, 0.011363636, 0.01101331, "NA", 0.01000000, 0.02162986, 0.01333333, 0.01668582, 0.08705221, 0.04733333, 0.17870370)))
ggplot(data = abun_plot, aes(x = as.factor(Tree.genus), y = P.sampled , fill = Category)) +
geom_bar(stat = "identity", position = position_dodge(1)) +
geom_errorbar(aes(ymin = P.sampled - P.sampled_SD, ymax = P.sampled + P.sampled_SD), width = 0.1, position = position_dodge(1)) +
scale_fill_discrete(name = "Category",
breaks = c(1, 2, 3),
labels = c("NrAm in SSM", "NrAm in FR", "Eurp in FR")) +
xlab("Genus") + ylab("No. of Focus sp. per total insect abundance")
Since doing this by hand takes a lot of time and several other plots have the same problem, I would prefer working with the original df (abun_all). Can I just subset my df in the ggplot() function to get the desired output ?
Since you want to just show the maximum value for each combination of genus and category, you can use a couple of dplyr functions (in the tidyverse alongside ggplot2) to group by both genus and category, then take the top value for each. That way, you aren't building abun_plot by hand the way you did in the second block.
library(dplyr)
library(ggplot2)
abun_plot <- abun_all %>%
group_by(Tree.genus, Category) %>%
top_n(1, P.sampled_mean)
head(abun_plot)
#> # A tibble: 6 x 6
#> # Groups: Tree.genus, Category [6]
#> Tree.genus P.sampled Insects.sampled Category P.sampled_mean P.sampled_sd
#> <fct> <dbl> <dbl> <fct> <dbl> <dbl>
#> 1 Acer 0.041 295. 3 0.0125 0.044
#> 2 Acer 0.044 81.8 1 0.166 0.037
#> 3 Acer 0.0085 379. 2 0.155 0.134
#> 4 Betula 0.0505 183. 2 0.170 0.0805
#> 5 Betula 0.0325 61.7 3 0.0405 0.0995
#> 6 Betula 0.0465 326. 1 0.0985 0.188
After that, the plotting works as you initially expected:
ggplot(data = abun_plot, aes(x = as.factor(Tree.genus), y = P.sampled , fill = Category)) +
geom_col(position = position_dodge(1)) +
geom_errorbar(aes(ymin = P.sampled - P.sampled_sd, ymax = P.sampled + P.sampled_sd), width = 0.1, position = position_dodge(1)) +
scale_fill_discrete(name = "Category",
breaks = c(1, 2, 3),
labels = c("NrAm in SSM", "NrAm in FR", "Eurp in FR")) +
xlab("Genus") + ylab("No. of Focus sp. per total insect abundance")
It's also worth noting that as of a few releases back of ggplot2, you can use geom_col() in place of geom_bar(stat = "identity").
Created on 2018-10-03 by the reprex package (v0.2.1)
I am tryig to add several lines of text to this facet. Sorry about the mess of code
From the object means1 I want to add the values of the variables "pCensCom" "pCensEx" and "pCensReg" for each facet, as described in the following figure
This is the object 'censTot1' used to build the chart
censo censTot tipoAni censAn año pCensAn
1: 2010-01-01 42 Hembra adulta 27 2010 64.285714
2: 2010-01-01 42 Joven 4 2010 9.523810
3: 2010-01-01 42 Macho adulto 1 2010 2.380952
4: 2010-01-01 42 Ternero 10 2010 23.809524
5: 2010-01-02 42 Hembra adulta 27 2010 64.285714
---
7300: 2014-12-30 57 Ternero 16 2014 28.070175
7301: 2014-12-31 57 Hembra adulta 32 2014 56.140351
7302: 2014-12-31 57 Joven 7 2014 12.280702
7303: 2014-12-31 57 Macho adulto 2 2014 3.508772
7304: 2014-12-31 57 Ternero 16 2014 28.070175
The following describes the code used to design the figure
# Plot color background
# %%%%%%%%%%%%%%%%%%%%%%
bg0<-data.table()
for(i in 1:5){
bg<-data.table(xstart=c(as.Date(paste0(años[i],"-01-01"), format="%Y-%m-%d"),as.Date(paste0(años[i],"-03-21"), format="%Y-%m-%d"), as.Date(paste0(años[i],"-06-21"),format = "%Y-%m-%d"),as.Date(paste0(años[i],"-09-21"),format = "%Y-%m-%d"),
as.Date(paste0(años[i],"-12-21"),format = "%Y-%m-%d")),xend=c(as.Date(paste0(años[i],"-03-21"), format="%Y-%m-%d"),
as.Date(paste0(años[i],"-06-21"),format = "%Y-%m-%d"), as.Date(paste0(años[i],"-09-21"),format = "%Y-%m-%d"),
as.Date(paste0(años[i],"-12-21"),format = "%Y-%m-%d"),as.Date(paste0(años[i],"-12-31"),format = "%Y-%m-%d")),
Estacion=c("Invierno","Primavera","Verano","Otoño","Invierno"))
l=list(bg0,bg); bg0<-rbindlist(l, fill=TRUE)
}
bg0<-bg0[,Estacion:=factor(ordered(Estacion,levels=c("Invierno","Primavera", "Verano", "Otoño")))]
cbPalette<-c("#FF3300","#006633","#FFFF00","#0000FF")
plotbg<-ggplot()+ geom_rect(data = bg0, aes(xmin = xstart, xmax = xend, ymin = 0, ymax = Inf, fill = Estacion), alpha = 0.10)+ scale_fill_manual(values=cbPalette)+ guides(fill=FALSE)+theme_bw()
means1<-data.table(tipoAni=c("Hembra adulta","Joven","Macho adulto","Ternero"),pCensCom=c(62.3,17.8,0.9,19.37),pCensEx=c(61.4,16.1,1.9,20.6),pCensReg=c(63.0,17.9,1.6,24.7))
# Plot
# %%%%
plotbg + geom_line(data=censTot1,aes(x=censo,y=pCensAn))+ facet_grid(tipoAni ~ .)+ xlab("Censos diarios") + ylab("Animales (%)") +theme_bw()+ theme(strip.text.x = element_text(size=8),strip.text.y = element_text(size=10, face="bold"),strip.background = element_rect(colour="red", fill="#CCCCFF"))
Please I need help, I tried several times using the functions annotation_custom, grobTree and textGrob and I have not been able to achieve
Here is a simplified answer. First I simulate some data dat, then a second data.table backgr that has the information for the background, and lastly textdt, which holds the information about the text elements.
The code looks like this:
library(data.table)
library(ggplot2)
library(scales)
dat <- data.table(x = rep(1:100, 2),
group = rep(LETTERS[1:2], each = 100),
val = rnorm(200))
dat[, price := 100 + cumsum(val), by = group]
# plot empty
ggplot(dat, aes(x = x, y = price)) +
geom_line() +
facet_grid(group~.)
# plot with added polygons
# for the background colors
backgr <- data.table(minval = c(10, 40, 60, 90),
maxval = c(20, 60, 80, 100),
backgroup = LETTERS[1:4])
# for the text elements
textdt <- data.table(xval = c(10, 50, 70),
yval = c(105, 100, 95),
textlabel = c("foo", "bar", "lorum"),
group = c("A", "A", "B"))
# plot
ggplot() +
geom_rect(data = backgr, aes(xmin = minval, xmax = maxval, ymin = -Inf,
ymax = Inf, fill = backgroup)) +
geom_line(data = dat, aes(x = x, y = price)) +
geom_text(data = textdt, aes(x = xval, y = yval, label = textlabel,
group = group)) +
facet_grid(group~.) +
scale_fill_manual(values = alpha(c("red", "green", "blue", "yellow"), 0.5))
Which results in a plot like this, which you can adjust to fit your data: