I have a Shiny app below, in which I am drawing a scatter plot on iris dataset using libraries highchart, ggplot and plotly.
library(shiny)
library(shinydashboard)
library(highcharter)
library(shinyWidgets)
library(plotly)
library(ggplot2)
library(data.table)
siderbar <- dashboardSidebar(
sidebarMenu(
# Add buttons to choose the way you want to select your data
selectizeInput(inputId = "inp_species", label = "Select by:", choices = c("setosa", "versicolor", "virginica"), selected = "setosa"),
awesomeRadio(inputId = "radioTest", label = "Choose one:",
choices=c("High Charter" = "highcharter",
"Simple Plot" = "simple",
"Plotly" = "plotly"),
inline = FALSE, selected = "highcharter")
)
)
body <- dashboardBody(
fluidRow(
tabBox(
side = "right",
selected = "Tab1",
tabPanel("Tab1", "Tab content 1", uiOutput("tabset1Selected"))
)
),
)
shinyApp(
ui = dashboardPage(
dashboardHeader(title = "tabBoxes"),
siderbar,
body
),
server = function(input, output, session) {
iris_dt <- reactive({
iris_table = data.table(copy(iris))
iris_table[Species == input$inp_species]
})
render_content <- reactive({
req(input$radioTest)
print(input$radioTest)
if(input$radioTest=='highcharter'){
output$plot1 <- renderHighchart({
highchart() %>%
hc_add_series(iris_dt(), type = "scatter", hcaes(x = Petal.Width, y = Sepal.Length))
})
out <- highchartOutput("plot1")
}
else if(input$radioTest=='plotly'){
output$plot2 <- renderPlotly({
plot_ly(iris_dt(), x = ~ Petal.Width, y = ~ Sepal.Length)
})
out <- plotlyOutput("plot2")
}
else if(input$radioTest=='simple'){
output$plot3 <- renderPlot({
ggplot(iris_dt(), aes(x = Petal.Width, y = Sepal.Length)) + geom_point()
})
out <- plotOutput("plot3")
}
return(out)
})
# The currently selected tab from the first box
output$tabset1Selected <- renderUI({
render_content()
})
}
)
I am selecting the library to draw the chart dynamically using a selectInput box.
Here is the problem -
I select a species in selectInput box and the highchart library draws a scatter plot
Then I select plotly in the radio button section and the rendering is done using plotly.
I change the species in selectInput and plotly re-renders the plot
Now, when I click on highchart radio button, the plot of the earlier species (from cache) is drawn for a few seconds and then the chart of the selected species is drawn.
Question
Is there a way to clear or disable the cache so that the rendering delay does not happen?
We can disable the animation effect. Although it's not a solution for the problem, it could help in the meantime.
output$plot1 <- renderHighchart({
highchart() %>%
hc_add_series(
data = iris_dt(),
type = "scatter",
hcaes(x = Petal.Width, y = Sepal.Length)
) %>%
hc_plotOptions(
series = list(
animation = FALSE
)
)
})
Related
I'm trying to build a simply R Shiny app that displays a bar chart with both axes as interactive elements. I'll demonstrate what I've done with the built in flights dataset.
I'm able to build a static bar chart, but only get errors when interactive. I've tried colnames(data), names(data), and aes_string in the server function. I think the issue is that in the ggplot aes the x label is read in as string but after_stat(count) isn't. Unfortunately I can't find any similar examples on the internet.
Any ideas how to resolve this? Thanks
# load packages
library(dplyr)
library(tidyr)
library(shiny)
library(ggplot2)
# data
library(nycflights13)
data = flights %>% select(carrier, origin, dest)
# desired bar chart
ggplot(data, aes(x=carrier, y=after_stat(count))) +
geom_bar(aes(fill = origin), position = "dodge")
ui <- fluidPage(
# sidebar
sidebarLayout(
selectInput(inputId = "xvar",
label = "X-axis variable",
choices = colnames(data),
#choices = names(data),
selected = "carrier"
),
selectInput(inputId = "yvar",
label = "Y-axis variable",
choices = colnames(data),
#choices = names(data),
selected = "origin"
)
),
# main plot
mainPanel(
plotOutput("id_main_plot")
)
)
# server logic to draw histogram
server <- function(input, output) {
output$id_main_plot <- renderPlot({
# Render bar chart
ggplot(data = data,
aes(x = input$xvar,
y = after_stat(count)
)
) +
geom_bar(aes(fill = input$yvar),
position = "dodge"
)
})
}
# create Shiny app
shinyApp(ui, server)
The issue is that input$xvar and input$yvar are just character strings. When you map these on aesehtics in ggplot2 they will be treated as constants. To tell ggplot2 that these character strings are names of columns in your dataset you could use the so-called .data pronoun. For more on the .data pro-noun in the context of ggplot2 and shiny see e.g. this example in Mastering Shiny
library(shiny)
library(dplyr)
library(ggplot2)
library(nycflights13)
data <- flights %>% select(carrier, origin, dest)
ui <- fluidPage(
sidebarLayout(
selectInput(
inputId = "xvar",
label = "X-axis variable",
choices = colnames(data),
selected = "carrier"
),
selectInput(
inputId = "yvar",
label = "Y-axis variable",
choices = colnames(data),
selected = "origin"
)
),
mainPanel(
plotOutput("id_main_plot")
)
)
server <- function(input, output) {
output$id_main_plot <- renderPlot({
ggplot(
data = data,
aes(
x = .data[[input$xvar]],
y = after_stat(count)
)
) +
geom_bar(aes(fill = .data[[input$yvar]]),
position = "dodge"
)
})
}
# create Shiny app
shinyApp(ui, server)
#>
#> Listening on http://127.0.0.1:3217
In addition to the errors I am encountering with legends when using deckgl in an Shiny application (Posted here: How do I remove deckgl legend on shiny dashboard?), I was wondering whether it would be possible to mirror user map interactions between two deckglOutput plots. This will ease user interactions when trying to make comparisons between the two plots. To clarify, if a user interacts with one plot, I would like the other plot to mirror the interaction and therefore show the same view.
So far I have managed to create a button that enables comparisons by plotting two instances of deck.gl but I at a miss as to if/how this would be possible.
Example below:
#packages
library(deckgl)
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "a nice map"),
dashboardSidebar(
dateInput(inputId = "date", label ="Select Date:", value = "2019-01-01",
min = "2019-01-01", max = "2019-01-31"),
actionButton(inputId = "reset", label = "Reset Map"),
switchInput(inputId = "compare", label = "Compare", onLabel = "ON", offLabel = "OFF" )),
dashboardBody(
uiOutput("map_out"))
)
server <- function(input, output) {
output$map_out <- renderUI({
if(input$compare == TRUE){
tagList(
deckglOutput('map', height = "45vh"),
deckglOutput('map_compare', height = "45vh"))
} else if(input$compare == FALSE){
deckglOutput('map', height = "90vh")
}
})
output$map <- renderDeckgl({
deckgl(zoom = 10) %>%
add_basemap()})
output$map_compare <- renderDeckgl({
deckgl(zoom = 10) %>%
add_basemap()})
observeEvent(input$date, {
#add a map layer that plots some data
map_data <- input$date
deckgl_proxy("map") %>%
add_geojson_layer(data = map_data,
) %>%
add_legend(
colors = "colour_pal",
labels = "colour_labs",
pos = "bottom-left",
title = "something",
) %>%
update_deckgl()
if(input$compare == TRUE){
deckgl_proxy("map_compare") %>%
add_geojson_layer(data = map_data,
) %>%
update_deckgl()
}
})
observeEvent(input$reset,
output$map <- renderDeckgl({
deckgl(zoom = 10) %>%
add_basemap()})
)
}
shinyApp(ui, server)
I am trying to make a shiny app that will allow to color the points of the scatterplot based on the selected categorical variables.
library(shiny)
data<-data.frame(iris)
ui <- navbarPage("Summary",
tabsetPanel(
tabPanel("Graph", fluid=T,
fluidPage(
sidebarPanel(selectInput(inputId = "varColor",
label = "Color",
choices = c("Species", "Other_Category"),
selected = "Species")),
mainPanel(plotOutput(outputId = "plot"))
)
)
)
)
server <- function(input, output) {
p<-reactive({ggplot(data,
aes(y = Sepal.Length, x = Petal.Length))+
# This Part needs help
geom_point(aes( input$varColor)) })
output$plot <- renderPlot({
p()
})
}
shinyApp(ui, server)
I think that now, the program reads the color selection from the input as a string, instead of taking it as category.
Thank you for help.
The issue is that input$colorVar is simply a character. Hence, ggplot2 will treat this character value as the one and only category. Hence, you end up with one color.
To tell ggplot2 that it should color the plot according to the data column whose named is stored in input$colorVar you could make use of the so called .data pronoun provided by the rlang package, i.e. do aes(color = .data[[input$varColor]]):
library(shiny)
library(ggplot2)
data <- data.frame(iris)
ui <- navbarPage(
"Summary",
tabsetPanel(
tabPanel("Graph",
fluid = T,
fluidPage(
sidebarPanel(selectInput(
inputId = "varColor",
label = "Color",
choices = c("Species", "Other_Category"),
selected = "Species"
)),
mainPanel(plotOutput(outputId = "plot"))
)
)
)
)
#> Warning: Navigation containers expect a collection of `bslib::nav()`/
#> `shiny::tabPanel()`s and/or `bslib::nav_menu()`/`shiny::navbarMenu()`s. Consider
#> using `header` or `footer` if you wish to place content above (or below) every
#> panel's contents.
server <- function(input, output) {
p <- reactive({
ggplot(
data,
aes(y = Sepal.Length, x = Petal.Length)
) +
# This Part needs help
geom_point(aes(color = .data[[input$varColor]]))
})
output$plot <- renderPlot({
p()
})
}
shinyApp(ui, server)
#>
#> Listening on http://127.0.0.1:3070
I'm having a problem with ggplotly objects simply not staying inside boxes with shiny and shinydashboard. Before something is plotted, everything is right. But when a plot is displayed, the box doubles its size and the plot stays on top.
It happens only with ggplotly. A common ggplot works fine.
I've made it reproducible with the iris dataset below.
ui.R
dashboardPage(dashboardHeader(title = "Title"),
dashboardSidebar(
sidebarMenu(
menuItem("Species Overview",
tabName = "species"),
menuItem(
pickerInput(
inputId = "species",
choices = species,
multiple = TRUE)))),
dashboardBody(
tabItems(
tabItem(tabName = "species",
fluidRow(
box(
title = "Plot1",
#width = 6,
id = "plot1",
plotlyOutput(
"plot1", width = "100%") ## box 1 with ggplotly object
),
box(
title = "Plot2",
id = "plot2",
#width = 6,
plotOutput(
"plot2", width = "100%") ## box 2 with ggplot object
))))))
server.R
shinyServer(function(input, output) {
v <- reactiveValues()
observe({
v$species <- input$species
})
species_selected <- reactive({
validate(
need(length(v$species) > 0, "Please select a species")
)
select_species(iris, v$species)})
plot1 = reactive({
plot_1(species_selected())
})
plot2 = reactive({
plot_2(species_selected())
})
output$plot1 = renderPlotly({
plot1() |> ggplotly() ##ggplot object
})
output$plot2 = renderPlot({
plot2() #ggplot object
})})
global.R
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(ggplot2)
library(tidyverse)
#library(bs4Dash)
data(iris)
species = iris$Species |> unique() |> as.character()
select_species = function(df, species) {
df = df |>
filter(Species %in% species)
return(df)
}
plot_1 = function(df) {
df = df
p = df |>
ggplot(aes(x = Petal.Width, y = Petal.Length, color = Species)) +
geom_point()
return(p)
}
plot_2 = function(df) {
p = df |>
ggplot(aes(x = Sepal.Width, y = Sepal.Length, color = Species)) +
geom_point()
return(p)
}
And this is what happens:
I'm open to any suggestions. I've tried bs4dash, shinydashboard, shinydashboardPlus. Packages are all up to date.
You can specify the height of the box and display the plotly object as shown below.
box(
title = "Plot1",
#width = 6,
height = 460,
id = "plot1",
plotlyOutput(
"plot1", width = "100%", height="400px") ## box 1 with ggplotly object
),
I have a shiny application with the following ui:
library(rhandsontable)
library(shiny)
library(ggplot2)
ui = fluidPage(
# App title ----
titlePanel("Tabsets"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Tabset w/ plot, summary, and table ----
tabsetPanel(type = "tabs",
tabPanel("Summary", rHandsontableOutput('contents'),
actionButton("saveBtn", "Save changes")
),
tabPanel("Tab",
rHandsontableOutput('contentFinal')),
tabPanel("Dashboard",
plotOutput('dashboard1'))
)
)
)
)
And the following server
library(dplyr)
library(rhandsontable)
options(shiny.maxRequestSize = 9*1024^2)
server = function(input, output) {
values <- reactiveValues()
Post <- c("", "")
list2 <- c(12,13)
df <- data.frame(Post, list2)
output$contents <- renderRHandsontable({
rhandsontable(df, width = 550, height = 300) %>%
hot_col(col = "Post", type = "dropdown")
})
saveData <- eventReactive({input$saveBtn},{
finalDF <- hot_to_r(input$contents)
finalDF$Post <- ifelse(finalDF$Post =="",NA,finalDF$Post)
newDF <- finalDF[complete.cases(finalDF),]
return(newDF)
})
output$contentFinal <- renderRHandsontable(
rhandsontable(saveData())
)
output$dashboard1 <- renderPlot(
ggplot(input$contentFinal, aes(x = Post, y = list2 )) +
geom_bar(stat = "identity")
)
observeEvent(input$saveBtn, saveData())
}
shinyApp(ui = ui, server = server)
The flow is like this:
In the first tab, I bring up data with an empty post column
In this tab, I can add a name for the post and save it.
As soon as I save he rows with values for post become visible in the next tab.
Then the next thing I want to do is to have a visual in the dashboard tab that shows the data. Therefore I create:
output$dashboard1 <- renderPlot(
ggplot(input$contentFinal, aes(x = Post, y = List2 )) +
geom_bar(stat = "identity")
)
This however gives me the following ggplot2 errror:
ggplot2 doesn't know how to deal with data of class list
Any thoughts on what goes wrong here?
The problem is because input$contentFinal is handsontable data. We need to convert it to R object using hot_to_r function.
The ggplot should be plotted using the following:
ggplot(hot_to_r(input$contentFinal), aes(x = Post, y = list2 )) +
geom_bar(stat = "identity")
Hope it helps!