0

I'm trying to get a graph with 2 y scales using 2 different dataframes. The first dataframe bargraph_dets_temp looks like this

bargraph_dets_temp = structure(list(Zone = structure(c(1L, 1L, 1L, 1L, 1L, 1L), .Label = c("1", 
                                                                             "2", "3", "4"), class = "factor"), month = structure(c(8L, 8L, 
                                                                                                                                    8L, 8L, 8L, 8L), .Label = c("Jan", "Feb", "Mar", "Apr", "May", 
                                                                                                                                                                "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"), class = c("ordered", 
                                                                                                                                                                                                                            "factor")), year = c(2016, 2016, 2016, 2016, 2016, 2017), location = c("HFX001", 
                                                                                                                                                                                                                                                                                                   "HFX002", "HFX003", "KETCH HARBOUR, NS", "NSTR001", "Gill Cove"
                                                                                                                                                                                                                            ), num_unique_tags = c(5, 4, 2, 5, 5, 6), total_res_time_in_seconds = c(10666, 
                                                                                                                                                                                                                                                                                                    14645, 6799, 0, 58959, 0), latitude = c(44.47846, 44.47222, 44.46643, 
                                                                                                                                                                                                                                                                                                                                            44.48427, 44.48422, 44.48467), longitude = c(-63.53341, -63.52704, 
                                                                                                                                                                                                                                                                                                                                                                                         -63.51983, -63.53338, -63.53246, -63.53316), geometry = structure(list(
                                                                                                                                                                                                                                                                                                                                                                                           structure(c(-63.53341, 44.47846), class = c("XY", "POINT", 
                                                                                                                                                                                                                                                                                                                                                                                                                                       "sfg")), structure(c(-63.52704, 44.47222), class = c("XY", 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            "POINT", "sfg")), structure(c(-63.51983, 44.46643), class = c("XY", 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          "POINT", "sfg")), structure(c(-63.53338, 44.48427), class = c("XY", 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        "POINT", "sfg")), structure(c(-63.53246, 44.48422), class = c("XY", 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      "POINT", "sfg")), structure(c(-63.53316, 44.48467), class = c("XY", 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    "POINT", "sfg"))), class = c("sfc_POINT", "sfc"), precision = 0, bbox = structure(c(xmin = -63.53341, 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        ymin = 44.46643, xmax = -63.51983, ymax = 44.48467), class = "bbox"), crs = structure(list(
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          epsg = 4326L, proj4string = "+proj=longlat +datum=WGS84 +no_defs"), class = "crs"), n_empty = 0L), 
                      distances = c(27.3573801954343, 26.4992220821035, 25.6385699365414, 
                                    27.8643036652756, 27.8152639871898, 27.8888441811952), ave_temp = c(6.417815, 
                                                                                                        6.417815, 6.417815, 6.417815, 6.417815, 5.786351)), row.names = c(NA, 
                                                                                                                                                                          -6L), groups = structure(list(month = structure(c(8L, 8L), .Label = c("Jan", 
                                                                                                                                                                                                                                                "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", 
                                                                                                                                                                                                                                                "Nov", "Dec"), class = c("ordered", "factor")), year = c(2016, 
                                                                                                                                                                                                                                                                                                         2017), .rows = list(1:5, 6L)), row.names = c(NA, -2L), class = c("tbl_df", 
                                                                                                                                                                                                                                                                                                                                                                          "tbl", "data.frame"), .drop = TRUE), class = c("grouped_df", 
                                                                                                                                                                                                                                                                                                                                                                                                                         "tbl_df", "tbl", "data.frame"))

from this dataframe I need the month, year, num_unique_tags, and Zone. My next dataframe mapoc_temp looks like this:

mapoc_temp = structure(list(month = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("Jan", 
"Feb", "Mar", "Apr", "May", "June", "Jul", "Aug", "Sept", "Oct", 
"Nov", "Dec"), class = c("ordered", "factor")), year = c(2016, 
2017, 2018, 2016, 2017, 2018), ave = c(6.52922242976571, 5.72051368352674, 
5.78635119450037, 6.43544457584707, 5.81728212255571, 5.79052889374
)), row.names = c(NA, -6L), class = c("grouped_df", "tbl_df", 
"tbl", "data.frame"), groups = structure(list(month = structure(1:2, .Label = c("Jan", 
"Feb", "Mar", "Apr", "May", "June", "Jul", "Aug", "Sept", "Oct", 
"Nov", "Dec"), class = c("ordered", "factor")), .rows = list(
    1:3, 4:6)), row.names = c(NA, -2L), class = c("tbl_df", "tbl", 
"data.frame"), .drop = TRUE))

from this dataframe I need the ave_temp

To graph the values from both dataframes I am using this code

#putting 2 y scales on one graph

