2

I have a data frame like so:

df<- data.frame(month= rep(c("Jan", "Feb", "Mar", "Apr", "May"), 3), 
       year= c(seq(2001:2003,5), rep(2002, 5), rep(2003, 5)), 
       clim_var= c(rep("precip_mm", 5), rep("tmin",5), rep("tmax", 5)), 
       anomaly= sample(-20:20, 15, replace = TRUE))
df<-df[-c(3,10),]
library("zoo")
df$date<- as.yearmon(paste(df$year, df$month), format= "%Y %b")

You will notice that some dates may be missing, but for the most part it is time series data for various climate variables. I would like each climate variable to be a facet. The y axis will plot anomaly for each level of of the clim_var column. Such that I should get a multifacted figure which each graph similar to this:

enter image description here

I have tried this code (modified from)

library(ggplot2)
gg<- ggplot(df, aes(x= seq_along(date), y = anomaly)) + 
geom_bar(stat = 'identity', aes(fill = anomaly>0), position = 'dodge', col = 
'transparent') + 
theme_bw() + scale_fill_discrete(guide = 'none') + 
labs(x = '', y = 'anomaly')
gg + facet_grid(clim_var~.)
gg+ scale_x_datetime(labels = date_format("%b %Y"))

The issue seems to be plotting the date. It's as though it is not being recognized as a date so data for each clim_var take up 1/3 of the plot area and the x-axis is continuous values rather than dates. I want the output to have axis label that include the month and year like so...

enter image description here

In my real dataset there are many years of data, so it may be most clean to specify labels for only Jan and then leave other months as tick marks without labels. Any insight to that would be appreciated.

Edit:

Corrected data frame such that each clim-var has multiple years of data

