Skip to content

Grouped boxplot data not centred on xaxis ticks, looses boxgap argument, and wont resize with subplots #1484

Open
@l-jaye

Description

@l-jaye

Hi @cpsievert!

Here after your Shiny webinar, great stuff!

I'm having issues with the boxplot data aligning with x-axis tick marks in subplots. Please see below:

library (data.table)
library (stringr)
library (plotly)
# some setup:
get_plot_title = function(this.plot.title, y.pos = 1, y.shift = 0){
  list(text = sprintf ("<b>%s</b>", this.plot.title), yshift = y.shift
       , xref = "paper", yref = "paper", yanchor = "center", xanchor = "center", align = "center"
       , x = 0.5, y = y.pos, showarrow = FALSE, font = list (size = 16, family = "Arial")
  )} 

generate_panel = function(dat, trace.name){
  my.plot = 
    plot_ly(dat, type = "box"
            , x= ~get(x_var), y= ~get(y_var), color = ~get(color_var)
            , whiskerwidth = 0.1
            , boxpoints = F
    )   %>% 
    layout(boxmode = "group", boxgroupgap = 0.1, boxgap = 0.15
           , plot_bgcolor = "#F5F5F5"
           , annotations = get_plot_title(trace.name, y.shift = 20)
           , xaxis = list(title = "", tickfont = list(size = 14, family = "Arial")
                          , tickmode = "linear", ticks = "outside")
           , yaxis = list(title = sprintf("<b>%s</b>", y_var), titlefont = list (size = 16, family = "Arial"))
           ) 
  my.plot #return
}

x_var = "cut"
y_var = "price"
color_var = "color" 
X_panel_var = "clarity"
test.dat = ggplot2::diamonds %>% setDT

Without subplots, everything looks great:

generate_panel(test.dat, trace.name = "all")

image

Adding two horizontal subplots:

test.dat[, get(X_panel_var) %>% levels][1:2] %>% 
  lapply(function(this.panel.var){
    generate_panel(dat = test.dat[this.panel.var, on = X_panel_var], trace.name = this.panel.var)
  }) %>% 
  subplot(shareY = T, shareX = F, titleX = F, nrows = 1, which_layout = 1, margin = 0.01)

Boxplot groups shift off the centre of the xaxis ticks, and the boxgap argument becomes irrelevant:
image

Enlarging this plot does not work at all (cuts off the data at the original subplot width and height, yikes!):

image

Interestingly, with 3 horizontal subplots, the middle plot data is centered around ticks, but the outer plots are even further away (and the boxgaps are worse):

test.dat[, get(X_panel_var) %>% levels][1:3] %>% 
  lapply(function(this.panel.var){
    generate_panel(dat = test.dat[this.panel.var, on = X_panel_var], trace.name = this.panel.var)
  }) %>% 
  subplot(shareY = T, shareX = F, titleX = F, nrows = 1, which_layout = 1, margin = 0.01) 

image

Just wondering if you have any ideas / suggestions?

Thank you!

Activity

linked a pull request that will close this issue on Apr 9, 2019
fabbra

fabbra commented on Apr 24, 2020

@fabbra

I have a similar / the same issue here:

image

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px

fig = make_subplots(rows=2, cols=1)
df = px.data.tips()

style1 = dict(name='Smokers', legendgroup='Smokers', line=dict(color='red'))
style2 = dict(name='Non-Smokers', legendgroup='Non-Smokers', line=dict(color='blue'))

fig.add_trace(go.Box(y=df[df.smoker=='Yes'].total_bill, **style1,
                     x=df[df.smoker=='Yes'].time),
                     row=1, col=1)
fig.add_trace(go.Box(y=df[df.smoker=='No'].total_bill, **style2,
                     x=df[df.smoker=='No'].time),
                     row=1, col=1)

fig.add_trace(go.Box(y=df[df.smoker=='Yes'].tip, **style1,
                     x=df[df.smoker=='Yes'].time, showlegend=False),
                     row=2, col=1)
fig.add_trace(go.Box(y=df[df.smoker=='No'].tip, **style2,
                     x=df[df.smoker=='No'].time, showlegend=False),
                     row=2, col=1)

