0

I have the following data set:

structure(list(Male = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 
3L, 3L, 3L, 3L, 3L, 3L), .Label = c("126", "331", "548"), class = "factor"), 
    Urban = c(43.36, 44.52, 44.77, 49.08, 47.88, 39.24, 41.75, 
    48.63, 49.95, 43.57, 41.94, 37.74, 40.97, 45.56, 45.65, 53.62, 
    58.19, 51.29, 51.85, 55.28, 55.66, 54.14, 49.4, 49.87, 44.81, 
    44.23, 47.99, 45.46, 44.9, 42.09, 57.23, 51.97, 46.85, 51.02, 
    41.56, 51.23, 44.79, 50.87, 46.6, 56.22, 46.98, 49.04, 50.07, 
    46.32, 48.75), LowFreq = c(3640, 3360.8, 3309.4, 3101.1, 
    3263.3, 3070, 3153.3, 3594, 4220, 3670, 3367.9, 3156.7, 3431, 
    3440.5, 3276.7, 3526.7, 3592.9, 3588.2, 3614.1, 3619.2, 3625.8, 
    3574.8, 3650, 3678.2, 3655.6, 3675.3, 3681.3, 3680.7, 3647.5, 
    3670, 2973.9, 2948.8, 2715.2, 2980.4, 2693.6, 2888.4, 2718.5, 
    2971, 2752.2, 3008.5, 2718.4, 2860.2, 2848, 2893.3, 2940.2
    ), idx = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 
    15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1, 
    2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)), .Names = c("Male", 
"Urban", "LowFreq", "idx"), row.names = c(NA, -45L), class = "data.frame")

I want to create plot where each panel looks somewhat like the panels below:

enter image description here

However, I want to have all panels stacked on top of one another, with no space between panels, and with only 1 x-axis since they all share a common x-axis. I used the following code to produce this plot:

awesome$idx<-ave(rep(1,nrow(awesome)),awesome$Male,FUN=seq_along)
free.y<-list(y=list(relation="free"))
require(lattice)
mA<-xyplot(Urban~idx|Male,data=awesome,type="l",scales=free.y)
mB<-xyplot(LowFreq~idx|Male,data=awesome,type="l",scales=free.y)
require(latticeExtra)
comb<-doubleYScale(mA,mB)
comb$x.between<-5
comb

I also want the labels '548', '331', and '126 removed from the top of each plot, change the line colors to black and change one of the lines to a dashed line, and have only 1 y-axis and x-axis label.

I would prefer this to be accomplished in GGPlot2 if possible, but Lattic may be the only way to do this. Any help that you can provide would be greatly appreciated!

IRTFM
  • 258,963
  • 21
  • 364
  • 487
Gavia_immer
  • 67
  • 1
  • 10
  • So which y-axis do you want to use? It seems like it would only be correct for one of the two data sets because they are on such different scales. – MrFlick Jul 17 '14 at 19:46

3 Answers3

3

I'm wondering if the lattice update function is what you want:

update(comb, layout=c(1,3))

enter image description here

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • This is the closest to what I am looking for. The only thing I am not crazy about with this solution is that it is done using Lattice, although that is no fault of yours, since it is what I asked. There are some minor formatting issues that I would need to fix, but I think I could do that. Thank you very much for this answer! However, @beginneR answer is appealing as well because it's done using ggplot2. – Gavia_immer Jul 17 '14 at 20:23
  • Also, is there any way to place 'LowFreq' on the y-axis next to the middle panel? – Gavia_immer Jul 17 '14 at 20:30
  • That update just swaps out 'LowFreq' for 'Urban' instead of placing 'LowFreq' on the right side of panel 2. This has been my biggest issue, trying to have 2 y-axes labels on opposite sides of a panel. – Gavia_immer Jul 17 '14 at 20:42
  • You should use `mtext()`. If you want the strips to disappear then use `strip=FALSE` either in the original call or update can do it. – IRTFM Jul 18 '14 at 17:12
2

You said that you only want 1 y-axis which means you wouldn't see much of the Urban variable (only a horizontal line) if both are shown on a single y-axis with their actual data. My suggestion would be to scale the data so that it can be displayed and compared easily. However, since the actual values are not visible this way, I don't know if this helps you at all. Anyway, since I wrote the code, I'll just post it. Also, the grid has little spaces between the plots - I don't know if or how this could be changed. Perhaps you can further adjust it to your needs.

