Displaying the value of bar created in R using shiny and plotly - r

If you run the R shiny script below, we get two boxes in a dashboard, the left box has a bar chart and right has a DT table, when I click on any bar of the chart using event_data("plotly_click"), I want the corresponding Employee to be displayed in the table besides, like when clicked on first bar, "r1" should be displayed in the table besides. I tried doing "user_cases$base1[d[3]]" but it throws an error as "Error: invalid subscript type 'list'". I will attach the snapshot for the reference, please help me with the same.
## app.R ##
library(shiny)
library(shinydashboard)
library(ggplot2)
library(plotly)
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "Sankey Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader =
T,
plotlyOutput("sankey_plot")),
box( title = "Case Summary", status = "primary", height = "455",solidHeader
= T,
dataTableOutput("sankey_table"))
)
)
server <- function(input, output)
{
output$sankey_plot <- renderPlotly({
height2 = c(56,45,23,19,8)
base1 = c("r1","r4","r2","r5","r3")
user_cases = data.frame(base1,height2)
pp1 <<- ggplot(user_cases, aes(x = reorder(base1,-height2), y = height2)) +
geom_bar(stat = "identity", fill = "#3399ff" ) + scale_y_discrete(name
="Cases") + scale_x_discrete(name = "Employee")
ggplotly(pp1, tooltip="text",height = 392)
})
output$sankey_table <- renderDataTable({
d <- event_data("plotly_click")
user_cases$base1[d[3]]
})
}
shinyApp(ui, server)
Dataset to be fetched
I am trying to fetch subset of the data from the patients dataset from bupaR library. The code for doing it is as follows:
patients_final <- patients[patients$employee == as.data.frame(
user_time$employee[as.numeric(d[3])])]
but the error I get is: "Can't use matrix or array for column indexing" attaching the snapshot for the help.

Have a look at the modified code, I have changed user_cases$base1[d[3]] to as.data.frame(user_cases$base1[as.numeric(d[3])])
## app.R ##
library(shiny)
library(shinydashboard)
library(ggplot2)
library(plotly)
library(DT)
height2 = c(56,45,23,19,8)
base1 = c("r1","r4","r2","r5","r3")
user_cases = data.frame(base1,height2)
ui <- dashboardPage(
dashboardHeader(title = "Sankey Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader =
T,
plotlyOutput("sankey_plot")),
box( title = "Case Summary", status = "primary", height = "455",solidHeader
= T,
dataTableOutput("sankey_table"))
)
)
server <- function(input, output)
{
output$sankey_plot <- renderPlotly({
pp1 <<- ggplot(user_cases, aes(x = reorder(base1,-height2), y = height2)) +
geom_bar(stat = "identity", fill = "#3399ff" ) + scale_y_discrete(name
="Cases") + scale_x_discrete(name = "Employee")
ggplotly(pp1, tooltip="text",height = 392)
})
output$sankey_table <- renderDataTable({
d <- event_data("plotly_click")
as.data.frame( user_cases$base1[as.numeric(d[3])])
})
}
shinyApp(ui, server)
The output is as below:
You can modify the dataframe output as per your requirement.
Hope it helps!

Related

How to display the plot considering the update with switch()?

