Positioning a dropdown in plotly - html

I want to position a dropdown menu under the legend. However depending on how big the plot in terms of resolution is, plotly changes the position of this dropdown (cf. uploaded pictures).
The first plot shows the output like it appears in the little Rstudio
plot tab. The second shows how far the dropdown goes to the right if I switch to fullscreen.
How can I fix the position of the dropdown menu? Any solution is appreciated whether it is html, R or anything else
Below you can find the code which I used to create the plots:
library(plotly)
x <- seq(-2 * pi, 2 * pi, length.out = 1000)
df <- data.frame(x, y1 = sin(x), y2 = cos(x),tan_h=tanh(x))
p <- plot_ly(df, x = ~x) %>%
add_lines(y = ~y1, name = "sin") %>%
add_lines(y = ~y2, name = "cos") %>%
add_lines(y = ~tan_h, name='tanh',visible=FALSE) %>%
layout(
title = "Drop down menus - Styling",
xaxis = list(domain = c(0.1, 1)),
yaxis = list(title = "y"),
updatemenus = list(
list(
y = 0.7,
x = 1.1,
buttons = list(
list(method = "restyle",
args = list("visible", list(TRUE, TRUE, FALSE)),
label = "Cos"),
list(method = "restyle",
args = list("visible", list(TRUE, FALSE, TRUE)),
label = "Tanh"),
list(method = "restyle",
args = list("visible", list(TRUE, TRUE, TRUE)),
label = "All")
))
)
)

This question is old now, but for Python you now at least can position this via the plotly API, as per: https://plotly.com/python/v3/dropdowns/#style-dropdown
You can pass the arguments x, y, xanchor and yanchor to the updatemenus argument of the plotly graphobjects Figure's update_layout method:
import plotly.graph_objects as go
fig = go.Figure()
fig.update_layout(
title="Demo",
updatemenus=[go.layout.Updatemenu(
active=0,
buttons=[{"label": "Demo button...", "args": [{"showlegend": False}]}],
x = 0.3,
xanchor = 'left',
y = 1.2,
yanchor = 'top',
)
]
)
fig.show()

Related

VisNetwork: Use VisConfigure argument container to move parameters to dropdownBlock (shinydashboardPlus)

I am having a hard time understanding how the container argument from function VisNetwork::VisConfigure works. It seems as though one can move the configuration list in another HTML container but my understanding is too limited (and I found no examples online).
My goal would be to place the configuration list in a shinydashboardPlus::dropdownBlock (i.e., in the dashboardHeader leftUI argument), see reproducible example below:
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(visNetwork)
# Define the function to retrieve the parameters from VisConfigure
# See: https://github.com/datastorm-open/visNetwork/issues/333
visShinyGetOptionsFromConfigurator <- function (graph, input = paste0(graph$id, "_configurator")) {
if (!any(class(graph) %in% "visNetwork_Proxy")) {
stop("Can't use visGetPositions with visNetwork object. Only within shiny & using visNetworkProxy")
}
data <- list(id = graph$id, input = input)
graph$session$sendCustomMessage("visShinyGetOptionsFromConfigurator", data)
graph
}
ui <- dashboardPage(
dashboardHeader(title = "Test visConfigure container argument",
leftUi = tagList(
shinydashboardPlus::dropdownBlock(
id = "graphparams",
title = "Graph parameters",
icon = shiny::icon("gears"),
shinyWidgets::prettyRadioButtons(
inputId = "physics",
label = "Parameters should appear here",
choices = c("Yes","No"))))),
dashboardSidebar(width = 220),
dashboardBody(
fluidRow(box(id = "network",
title = "Network",
status = "primary",
width = 12,
solidHeader = TRUE,
collapsible = TRUE,
visNetworkOutput('network'))),
fluidRow(actionButton("ops", "Options"))))
server <- function(input, output, session) {
getDiagramPlot <- function(nodes, edges){
v <- visNetwork(
nodes,
edges) %>%
visIgraphLayout(layout = "layout_on_sphere", physics = TRUE, randomSeed = 1234) %>%
visPhysics(solver = "hierarchicalRepulsion",
hierarchicalRepulsion = list(springLength = 850, nodeDistance = 90),
stabilization = "onlyDynamicEdges") %>%
visOptions(highlightNearest = list(enabled = T, degree = 1, hover = F), autoResize = TRUE, collapse = FALSE) %>%
visEdges(color = list(highlight = "red")) %>%
visEdges(arrows = edges$arrows) %>%
visConfigure(enabled = TRUE, filter = "physics", container = NULL) %>%
visInteraction(multiselect = F)
return(v)
}
nodes <- data.frame(id = 0:20, label = LETTERS[1:21])
edges <- data.frame(from = 0, to = 1:20, value = seq(0.35, 0.5, length.out = 20))
output$network <- renderVisNetwork(
getDiagramPlot(nodes, edges)
)
# Send to console the settings from VisConfigure
# See: https://github.com/datastorm-open/visNetwork/issues/333
observeEvent(input$ops, { visNetworkProxy("network") %>% visShinyGetOptionsFromConfigurator() })
observe({ if(!is.null(input$network_configurator)) print(input$network_configurator)
})
session$onSessionEnded(stopApp)
}
shinyApp(ui, server)
Any idea?
Best,
C.
I tried to set container = input$graphparams but it didn't work.

