shiny: How to update a reactiveValues object? - r

I have a pair of auxiliary inputs that allows user to choose combinations from a set of choices. Also, it is convenient one to be able to remove an item that was created before.
For this task, a named list, in the form of reactiveValues object, listN <- reactiveValues(), will be in charge to store these information.
The function to ADD items is working like a charm, but when I try to REMOVE items from listN, its item names persists forever!
My strategy was make use of reactiveValuesToList(), manipulate its items and replace listN with a brand new instance of reactiveValues() (or do.call(reactiveValues, listN_as_list).
I stored a reproducible app at Gist. I hope it is sufficient to you guys help me out. Please insist in more clarification if needed.
URL:
gist.github.com/d43e72959c4576d27535
Code to run on console:
shiny::runGist('d43e72959c4576d27535')
Thanks in advance!

Answer from Joe Cheng at Shiny Google Groups:
Yeah, you can't replace an entire reactiveValues instance like that
and expect anything that's bound to the previous reactiveValues
instance to instantly know about the new one. The slots on the
reactiveValues instance itself are reactive, but its own variable is
not.
I think the real issue here is that, unlike lists and envs, you can't
remove values from reactiveValues, only set them to NULL.
There are two easy workarounds I can think of:
1) In addition to the reactiveValues instance's slots being reactive, also make the variable
reactive, using makeReactiveBinding.
2) You could also use reactiveValues
as normal, but keep a list IN the reactiveValues that holds the
combinations, not having the reactiveValues itself hold the values. In
other words, values <- reactiveValues(combos = list()), and when
something new gets added, values$combos[[x]] <- y.
In trying out fix
number 1 above, I found that updateSelectInput doesn't work properly when choices is a length-0 vector. Instead of sending a 0-length vector to
the client, it doesn't send anything for choices at all, so the
choices never change.
I've forked your gist and added two revisions: one that implements
workaround #1 (along with some other problems I found), and one that
works around the updateSelectInput issue by using renderUI.
https://gist.github.com/jcheng5/eaedfed5095d37217fca/revisions

Related

Is there a way to slow down the input update from a numericInput ui object

So as the title say I'm looking for a way to slow down the input update form a numericInput ui object.
As a little preface, I am developing an application where I have dynamically built numeric inputs using a map function based on a drop down choice selection of numbers 1-8. So based on how many numeric inputs the user wants to compare the server will dynamically build them. And, in order to display some descriptive statistics, I had to add a actionButton that updates tables built from reactive values.
The problem arises from when I'm looking to type values into the numeric input fields. I only have about 1 second from the initial number click to finish my typing my value until I get kicked out of the numeric input field. In order to finish the number I wish to type I have to click back into the field once or twice to finish typing out the number. Once I have the number typed, I can then hit my action button to update the tables.
How do I make the numeric input fields "sleep" until the button press pulls the values for the reactive tables. I've had to do several odd workarounds due to the nature of the dynamically built numeric inputs and reactive tables/plots. Any input is very welcome.
It's hard to help without some code...
You can do something like that:
go <- reactiveVal(FALSE)
observeEvent(input[["button"]], {
go(TRUE)
})
output[["table"]] <- renderTable({
req(go())
something using the numeric inputs...
})
Does it help?

Deleting always the first row in a shiny CRUD app only after adding preexsitent data

I am stuck and need help.
I am working with this gist https://gist.github.com/gluc/d39cea3d11f03542970b
Basically in a shiny app it provides the possibility to make CRUD maneuvers and it works perfect.
I now managed to store the data on googlesheets and also to load the data in with:
read_sheet function from googlesheets4 package.
The issue is if I want to delete the last row of the table within the shiny app the first row is deleted after pressing the delete button.
This problem occurs only if I load in preexistend data (in my case from googlesheets).
I have encountered the problem: The id is not updating when I click the rows in the shiny app table.
I have used browser() and went through each function but I can't find the problem.
If I click on first row and delete the first row everything works perfect, but clicking the second or any other row except the first, always the first row is deleted.
Update:
I think the main issue is that after reading in the data from gogglesheets the disabled Id field is not navigating with the table, see picture.
If I click row 3 then the Id field should be 3 but it stays at 1 all the time. Therefore any action (for example deleting) on the table removes row one.
I can't get the link between the dataframe that is loaded at the beginning in the environment and the data that is defined by the CRUD application. The idea of akrun is perfect and should work but it does not:
I assign at the beginning of the code the read_sheet(...) table to responses like:
df_id_read_sheet <- read_sheet("......")
responses <- df_id_read_sheet
After one night without sleep. I found the solution. And it was as simple as I thought. Following one of the first advice by dear #akrun I checked with str the structure of the loaded googlesheet.
The sheet is imported as tibble after transforming it to data.frame and assigning to responses the complete code worked as expected. The isssue arised because of the rownames.
Using browser() immediately after assigning the sheet to responses I was able to see and check the structure within the shiny app on my console.
I really love debuging with broswer() as it enables me to see what is going on in shiny apps also.
Here is the simple yet hard discovered solution: At the beginning of your shiny app code:
library(magritter)
df_id_read_sheet <- read_sheet("put your sheet id here")
responses <- df_id_read_sheet
responses %<>%
as.data.frame()