So I'm trying to create a shiny app to visualize some probability functions. I've got an old version (which works) with some very heavy code and now I want to update it using the switch functions. But my plot does not seem to respond very well to that.
I've tried to use the req() function to force the update of the data. But then I thought that maybe the problem was I just can't use the same name for the plot in two panels.
ui <- dashboardPage(
dashboardHeader(title = "probability laws"),
dashboardSidebar(
sidebarMenu(id='menus',
menuItem(text = "Plotting some densities" , icon = icon("atlas"),tabName = "density"),
menuItem(text = "repartition functions", icon = icon("cog", lib = 'glyphicon'),tabName = "repartition")
)
),
dashboardBody(
tabItems(
tabItem("density",
fluidRow(
tabsetPanel(id = 'tabs',
tabPanel(title='uniforme',value='unif',fluidRow(
column(8, plotOutput('graphe')),
column(3,wellPanel(
sliderInput(inputId = "inf",label = "borne inf",min = -10,max = 10,value = 0,step = 0.2),br(),
sliderInput(inputId = "sup",label = "borne sup",min = -10,max = 10,value = 1,step = 0.2),br())
))),
tabPanel(title='normale',value='norm',fluidRow(
column(8, plotOutput('graphe')),
column(3,wellPanel(
sliderInput(inputId = "mu",label = "mean",min = -10,max = 10,value = 0,step = 0.2),br(),
sliderInput(inputId = "var",label = "variance",min = 0,max = 10,value = 1,step = 0.2),br())
)))
)
)))))
And in the server:
server <- function(input, output,session) {
x <- reactive({switch (input$tabs,
'unif' = seq(-10,10,0.1),
'norm' = seq(-10,10,0.1)
)})
data <- reactive({switch(input$tabs,
'unif' = dunif(x(),0,1),
'norm' = dnorm(x(),0,1)
)})
data2 <- reactive({switch(input$tabs,
'unif' = dunif(x(),min(input$inf, input$sup),max(input$inf,input$sup)),
'norm' = dnorm(x(), input$mu, sqrt(input$var))
)})
output$graphe <- renderPlot({df <- melt(data.frame(x(),data(),data2()), id='x..')
ggplot(data=df, aes(x=x.., y=value, colour=variable)) + geom_line() + xlim(-10,10) + ylim(0,1) + theme(legend.position = 'none')
})
}
The thing is R doesn't find any error, and if I just keep the unif part it works. But when I add the normal distribution panel I'm left with a blank space.
Any help is greatly appreciated.
So with some research I solved this by using graphe1 and graph2 like :
output$graphe1 <- output$graphe2 <- renderPlot(...)
Thank you #Stéphane_Laurent for pointing out where the mistake was.

R shinydashboard display sum of selected input in a valuebox

