Force to update output when shiny app is loading - r

I am using leaflet and shinydashboard to create shiny app which have multiple menus which have a problem of leaftletProxy.
Here I created minimum example to show my question (https://gist.github.com/byzheng/074c3c1ff75ea9f951f5).
In the app, there are two sidebar menus 1) the first menu has a link click me; 2) the second menu has a leaflet map. After clicking click me in the first page, the second page is enabled and then setView of leaflet map to a random place.
The problem is the js console has an error message Couldn't find map with id map when the click me is clicked in the first time and leafletProxy is called.
I think this problem is related with leaflet map isn't initialized when shiny app is loading. After clicking more than one time, everything is working as expected.
So my question is how to force shiny to draw leaflet map when shiny app is loading.
Thanks for any suggestions.

The issue here is that the code creating the leaflet map is suspended while the output$map is hidden.
One way to fix this could be to use:
outputOptions(output,"map",suspendWhenHidden=FALSE)
Unfortunately this seems to be buggy right now but could be fixed soon, it currently throws a js error (see here).
Since output$summary seems to be run after the renderLeaflet, you could use setView in that block as a temporary solution.
output$summary <- renderPrint({
leafletProxy('map') %>% setView(runif(1) * 30 +2, runif(1) * 30 + 2, 7)
print(input$mydata)
print(leafletProxy('map')$id)
})

You should put a need in your reactive. For example:
need(input$button, "Click the button")
Documentation here: http://shiny.rstudio.com/reference/shiny/latest/validate.html
Or you could just return when the proxy is NULL:
if (is.null(proxy)) {
return(NULL)
}

Related

Shiny Interactive plots with leaflet map doing click change the data of charts

I have a leaflet map in shiny, a chart (inside a pop up and behind the map) so i need to change the charts depending to the country i made the last click.
I tried with this code call the clicked country but doesnt work when i put it in a chart
clickpais <- input$mymap_shape_click
clickpais<- clickpais$id
pais<-table_id()[table_id()$idtable==clickpais,]$nametable
ando also i tried with observeEvent with no result
observeEvent( input$mymap_shape_click,{
if(is.null(click)){}
else{
p_click<- input$mymap_shape_click
p_click<- p$id
print(p_click)
}
})
The app whith the data are in this link if any one could help or want to replicate for your work INFORMATION I appreciate your help.

Render table R Shiny upon action button