precip_mm<- data.frame(clim_var= rep("precip_mm",36),  month= rep(c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" ), 3), 
                   year= c(rep(2001,12),rep(2002,12), rep(2003, 12)), 
                   anomaly= sample(-20:20, 36, replace = TRUE))
tmin<- data.frame(clim_var= rep("tmin",36),  month= rep(c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" ), 3), 
                   year= c(rep(2001,12),rep(2002,12), rep(2003, 12)), 
                   anomaly= sample(-20:20, 36, replace = TRUE))
tmax<- data.frame(clim_var= rep("tmax",36),  month= rep(c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" ), 3), 
                   year= c(rep(2001,12),rep(2002,12), rep(2003, 12)), 
                   anomaly= sample(-20:20, 36, replace = TRUE))
df<- rbind(precip_mm, tmin)
df<-rbind(df, tmax)
df<-df[-c(3,10, 50, 100),]

library("zoo")
df$date<- as.yearmon(paste(df$year, df$month), format= "%Y %b")

Adjustments suggested in comments

library(ggplot2)
gg<- ggplot(df, aes(x= date, y = anomaly)) + 
 geom_bar(stat = 'identity', aes(fill = anomaly>0), position = 'dodge', col = 
         'transparent') + 
theme_bw() + scale_fill_discrete(guide = 'none') + 
labs(x = '', y = 'anomaly')
gg + facet_grid(clim_var~.)
gg+ scale_x_yearmon()

Output does not facet each clim_var, however x-axis is correctly labeled.

Edit2:

labels_month <- format(seq(from = min(df$date), to = 
max(df$date), by = "1 months"), "%Y-%b")
labels_month[rep(c(FALSE, TRUE), c(1, 11))] <- ""
labels_month<- as.Date(labels_month, format= "%Y-%b")

x_breaks <- seq(min(df$date), max(df$date), by = "1 months")

p1 <- ggplot(df, aes(x = factor(date), y = df)) +
geom_col(aes(fill = anomoly > 0),
       position = "dodge",
       col = "transparent") +
theme_bw(base_size = 12) + 
scale_fill_discrete(guide = "none") +
labs(x = "", y = "") + 
scale_x_date(expand = c(0.015, 0.015),
           labels = labels_month, 
           breaks = x_breaks) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5))
facet_grid(climvar ~ ., 
         labeller = label_parsed,
         switch = "y",
         scales = 'free_y') 
p1
Danielle
  • 785
  • 7
  • 15
  • 1
    I'm not sure I'm understanding the `seq_along()`. Are you trying to get rid of the spaces for missing dates? If so, you can convert the `yearmon` to factors for plotting. If not, use `x = date` and use `+ scale_x_yearmon()` (this is a function from **zoo**). – aosmith Nov 07 '18 at 19:50
  • I have edited my post. After reading your comment I realized an error in my posted data. That aside, I have attempted your suggestion on the new data and am not getting a multi-faceted output. Any idea how to correct? – Danielle Nov 07 '18 at 20:18
  • I think your mistake was that you did assign `gg` to an object after you faceted, so you add the scale to the original graphic and not the faceted graphic. You'd want, e.g., `gg + facet_grid(clim_var ~ .) + scale_x_yearmon()` – aosmith Nov 07 '18 at 21:35

2 Answers2

0

You might be better off with facet_wrap if you have a large number of facets and it solves your scale problem like this:

gg<- ggplot(df, aes(x= seq_along(date), y = anomaly)) + 
  geom_bar(stat = 'identity', aes(fill = anomaly>0), position = 'dodge', col = 
             'transparent') + 
  theme_bw() + scale_fill_discrete(guide = 'none') + 
  labs(x = '', y = 'anomaly')
gg + facet_wrap(clim_var~., scales= "free_x")

enter image description here

You can use the nrow and ncol of facet_wrap to shape it as you please.

So with the date format:

df$date<- as.Date(paste(df$year, df$month, "1", sep="-"), format="%Y-%b-%d")

library(ggplot2)
library(scales)
gg<- ggplot(df, aes(x= date, y = anomaly)) + 
  geom_bar(stat = 'identity', aes(fill = anomaly>0), position = 'dodge', col = 
             'transparent') + 
  theme_bw() + scale_fill_discrete(guide = 'none') + 
  labs(x = '', y = 'anomaly')
gg + facet_wrap(clim_var~., scales= "free")+ scale_x_date(breaks = date_breaks("2 months"),labels = date_format("%m/%y"))

enter image description here

I prefer this method as it gives me a lot of flexibility for my date axis.

Jrakru56
  • 1,211
  • 9
  • 16
  • Note that the units of precipitation and temperature are different so this plot doesn't make that much sense – Tung Nov 07 '18 at 19:58
  • @Tung You are right. the `free` option should be used instead of `free_x`. I was only fixing the *shared* scale problem that was asked. – Jrakru56 Nov 07 '18 at 20:02
  • This is correct, they are different units. Also, with long term data I prefer horizontal facets for comparison. Better fit in publications and slides for >20year data. – Danielle Nov 07 '18 at 20:20
  • @Danielle I cant comment on your post since my reputation is less than 50 but you forgot to add the `scales= "free"` option for the `facet_wrap` – Jrakru56 Nov 07 '18 at 20:46
0

Is this what you are looking for?

library(zoo)
library(ggplot2)

set.seed(123)
precip_mm <- data.frame(
  clim_var = rep("precip_mm", 36),
  month = rep(c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"), 3),
  year = c(rep(2001, 12), rep(2002, 12), rep(2003, 12)),
  anomaly = sample(-20:20, 36, replace = TRUE))
tmin <- data.frame(
  clim_var = rep("tmin", 36),
  month = rep(c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"), 3),
  year = c(rep(2001, 12), rep(2002, 12), rep(2003, 12)),
  anomaly = sample(-20:20, 36, replace = TRUE))
tmax <- data.frame(
  clim_var = rep("tmax", 36),
  month = rep(c("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"), 3),
  year = c(rep(2001, 12), rep(2002, 12), rep(2003, 12)),
  anomaly = sample(-20:20, 36, replace = TRUE))
df <- rbind(precip_mm, tmin)
df <- rbind(df, tmax)
df <- df[-c(3, 10, 50, 100), ]
df$date <- as.yearmon(paste(df$year, df$month), format = "%Y %b")


# Setup nice labels for T and P
df$clim_var <- factor(df$clim_var, 
                      levels = c("tmax", "tmin", "precip_mm"),
                      labels = c(expression("T"[max]~anomaly~(degree*C)),
                                 expression("T"[min]~anomaly~(degree*C)),
                                 expression("Precip anomaly ("*"mm)")))
# Plot
p1 <- ggplot(df, aes(x = factor(date), y = anomaly)) +
  geom_col(aes(fill = anomaly > 0),
           position = "dodge",
           col = "transparent") +
  theme_bw(base_size = 12) + 
  scale_fill_discrete(guide = "none") +
  labs(x = "", y = "") + 
  facet_grid(clim_var ~ ., 
             labeller = label_parsed,
             switch = "y",
             scales = 'free_y') +
  theme(strip.placement = 'outside',
        strip.background = element_blank(),
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) 
p1

If you want to modify the x-axis, check this answer

df$date2 <- as.Date(paste(df$year, df$month, "01", sep = "-"), format = "%Y-%b-%d")
p2 <- ggplot(df, aes(x = date2, y = anomaly)) +
  geom_col(aes(fill = anomaly > 0),
           position = "dodge",
           col = "transparent") +
  theme_bw(base_size = 12) + 
  scale_fill_discrete(guide = "none") +
  labs(x = "", y = "") + 
  facet_grid(clim_var ~ ., 
             labeller = label_parsed,
             switch = "y",
             scales = 'free_y') +
  theme(strip.placement = 'outside',
        strip.background = element_blank())  +
  scale_x_date(date_breaks = "12 months", date_labels = "%b-%Y")
p2

Tung
  • 26,371
  • 7
  • 91
  • 115
  • Thank you @Tung. I have added an edit based on your suggestion, but am wondering if you can help me figure out why I am not able to number the axis every 12 months. – Danielle Nov 07 '18 at 23:28