My question relates to "value4" which is a valuebox in the below code.
I have created a select input which allows the user to choose a name, based on that name I want the app to find the number of projects that are associated to the name picked (number of projects = "X..setup") and then display the total number of projects in a valuebox("value4").
The problem I am having is getting the sum of all projects.
Please find my code below:
setups <- read.csv("C:/Users/obria/Desktop/setUps/setUp.csv",stringsAsFactors = F, header = TRUE)
View(setups)
head(setups)
searchDF <- setups[c(1,2,3,4,7,8,9,10,11)]
#lst.Owners <- as.list(unique(setups$Owners))
lst.Owners = as.character(setups$Owners)
Owners <- unique(lst.Owners)
userInput <- sum(str_count(setups$Over.all.Status.of.Project,"WIP")) %>% groub_by(Owners)
install.packages("dplyr")
install.packages("ggplot2")
library(ggplot2)
library(dplyr)
library(shiny)
library(shinydashboard)
library(stringr)
library (DT)
ui = dashboardPage(
#Header
dashboardHeader(title = "Set ups dashboard"),
#Sidebar
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard"),
menuItem("Search", tabName = "search"),
menuItem("Break Down", tabName = "breakDown")
)
),
#Body
dashboardBody(tabItems(
# First tab content
tabItem(tabName = "dashboard",
fluidRow(
valueBoxOutput("value1")
,valueBoxOutput("value2")
,valueBoxOutput("value3"),
fluidRow(
box(
title= "Owner Vs Set Ups"
,status = "primary"
,solidheader = TRUE
,collapsible = TRUE
,plotOutput("nameStatus", height = "300px")
)
,box(
title= " Pant Vs Set Ups"
,status = "primary"
,solidheader = TRUE
,collapsible = TRUE
,plotOutput("plantSetUps", height = "300px"))))
),
# Second tab content #
tabItem(tabName = "search",
fluidRow(
h2("Search Set ups"),
DT::dataTableOutput("mytable")
)),
# Third tab content #
tabItem(tabName = "breakDown",
h2("Search Set ups"),
fluidRow(
box(
selectInput("selectVariable", "Select Variable:",
choices = Owners,
selected = 1))),
fluidRow(
valueBoxOutput("value4")
))))
)
server = function(input, output) {
# Get some data #
# Total Set ups #
totalSetUps <- sum(setups$X..setups)
# Number of WIPs #
workIP1 <- sum(str_count(setups$Over.all.Status.of.Project,"WIP"))
workIP2 <- sum(str_count(setups$Over.all.Status.of.Project,"wip"))
workInProgress <- (workIP1 + workIP2)
# Number of Outstanding #
outstanding <- sum(str_count(setups$Over.all.Status.of.Project,"Outstanding"))
# Colonia - Test Val;ue box #
#colonia <- sum(str_count(setups$Plant,"Colonia"))
setUpByName <- reactive ({
setups %>%
filter(Owners == input$selectVariable) %>%
sum(.$X..setups)
})
# Create the valueBoxOutput Content #
output$value1 <- renderValueBox({
valueBox(
format(totalSetUps, format="d", big.mark=",")
,"Total Number of Set Ups"
,icon = icon("stats",lib="glyphicon")
,color = "purple")
})
output$value2 <- renderValueBox({
valueBox(
format(workInProgress, format="d", big.mark=",")
,"No. of project that are WIP"
,icon = icon("gbp",lib="glyphicon")
,color = "green")
})
output$value3 <- renderValueBox({
valueBox(
format(outstanding, format="d", big.mark=",")
,"No. of project that are Outstanding"
,icon = icon("menu-hamburger",lib="glyphicon")
,color = "yellow")
})
output$value4 <- renderValueBox({
valueBox(
format(setUpByName(), format="d", big.mark=",")
,"total # Set ups"
,icon = icon("menu-hamburger",lib="glyphicon")
,color = "yellow")
})
# Creating plot output content #
output$nameStatus <- renderPlot({
ggplot(data = setups,
aes(x=setups$Owners, y=setups$X..setup, fill=factor(Over.all.Status.of.Project))) +
geom_bar(position = "dodge", stat = "identity") + ylab("No. of Set ups") +
xlab("Owners") + theme(legend.position="bottom"
,plot.title = element_text(size=15, face="bold")) +
ggtitle("Owners vs No. of Set Ups") + labs(fill = "Status")
})
output$plantSetUps <- renderPlot({
ggplot(data=setups, aes(x=setups$Plant, y= setups$X..setup)) +
geom_bar(stat="identity", col="blue", fill="blue") +
labs(title ="No of Set ups by plant")
})
output$mytable = DT::renderDataTable({
setups
})
output$result <- renderText({
paste("You chose", input$selectVariable)
})
}
shinyApp(ui, server)
str(setups)
DF Columns
Error
CodeError2
ShinyError2
Data
Data Types
Any help would be greatly appreciated.
Thank you
calling select works like a select statement in SQL, meaning that after that statement X..setups is the only column that remains. If you want to include only setups for the person selected in input$selectVariable you should first filter the setups data frame. Secondly, the functions in dplyr return objects that are of the same class as the input object. Your are passing a tibble into the function, so it is returning a tibble. However, you need it to be a scalar in order to be rendered in the valueBox. You can make it a scalar by passing the filtered data to the base sum function and only summing the X..setups column.
setUpByName <- reactive ({
setups_filtered <- setups %>%
filter(Owners == input$selectVariable)
sum(setups_filtered$X..setups)
})

How to persist event_data across tabs in Shiny?

