I have an output from plotOutput and when there is a double click on the map, I want to see an output from leafletoutput. In the code below, when there is a double click on the map, the leaflet map shows below the google map. Before double click the the first image shows but after double clicking, I want to see the leaflet map only. Any suggestions on how to do this?
library(shiny)
library(shinydashboard)
library(leaflet)
library(dismo)
library(ggmap)
library(dplyr)
shinyApp(
ui = dashboardPage(
dashboardHeader(title=""),
dashboardSidebar(width = 200 ),
dashboardBody(
fluidRow(
plotOutput("USA_GoogleMap",dblclick='plot_dblclick'),
leafletOutput("leaflet_map")
)
)),
server=function(input, output, session) {
double_clicked <- reactiveValues(
center = NULL
)
# Handle double clicks on the plot
observeEvent(input$plot_dblclick, {
double_clicked$center <- c(input$plot_dblclick$x,input$plot_dblclick$y)
})
output$USA_GoogleMap<-renderPlot({
statesMap = map_data("state")
xy=cbind(statesMap$long,statesMap$lat)
y=c(36.4,41.5,42.25,27.7,32.77)
x=c(-115.5,-100,-75,-81.5,-97.45)
state=c("Nevada","Nebraska","New York","Florida","Texas")
bases=cbind(x,y)
bases_mercator=data_frame(Mercator_X=Mercator(bases)[,1],Mercator_Y=Mercator(bases)[,2],State=state)
g = gmap(xy, type='satellite',zoom=4)
plot(g, inter=TRUE)
points(Mercator(bases) , pch=20,cex=16, col=adjustcolor("white", alpha=0.2))
points(Mercator(bases) , pch=20,cex=16, col=adjustcolor("yellow", alpha=0.4))
text(bases_mercator$Mercator_X,bases_mercator$Mercator_Y,state)
})
output$leaflet_map <- renderLeaflet({
if(!is.null(double_clicked$center)){
leaflet()%>%setView(lng = -71.0589, lat = 42.3601, zoom = 12)%>%addTiles()
}
})
}
)
shinyApp(ui = ui, server = server)
First Image
Second image
Let me first preface this by saying - there's a better way to do this than I'm showing. I just haven't found one yet. I'm sure a much better programmer than I would know of it, but at least I can say this works. Even though it's hideous. The key to hiding the plot was using conditionalPanel (which I was previously unfamiliar with).
I have a text trigger for identifying whether or not the plot was double-clicked, and use that to trigger whether or not to show the panel. However, I couldn't get the text to initialize without calling it with textOutput... so I have a textOutput call with a font size of zero. Again, there must be a much better way of triggering that than I'm doing it... but again, at least it works. Hopefully it will help.
library('shiny')
library('shinydashboard')
library('leaflet')
library('dismo')
library('ggmap')
library('dplyr')
shinyApp(
ui = dashboardPage(
dashboardHeader(title=""),
dashboardSidebar(width = 200 ),
dashboardBody(
fluidRow(
conditionalPanel(
condition = 'output.condition == 0',
plotOutput("USA_GoogleMap",dblclick='plot_dblclick')
),
leafletOutput("leaflet_map"),
textOutput('condition'),
tags$head(tags$style("#condition{font-size: 0px}"))
)
)),
server=function(input, output, session) {
double_clicked <- reactiveValues(
center = NULL
)
# Handle double clicks on the plot
observeEvent(input$plot_dblclick, {
double_clicked$center <- c(input$plot_dblclick$x,input$plot_dblclick$y)
})
output$USA_GoogleMap<-renderPlot({
if(is.null(double_clicked$center)){
statesMap = map_data("state")
xy=cbind(statesMap$long,statesMap$lat)
y=c(36.4,41.5,42.25,27.7,32.77)
x=c(-115.5,-100,-75,-81.5,-97.45)
state=c("Nevada","Nebraska","New York","Florida","Texas")
bases=cbind(x,y)
bases_mercator=data_frame(Mercator_X=Mercator(bases)[,1],Mercator_Y=Mercator(bases)[,2],State=state)
g = gmap(xy, type='satellite',zoom=4)
plot(g, inter=TRUE)
points(Mercator(bases) , pch=20,cex=16, col=adjustcolor("white", alpha=0.2))
points(Mercator(bases) , pch=20,cex=16, col=adjustcolor("yellow", alpha=0.4))
text(bases_mercator$Mercator_X,bases_mercator$Mercator_Y,state)
}
})
output$leaflet_map <- renderLeaflet({
if(!is.null(double_clicked$center)){
leaflet()%>%setView(lng = -71.0589, lat = 42.3601, zoom = 12)%>%addTiles()
}
})
output$condition <- renderText({
ifelse(!is.null(double_clicked$center), 1, 0)
})
}
)
Related
I have an issue with the waiter which I need for an app built with R shiny.
The example below (based on the fantastic website on the waiter package by John Coene: https://waiter.john-coene.com/#/waiter/examples#on-render) helps me illustrate my issue.
The app is made of two tabPanels, the first one which shows a table, and the second one that shows a chart. The table and the chart will appear after some waiting time, and the waiter spinner should, in the meantime, appear in the middle of the rendering areas of both tabPanels.
However, what actually happen is that the waiter spinner only shows up in the middle of the rendering area of the tabPanel I open first, whereas in the other tabPanel it is stuck in the top-left corner of the page.
Many thanks in advance for whoever can help me fix this problem!
library(shiny)
library(highcharter)
library(shinythemes)
library(waiter)
ui <- fluidPage(
theme = shinytheme("cyborg"),
useWaiter(),
actionButton("draw", "render stuff"),
fluidPage(
tabsetPanel(
tabPanel("Table", tableOutput("table")),
tabPanel("Chart", highchartOutput("hc"))
)
)
)
server <- function(input, output){
# specify the id
w <- Waiter$new(id = c("hc", "table"))
dataset <- reactive({
input$draw
w$show()
Sys.sleep(8)
head(cars)
})
output$table <- renderTable(dataset())
output$hc <- renderHighchart({
hchart(dataset(), "scatter", hcaes(speed, dist))
})
}
shinyApp(ui, server)
I would recommend you use shinycssloaders instead. The reason is that loaders' positions in waiter are calculated by current visible height and width. However, there is no visible position in the second tab or the hidden tabs, so waiter can't add the loader to the right spot. There is no fix we can do here. This is a feature that waiter doesn't support currently.
library(shiny)
library(highcharter)
library(shinythemes)
library(shinycssloaders)
ui <- fluidPage(
theme = shinytheme("cyborg"),
actionButton("draw", "render stuff"),
fluidPage(
tabsetPanel(
tabPanel("Table", withSpinner(tableOutput("table"), type = 3, color.background = "#060606", color = "#EEEEEE")),
tabPanel("Chart", withSpinner(highchartOutput("hc"), type = 3, color.background = "#060606", color = "#EEEEEE"))
)
)
)
server <- function(input, output){
dataset <- reactive({
input$draw
Sys.sleep(4)
head(cars)
})
output$table <- renderTable(dataset())
output$hc <- renderHighchart({
hchart(dataset(), "scatter", hcaes(speed, dist))
})
}
shinyApp(ui, server)
I am testing out to way of creating Shiny UI elements dynamically with a loop from the server side in a way that the user could control how many elements are actually produced. In my case the element is Shiny Dashboard box with two dropdown menus and one button. Everything works fine, except something extra is printed out as you can see from the image:
My ui.r looks as follows:
library(shiny)
library(shinydashboard)
shinyUI(dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
# Sidebar with a slider input for number of bins
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
)
...and server.r looks as follows:
library(shiny)
library(shinydashboard)
shinyServer(function(input, output) {
output$boxes <- renderUI({
boxlist = c()
for(i in 1:input$numberOfBoxes) {
ddmenu1 <- selectInput(paste0("ddmenu1_in_box",i), "Animal", list('cat', 'dog', 'rabbit'))
ddmenu2 <- selectInput(paste0("ddmenu2_in_box",i), "Color", list('red', 'blue', 'green'))
button <- actionButton(paste0("justabutton_in_box",i), "Click me!")
boxlist <- c(boxlist,column(1, box(ddmenu1, ddmenu2, button)))
}
boxlist
})
})
So where does this "div col-sm-1" times the number of boxes crap come from, and how do I get rid of it?
I'd recommend working with lapply rather than using a for-loop.
Here is explained why this is advantageous. Also see this overview.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
server <- function(input, output, session) {
output$boxes <- renderUI({
lapply(seq_len(input$numberOfBoxes), function(i){
box(
selectInput(paste0("ddmenu1_in_box", i), "Animal", list('cat', 'dog', 'rabbit')),
selectInput(paste0("ddmenu2_in_box", i), "Color", list('red', 'blue', 'green')),
actionButton(paste0("justabutton_in_box", i), "Click me!")
)
})
})
}
shinyApp(ui, server)
Since, the "crap" lies somewhere in the list object, I decided to take a closer look at it.
So I developed this "hack" to overwrite the text with empty string:
ui.r (No modifications)
library(shiny)
library(shinydashboard)
shinyUI(dashboardPage(
dashboardHeader(title = 'The Box Experiment'),
# Sidebar with a slider input for number of bins
dashboardSidebar(
sliderInput("numberOfBoxes",
"Number of boxes:",
min = 1,
max = 50,
value = 5)
),
dashboardBody(uiOutput("boxes"))
)
)
server.r (This time includes a loop to overwrite unwanted strings)
library(shiny)
library(shinydashboard)
shinyServer(function(input, output) {
output$boxes <- renderUI({
boxlist = list()
for(i in 1:input$numberOfBoxes) {
ddmenu1 <- selectInput(paste0("ddmenu1_in_box",i), "Animal", list('cat', 'dog', 'rabbit'))
ddmenu2 <- selectInput(paste0("ddmenu2_in_box",i), "Color", list('red', 'blue', 'green'))
button <- actionButton(paste0("justabutton_in_box",i), "Click me!")
boxlist <- append(boxlist,(column(1, box(ddmenu1, ddmenu2, button))))
}
#Let's go through every attribute
for(i in 1:length(attributes(boxlist)$names)) {
#If the attribute name is NOT "children"
if(attributes(boxlist)$names[i] != "children") {
#...and the length of corresponding variable "name" equals one (text string)...
if(length(boxlist[i]$name) == 1) {
boxlist[i]$name <- ''
}
#...and the length of corresponding variable "attribs$class" equals one (text string)...
if(length(boxlist[i]$attribs$class) == 1) {
boxlist[i]$attribs$class <- ''
}
}
}
boxlist
})
})
I honestly think that this is a wrong way of doing this, and there has to be a better way to proceed, but until someone post it here, this seems to be the way to go. At least the crap is gone:
I am working on an application in sinydashboard in which the user generates a random number on the click of a button. The random number corresponds to a row in a dataframe which I need to display on the dashboard using an infoBox. Each infoBox needs to persist on the screen until the user closes the application.
I tried generating a new output variable on each click in server.R, however I could not find a way of referencing it in ui.R. Minimal example below. I've not included generating a name for an output variable on each button click as that's not working at all.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(dashboardHeader(title = ""),
dashboardSidebar(),
dashboardBody(fluidRow(
box(
width = 3,
actionButton(inputId = "generateButton",
label = "Generate")
),
box(infoBoxOutput("rnum1"))
)))
server <- function(input, output) {
randomData <- data.frame("RN" = runif(100, 1, 100))
observeEvent(input$generateButton, {
randomNumber <- floor(runif(1, 1, 100))
dataRow <- randomData[randomNumber,]
# Display dataRow in a persistent infoBox
# in a way that 5 clicks will produce 5 boxes
# Number of clicks is not known in advance
output$rnum1 <- renderInfoBox({
infoBox("Number", dataRow)
})
})
}
shinyApp(ui = ui, server = server)
Maybe this is what you want, at leat this a draft. You'll need a reactive variable to store the already generated numbers to be able to have something persistent.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(dashboardHeader(title = ""),
dashboardSidebar(),
dashboardBody(actionButton(inputId = "generateButton",
label = "Generate")
,
uiOutput('infoBoxes'))
)
server <- function(input, output) {
randomData <- data.frame("RN" = runif(100, 1, 100))
rv <- reactiveValues()
observeEvent(input$generateButton, {
randomNumber <- floor(runif(1, 1, 100))
dataRow <- randomData[randomNumber,]
print(dataRow)
rv$persistent <- c(rv$persistent, dataRow)
# Display dataRow in a persistent infoBox
})
output$infoBoxes = renderUI({
if(length(rv$persistent) > 0 ) {
fluidRow(
Map(function(x) infoBox('title', rv$persistent[x]), 1:length(rv$persistent))
)
}
})
}
shinyApp(ui = ui, server = server)
I am trying to create an interactive webmap in R to display locations using Shiny and Leaflet
The idea is that the user selects one input and the markers corresponding to that input(lat/long which are to be fetched from data set of the corresponding input) are displayed in a Leaflet map (with zoom in/out function).
Any help/advice would be greatly appreciated!
(sample data file uploaded here):
enter code here
Server.R
library(shiny)
library(rpart.plot)
library(leaflet)
shinyServer(
function(input, output) {
output$dtmplot <- renderPlot({
dtmplot <- rpart.plot(dtm, type=4, extra=101)
})
observe({
output$map <- renderLeaflet( {
for(j in 1:nrow(df))
{
if(df[j, "col1"]==input$input1) {
map <- leaflet() %>%
addTiles() %>%
addMarkers(lng=df[j,"Longitude"], lat=df[j,"Latitude)
}
}
})
})
}
)
enter code here
UI.R
library(shiny)
library(leaflet)
shinyUI(
pageWithSidebar(
headerPanel("Sample project"),
sidebarPanel(
plotOutput("dtmplot"),
selectInput("input1",
label = "label1:",
choices = c(“choice1”,”choice2”),
selected = " choice1"),
sliderInput("slider","Please select slider input", min=1,max=100,value=20,step=10)
),
mainPanel(
leafletOutput("map")
)
))
The basic code to handle custom points in a leaflet map is available below. The code utilises the official example available on the leaflet GitHub and provided end-user with the functionality to display custom location on the map.
app.R
library(shiny)
library(leaflet)
r_colors <- rgb(t(col2rgb(colors()) / 255))
names(r_colors) <- colors()
ui <- fluidPage(
leafletOutput("mymap"),
p(),
h1("Added example to add more points here:"),
p(),
numericInput("long", label = h3("Longitude:"), value = 11.242828),
numericInput("lat", label = h3("Latitude:"), value = 30.51470),
actionButton("recalc", "Show point")
)
server <- function(input, output, session) {
points <- eventReactive(input$recalc, {
cbind(input$long, input$lat)
}, ignoreNULL = FALSE)
output$mymap <- renderLeaflet({
leaflet() %>%
setView(lat = 30, lng = 11, zoom = 4) %>%
addProviderTiles("Stamen.TonerLite",
options = providerTileOptions(noWrap = TRUE)
) %>%
addMarkers(data = points())
})
}
shinyApp(ui, server)
Results
The obtained map looks like that:
Explanation
The mechanics is fairly simple and can be summarised in the following steps:
You need to pas lat and lon to your map to addMarkers. In my example this is done via primitive input files but it can be done in a number of ways.
You have to decide on the logic of dynamically adding markers to your map; in the presented case this is done with use of an actionButton.
Side notes
As at the time of drafting this answer there was no clarity with respect to the actual data that should be represented on the map, I found it more informative to generate the desired functionality following the official example instead of trying to modify the provided code.
The thing worth noting is that the lat/lon values have to be of correct format to appear on the map.
The map setView to make the example more presentable but in an actual solution, default lat/lon values should be generated dynamically.
I am doing a project where I use the shiny server and connect R to mongodb to fetch results from database and display it dynamically.
However, I face the following problem in it. I initially get the results from db and make a plot. After this plot is done, I want the user to make make two mouse clicks on the plot based on which it should take the two values as xlim and plot a zoomed version of the previous plot. However, I am not able to do it successfully.
Here is the code that I have written.
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("LOAD AND PERFORMANCE DASHBOARD"),
sidebarLayout(
sidebarPanel(
fluidRow(
selectInput("select", label = h3("Select type of testing"),
choices = list("Performance Testing"=1, "Capacity Testing"=2)),
radioButtons("radio", label = h3("Select parameter to plot"),
choices = list("Disk" = 1, "Flit" = 2,"CPU" = 3,"Egress" =4,
"Memory" = 5))
)),
mainPanel(
plotOutput("plot",clickId="plot_click"),
textOutput("text1"),
plotOutput("plot2")
)
)
))
server.R
library(shiny)
library(rmongodb)
cursor <- vector()
shinyServer(function(input, output) {
initialize <- reactive({
mongo = mongo.create(host = "localhost")
})
calculate <- reactive({
if(input$radio==1)
xvalue <- mongo.distinct(mongo,ns = "mydb.vload", "disk")
else if(input$radio==2)
xvalue <- mongo.distinct(mongo,ns = "mydb.vload", "flit")
else if(input$radio==3)
xvalue <- mongo.distinct(mongo,ns = "mydb.vload", "cpu")
else if(input$radio==4)
xvalue <- mongo.distinct(mongo,ns = "mydb.vload", "egress")
else if(input$radio==5)
xvalue <- mongo.distinct(mongo,ns = "mydb.vload", "memory")
})
output$plot <- renderPlot({
initialize()
value <- calculate()
plot(value,xlab="Time",ylab="% Consumed")
lines(value)
cursor <- value
})
output$text1 <- renderText({
paste("You have selected",input$plot_click$x)
})
output$plot2 <- renderPlot({
plot(cursor[cursor<input$plot_click$x && cursor>first_click ],xlab="Time",ylab="% Consumed") lines(cursor)
first_click <- input$plot_click$x
})
})
Thanks in advance for the help :)
Here's a simple example that demonstrates the behavior you want, just run this code (or save as a file and source it). This code uses the new observeEvent function that debuted in Shiny 0.11, which just hit CRAN over the weekend.
The basic idea is that we track two reactive values, click1 and range. click1 represents the first mouse click, if any exists; and range represents the x-values of both mouse clicks. Clicking on the plot simply manipulates these two reactive values, and the plotting operation reads them.
library(shiny)
ui <- fluidPage(
h1("Plot click demo"),
plotOutput("plot", clickId = "plot_click"),
actionButton("reset", "Reset zoom")
)
server <- function(input, output, session) {
v <- reactiveValues(
click1 = NULL, # Represents the first mouse click, if any
range = NULL # After two clicks, this stores the range of x
)
# Handle clicks on the plot
observeEvent(input$plot_click, {
if (is.null(v$click1)) {
# We don't have a first click, so this is the first click
v$click1 <- input$plot_click
} else {
# We already had a first click, so this is the second click.
# Make a range from the previous click and this one.
v$range <- range(v$click1$x, input$plot_click$x)
# And clear the first click so the next click starts a new
# range.
v$click1 <- NULL
}
})
observeEvent(input$reset, {
# Reset both the range and the first click, if any.
v$range <- NULL
v$click1 <- NULL
})
output$plot <- renderPlot({
plot(cars, xlim = v$range)
if (!is.null(v$click1$x))
abline(v = v$click1$x)
})
}
shinyApp(ui, server)