Using reactiveFileReader function in Shiny - r

I would like your help to access the result elements that the reactiveFileReader function offers me, in which case the result is fileData ()
The server code is this:
server <- function(input, output,session) {
fileData <- reactiveFileReader(1000,session,filePath = 'ddeLink.xlsm', readFunc = read_excel)
output$data <- renderTable({
fileData()
})
}
The excel spreadsheet linkdde.xslm every five minutes updates. It is composed of 2 columns where only column b is updated. The excel file bellow:
The code works fine. That is, whenever the excel spreadsheet updates my app Shiny also updates the mmatrix above, which is the fileData ()result.
The fileData()is always updating. The fileData() is the matrix above.
But my question is: How do I access the values ​​of this mtrix, represented by the fileData () to create a plot that would be updated because the fileData () is updating. In other words I want to have a plot updating every 5 minutes using the 5 minutes fileData () matrix?
I did this:
output$data <- renderPlot({
df<-as.data.frame(fileData())
plot(df[,1])
})
But it didnt work.
Any help guys
Many thanks

The below example seems to work, where the plot is updated when the Excel file is updated. Is this what you are looking for? If not, please describe further what you need.
library(shiny)
library(readxl)
ui <- fluidPage(
mainPanel(
uiOutput("data"),
plotOutput("plot")
)
)
server <- function(input, output,session) {
fileData <- reactiveFileReader(1000,
session,
filePath = 'ddeLink.xlsx',
readFunc = read_excel)
output$data <- renderTable({
fileData()
})
output$plot <- renderPlot({
df<-as.data.frame(fileData())
plot(df[,2])
})
}
shinyApp(ui, server)

Related

Can you parse an XML into R Shiny and view as a data frame?

I'm new to R-shiny and I'm trying to develop an R-shiny application that would allow the user to upload an XML file, view the table as a data frame, and then download it as a CSV.
I've so far had no luck anywhere trying to find info on parsing XML's into R-shiny. Below is some code that I found from someone else's post on here which allows you to read in an XML and it will display the raw text, but I'm looking to get a proper data frame so that I can do some analysis on the data that the user uploads.
library(shiny)
ui <- fluidPage(
fileInput("File", "Choose file"),
tableOutput("Data")
)
server <- function(input, output, session) {
Data <- eventReactive(input$File, {
read_xml(input$File$datapath)
})
output$Data <- renderTable({
head(xml_text(Data()))
})
}
shinyApp(ui, server)
The code to do what I need in R is very simple, but converting this over to R-shiny is causing me lots of trouble.
data <- xmlParse("C:/filepath/data.xml")
df <- xmlToDataFrame(data, nodes =getNodeSet(data, "//nm:Row",
namespaces=c(nm = "urn:schemas-microsoft-com:office:spreadsheet")))
Can anyone help please?
Thanks in advance!
You can use package XMLthe same way you do in base R:
library(shiny)
library(XML)
ui <- fluidPage(
fileInput("File", "Choose file"),
tableOutput("Data")
)
server <- function(input, output, session) {
df <- eventReactive(input$File, {
xmlToDataFrame(input$File$datapath)
})
output$Data <- renderTable( head( df()))
}
shinyApp(ui, server)
Update: I've managed to solve the issue by writing a function that converts the "table" node of the xml into a data frame, and calling this function from within the server.
converter <- function(xml_data){
data <- xmlParse(xml_data)
df <- xmlToDataFrame(data, nodes =getNodeSet(data, "//nm:Row",
namespaces=c(nm = "urn:schemas-microsoft-com:office:spreadsheet")))
colnames(df) <- df[1,]
df <- df[-1, ]
return(df)
}
ui <- fluidPage(
fileInput("File", "Choose file"),
tableOutput("Data")
)
server <- function(input, output, session) {
df <- eventReactive(input$File, {
converter(input$File$datapath)
})
output$Data <- renderTable( head( df()))
}
shinyApp(ui, server)

How to save data in database from shiny app?

