Converting ggplot object to plotly object creates axis title that overlaps tick values

痞子三分冷 提交于 2020-01-13 19:48:08

问题


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()

回答1:


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)
}




回答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))
  )

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


来源:https://stackoverflow.com/questions/47523919/converting-ggplot-object-to-plotly-object-creates-axis-title-that-overlaps-tick

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!