R Shiny / CSS: Relative and absolute positioning of divs

I'm working on a shiny app that requires a lot of interaction with plots. Its quite complex, therefore I'll provide minimal examples that try to abstract the problem and reduce the code you have to copy and paste to a minimum.
One problem that I faced regarding computational efficiency when the plot changes has been solved here.
With this solution however I'm running into a different problem. Before incorporating the solution the app looked like this.
library(shiny)
ui <- fluidPage(
wellPanel(
fluidRow(
column(
width = 12,
fluidRow(
sliderInput(inputId = "slider_input", label = "Reactive values (Number of red points):", min = 1, max = 100, value = 10),
plotOutput(outputId = "plotx")
),
fluidRow(
selectInput(
inputId = "color_input",
label = "Choose color:",
choices = c("red", "blue", "green")
),
sliderInput(
inputId = "size_input",
min = 1,
max = 5,
step = 0.25,
value = 1.5,
label = "Choose size:"
)
)
)
)
)
)
slow_server <- function(input, output, session){
base_data <- reactiveVal(value = data.frame(x = rnorm(n = 200000), y = rnorm(n = 200000)))
output$plotx <- renderPlot({
# slow non reactive layer
plot(x = base_data()$x, y = base_data()$y)
# reactive layer
points(
x = sample(x = -4:4, size = input$slider_input, replace = T),
y = sample(x = -4:4, size = input$slider_input, replace = T),
col = input$color_input,
cex = input$size_input,
pch = 19
)
})
}
shinyApp(ui = ui, server = slow_server)
It differs from the example given in the solved question in so far as that it now features a well panel and some additional inputs below the plot. I had not mentioned this before because I thought it was not important to the problem.
Incorporating the solution the app now looks like this:
library(shiny)
library(ggplot2)
ui <- fluidPage(
wellPanel(
fluidRow(
column(
width = 12,
fluidRow(
sliderInput(inputId = "slider_input", label = "Reactive values (Number of red points):", min = 1, max = 100, value = 10),
div(
class = "large-plot",
plotOutput(outputId = "plot_bg"),
plotOutput(outputId = "plotx")
),
tags$style(
"
.large-plot {
position: relative;
}
#plot_bg {
position: absolute;
}
#plotx {
position: absolute;
}
"
)
),
fluidRow(
selectInput(
inputId = "color_input",
label = "Choose color:",
choices = c("red", "blue", "green")
),
sliderInput(
inputId = "size_input",
min = 1,
max = 5,
step = 0.25,
value = 1.5,
label = "Choose size:"
)
)
)
)
)
)
quick_server <- function(input, output, session){
base_data <- reactiveVal(value = data.frame(x = rnorm(n = 200000), y = rnorm(n = 200000)))
output$plot_bg <- renderPlot({
ggplot(base_data()) +
geom_point(aes(x,y)) +
scale_x_continuous(breaks = -4:4) +
scale_y_continuous(breaks = -4:4) +
xlim(-5, 5) +
ylim(-5, 5)
})
output$plotx <- renderPlot({
data.frame(
x = sample(x = -4:4, size = input$slider_input, replace = T),
y = sample(x = -4:4, size = input$slider_input, replace = T)
) %>%
ggplot() +
geom_point(mapping = aes(x,y), color = input$color_input, size = input$size_input) +
scale_x_continuous(breaks = -4:4) +
scale_y_continuous(breaks = -4:4) +
theme(
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent", color = NA),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.background = element_rect(fill = "transparent"),
legend.box.background = element_rect(fill = "transparent")
)+
xlim(-5, 5) +
ylim(-5, 5)
}, bg="transparent")
}
shinyApp(ui = ui, server = quick_server)
The plot has become way quicker. But now the plot inputs are placed on top of it. I assume it is due to the relative positioning in the new CSS class 'large-plot'. I have been fiddling around with shiny::tags$style() and shiny::verticalLayout() but my knowledge of CSS only allows my to understand CSS code not reakky to change it and I'm not making any progress.
How can I keep the relative positioning of the two overlapping plots (like in example 2) and place the additional inputs in the row below the plot (as in example 1)?
Any help is appreciated. If you need more information about the app please tell me and I'll provide it!
Thanks in advance!!
so just add some height to the large-plot class. I didn't know you wanted to add content below. So the absolute position of plots will make container large-plot have no height.
Fix is very easy. Since the plotOutput is fixed height of 400px, you can just add the same height to the container:
.large-plot {
position: relative;
height: 400px;
}