fig.update_layout(
    boxmode='group'
)
fig.show()

Is there a workaround for this problem?

I would have expected that legendgroup would work to properly group the boxplots when using boxmode='group'.

kmcentush

kmcentush commented on May 4, 2020

@kmcentush

I'm having the same problem. The code snippet provided by @fabbra is a good example.

It's interesting to note that when using plotly express w/ facet rows/cols, the boxplots are grouped properly. I haven't had a chance to dig into this yet, so I'm not sure why.

FelipeMoser

FelipeMoser commented on Dec 26, 2020

@FelipeMoser

Hi, I know this post is a bit old but I struggled with the same problem. The solution was to put the boxes I wanted aligned into the same "offsetgroup". Using Fanbras' code:

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px

fig = make_subplots(rows=2, cols=1)
df = px.data.tips()

style1 = dict(name='Smokers', legendgroup='Smokers', line=dict(color='red'))
style2 = dict(name='Non-Smokers', legendgroup='Non-Smokers', line=dict(color='blue'))

fig.add_trace(go.Box(y=df[df.smoker=='Yes'].total_bill, **style1,
                     x=df[df.smoker=='Yes'].time, offsetgroup="A"),
                     row=1, col=1)
fig.add_trace(go.Box(y=df[df.smoker=='No'].total_bill, **style2,
                     x=df[df.smoker=='No'].time, offsetgroup="B"),
                     row=1, col=1)

fig.add_trace(go.Box(y=df[df.smoker=='Yes'].tip, **style1,
                     x=df[df.smoker=='Yes'].time, showlegend=False, offsetgroup="A"),
                     row=2, col=1)
fig.add_trace(go.Box(y=df[df.smoker=='No'].tip, **style2,
                     x=df[df.smoker=='No'].time, showlegend=False, offsetgroup="B"),
                     row=2, col=1)

fig.update_layout(
    boxmode='group'
)
fig.show()
LukasHebing

LukasHebing commented on Nov 30, 2023

@LukasHebing

Is there a solution for the error in plotly express using facet_row or facet_col? The workaround to add each trace individually seems very tedious.

mpage21

mpage21 commented on Mar 11, 2024

@mpage21

Still seeing this issue where grouped boxplots are being offset when two plots are combined with subplots. Because I'm working with tibbles, I don't see how I can apply the offset group suggested previously. Also, I need to be working with just plotly and not ggplotly, due to speed the plots need to be rendered at.
@cpsievert Do you have any suggestions?

image

Here is a simplified version of my code:

library(plotly)
library(tidyverse)
library(scales)

expr <- read_tsv('../path/to/file.tsv')
colorLevels <- setNames(hue_pal()(9), levels(as.factor(names(expr$site_detail))))

plot_boxpot <- function(data, value_col, colorLevels, ids) {
  p <- plot_ly(data, 
               y = ~id, 
               x = as.formula(paste0("~", value_col)), 
               color = ~site_detail,
               colors = colorLevels,
               type = 'box', 
               boxpoints = 'all',
               pointpos = 0) %>%
    layout(
      boxmode = 'group',
      boxgap = 0.2
    ) %>%
    layout(
      yaxis = list(
        tickmode = "array",
        tickvals = ~id,
        ticktext = ~id
      )
    )
}

p1 <- plot_boxpot(expr, expr_col, colorLevels, ids)
p2 <- plot_boxpot(expr, expr_col_2, colorLevels, ids)

fig <- subplot(p1, p2, nrows = 1, shareY = TRUE) %>%
    layout(
      yaxis = list(
        tickmode = "category", 
        tickvals = ids, 
        ticktext = ids),
      legend = list(
        orientation = 'h',
        xanchor = 'center', 
        yanchor = 'top'
      )
    )
fig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @fabbra@kmcentush@mpage21@FelipeMoser@l-jaye

      Issue actions

        Grouped boxplot data not centred on xaxis ticks, looses boxgap argument, and wont resize with subplots · Issue #1484 · plotly/plotly.R