1

I have a dataframe that has precipitation (cm) for Y and days for X.

> head(precip)
  Day     mean
1   1 1.784654
2   2 1.850796
3   3 1.850486
4   4 1.858424
5   5 1.884435
6   6 1.907781

until 366 days (averages include leap years). Both columns are currently as numeric. This is my code for line plotting it:

precip_plots <- ggplot(data = precip, aes_string(x = "Day", y = "mean", group=1)) +
  geom_line(size = 1)+
  theme_bw()+
  labs(title = "Daily precipitation",
      x = "Day",
      y = "Precipitation (cm)")

Which looks like this

I want the days to be on the X-axis, but below (also on X-axis) I want there to be month letters (JFMAMJJASOND) for each range of the month, like this plot with days and months

I have tried adding this to the ggplot:

scale_x_discrete(limits = 1:366, labels=Day[1:31] = "J", Day[32:60] = "F", Day[61:91] = "M", 
                   Day[92:121] = "A", Day[122:152] = "M", Day[153:182] = "J", Day[183:213] = "J",
                   Day[214:244] = "A", Day[245:274] = "S", Day[275:305] = "O", Day[306:335] = "N", 
                   Day[336:366] = "D")

but it just returns a bunch of "Error: unexpected '='" and "Error: unexpected ','".

I've looked everywhere online and on SO and I can't seem to find anyone with a similar issue.

ags
  • 43
  • 6
  • See https://stackoverflow.com/a/51312611/5221626 – Phil Aug 06 '21 at 16:30
  • Adding `coord_fixed(clip = 'off')` allows you to add text outside of the plot area. It's then a question of trial and error to get the text in the right location. – Phil Aug 06 '21 at 16:33
  • 1
    This nice answer may give you some inspiration: [Axis labels on two lines with nested x variables (year below months)](https://stackoverflow.com/a/44616739/1851712) – Henrik Aug 06 '21 at 16:37

1 Answers1

1

Update
Here is one way to do it using a function as labels argument in scale_x_continuous. This works only if the breaks contains all days as well as the regular breaks (100, 200 etc.). Since this messes up the break lines and axis ticks (they are not symmetrically anymore) I've hidden them with element_blank() and inserted custom break lines with geom_vline.

library(tidyverse)

# some toy data similar to the original data
dat <- tibble(Day = 1:366,
              mean = 2+rnorm(366))

# setup breaks
month <- c(31,60,91,121,152,182,213,244,274,305,335,365)
breaks <- seq(100,300,100)
mybreaks <- sort(c(month,breaks))

precip_plots <- ggplot(data = dat,
                       aes_string(x = "Day",
                                  y = "mean",
                                  group = 1)) +
  geom_line(size = 1) +
  scale_x_continuous(
    breaks = mybreaks,
    # custom function using `dplyr::case_when`
    labels = function(x) {
      
      case_when(
        x == 31  ~ "\nJ",
        x == 60  ~ "\nF",
        x == 91 ~ "\nM",
        x == 121 ~ "\nA",
        x == 152 ~ "\nM",
        x == 182 ~ "\nJ",
        x == 213 ~ "\nJ",
        x == 244 ~ "\nA",
        x == 274 ~ "\nS",
        x == 305 ~ "\nO",
        x == 335 ~ "\nN",
        x == 365 ~ "\nD",
        x %% 100 == 0 ~ as.character(x))
      
    }) +
  # creates fake break lines
  geom_vline(xintercept = breaks,
             color = "#d6d6d6",
             size = 0.5) + 
  theme_bw() +
  # hides original break lines and axis ticks
  theme(panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        axis.ticks.x = element_blank()
  ) +
  labs(title = "Daily precipitation",
       x     = "Day",
       y     = "Precipitation (cm)") 

precip_plots

Created on 2021-08-07 by the reprex package (v0.3.0)

TimTeaFan
  • 17,549
  • 4
  • 18
  • 39
  • This works great (albeit I don't understand all the code completely) but I would prefer if there were margins on the side of the line. Is there a code that is removing those default ggplot2 margins? Or how can I add the default margins back. – ags Aug 07 '21 at 20:44
  • 1
    @HarleyZhang: Great that it works. Do you mean the margin inside the plot area between the actual data line and the x and y axis? In this case you can delete the argument `expand = c(0, 0)` from the `scale_x_continuous` function. Does this help? I updated my answer accordingly. – TimTeaFan Aug 07 '21 at 20:46
  • Thanks, everything is perfect. One last question: how could I add horizontal grid lines for each of the y values (precipitation)? – ags Aug 07 '21 at 21:17
  • 1
    @HarleyZhang: I updated my answer and have now only hidden the original grid lines and ticks on the x axis. The y axis is now untouched and can be customized further with `scale_y_continous` if needed. – TimTeaFan Aug 07 '21 at 21:45