I have a shiny application in which I'd like to capture which bar a user clicks on and store that value in a reactive expression to be referenced elsewhere for filtering. The problem is that the reactive expression reruns when I switch tabs and so the value doesn't sync up between the two tabs.
I have a reproducible example below.
When you load the app and click on the Goats bar, the selection at the bottom changes to 'Goats', but if you then change the tab to Bar2 the reactive expression reruns and therefore returns Giraffes again. So I end up with two separate values for the reactive expression across the different tabs. If I choose Goats on the first tab, I want it to remain when I switch to Bar2 tab and only update when I make another click.
Note that I realize I can resolve this in this example by removing the source argument from the event_data function, but in my application I have other charts which I do not want the user to be able to click on so I need to set the source to only these charts.
library(shiny)
library(plotly)
library(ggplot2)
library(shinydashboard)
df_test <- data.frame(c("Giraffes","Goats"),c(1,4))
df_test <- setNames(df_test,c("species","amount"))
ui <- dashboardPage(
dashboardHeader(title = "Click Example",
titleWidth = 300),
dashboardSidebar(
width = 300,
sidebarMenu(
menuItem("Tab", tabName = "tab")
)
),
dashboardBody(
tabItems(
tabItem(tabName = "tab",
fluidRow(
column(12, tabBox(
title = "",
id = "tabSet",
width = 12,
height = 500,
tabPanel("Bar1", plotlyOutput(outputId="bar_one")),
tabPanel("Bar2", plotlyOutput(outputId="bar_two"))
)
),
column(12,textOutput(outputId = "selection")))
)
)
)
)
server <- function(input, output, session) {
click_reactive = reactive({
d <- event_data("plotly_click",source=input$tabSet)
if (length(d) == 0) {species = as.vector(df_test$species[1])}
else {species = as.character(d[4])}
return(species)
})
output$bar_one <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar1")
})
output$bar_two <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar2")
})
output$selection <- renderText({
species <- click_reactive()
return(species)
})
}
shinyApp(ui, server)
You need to change the source to be under one name:
library(shiny)
library(plotly)
library(ggplot2)
library(shinydashboard)
df_test <- data.frame(c("Giraffes","Goats"),c(1,4))
df_test <- setNames(df_test,c("species","amount"))
ui <- dashboardPage(
dashboardHeader(title = "Click Example",
titleWidth = 300),
dashboardSidebar(
width = 300,
sidebarMenu(
menuItem("Tab", tabName = "tab")
)
),
dashboardBody(
tabItems(
tabItem(tabName = "tab",
fluidRow(
column(12, tabBox(
title = "",
id = "tabSet",
width = 12,
height = 500,
tabPanel("Bar1", plotlyOutput(outputId="bar_one")),
tabPanel("Bar2", plotlyOutput(outputId="bar_two"))
)
),
column(12,textOutput(outputId = "selection")))
)
)
)
)
server <- function(input, output, session) {
v <- reactiveValues()
observe({
d <- event_data("plotly_click",source="Bar1")
if (length(d) == 0) {species = as.vector(df_test$species[1])}
else {species = as.character(d[4])}
v$click <- species
})
output$bar_one <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar1")
})
output$bar_two <- renderPlotly({
p <- plot_ly(data = df_test, x = ~amount, y = ~species, type = 'bar', orientation = 'h', source = "Bar1")
})
output$selection <- renderText({
v$click
})
}
shinyApp(ui, server)

Displaying the table details from sankey chart in R shiny