I have been using R for about a year but am only a few weeks into Shiny. I have some code which calls an API and spits out a nice tables of results which I would like to use in a Shiny App - with the API being called when an action button is clicked.
I've been trouble shooting this for a few days but can't figure it out, below are a few of the things I have tried.
If I remove the action button, the API calls and displays as soon as the app is opened.
Replacing the API with simple text shows the text when the button is clicked.
Rendering the table inside the action results in the UI wondering where the table is (as button as not been pressed) and giving an error.
The API contains sensitive info so I have removed some details added a typical return (it returns Json to the browser when URL is visited).
Any ideas on what i might be missing?
API return
{"meta":{"request":{"granularity":"Monthly","main_domain_only":false,"format":null,"domain":"cnn.com","start_date":"2017-02-01","end_date":"2017-02-28","limit":null,"country":"world"},"status":"Success","last_updated":"2017-04-30"},"visits":[{"date":"2017-02-01","visits":100000`}]}
UI.r
library(shiny)
shinyUI(fluidPage(
headerPanel(actionButton("do", "Click Me")),
mainPanel(dataTableOutput("mytable"))
))
Server.r
library(shiny)
function(input, output) {
#Call API, flatten Json return
Visits_Final<- eventReactive(input$do, {
Results<- paste0("https://api.com/",
"site.com",
"apikey=***") %>%
map(fromJSON, flatten = FALSE)
#Transform into DF
visits_temp= data.frame(date=NA,visits=NA,ID=NA)
for(i in 1:1){
DF_L<- as.data.frame(Results[[i]]$visits)
ID <- (rep(i, nrow(DF_L)))
DF_L<- cbind(DF_L, ID)
Visits_Final<-rbind(visits_temp, DF_L)}})
#Output to UI
output$mytable <- renderDataTable({Visits_Final()})
}
Thanks in advance!
Edits
for(i in 1:i){
As per BigDataScientist comment, changed to
for(i in 1:1){
Code comments added
System info added:
R 3.3.2
R Studio Version 1.0.143
OS Sierra 10_12_3
Solved - In the Server file I changed eventReactive to observeEvent
Honestly, not 100% understanding this documentation but it did help
Shiny: what is the difference between observeEvent and eventReactive?
Feel free to comment with similar problems.

Q: K. Rohde's shiny leaflet popup: how to ensure popups are properly displayed regardless of initial tabPanel?

In implementing an advanced shiny popup solution from K. Rohde, I've run into a problem using a navbarPage and tabPanels. Per the linked solution, the following code is in the appropriate tabPanel:
tabPanel("Multiple Locations",
uiOutput("script"),
tags$div(id="garbage"),
...rest of UI...
)
If Multiple Locations is the only tabPanel, or if navbarPage(selected="Multiple Locations") is set, everything works wonderfully (I have implemented nearly identically to the example in the linked solution). But if navbarPage(selected="someOtherPanel") is set, and the user subsequently navigates to the Multiple Locations tabPanel, the popups show up empty.
I've tried moving the uiOutput("script") and tags$div(id="garbage") lines into the other tabPanel (the one that's active on startup), I've tried moving it right under the navbarPage (before any tabPanel elements), and I've tried duplicating it in those locations as well, to no avail. Moving it right under the navbarMenu() appears to insert a div into the menu itself. Here's the setup that works:
ui<-navbarPage(id="page", selected="Multiple Locations",
tags$head(tags$link(href="myfavicon.ico", rel="icon"),
includeCSS("www/style.css"),
tags$script(type="text/javascript", src = "baranim.js")
),
navbarMenu("Explorer",
tabPanel("Single Location",
...UI elements...
),
tabPanel("Multiple Locations",
uiOutput("script"),
tags$div(id="garbage"),
...UI elements...
)
)
)
Though the app is not yet complete, I don't imagine I'll have users starting on the Multiple Locations tabPanel. But clearly, I'd still like the popups to function.
Many thanks to K. Rohde for the original solution.
First off, I really appreciate that you liked my post. This is very encouraging.
So I tried to reconstruct your situation and managed to reproduce the behavior you explained. My detective work showed, that you have another leaflet inside the Single Locations tab. Is that correct? The solution you linked was only designed for one single leaflet. It addresses the div of class leaflet-popup-pane, but if there are more than one, only the first one which is rendered, will be adressed. This explains the behavior with the tab choice in the beginning.
I have modified the script such that all available leaflet-popup-panes are addressed:
output$script <- renderUI({
tags$script(HTML('
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if(mutation.addedNodes.length > 0){
Shiny.bindAll(".leaflet-popup-content");
};
if(mutation.removedNodes.length > 0){
var popupNode = mutation.removedNodes[0].childNodes[1].childNodes[0].childNodes[0];
var garbageCan = document.getElementById("garbage");
garbageCan.appendChild(popupNode);
Shiny.unbindAll("#garbage");
garbageCan.innerHTML = "";
};
});
});
$(".leaflet-popup-pane").each(function() {
observer.observe(this, {childList: true});
});
'))
})
This should do the trick.
Some advice on placement: The garbage-div must only be placed once, to avoid duplicate Id problems. But it can be placed anywhere in the ui. If you have multiple leaflets with expanded popups, place one script output beneath each of those (or one beneath the last if there are several on the same page). Especially with tabPanels, this ensures that your leaflets have been fully rendered when the script is executed.
Please comment, if this doesn't solve your problem or if there is something I missed.

Accessing uiOutput Value On App Load

To simplify this example I've only included the necessary code to describe the issue I'm having. Should it be required, I will include a fully reproducible example, but I have a hunch that this issue can be solved through theory alone by someone with more experience using Shiny. Basically, I've programmed a Shiny app in R which looks something like this:
ui.R
plotOutput(outputId = 'heatmap1', height = "800px")
uiOutput('selectStrains')
uiOutput('selectRegions')
server.R
output$selectStrains = renderUI({
checkboxGroupInput(inputId='strains',
choices=sort(colnames(mousedata)),
selected=colnames(mousedata))
})
output$selectRegions = renderUI({
checkboxGroupInput(inputId='regions',
choices=sort(rownames(mousedata)),
selected=rownames(mousedata))
})
# more code
output$heatmap1 = renderPlot({
input$recalculate
mousedatamat = as.matrix(mousedata[isolate(input$strains), isolate(input$regions)])
heatmap.2(mousedatamat)
})
problem:
My problem is that in server.R, when the app is first loaded, input$strains and input$regions are both NULL. Therefore, mousedatamat in server.R will be a 0x0 matrix, and the heatmap will be empty on the front page of the app, which makes for a pretty poor user experience. I don't know how the ui.R and server.R files interact when an app is launched, so I'm finding it difficult to debug. To make the plot show up I either need to click a recalculate button (input$recalculate), or resize the window (but only in the horizontal dimension for some reason).
To add more mystery to the mix, I have the same heatmap figure on page 2 (I'm using a navbarPage layout), which shows up on the app load when I navigate to that tab! It is the very same code, only instead it is assigned to output$heatmap2. When I navigate back to page 1, output$heatmap1 still does not display.
I've tried placing the calls to uiOutput above plotOutput in ui.R, but the main reason I don't know how to solve this I think is because I don't know much about execution flow when an app is started. Any ideas or information on this topic?

Update Shinygooglevis chart without full reload

Is it possible to change the data of a googlevis chart (any of them!) without forcing a full reload of the page/chart?
Current code that gives a very undesirable flicker when the map is being reloaded:
shinyServer(function(input, output, session) {
observe({
print("Reloading..")
invalidateLater(update_freq*1000, session)
data <- loadDataFiles()
output$gvis <- renderGvis(mapPlot(data)) //mapPlot returns a new gvisGeoChart
})
Ideally I'd just reload my markers, not the chart itself.
The googleVis Shiny bindings need to be rewritten to fix this problem. In the meantime I have prototyped some ideas here that you might want to check out; you can install it using devtools::install_github("jcheng5/googleCharts") and see the example here. It is pretty rough but you won't get the flickering and instability that currently occurs with googleVis + shiny.

Resources