plotly / plotly.R

An interactive graphing library for R
https://plotly-r.com
Other
2.56k stars 626 forks source link

plotly parcoords (parallel coordinates) cannot plot a single line #2385

Open MLopez-Ibanez opened 2 months ago

MLopez-Ibanez commented 2 months ago

The following generates no plot, no warnings and no errors:

# Example from https://plotly.com/r/parallel-coordinates-plot/
library(plotly)
df <- read.csv("https://raw.githubusercontent.com/bcdunbar/datasets/master/iris.csv")
df <- df[1L, , drop=FALSE] # plot one line only
fig <- df %>% plot_ly(type = 'parcoords',
          line = list(color = ~species_id,
                      colorscale = list(c(0,'red'),c(0.5,'green'),c(1,'blue'))),
          dimensions = list(
            list(range = c(2,4.5),
                 label = 'Sepal Width', values = ~sepal_width),
            list(range = c(4,8),
                 constraintrange = c(5,6),
                 label = 'Sepal Length', values = ~sepal_length),
            list(range = c(0,2.5),
                 label = 'Petal Width', values = ~petal_width),
            list(range = c(1,7),
                 label = 'Petal Length', values = ~petal_length)
            )
          )
fig
trekonom commented 2 months ago

The issue is that with only row the single values get converted to a scalar instead of an array which is the datatype required by plotly.js. In general, plotly already accounts for that. Unfortunately this fails for parcoords traces (and I would guess that this is also true for other "special" trace types.)

As a workaround you could wrap in AsIs aka I():

library(plotly)

df <- read.csv("https://raw.githubusercontent.com/bcdunbar/datasets/master/iris.csv")
df <- df[1, , drop = FALSE]

fig1 <- df %>%
  plot_ly(
    type = "parcoords",
    dimensions = list(
      list(
        range = c(2, 4.5),
        label = "Sepal Width",
        values = ~ I(sepal_width)
      ),
      list(
        label = "Sepal Length",
        values = ~ I(sepal_length)
      ),
      list(
        range = c(0, 2.5),
        label = "Petal Width",
        values = ~ I(petal_width)
      ),
      list(
        range = c(1, 7),
        label = "Petal Length",
        values = ~ I(petal_length)
      )
    )
  )
fig1

image

trekonom commented 2 months ago

I just checked and the same issue arises with parcats traces:

library(plotly)

dd <- data.frame(
  from = "A",
  to = "B"
)

plot_ly(dd) %>%
  add_trace(
    type = "parcats",
    dimensions = list(
      list(values = ~ from),
      list(values = ~ to)
    )
  )

And can be fixed by wrapping in I():

plot_ly(dd) %>%
  add_trace(
    type = "parcats",
    dimensions = list(
      list(values = ~ I(from)),
      list(values = ~ I(to))
    )
  )

Created on 2024-08-31 with reprex v2.1.1

trekonom commented 2 months ago

And also for splom traces:

library(plotly)

plot_ly(
  type = "splom",
  dimensions = list(
    list(values = 1, label = "A"),
    list(values = 2, label = "B")
  )
)


plot_ly(
  type = "splom",
  dimensions = list(
    list(values = I(1), label = "A"),
    list(values = I(2), label = "B")
  )
)

Created on 2024-08-31 with reprex v2.1.1