library(dplyr)
library(ggplot2)
library(reshape2)

df %>% 
  group_by(Male) %>%
  mutate(idx = 1:n(),
         Urban_scaled = (Urban - min(Urban))/max((Urban - min(Urban)))*100,
         LowFreq_scaled = (LowFreq - min(LowFreq)) / max((LowFreq - min(LowFreq)))*100) %>%
  select(-c(Urban, LowFreq)) %>%
  melt(., id = c("Male", "idx")) %>%
  ggplot(., aes(x = idx, y = value)) + 
  geom_line(aes(linetype = variable)) + 
  facet_grid(Male ~.) +
  ylab("Urban and LowFreq [scaled to 0 - 100]")

chart

talat
  • 68,970
  • 21
  • 126
  • 157
  • This answer is ver appealing since it was done using GGplot, however the second y axis is missing, showing the range of 'LowFreq', which is critical for me to have. I also would like the scales on the 'Urban' y axis to reflect the range of the actual data. The small spaces between the plots doesn't look bad at all and actually I quite like it. Thank you for your work on this. If you could address my further issues, that would be greatly appreciated! – Gavia_immer Jul 17 '14 at 20:27
  • Also, when I said I wanted only 1 y-axis label, I meant the actual label of the axis. It would be redundant to put either 'Urban' or 'LowFreq' next to each panel. Instead, having these labels on either side of the middle panel would be most desirable. – Gavia_immer Jul 17 '14 at 20:29
  • @user3494534 please have a look at hadley's answer and discussion in comments [here](http://stackoverflow.com/a/3101876/3521006) on why it's not possible in `ggplot2` to have a second y-axis that is not a transformation of the other y-axis. – talat Jul 17 '14 at 20:35
  • It appears to be possible if you follow [link](http://rstudio-pubs-static.s3.amazonaws.com/1963_60f8740918d5416e8d54f07f48ce04fd.html). I have made the plots myself, but can't seem to stack them and then label the axes correctly. – Gavia_immer Jul 17 '14 at 20:46
  • I'm not familiar with `gtable` and `grid`, so I can't help you any further unfortunately. – talat Jul 17 '14 at 21:10
1

I know this is not a minimum answer, but this is as close to the answer as I can get. I had to separate the data for each male into 3 dataframes to pull this one off. I put this together using answers to this question, answers from other questions, manuals, and my own exploration. I took out the code for axis labels, font, and font size to reduce the code somewhat. I hope this turns out to be useful for someone out there.

library(ggplot2)
library(gtable)
library(grid)
library(gridExtra) 

##Create Plot1 for Male 331
q1<-ggplot(m331,aes(Count,Urban))+geom_line(linetype="dashed",size=1)+theme_bw()+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+theme(axis.title.x = element_blank())+theme(axis.title.y = element_blank())+scale_x_continuous(breaks = round(seq(min(m331$Count), max(m331$Count), by = 2),1))+scale_y_continuous(breaks = round(seq(min(m331$Urban), max(m331$Urban), by = 5),0))+theme(plot.margin=unit(c(1,1,0,1), "cm"))
    q2<-ggplot(m331,aes(Count,LowFreq))+geom_line(linetype="solid",size=1)+theme_bw()%+replace%theme(panel.background = element_rect(fill = NA))+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+theme(axis.title.x = element_blank())+scale_y_continuous(breaks = round(seq(min(3400), max(3700), by = 50),0))+theme(plot.margin=unit(c(1,1,0,1), "cm"))
    h1<-ggplot_gtable(ggplot_build(q1))
    h2<-ggplot_gtable(ggplot_build(q2))
    qq<-c(subset(h1$layout,name=="panel",se=t:r))
    h<-gtable_add_grob(h1,h2$grobs[[which(h2$layout$name=="panel")]],qq$t,qq$l,qq$b,qq$l)

    ia <- which(h2$layout$name == "axis-l")
    ga <- h2$grobs[[ia]]
    ax <- ga$children[[2]]
    ax$widths <- rev(ax$widths)
    ax$grobs <- rev(ax$grobs)
    ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15,"cm")
    h <- gtable_add_cols(h, h2$widths[h2$layout[ia, ]$l], length(h$widths) - 1)
    h <- gtable_add_grob(h, ax, qq$t, length(h$widths) - 1, qq$b)

    grid.draw(h)


    ##Create Plot2 for Male 126
    p1<-ggplot(m126,aes(Count,Urban))+geom_line(linetype="dashed",size=1)+theme_bw()+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+theme(axis.title.x = element_blank())+scale_x_continuous(breaks = round(seq(min(m126$Count), max(m126$Count), by = 2),1))+scale_y_continuous(breaks = round(seq(min(m126$Urban), max(m126$Urban), by = 5),0))+theme(plot.margin=unit(c(0,1,0,1), "cm"))
    p2<-ggplot(m126,aes(Count,LowFreq))+geom_line(linetype="solid",size=1)+theme_bw()%+replace%theme(panel.background = element_rect(fill = NA))+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+ theme(axis.title.x = element_blank())+scale_y_continuous(breaks = round(seq(min(3000), max(4200), by = 400),0))+theme(plot.margin=unit(c(0,1,0,1), "cm"))
    g1<-ggplot_gtable(ggplot_build(p1))
    g2<-ggplot_gtable(ggplot_build(p2))
    pp<-c(subset(g1$layout,name=="panel",se=t:r))
    g<-gtable_add_grob(g1,g2$grobs[[which(g2$layout$name=="panel")]],pp$t,pp$l,pp$b,pp$l)

    ia <- which(g2$layout$name == "axis-l")
    ga <- g2$grobs[[ia]]
    ax <- ga$children[[2]]
    ax$widths <- rev(ax$widths)
    ax$grobs <- rev(ax$grobs)
    ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15,"cm")
    g <- gtable_add_cols(g, g2$widths[g2$layout[ia, ]$l], length(g$widths) - 1)
    g <- gtable_add_grob(g, ax, pp$t, length(g$widths) - 1, pp$b)
    g <- gtable_add_grob(g, g2$grob[[7]], pp$t, length(g$widths), pp$b)

    grid.draw(g)


    ##Create Plot3 for Male 548
    r1<-ggplot(m548,aes(Count,Urban))+geom_line(linetype="dashed",size=1)+theme_bw()+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+theme(axis.title.y = element_blank())+scale_x_continuous(breaks = round(seq(min(m548$Count), max(m548$Count), by = 2),1))+scale_y_continuous(breaks = round(seq(min(m548$Urban), max(m548$Urban), by = 5),0))+theme(plot.margin=unit(c(0,1,1,1), "cm"))
    r2<-ggplot(m548,aes(Count,LowFreq))+geom_line(linetype="solid",size=1)+theme_bw()%+replace%theme(panel.background = element_rect(fill = NA))+theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+theme(axis.title.y = element_blank())+scale_y_continuous(breaks = round(seq(min(2700), max(3000), by = 100),0))+theme(plot.margin=unit(c(0,1,1,1), "cm"))
    i1<-ggplot_gtable(ggplot_build(r1))
    i2<-ggplot_gtable(ggplot_build(r2))
    rr<-c(subset(i1$layout,name=="panel",se=t:r))
    i<-gtable_add_grob(i1,i2$grobs[[which(i2$layout$name=="panel")]],rr$t,rr$l,rr$b,rr$l)

    ia <- which(i2$layout$name == "axis-l")
    ga <- i2$grobs[[ia]]
    ax <- ga$children[[2]]
    ax$widths <- rev(ax$widths)
    ax$grobs <- rev(ax$grobs)
    ax$grobs[[1]]$x <- ax$grobs[[1]]$x - unit(1, "npc") + unit(0.15,"cm")
    i <- gtable_add_cols(i, i2$widths[i2$layout[ia, ]$l], length(i$widths) - 1)
    i <- gtable_add_grob(i, ax, rr$t, length(i$widths) - 1, rr$b)

    grid.draw(i)


    ##Combine Graphs
    grid.arrange(h, g, i, nrow=3)

enter image description here

Gavia_immer
  • 67
  • 1
  • 10
  • +1 for putting quite some time into answering this question (judging by the length of your code) and the result is quite close to what was asked for. – talat Jul 18 '14 at 11:58
  • I also found a way to add two y-axis labels, one on each side of the plot, so all can be done with just the right amount of persistence and help. – Gavia_immer Jul 18 '14 at 12:38