ggplot(bargraph_dets_temp, 
       aes(x = month, y = num_unique_tags)) +
  geom_col(position = position_dodge(), 
           aes(fill = as.factor(Zone))) +
  geom_line(inherit.aes = FALSE, data = mapoc_temp,
            aes(x = month, y = ave, group = 2),
            color = "forestgreen", size = 1.5) +
  scale_x_discrete(limits = c("Jan","Feb","Mar","Apr","May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")) +
  scale_y_continuous(limits = c(0,11), name = "Total Unique Detections", 
                     sec.axis = sec_axis(~ . , name = "Average Temp (Celsius)")) +
  scale_fill_manual(name = "Zone",values=c("#01579B", "#4FC3F7", "#ffa600", "#ff6361")) +
  xlab("Month") +
  facet_wrap(~ year, scales = "free", nrow = 3, strip.position = "top") + 
  theme_bw() + 
  theme(panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(),
        panel.background = element_blank(),
        panel.border = element_blank(),

        axis.line = element_line(),

        axis.line.y.right = element_line(color = "forestgreen"), 
        axis.ticks.y.right = element_line(color = "forestgreen"),
        axis.text.y.right = element_text(color = "forestgreen"),
        axis.title.y.right = element_text(margin = margin(t = 0, r = 0, b = 0, l = 30)),
        axis.title.y.left = element_text(margin = margin(t = 0, r = 30, b = 0, l = 0)),
        axis.title.x = element_text(margin = margin(t = 40, r = 0, b = 0, l = 0)),


        strip.background =  element_rect(fill = NA, colour = NA), 
        strip.text = element_text(size = 25),
        text = element_text(size = 24))

This is the image I get enter image description here

As you can see the temperature data goes straight across. But I want to show the temperature line increasing and decreasing, so I need the second y scale to be finer to show the change in temperature. Is there a way to fix the values of the second y scale so they go from 5-7 instead of 0-9?

Kristen Cyr
  • 629
  • 5
  • 16

2 Answers2

0

Having two different y-scales in one chart is typically discouraged -- and also not possible in ggplot by design -- see the explanation by the package author: https://stackoverflow.com/a/3101876/5726768.

There are workarounds, such as one described in this article: https://drawar.github.io/posts/dual-y-axis-ggplot2/

Alternatively, you can produce two different charts with aligned x-axes.

ozacha
  • 1,212
  • 9
  • 14
  • I know they're typically discouraged but in this case it's the best way to illustrate the comparison of temperature to detections. The link you sent me for workarounds is only using 1 dataframe, so I'm not really sure how I can melt the 2 together. The alternative of 2 different charts with aligned x axis, I'm trying to picture what that would like with my already facet wrapped graphs. Would the temperature data just sit ontop of the current graphs, and if that's the case how do you facet wrap twice? – Kristen Cyr Feb 15 '20 at 15:05
0

The main issue when using sec.axis is to find the appropriate ratio to convert your second dataset and get a nice looking second y axis.

Here, I recreate your dataframe (because they were not enough descriptive for all months and years):

library(lubridate)
Month <- month(seq(ymd("2020-01-01"),ymd("2020-12-31"), by = "month"), label = TRUE)
bargraph <- data.frame(Month = rep(Month,3),
                       year = rep(c(2016,2017,2018),each = 12),
                       tags = sample(1:9,36,replace = TRUE),
                       zone = sample(1:4,36, replace = TRUE))

mapoc <- data.frame(Month = rep(Month,3),
                    year = rep(c(2016,2017,2018),each = 12),
                    ave = rnorm(36, mean = 6, sd = 0.5))

Basically, it seems that your bargraph dataset contains values ranging from 0 to 11 (it's your first scale you passed in the scale_y_continuous). Your temperature dataset has values that seems to have a mean around 6 and a standard deviation of 0.5 (based on the example you provided). So, basically you want your second y-axis to be ranging from 4 to 7 ich.

Here, a good ratio that I found was *3-11 (multiply by the interval of the second axis 7-4 and substract the interval of the first axis 11-0):

library(ggplot2)
ggplot(bargraph, aes(x = Month, y = tags))+
  geom_col(position = position_dodge(), aes(fill = as.factor(zone)))+
  geom_line(inherit.aes = FALSE, data = mapoc,
            aes(x = Month, y = ave*3-11, group = 2),
            color = "forestgreen", size = 1.5) +
  facet_wrap(~ year, scales = "free", nrow = 3, strip.position = "top")+
  scale_y_continuous(limits = c(0,11), name = "Total Unique Detections", 
                     sec.axis = sec_axis(~(.+11)/3 , name = "Average Temp (Celsius)"))

And you get:

enter image description here

So, it is not perfect but it allow you to have a better representation of your second y axis.

Does it answer your question ?


NB: In your question, you can't obtain the graph you are showing with the code you are posting because you used nrow = 3 in your facet_wrap, so you should have obtained a similar graph to the one I'm posting.

dc37
  • 15,840
  • 4
  • 15
  • 32