Optimising Shiny Dashboard plot redraw - r

I have built a shiny dashboard which has a set of data loaded in as a data frame. It uses dplyr to then select columns, mutate new columns if needed, apply a set of filters and then plot using a variety of high-level ggplot2-based packages.
We try to do the data load, select and mutate just the once. The filtering is sat in a reactive variable, accessed by the plot, and is based upon different input values.
As far as I see this is a pretty standard and typical use case.
I'm wondering whether anyone could advise on workflow patterns to make the output more responsive.
There are two scenarios I encounter with this writing pattern which appear to cause significant user interface delay which I'd like to avoid:
Firstly, when the dashboard first loads it tries to plot the charts using NULL data. I've found I can get around this by using if(is.null(my_data_frame)) and returning geom_blank() rather than our plot. Is there a neater / faster way to do this?
Secondly (and more challengingly): to the right of my plot are a (potentially large) set of filter options to allow the user to analyse subsets. If the user clicks several of these options in rapid succession, Shiny will repeatedly recalculate our reactive() value and replot the chart for each click event: where the user actually just needed to set or clear 5 options. Is there a way to prevent this happening - so if the recalculation isn't complete we don't continue with the plot in progress as we've just made the data stale? Or do you think about grouping options with an update button to prevent this?

In response to your second bullet. Check out shiny's debounce/throttle capabilities. These should slow down the reactive response so your user can finish with the UI control before the chart or presentation element recalculates.

For your first question, try using the req function inside your reactive block. If your plot is waiting on the data frame to load, you can put the code for loading the data frame in a named reactive block (it seems like you may have already done this), then pass that to req. This will prevent the plot from attempting to render until it receives a valid value for whatever you passed to req.
For the second, I'd recommend wrapping your plot render in an observeEvent and having an 'Update' button, if you typically expect users to change multiple options between desired plot updates.
Finally, for added performance, I just saw today that Shiny v1.2.0 has either just been released or is about to be, the major feature of which is plot caching. You can find more details HERE.

Related

Obtain values from Shiny context from cmd

I am looking to get the values from a reactive function, based on a specific set of inputs, but without the dashboard open or visible. Is this possible?
I have two possible solutions, both of them I am not sure are possible, and which of the two would be better. Also, I do think there could be a better solution.
Start the dashboard at a specific time and write away a csv with the required information. I don't know how to put the input values to the right settings though (they would be different from the normal initial settings). Hopefully start this without a visible endpoint (headless chromedriver for example).
Within Shiny, do a check if it's a specific time. If that's the case, change all inputs to the right settings, and export/do something with the required values. I don't prefer this, as there will be users using the dashboard at that time, and I don't want to disturb their work.
To give a bit more context, I would like to obtain values/dataframes from several dashboards at a specific time. These values are calculated via a chain of multiple reactives and inputs. I cannot trust that these dashboards are already running, so I need to start them.

How to re-intitialize reactive render values Shiny?

I work on a Shiny app with multiple reactive variables as well as output objects scattered in numerous tabItems.
The idea behind this app is that on the first page you download a selected dataset, through an action button, that will be used by the entire app. After having created multiple reactive values and output objects when the user will explore the app, I would like to know if there is a simple way to re-initialize the application (reactive variables, output objects) as soon as we download another dataset thanks to the previous action button I have mentionned earlier.
In fact, I want to delete the value of reactive variables and output objects from the memory every time I click on this specific button and DL a new dataset.
I want this app to be the same as it is when I launch my code for the first time.
Regards
Thibaut
I tried to use reactive values a lot but it has to be done for every variables.
Perhaps, there is a simpler way.

Render output only when conditionalPanel conditions satisfied