I want to save user'S data in the db.
Every user's data should be submitted per row without any error. The data is in a function with if else condition. Every if else's output is to be saved against it's user. How can I do it?
I tried creating a dataframe for it but still the data wasn't saved in it.
Here is reprex of my code.
library(shiny)
library(tidyverse)
ui <- fluidPage(
textInput("my_in","type a value for an entry"),
actionButton("newline_but","press for a new entry"),
tableOutput("showmytable")
)
server <- function(input, output, session) {
mydf <- reactiveVal(tibble(msg=NA_character_))
output$showmytable <- renderTable({
mydf()
})
observeEvent(input$my_in,{
local_df <- req(mydf())
curr_row <- nrow(local_df)
local_df[curr_row,1] <- input$my_in
mydf(local_df)
})
observeEvent(input$newline_but,{
local_df <- req(mydf())
mydf(add_row(local_df))
})
observeEvent(mydf(),
{
#export to a global but would be better to maybe write to a database
assign(x="exported_df",
value=mydf(),
envir = .GlobalEnv)
})
}
shinyApp(ui,server)```

Object not found R Shiny

I am trying to access the data frame created in one render function into another render function.
There are two server outputs, lvi and Category, in lvi I have created Data1 data frame and Category I have created Data2 dataframe. I want to select Data2 where Data1 ID is matching.
I am following the below steps to achieve my objective but I get error "Object Data1 not found".
My UI is
ui <- fluidPage(
# App title ----
titlePanel("Phase1"),
fluidPage(
column(4,
# Input: Select a file ----
fileInput("file1", "Import file1")
)
),
fluidPage(
column(4,
# Input: Select a file ----
fileInput("file2", "Import File2")
)
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
dataTableOutput("lvi"),
dataTableOutput("category")
)
)
My server code is
server <- function(input, output) {
output$lvi <- renderDataTable({
req(input$file1)
Data1 <- as.data.frame(read_excel(input$file1$datapath, sheet = "Sheet1"))
})
output$category <- renderDataTable({
req(input$file2)
Data2 <- as.data.frame(read_excel(input$file2$datapath, sheet = "Sheet1"))
Data2 <- Data2[,c(2,8)]
Data2 <- Data2[Data1$ID == "ID001",]
})
}
shinyApp(ui, server)
Once a reactive block is done executing, all elements within it go away, like a function. The only thing that survives is what is "returned" from that block, which is typically either the last expression in the block (or, when in a real function, something in return(...)). If you think of reactive (and observe) blocks as "functions", you may realize that the only thing that something outside of the function knows of what goes on inside the function is if the function explicitly returns it somehow.
With that in mind, the way you get to a frame inside one render/reactive block is to not calculate it inside that reactive block: instead, create that frame in its own data-reactive block and use it in both the render and the other render.
Try this (untested):
server <- function(input, output) {
Data1_rx <- eventReactive(input$file1, {
req(input$file1, file.exists(input$file1$datapath))
as.dataframe(read_excel(input$file1$datapath, sheet = "Sheet1"))
})
output$lvi <- renderDataTable({ req(Data1_rx()) })
output$category <- renderDataTable({
req(input$file2, file.exists(input$file2$datapath),
Data1_rx(), "ID" %in% names(Data1_rx()))
Data2 <- as.data.frame(read_excel(input$file2$datapath, sheet = "Sheet1"))
Data2 <- Data2[,c(2,8)]
Data2 <- Data2[Data1_rx()$ID == "ID001",]
})
}
shinyApp(ui, server)
But since we're already going down the road of "better design" and "best practices", let's break data2 out and the data2-filtered frame as well ... you may not be using it separately now, but it's often better to separate "loading/generate frames" from "rendering into something beautiful". That way, if you need to know something about the data you loaded, you don't have to (a) reload it elsewhere, inefficient; or (b) try to rip into the internals of the shiny DataTable object and get it manually. (Both are really bad ideas.)
So a slightly better solution might start with:
server <- function(input, output) {
Data1_rx <- eventReactive(input$file1, {
req(input$file1, file.exists(input$file1$datapath))
as.dataframe(read_excel(input$file1$datapath, sheet = "Sheet1"))
})
Data2_rx <- eventReactive(input$file2, {
req(input$file2, file.exists(input$file2$datapath))
dat <- as.dataframe(read_excel(input$file2$datapath, sheet = "Sheet1"))
dat[,c(2,8)]
})
Data12_rx <- reactive({
req(Data1_rx(), Data2_rx())
Data2_rx()[ Data1_rx()$ID == "ID001", ]
})
output$lvi <- renderDataTable({ req(Data1_rx()); })
output$category <- renderDataTable({ req(Data12_rx()); })
}
shinyApp(ui, server)
While this code is a little longer, it also groups "data loading/munging" together, and "render data into something beautiful" together. And if you need to look at early data or filtered data, it's all right there.
(Side note: one performance hit you might see from this is that you now have more copies of data floating around. As long you are not dealing with "large" data, this isn't a huge deal.)

Accessing data in different parts of server() in shiny

I am having a problem with accessing data in different parts of my server() function. The basic structure is something like this:
server <- shinyServer(function(input, output) {
# get the data from a file obtained from a textInput in the ui
data <- reactive({
req(input$file)
file <- input$file$datapath
# process the file and return a new dataframe
})
output$head <- renderTable({
mydf <- data()
head(mydf)
})
output$tail <- renderTable({
mydf <- data()
tail(mydf)
})
})
I would like to avoid having to call data() twice but I haven't found a way to do that.
Edit following the comment by #KentJohnson
What I am trying to achieve is for the user to select a file to open, using textInput, and after the file is opened, the app should do some processing and populate the two tables in the ui. After this, the user then chooses some other actions which also require the same data.
I wanted to avoid having to call data() twice but I haven't found a way to do that. I was assuming that each call would mean reading from the file each time. The file is very large so that is my motivation.
As #KentJohnson points out, reactive already achieves your goal. The expression that makes up data...
req(input$file)
file <- input$file$datapath
# process the file and return a new dataframe
...only runs when input$file$datapath changes. It does not rerun each time data() is called.
Putting your two tables into an observe environment makes it possible to call data() only twice, but I don't know if it will fit with what you want to do. Notice that here, I didn't put a textInput or things like that because my point was to show the observe environment. I'll let you adapt it to your situation (since you didn't put the ui part in your post):
library(shiny)
ui <- basicPage(
fileInput("file",
"Import a CSV file",
accept = ".csv"),
tableOutput("head"),
tableOutput("tail")
)
server <- shinyServer(function(input, output) {
# get the data from a file obtained from a textInput in the ui
data <- reactive({
req(input$file)
inFile <- input$file
read.csv(inFile$datapath, header = F, sep = ";")
# process the file and return a new dataframe
})
observe({
mydf <- data()
if (is.null(mydf)){
output$head <- renderTable({})
output$tail <- renderTable({})
}
else {
output$head <- renderTable({
head(mydf)
})
output$tail <- renderTable({
tail(mydf)
})
}
})
})
shinyApp(ui, server)
Edit: I misunderstood the OP's question, see #SmokeyShakers' answer for a more appropriate answer.

Shiny Server get number of records in a dataframe

Im trying to learn shiny and to read in an excel sheet and show both the contents of the excel sheet and the number of records in the UI
I'm a bit lost. when i read in the data set, how do i reference the dataframe that i have read in
# Server Code
server <- shinyServer(function(input, output) {
# Read the Data in
library(xlsx)
# Output the actual Table
output$contents <- renderTable({
test_df <- read.xlsx(inFile$datapath,1)
test_df
)})
# Output the number of records to check
output$text <- renderText({
paste("Number of records is:", nrow(test_df))
})
})
Best practice would be to have your library calls and any read_* functions in your global.R file (which should be in the same directory as server.R and ui.R. global.R will be parsed at the beginning of your web application and the file will be available in both the ui and the server (though you only need it in the server here).
So something like:
#in globar.R
library(xlsx)
test_df <- read.xlsx(inFile$datapath,1)
#and server
server <- shinyServer(function(input, output) {
# Output the actual Table
output$contents <- renderTable({
test_df
)})
# Output the number of records to check
output$text <- renderText({
paste("Number of records is:", nrow(test_df))
})
})
should work fine.

Resources