Is there any equivalent of web sockets in shiny world

I was trying to learn web technology and I came upon this word WEB SOCKET. My dashboards update their entire page when I try to update only value box or flex box.

Its there any package that can help establish a web socket so that only the values will be updated and not the entire page.

1 Like

Shiny is built on top of websockets (originally via the now-defunct websockets package, and nowadays via httpuv). A brief description of how this works for Shiny (from Debugging Shiny Applications):

Shiny’s architecture consists of a client (the browser) and a server (an R process). The two are connected by a websocket that receives state changes from the client, such as new values for input controls, and distributes state changes from the server, such as new output values.

6 Likes

To address your first problem. Shiny should only invalidate the values that depend on the values that you updated. That is the preferred design from a reactive perspective, as I understand it, at least. If that is not the case in your application, you may want to do a bit more work on the reactive dependency tree to explore that possibility.

Do you have a simple example that it is possible to discuss / troubleshoot / share? If you want to control reactivity with a bit more fine-toothed comb, you can look at functions debounce, throttle, and isolate. Also, throwing in a button in the dependency tree will require the user to press the button before changes are fired through the downstream dependencies.

3 Likes

If you do want to try out web sockets and R see the websocket package (not to be confused with the defunct websockets package).

3 Likes

This is a link to a dashboard which updates itself every 5 seconds. and you can see the boxes getting dim and then rebuild again and again.

https://vikramsinghrawat.shinyapps.io/LumaX/

It should not happen

it's just a basic app and if you still want to read the code this is where you can check it.

just download the repo and run the app.

Like @cole suggested, this seems to be a result of the reactive dependency tree in this example app. At the beginning of server(), you’ve got this:

    num <- reactive({
        invalidateLater(5000)
        floor(((minute(Sys.time(
        )) * 60) + second(Sys.time())) * 7)
    })
    
    
    df <- reactive({
        data[1:num(), ]
    })

Then every single output in the app is constructed from df(). With the number of rows in the underlying data frame changing every 5 seconds, how should outputs that depend on that data frame (filtering, making calculations, plotting the data) not also need to be recalculated? Can you describe in more detail what you are hoping for here?

5 Likes

Thanks for pointing it out. I was just trying to learn a little bit webprogramming so don't know much about it. I just wanted to know if there is any way we can use websockets in Shiny so that I can update values without updating the entire UI element.

You could be perfectly right.:grinning::grinning::grinning:

If shiny does it as default app then It meets my need perfectly fine. Could you please explain me why does the value box blink while updating the data.

Is it something I can stop because it doesn't look neat that a box flashes for half second before it updates. what should I do in such scenarios where I want to update value box every second but I don't want to show the flash. I just want to update the values.

So the issue here is with the specific UI item you are using. Certain types of UI objects (available via R packages like shiny, etc.) allow a renderObject, objectOutput pattern that allows you to send updated data and the client-side-rendered-UI knows how to, for instance, just replace the number without repainting the whole UI.

However, the data boxes here (in fact, it seems you are following a similar pattern) must be repainting the whole UI. I suspect it would take a bit of JavaScript to circumvent the repainting (and just update the numbers). If I were to guess why "repaint everything" is the default, it would be because box color may be dependent on the new value? Definitely a feature request for that particular "valueBox" implementation, though!

3 Likes

Even the Graph gets re-rendered. It's not just the valuebox. When the entire scenario is to show updated numbers every second. There should be a package or a method I could use to just show them neatly.

Something like you see on a stock tick which updates automatically without updating the entire plot.

Yeah, this makes sense. I think what you're talking about is definitely do-able. The difficulty is largely because these packages are mostly built (by my guess) to expect new data = new graph. So what you're looking for is a "smart" client-side library that knows how to accept only "appends" or minor changes. I had a similar desire recently. r2d3 might be a good place to get started for ultimate customization, or try to find users with similar desires - I think it would make a killer R package (or update to an existing)!

4 Likes

Well I don't know much about programming. But if I know correctly. Htmlwidget provides data to all the libraries. From dygraph to plotly and almost every other one. If we could find a way to append new data without changing the old one. May be that would work.

But this is what I wanted to know from the beginning is there a way to implement web sockets in R. This is how web sockets usually work. By creating a constant stream of data in and out from server to client. Unlike the render and serve approach. It doesn't require an event to trigger the changes in data or ui.

I think I am stuck with such a task. The data file included in my git is from a machine and I have to create a dashboard so that we can see the production and temperature and stuff of the machine real-time. Some of these machine need data updation in like every second.

So if there is any work around I would love to know it. Else I have to tell them this is not something I could do. 1 minute would be a more realistic approach.

Please do let me know if you have any tricks left up your sleeve. I am all ears.:roll_eyes:

The point from @jcblum above is that Shiny does use websockets, so this functionality is technically available. The problem is that the display libraries you are using are not taking advantage of streaming data. They are doing batch oriented data processing. This is just a function of the (1) easier thing to program, (2) most common use case.

I guess what I'm saying is that I (and hopefully others) are interested in this use case, so hopefully we can find / craft package resources that start moving this direction! What are the particular resources you are looking for? A valueBox that just updates the number? A dygraph that doesn't redraw the whole thing, but just adds a new data-point?

3 Likes

Value box
Flex box
Guage chart
Time series graphs

Are I think most important one that should use this functionality. I will open an issue on github and see if I get any response.

1 Like

This is something I opened and let's see what we get on this.

I have my fingers crossed. If we could achieve it. This might reduce the burden on shiny server of recreating the graph every second. It might speed things up because shiny shouldn't have to throw the entire js code to the web but just the data. Which is huge advantage. Because that is what most of the back end do.

@Anantadinath, @cole is correct in that most packages are doing batch processing. This does not allow for small updates to existing graphs.

leaflet and plotly have added a method called leafletProxy and plotlyProxy to handle updates to existing graphics. dygraphs does not have a proxy method, so it must do a full redraw, regardless of how small the update.


If you want to push data to the browser manually for you to handle with custom javascript, please look at https://shiny.rstudio.com/articles/js-send-message.html.


As @nteetor stated above, there is a websocket package for R: https://github.com/rstudio/websocket. But I would recommend using shiny's existing websocket infrastructure with sendCustomMessage rather than building the wheel from scratch.

3 Likes

@jbkunst worked out how to stream data into a highchart in shiny a while back :raised_hands:

app: http://104.140.247.162:3838/shiny-apps-highcharter/real-time-chart/

repo:
https://github.com/jbkunst/shiny-apps-highcharter/tree/master/real-time-chart

3 Likes

Thanks for such a great reply this is exactly what I wanted to know. Just wanted to know what's available and what's not.

Thanks again.

1 Like

So I was just poking at this for fun on one of the easier cases (valueBox). The whole box is getting repainted, but it happens so fast that a user is basically unable to tell. The only way it is obvious to me is by watching in the browser devtools. Is there a particular problem you are having in the valueBox case with the div getting rebuilt?

The example, if anyone is interested:

library(shiny)
library(shinydashboard)

ui <- dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
        valueBoxOutput("value_box"),
        infoBoxOutput("info_box")
    ),
    title = "Test Streaming"
)

server <- function(input, output) {
    value <- reactiveVal(45)
  output$value_box <- renderValueBox({
      valueBox(value(), "Subtitle", icon = icon("dashboard"))
  })
  output$info_box <- renderInfoBox({
      infoBox("Title", value(), "Subtitle", icon = icon("bar-chart"))
  })
    observe({
        invalidateLater(1000)
        isolate(value(value() + 1))
        print(paste("Updated value:", value()))
    })
}

# Run the application
shinyApp(ui = ui, server = server)
1 Like

As I told you before in my code it blinks. May be because your hardware would be better than mine. But in my code it does blink a little and I was worried about if I had to do it for 150 machine real time.

But now I have convinced them to refresh every minute instead of seconds.

So I think I am good now.

Thanks anyways.

:grinning:

Always love it when the people side can solve the technical problem :slight_smile:

In any case, for my own learning and for fun, I created a proposed implementation of this for the simple case of infoBox and valueBox. It can be seen in this PR, or installed with
devtools::install_github("colearendt/shinydashboard@stream-box")

Further, this is an example in action (alongside the previous):

library(shiny)
library(shinydashboard)

ui <- dashboardPage(
    dashboardHeader(),
    dashboardSidebar(),
    dashboardBody(
        valueBoxOutput("value_box"),
        infoBoxOutput("info_box"),
        infoBox("Title", 45, "Subtitle", icon = icon("bar-chart"), id = "testbox"),
        valueBox(id = "someid", 45, "Subtitle", icon = icon("dashboard"))
    ),
    title = "Test Streaming"
)

server <- function(input, output, session) {
  value <- reactiveVal(45)
  output$value_box <- renderValueBox({
      valueBox(value(), "Subtitle", icon = icon("dashboard"))
  })
  output$info_box <- renderInfoBox({
      infoBox("Title", value(), "Subtitle", icon = icon("bar-chart"))
  })
    observe({
        invalidateLater(1000)
        isolate(value(value() + 1))
        print(paste("Updated value:", value()))
        updateBoxValue(
          session,
          someid = value(),
          testbox = value()
        )
    })
}

# Run the application
shinyApp(ui = ui, server = server)
1 Like