I am writing a Shiny app that will be deployed across various users with screen resolutions ranging from 720p to 1080p. The application will be deployed on the web.
My page has a simple sidebar and a main content area. In order to adjust the width of the sidebar (to contain all the contents without any scrolling), I used two conditionalPanels in my UI.r, which render the appropriate 1080p or 720p UIs by evaluating "screen.width > 1600" or "screen.width < 1600".
This works fine, and the appropriate UIs are rendered as required.
However, after profiling the application, I realized that while the appropriate UI panels were indeed displayed, my server code was rendering both the high resolution and low resolution outputs, even though only one is being displayed at any given time.
Is there any way to disable the output that is not being displayed? I was looking into using global variables, since the screen width is never going to change during a session, but I was having trouble with shinyjs and evaluating the "screen.width" expression--it seems to return NULL anywhere but inside a conditionalPanel
Thanks
Without a minimal reproducible example, providing a solution is difficult. But req or validate and need might be what you want.
req is used to check values exist prior to execution: req documentation.
validate and need can be used together in a very similar way: validate documentation.
For example, you might try:
output$my_1080_plot = renderPlot(
validate(need(screen.width > 1600, message = FALSE))
# other commands to make plot
)
If the logical condition is not met then evaluation ceases and the other command are not run.

Reset text output from R in spotfire

I have written a code to generate texts based on certain conditions in Spotfire using R. The code refreshes automatically whenever a selection is made. Since there are a lot of if-else condition used in R, the code takes a noticeable time to refresh the content. The dashboards change but the text changes after a lag.
Is there anyway to reset the text output while the R code runs so that the user doesn't get confused?
I've go some Python triggered data function that can take between 5 minutes to an hour to execute. The hardest part is getting the HTML of a text area to update. What I've currently implemented is a loading bar coded by Halpenfield. Something I've been meaning to try but haven't gotten to yet is a more descriptive popup.
These won't reset the displayed text before executing code but they will make it clear to the user something is happening. There might be a way to do directly what you are asking with two HTML's and a forced refresh like Halpenfield uses.

Shinobi charts recreating every time

I am using shinobicharts ChartFragment. I have scenario that each time I have to load the chart with different data within same activity i.e I am not recreating that activity. But I am failed to do this. It not recreating and not clearing the series which I previously set to that chart.
Can anybody help, how can I remove old series in that chart and load new series each time? I tried shinobiChart().removeSeries() but it didn't work.
Thanks
If you wish to dynamically load new data, you do not necessarily need to remove the series. Instead you can simply add data points to your data adapter. You will find the following methods useful:
https://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.7.2/Premium/Normal/apidocs/docs/reference/com/shinobicontrols/charts/DataAdapter.html#add(int, com.shinobicontrols.charts.Data)
https://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.7.2/Premium/Normal/apidocs/docs/reference/com/shinobicontrols/charts/DataAdapter.html#add(com.shinobicontrols.charts.Data)
https://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.7.2/Premium/Normal/apidocs/docs/reference/com/shinobicontrols/charts/DataAdapter.html#addAll(int, java.util.Collection>)
https://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.7.2/Premium/Normal/apidocs/docs/reference/com/shinobicontrols/charts/DataAdapter.html#addAll(java.util.Collection>)
In these api docs you will also find similar methods to remove data points.
One thing to bear in mind is that adding or removing a data point to / from a SimpleDataAdapter class instance which is set on a series will trigger a redraw of that series. If you are working with large numbers of data points, this might not be performant. In this case a more suitable approach might be to temporarily remove the data adapter from the series, perform the modification to the data and then re add the data adapter back to the series. Alternatively you might like to implement your own DataAdapter and control when you instruct the chart to redraw that series (via the fireUpdateHandler method).
You can of course remove the series itself and add a new one, but this approach is potentially inefficient. That said, if you wish to remove a series from a chart you need to use the following method:
https://www.shinobicontrols.com/docs/ShinobiControls/ShinobiChartsAndroid/1.7.2/Premium/Normal/apidocs/docs/reference/com/shinobicontrols/charts/ShinobiChart.html#removeSeries(com.shinobicontrols.charts.Series)
In order for this method to be successful you will first need to obtain a reference to the correct series, which you must pass to this method as a parameter.
I hope that you find this information useful. If you need any further help please if possible post any relevant code, such as that which you use to create your fragments and set up your chart.
Thanks and kind regards,
Kai.
Disclaimer - I work for ShinobiControls.

Resources