plotly html embedded in shiny

I have generated few plots using plotly and saved them as offline html (I don't want to generate them live as it would take so long to generate them in the background). The followings are the two plots taken from plotly site and I saved them as html.
#Graph 1
Animals <- c("giraffes", "orangutans", "monkeys")
SF_Zoo <- c(20, 14, 23)
LA_Zoo <- c(12, 18, 29)
data <- data.frame(Animals, SF_Zoo, LA_Zoo)
p <- plot_ly(data, x = ~Animals, y = ~SF_Zoo, type = 'bar', name = 'SF Zoo') %>%
add_trace(y = ~LA_Zoo, name = 'LA Zoo') %>%
layout(yaxis = list(title = 'Count'), barmode = 'group')
htmlwidgets::saveWidget(p, file="zoo.html")
#Graph 2
x <- c('Product A', 'Product B', 'Product C')
y <- c(20, 14, 23)
text <- c('27% market share', '24% market share', '19% market share')
data <- data.frame(x, y, text)
p <- plot_ly(data, x = ~x, y = ~y, type = 'bar', text = text,
marker = list(color = 'rgb(158,202,225)',
line = list(color = 'rgb(8,48,107)',
width = 1.5))) %>%
layout(title = "January 2013 Sales Report",
xaxis = list(title = ""),
yaxis = list(title = ""))
htmlwidgets::saveWidget(p, file="product.html")
I have written some shiny codes that can show html output from Rmarkdown but not the html that i generated from plotly above. Note that the first choice(sample) in the selectInput() is what I generated from default Rmarkdown html and that works. I also generated multiple rmarkdown html and I could also switch between htmls in the shiny app but not for plotly html.
ui= fluidPage(
titlePanel("opening web pages"),
sidebarPanel(
selectInput(inputId='test',label=1,choices=c("sample","zoo","product"))
),
mainPanel(
htmlOutput("inc")
)
)
server = function(input, output) {
getPage<-function() {
return(includeHTML(paste0("file:///C:/Users/home/Documents/",input$test,".html")))
}
output$inc<-renderUI({getPage()})
}
shinyApp(ui, server)
You can use an iframe for this - also have a look at addResourcePath:
ui = fluidPage(
titlePanel("opening web pages"),
sidebarPanel(selectInput(
inputId = 'test',
label = 1,
choices = c("sample", "zoo", "product")
)),
mainPanel(htmlOutput("inc"))
)
server = function(input, output) {
myhtmlfilepath <- getwd() # change to your path
addResourcePath('myhtmlfiles', myhtmlfilepath)
getPage <- function() {
return(tags$iframe(src = paste0("myhtmlfiles/", input$test, ".html"), height = "100%", width = "100%", scrolling = "yes"))
}
output$inc <- renderUI({
req(input$test)
getPage()
})
}
shinyApp(ui, server)

ggplotly & Plotly missing values when I expand window

I am creating a shiny app and using plotly and ggplotly. For some reason when I expand the size of the window, the plot loses some of the data points. Your help is much appreciated.
dashboardBody(
tabItems(
tabItem(
tabName = "calendar",
fluidRow(width = 12,
column(width = 8,
box( width = NULL, height = 400,
title = "Yang Zhang Estimator", solidHeader = T, status = "danger",
plotlyOutput("yang_zhang", height = "320px")
)) ...
server <- function(input, output) {
spy = getSymbols("SPY", from = Sys.Date()-100, to = Sys.Date(), auto.assign =F)
yz_vol = reactive({
volatility(spy, n = as.numeric(input$slider_yz), calc = "yang.zhang", N = 252,
mean0 = F)
})
output$yang_zhang = renderPlotly({
plot_ly(as.data.frame(yz_vol()), x = as.Date(index(yz_vol())), y =
as.numeric(yz_vol()), type = "scatter")
})
}

How to plot country-based choropleths using leaflet R

World boundaries geo.json downloaded from here.https://github.com/johan/world.geo.json
I am trying to highlight 3 countries(in a world map view) and paint them in gradient color according to numbers of projects in that country.
Here're my steps:
Firstly download world boundary geo.json file and read it as the basemap;
Then I try highlight the country polygons in my data. However it turns out that All the world countries are ramdomly colored and labeled by the 3 countries' information. Is it geo dataframe subsetting issue?
WorldCountry <-geojsonio::geojson_read("./GeoData/countries.geo.json", what = "sp")
#Dataframe for choropleth map
Country <- c("Bulgaria","Pakistan","Turkey")
Projects <- c(2,1,6)
data <- data.frame(Country,Projects)
#basemap
Map <- leaflet(WorldCountry) %>% addTiles() %>% addPolygons()
#set bin and color for choropleth map
bins <- c(0,1,2,3,4,5,6,7,8,9,10,Inf)
pal <- colorBin("YlOrRd", domain = data$Projects, bins = bins)
#set labels
labels <- sprintf(
"<strong>%s</strong><br/>%g projects <sup></sup>",
data$Country, data$Projects) %>% lapply(htmltools::HTML)
#add polygons,labels and mouse over effect
Map %>% addPolygons(
fillColor = ~pal(data$Projects),
weight = 2,
opacity = 1,
color = 'white',
dashArray = '3',
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")
)
I am expecting something like this:
This will do the trick! Subset the WorldCountry using:
data_Map <- WorldCountry[WorldCountry$id %in% data$Country, ]
Map <- leaflet(data_Map) %>% addTiles() %>% addPolygons()
The subset would be with WorldCountry$name
data_Map <- WorldCountry[WorldCountry$name %in% data$Country, ]
Map <- leaflet(data_Map) %>% addTiles() %>% addPolygons(
fillColor = ~pal(data$Projects),
weight = 2,
opacity = 1,
color = 'white',
dashArray = '3',
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 5,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
label = labels,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")
)