4

I had the same issue described in this question:

R: ggplot and plotly axis margin won't change

but when I implemented the solution, I got the following error:

Warning: Ignoring unknown aesthetics: text We recommend that you use the dev version of ggplot2 with ggplotly() Install it with: devtools::install_github('hadley/ggplot2') Error in tmp[[2]] : subscript out of bounds

This code will produce this error on my machine:

library(gapminder)
library(plotly)
library(ggplot2)

lead <- rep("Fred Smith", 30)
lead <- append(lead, rep("Terry Jones", 30))
lead <- append(lead, rep("Henry Sarduci", 30))
proj_date <- seq(as.Date('2017-11-01'), as.Date('2017-11-30'), by = 'day')
proj_date <- append(proj_date, rep(proj_date, 2))
set.seed(1237)
actHrs <- runif(90, 1, 100)
cummActHrs <- cumsum(actHrs)
forHrs <- runif(90, 1, 100)
cummForHrs <- cumsum(forHrs)
df <- data.frame(Lead = lead, date_seq = proj_date,
                 cActHrs = cummActHrs,
                 cForHrs = cummForHrs)

makePlot <- function(dat=df, man_level = 'Lead') {
    p <- ggplot(dat, aes_string(x='date_seq', y='cActHrs',
                               group = man_level,
                               color = man_level),
                linetype = 1) +
         geom_line() +
         geom_line(data=df,
                   aes_string(x='date_seq', y = 'cForHrs',
                              group = man_level,
                              color = man_level),
                   linetype = 2)

    p <- p + geom_point(aes(text=sprintf('%s\nManager: %s\n MTD Actual Hrs: %s\nMTD Forecasted Hrs: %s',
                                         date_seq, Lead, round(cActHrs, 2), round(cForHrs, 2))))

    p <- p + theme_classic() + ylab('Hours') + xlab('Date')

    gp <- ggplotly(p, tooltip = "text") %>% layout(hovermode = "compare")
    ### FIX IMPLEMENTED HERE ###
    gp[['x']][['layout']][['annotations']][[2]][['x']] <- -0.1
    gp %>% layout(margin = list(l = 75))

    return(gp)
}