R shiny gvisTable with columns selected by user in defined order

I have an R shiny webpage where I currently use gvisTable to show a selection of columns from a data.frame. The rows are dynamically selected by the user with the sidebarPanel, but right now the columns are hard-coded inside the gvisTable call.
I would like to allow the user to dynamically select the columns from a drop-down menu (see snapshot of a similar system from a non-shiny webpage). The key feature I want is to allow resorting of the columns.
Any ideas how to pass this sorted selection of columns in shiny?
I don't mind using something else instead of gvisTable if it does the job.
EDIT: Thanks for showing a solution using the sortable answer. It works both for my old and new versions of shiny. Yet, this does not seem to remember the order upon hitting "Refresh", which would be really nice to have.
So, can it save the last chosen order as a browser cookie or a similar way? The server is authenticated, and I've been told I could put the variable order in a list with the user id as the key. An example of that would be great.
In Shiny you would have to use multiple selectInput's. However, you could install ShinySky by ZJ (https://github.com/AnalytixWare/ShinySky) and use his select2 binding which allows sorting. Alternatively, you could modify the sortable binding at https://github.com/mostly-harmless/sortable.
Edit: I don't know about cookies. I use sortable in a larger app. There I have an action button to save the order selected by the user. See Data > Transform > Reorder columns. In the app data is stored in a reactiveValue. To save the data order I use values[[input$datasets]] <- values[[input$datasets]][,input$tr_reorder_cols] where input$datasets is the active dataset, input$tr_reorder_cols is the users selected variable ordering, and values is the reactiveValue that contains the data.
The source for the app is on Github: https://github.com/mostly-harmless/radiant
As an alternative, you could also save the order of the variables in a reactiveValue. See the Shiny documentation for details.
Edit:
In global.R define a reactiveValue:
savedOrder <- reactiveValues()
When a user changes the order (this assumes you have userid available as a variable in R):
if(!is.null(input$sortable)) {
savedOrder[[userid]] <- input$sortable
}
Also, you could pass the id-value to returnOrder in case of a refresh:
if(!is.null(savedOrder[[userid]])) {
returnOrder("sortable",savedOrder[[userid]])
} else {
returnOrder("sortable",colnames(dat))
}

Selecting a row in a dataframe in RGTK2

I want to perform something like the one below:
display a dataframe in RGTK2 window, with scrollbar on the right
user can select the specific row in the dataframe by clicking on it, and I can "get" which row the user has actually clicked
I wonder if this can be done using RGtk2. Thanks.
Yes, of course. Have a look at: https://github.com/jverzani/gWidgets2RGtk2/blob/master/R/gtable.R . You can pull out most of the first request in the initialize method and the second in the set_selected and get_selected methods. The task is made much easier (and faster!) by Michael Lawrence's rGtkDataFrame constructor to turn data frames into models that RGtk2's views can use quite easier.

AdvancedDataGrid (grouping) quick jump to row

I have a problem with the AdvancedDataGrid widget. When the dataProvider is an ArrayCollection (of arrays), the nth array (within the collection) is also the nth row within the grid, and I can jump and display the i-th row by scripting
adg.selectedIndex = i;
adg.scrollToIndex(i);
now, when I add a Grouping, the dataProvider ends up being a GroupingCollection2, and now the index in the dataprovider's source does not correspond to the index in the adg anymore (which is understandable, because it's being grouped).
How can I select and display a row in grouped data efficiently? Currently, I have to traverse the adg and compare each found item with its data attributes in order to find the correct index of the row within the adg, and jump to it like above. This process is very slow. Any thoughts?
edited later:
We already used a caching object as Shaun suggests, but it still didn't compensate for the search times. In order to fully construct a sorting of a list of things (which this problem equates to, as the list is completely reordered by the grouping), you always have to know the entire set. In the end we didn't solve that problem. The project is over now. I will accept Shaun's answer if no one knows a better way in three days.
Depending on what values your comparing against you can store the objects in a dictionary with the lookup using the property/properties that would be searched for, this way you have a constant time look-up for the object (no need to look at every single item). Say for example your using a property called id on an object then you can create an AS object like
var idLookup:Object = {};
for(myObject in objects)
idLookup[myObject.id] = myObject;
//Say you want multiple properties
//idLookup[myObject.id]={};
//idLookup[myObject.id][myObject.otherProp] = myObject;
now say the user types in an id you go into the idLookup object at that id property and retrieve the object:
var myObject:Object = idLookup[userInput.text];
myAdg.expandItem(myObject, true);
now when you want to get an object by id you can just do
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/controls/AdvancedDataGrid.html#expandItem()
I haven't done any thorough testing of this directly, but use a similar concept for doing quick look-ups for advanced filtering. Let me know if this helps at all or is going in the wrong direction. Also if you could clarify a bit more in terms of what types/number of values you need to lookup and if there's the possibility for multiple matches etc. I may be able to provide a better answer.
Good luck,
Shaun

Resources