The script below works on the patients data from bupaR package,and creates a sankey plot listing the relation between a resource from the "employee" column with the activity he is involved in from the "handling" column in the patients data. Besides the plot there is a data table available from DT which gives details of every sankey plot path when clicked. I want a functionality such that when I click on any path, say path connecting "r1" employee and "Registration" handling activity, I want all the rows from patients data with both these fields available in the plot besides, similarly for all other paths, this should be dynamic as I shall apply the functionality on larger datasets. Attaching the snapshot for reference. Thanks and please help.
## app.R ##
library(shiny)
library(shinydashboard)
library(devtools)
library(ggplot2)
library(plotly)
library(proto)
library(RColorBrewer)
library(gapminder)
library(stringr)
library(broom)
library(mnormt)
library(DT)
library(bupaR)
ui <- dashboardPage(
dashboardHeader(title = "Sankey Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader = T,
plotlyOutput("sankey_plot")),
box( title = "Case Summary", status = "primary", height = "455",solidHeader = T,
dataTableOutput("sankey_table"))
)
)
server <- function(input, output)
{
output$sankey_plot <- renderPlotly({
sankeyData <- patients %>%
group_by(employee,handling) %>%
count()
sankeyNodes <- list(label = c(sankeyData$employee,sankeyData$handling))
trace2 <- list(
domain = list(
x = c(0, 1),
y = c(0, 1)
),
link = list(
label = paste0("Case",1:nrow(sankeyData)),
source = sapply(sankeyData$employee,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
target = sapply(sankeyData$handling,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
value = sankeyData$n
),
node = list(label = sankeyNodes$label),
type = "sankey"
)
data2 <- list(trace2)
p <- plot_ly()
p <- add_trace(p, domain=trace2$domain, link=trace2$link,
node=trace2$node, type=trace2$type)
p
})
output$sankey_table <- renderDataTable({
d <- event_data("plotly_click")
d
})
}
shinyApp(ui, server)
Hi I interpreted the output from event_data as such that pointNumber is the index of the link but I might be wrong here. Any way this is my Solution and it works for this data
library(shiny)
library(shinydashboard)
library(devtools)
library(ggplot2)
library(plotly)
library(proto)
library(RColorBrewer)
library(gapminder)
library(stringr)
library(broom)
library(mnormt)
library(DT)
library(bupaR)
library(dplyr)
ui <- dashboardPage(
dashboardHeader(title = "Sankey Chart"),
dashboardSidebar(
width = 0
),
dashboardBody(
box(title = "Sankey Chart", status = "primary",height = "455" ,solidHeader = T,
plotlyOutput("sankey_plot")),
box( title = "Case Summary", status = "primary", height = "455",solidHeader = T,
dataTableOutput("sankey_table"))
)
)
server <- function(input, output)
{
sankeyData <- reactive({
sankeyData <- patients %>%
group_by(employee,handling) %>%
count()
sankeyNodes <- list(label = c(sankeyData$employee,sankeyData$handling) %>% unique())
trace2 <- list(
domain = list(
x = c(0, 1),
y = c(0, 1)
),
link = list(
label = paste0("Case",1:nrow(sankeyData)),
source = sapply(sankeyData$employee,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
target = sapply(sankeyData$handling,function(e) {which(e ==
sankeyNodes$label) }, USE.NAMES = FALSE) - 1,
value = sankeyData$n
),
node = list(label = sankeyNodes$label),
type = "sankey"
)
trace2
})
output$sankey_plot <- renderPlotly({
trace2 <- sankeyData()
p <- plot_ly()
p <- add_trace(p, domain=trace2$domain, link=trace2$link,
node=trace2$node, type=trace2$type)
p
})
output$sankey_table <- renderDataTable({
d <- event_data("plotly_click")
req(d)
trace2 <- sankeyData()
sIdx <- trace2$link$source[d$pointNumber+1]
Source <- trace2$node$label[sIdx + 1 ]
tIdx <- trace2$link$target[d$pointNumber+1]
Target <- trace2$node$label[tIdx+1]
patients %>% filter(employee == Source & handling == Target)
})
}
shinyApp(ui, server)
hope it helps!

Display R Shiny Plot After Inputting File

I would like to display a chart (for a Shiny app), based on data inputted by a user through a file. With the current setup, there is an error message claiming the data is not found, so the plot (from the rCharts package) does not get displayed.
Code attached below:
ui.R
library(rCharts)
library(shinydashboard)
library(shiny)
dashboardPage(
skin = "black",
header <- dashboardHeader(
titleWidth = 475
),
sidebar <- dashboardSidebar(
sidebarMenu(
)
),
body <- dashboardBody(
tabItems(
tabItem("setup",
box(width = 4,title = tags$b('Input Dataset'), solidHeader = T, status = 'primary', collapsible = T,
helpText("Default max. file size is 5 MB. Please upload both files for analysis in csv format."),
fileInput("file1","Upload the first file"),
fileInput("file2","Upload the second file")
),
box(height = 500, width = 12,title = tags$b('Visualize Data'), solidHeader = T, status = 'primary',
showOutput("myPlot", "Highcharts")
)
)
)
)
)
server.R
library(shiny)
library(rCharts)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
observe({
file1 = input$file1
file2 = input$file2
if (is.null(file1) || is.null(file2)) {
return(NULL)
}
data1 = read.csv(file1$datapath)
data2 = read.csv(file2$datapath)
})
output$myPlot<-renderChart2({
# Prepare data
data1[,2] <- (data1[,2])/sum(data1[,2])
# Create chart
a <- rCharts:::Highcharts$new()
a$chart(type = "column")
a$xAxis(categories = rownames(x))
a$yAxis(title = list(text = "Normalized Intensity"))
a$data(data1)
a$set(width = 600, height = 500)
return(a)
})
})
Try adding something like this. Make sure you check for nrow and return and empty Highcharts$new() object as renderChart2 expects one.
library(shiny)
library(rCharts)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
data1 <- reactive({read.csv(file1$datapath)})
data2 <- reactive({read.csv(file2$datapath)})
output$myPlot<-renderChart2({
data1 <- data1()
# Prepare data
if(nrow(data1==0)){return(Highcharts$new())}
data1[,2] <- (data1[,2])/sum(data1[,2])
# Create chart
a <- rCharts:::Highcharts$new()
a$chart(type = "column")
a$xAxis(categories = rownames(x))
a$yAxis(title = list(text = "Normalized Intensity"))
a$data(data1)
a$set(width = 600, height = 500)
return(a)
})
})

Resources