## run the example
p1 <- makePlot()
Michael Szczepaniak
  • 1,970
  • 26
  • 35
  • 1) This is no error, it's a warning. 2) I can not reproduce your code, because I get another error at `gp[['x']][['layout']][['annotations']][[2]][['x']] <- -0.1` >Error in `*tmp*`[[2]] : subscript out of bounds – J_F Nov 28 '17 at 09:10
  • The answer on [this question](https://stackoverflow.com/questions/47227506/change-axis-title-position-in-ggplot-using-plotly) solves the error. Because your plot is not facetted, the `gp[['x']][['layout']][['annotations']]` list does not exist, causing the error when you try to modify it. – Bart VdW Nov 28 '17 at 12:11
  • @J_F If you look closely at the entire warning/error I originally posted, you'll see the error you describe. – Michael Szczepaniak Nov 29 '17 at 15:50

2 Answers2

3

Try this:

makePlot <- function(dat=df, man_level = "Lead") {
  dat$var <- dat[,man_level]
  dat$grp <- ""
  p <- ggplot(dat, aes(x=date_seq, y=cActHrs,
              group = var, color = var,
              text=paste0("Manager:", date_seq,"<br>MTD Actual Hrs:", round(cActHrs, 2),
                          "<br>MTD Forecasted Hrs:", round(cForHrs, 2))),
              linetype = 1) +
       geom_line() +
       geom_line(data=dat,
                 aes(x=date_seq, y = cForHrs,
                     group = var, color = var),
                 linetype = 2) +
        geom_point() +
        theme_classic() + ylab("Hours") + xlab("Date") +
        scale_color_discrete(name=man_level) +
        facet_wrap(~grp)

    gp <- ggplotly(p, tooltip = "text") 
    # Set y-axis label position
    gp[["x"]][["layout"]][["annotations"]][[2]][["x"]] <- -0.06
    # Set legend label position    
    gp[["x"]][["layout"]][["annotations"]][[3]][["y"]] <- 0.93
    gp <- gp %>% layout(margin = list(l = 120, b=70), hovermode = "compare")

    return(gp)
}

enter image description here

Marco Sandri
  • 23,289
  • 7
  • 54
  • 58
  • This causes the disappearance of the legend title but it doesn't move the axis title. – Maximilian Peters Nov 28 '17 at 13:47
  • @MaximilianPeters Thank you for your comment. I updated my answer. Now the legend title is printed and the y-axis title is moved. Please, test it, if possible. – Marco Sandri Nov 28 '17 at 15:19
  • @Marco Thx. Upvoted because it works fine on my system. I accepted Max's answer as the final solution because it's more readable. – Michael Szczepaniak Nov 29 '17 at 15:47
  • @MichaelSzczepaniak OK. I directly answer to your question, showing you why `gp[['x']][['layout']][['annotations']][[2]][['x']] <- -0.1` does not work. Moreover, have you tested Max solution ? On my R axes his code does not change axis label position, unfortunately. – Marco Sandri Nov 29 '17 at 17:16
  • You are right. Max's solution doesn't change my y axis label either. I was a bit hasty. Thx for pointing this out. – Michael Szczepaniak Nov 29 '17 at 23:30
2

The problem in your case is the opposite of the linked question. Your axis title is a real axis title, not an annotation. Currently there is no solution to move axis titles in any direction (see https://github.com/lleslie84/plotly.js/pull/1).

Workarounds like adding line breaks to the axis title or adding spaces to the tick labels don't work in your case.

One possible workaround would be to add an annotation with your axis title. The annotation can then be freely moved.

gp <- layout(gp, yaxis = list(title = ""),
             margin = list(l = 100), 
             annotations = c(list(text = "Hours",
                                  x = -0.15,
                                  xref = "paper",
                                  showarrow = F,
                                  textangle = -90))
  )

enter image description here

Complete code

library(gapminder)
library(plotly)
library(ggplot2)

lead <- rep("Fred Smith", 30)
lead <- append(lead, rep("Terry Jones", 30))
lead <- append(lead, rep("Henry Sarduci", 30))
proj_date <- seq(as.Date('2017-11-01'), as.Date('2017-11-30'), by = 'day')
proj_date <- append(proj_date, rep(proj_date, 2))
set.seed(1237)
actHrs <- runif(90, 1, 100)
cummActHrs <- cumsum(actHrs)
forHrs <- runif(90, 1, 100)
cummForHrs <- cumsum(forHrs)
df <- data.frame(Lead = lead, date_seq = proj_date,
                 cActHrs = cummActHrs,
                 cForHrs = cummForHrs)

makePlot <- function(dat=df, man_level = 'Lead') {
  p <- ggplot(dat, aes_string(x='date_seq', y='cActHrs',
                              group = man_level,
                              color = man_level),
              linetype = 1) +
    geom_line() +
    geom_line(data=df,
              aes_string(x='date_seq', y = 'cForHrs',
                         group = man_level,
                         color = man_level),
              linetype = 2)

  p <- p + geom_point(aes(text=sprintf('%s\nManager: %s\n MTD Actual Hrs: %s\nMTD Forecasted Hrs: %s',
                                       date_seq, Lead, round(cActHrs, 2), round(cForHrs, 2))))

  p <- p + theme_classic() + ylab('Hours') + xlab('Date')

  gp <- ggplotly(p, tooltip = "text") %>% layout(hovermode = "compare")

  ### FIX IMPLEMENTED HERE ###
  gp <- layout(gp,
               yaxis = list(title = ""),
               margin = list(l = 100),
               annotations = c(list(text = "Hours",
                                    x = -0.15,
                                    xref = "paper",
                                    showarrow = F,
                                    textangle = -90))
  )

  return(gp)
}

## run the example
p1 <- makePlot()
p1
Maximilian Peters
  • 30,348
  • 12
  • 86
  • 99