I am trying to use ggplot2
with plotly
in a shiny
app in R. Following is the code I use:
# Loading the libraries ---------------
library(shiny)
library(tidyverse)
library(plotly)
# Global ----------------
if (!exists('ds', envir = .GlobalEnv, inherits = FALSE)) {
ds <- readRDS("Analysis/Data/df_sim_updated.rds")
}
if (!exists('ado', envir = .GlobalEnv, inherits = FALSE)) {
ado <- readRDS("Analysis/Data/df_ADOs.rds")
}
ds <- as_tibble(ds)
file_ID <- unique(ds$file.ID)
ado_Name <- c("ditiExpeon6", "VanC5", "NeonC4", "llacCadi3", "WhiteC2",
"Ford1", "BMWC10", "StarT7", "owT8Yell", "peC9Esca", "tarCWins13",
"rC11RoveLand", "F150C12", "CargoT4", "SemiT3", "RedT1", "RaceT11",
"BlueT5", "artTWalm9", "ghtTFrei10", "MoveT12", "WhiteT2", "ilT6Carg"
)
ado <- as_tibble(ado)
# Define UI for application --------------------
ui <- fluidPage(
# Application title
titlePanel("exploRing simulation"),
# Sidebar
sidebarLayout(
sidebarPanel(
selectInput("fileid", label = h3("Select scenario"),
choices = file_ID),
selectInput("adoName", label = h3("Select ADO(s)"),
multiple = TRUE, choices = ado_Name)
),
# Main Panel
mainPanel(
uiOutput("FS"),
plotlyOutput("plot1")
)
)
)
# Define server logic ---------------------------------
server <- function(input, output) {
# Filter ds according to fileid
data <- reactive({ds %>% filter(file.ID==input$fileid)})
# Time Frame Slider
output$FS <- renderUI(
sliderInput("fs", label = h3("Time Frame"), min = min(data()$frames),
max = max(data()$frames), value = min(data()$frames), width = "800px")
)
# Position of OV at given time
data2 <- reactive({data() %>% filter(frames==input$fs)})
# Filter ado(s) according to fileid
ado_data1 <- reactive(ado %>%
filter(file.ID==input$fileid,
ADO_name %in% input$adoName))
# Position of ado at given time
ado_data2 <- reactive(ado_data1() %>%
filter(frames==input$fs))
# Plot data
output$plot1 <- renderPlotly(
ggplotly( ggplot() +
geom_line(data=data(),
aes(x = x, y = y)) +
geom_point(data = data2(),
aes(x = x, y = y), size = 2) +
geom_line(data = ado_data1(),
aes(x = pos.2, y = pos.1, color = ADO_name)) +
geom_point(data = ado_data2(),
aes(x = pos.2, y = pos.1, color = ADO_name),
size = 2) +
geom_hline(yintercept = 278, linetype="longdash") +
geom_hline(yintercept = 278-16) +
geom_hline(yintercept = 278+16) +
labs(x = "Longitudinal Position",
y = "Lateral Position") +
theme_bw())
)
}
# Run the application ---------------------------------
shinyApp(ui = ui, server = server)
Following is the error message that I get:
> runApp('exploRe')
Listening on http://127.0.0.1:7666
Warning: Error in filter_impl: incorrect length (0), expecting: 26826
Stack trace (innermost first):
109: <Anonymous>
108: stop
107: filter_impl
106: filter_.tbl_df
105: filter_
104: filter
103: function_list[[k]]
102: withVisible
101: freduce
100: _fseq
99: eval
98: eval
97: withVisible
96: %>%
95: <reactive:data2> [C:\Users\my_username\Google Drive\DrivingSimulator\exploRe/app.R#65]
84: data2
83: fortify
82: layer
81: geom_point
80: ggplotly
79: ggplotly
78: func
77: origRenderFunc
76: output$plot1
1: runApp
Warning: Error in order: argument 1 is not a vector
Stack trace (innermost first):
88: order
87: [.data.frame
86: [
85: to_basic.GeomLine
84: to_basic
83: layers2traces
82: gg2list
81: ggplotly.ggplot
80: ggplotly
79: ggplotly
78: func
77: origRenderFunc
76: output$plot1
1: runApp
If I just use renderPlot
and plotOutput
, the app works fine. What am I doing wrong here?
I can't reproduce your example, but I've encountered and solved the exact same error in my own app. The reason for this error is because Plotly is being passed a plot object that as no data in the plot object itself, but only has data associated with the additional geometry layers. This is because you haven't passed any data in the initial call of ggplot()
, and there is probably something wrong (i.e. missing) with one of the important columns of the data passed to at least one of the geometries. (geom_path
orders each of the axes before plotting, so it's probably x
or y
.)
If you run:
plot <- ggplot() +
geom_line(data=data(),
aes(x = x, y = y)) +
geom_point(data = data2(),
aes(x = x, y = y), size = 2) +
geom_line(data = ado_data1(),
aes(x = pos.2, y = pos.1, color = ADO_name)) +
geom_point(data = ado_data2(),
aes(x = pos.2, y = pos.1, color = ADO_name),
size = 2) +
geom_hline(yintercept = 278, linetype="longdash") +
geom_hline(yintercept = 278-16) +
geom_hline(yintercept = 278+16) +
labs(x = "Longitudinal Position",
y = "Lateral Position") +
theme_bw())
plot$data
You will probably find an output like:
list()
attr(,"class")
[1] "waiver"
Apparently ggplot is fine with this empty object, even if there are some issues with one of the layers. It will print a warning, and just miss those points/layers which can't be plotted because a dimension is missing.
Likewise Plotly is (usually) unfussed with a malfunctioning layer, provided there's some data in the underlying plot object, the other layers will still present ok. It's the combination of an issue with the data for one of the layers, as well as there being no data in the main plot object that causes the issue with Plotly.
I suggest you try plotting each layer separately, but calling the data within ggplot()
, to identify if there's an issue with one layer in particular (which I strongly suspect there is). Also, plot each object as a normal plot before passing to plotly.
i.e.:
plot <- ggplot(data = data()) +
geom_line(aes(x = x, y = y))
print(plot)
ggplotly(plot)
plot <- ggplot(data = data2())+
geom_point(aes(x = x, y = y), size = 2)
print(plot)
ggplotly(plot)
# and so on...
If you make those checks both in a test script, and inside the shiny app, I'm sure you'll isolate the problem.
I also found that trying to join the different data objects together before plotting them could also help, even crudely with bind_rows()
. (Only if that's appropriate.) That way you can pass one piece of data to the ggplot()
call first, and adjust the aesthetics separately for each geometry. Plotly still gets an underlying data object for the plot, which seems smooth things over, but might not reveal the real underlying issue as quickly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With