How to specify detailed layout inside renderPlotly (Shiny r) - r

Trying to render a Plotly graph in a shiny app. The basic graph is getting generated but unable to format the axes. Able to get the desired graph options in the Plotly Web Application with the layout as given below.
"layout": {
"autosize": true,
"height": 831.625,
"hovermode": "x",
"width": 1480,
"xaxis": {
"autorange": true,
"hoverformat": "%Y-%m",
"range": [
1356978600000,
1391193000000
],
"rangeselector": {
"buttons": [
{
"label": "reset",
"step": "all"
},
{
"label": "#1",
"step": "month"
}
]
},
"tickformat": "%Y-%m",
"tickmode": "auto",
"tickprefix": "",
"title": "B",
"type": "date"
},
"yaxis": {
"autorange": true,
"range": [
-19.888888888888893,
397.8888888888889
],
"title": "A",
"type": "linear"
}
}
Facing issue in specifying this layout within the shiny code. For simple objects like title, it works (as shown below).
output$plot <- renderPlotly({
new_plot <- plot_ly(plot_data, x = plot_data$FY_Month, y = plot_data$Booking_Amount , name = "Test Data (Actual)")
new_plot <- layout(new_plot,title = "Random Title")
new_plot
})
How do I give the complex xaxis and yaxis layouts?

Found an answer to the question myself. Both xaxis and yaxis layouts can be specified as shown below:
x_axis <- list(
title = "Fiscal Year / Month",
autorange = "true",
hoverformat = "%Y-%m",
tickformat = "%Y-%m",
tickmode = "auto",
type = "date"
)
y_axis <- list(
title = "A",
type ="linear"
)
output$plot <- renderPlotly({
new_plot <- plot_ly(plot_data, x = plot_data$FY_Month, y = plot_data$Booking_Amount , name = "Test Data (Actual)")
new_plot <- layout(new_plot,title = "Random Title")
new_plot <- layout(new_plot, xaxis=x_axis, yaxis = y_axis)
new_plot
})
Similarly, other such formats can be specified. Used the following reference.Plotly R API reference doc for Axes Labels

Related

Leaflet map crashes on recoloring after translation (Shiny, Leaflet, shiny.i18n)

I'm currently trying to make a Shiny app for Leaflet cards with simple translations. Each leaflet card has several base groups that are linked to different variables. To avoid re-rendering the leaflet maps every time the base group changes, I have adopted a function I found here which only changes the fill of the polygons.
As long as I only use one language, the app works without problems, but when multiple translations options are implemented, the app crashes. The problem seems to occur when I try to link input$map_groups to variables needed for colouring.
My code looks like this:
library(shiny)
library(shinyWidgets)
library(leaflet)
library(sf)
library(dplyr)
library(shiny.i18n)
#--- Loading Generic Shape File For Demonstration
shape <- st_read(system.file("shape/nc.shp", package = "sf"),
stringsAsFactors = FALSE) %>%
#--- Mutating Two Variables To Factors As My Map Uses Factors
mutate(One = as.factor(SID74), Two = as.factor(SID79)) %>%
#--- Keep Just This Three Variables
select(c(CNTY_ID, One, Two))
#--- Color Palette For Filling Polygons
scale.color <- colorFactor(palette = "RdYlBu", levels = seq(1:60))
#--- Loading And Rgistering Translation File
lang <- Translator$new(translation_json_path = "./translations.json")
lang$set_translation_language("gb")
language <- c("English", "Deutsch", "Français" , "Español")
#--- Naming Vector For Base Groups And Related Variables
layer_calls <- setNames(c('One', 'Two'), c("First", "Second"))
#--- A Function For Recoloring An Existing Polygon And Related JS-Code
#----- Source: https://github.com/rstudio/leaflet/issues/496#issuecomment-650122985
setShapeStyle <- function(map, data = getMapData(map), layerId, stroke = NULL, color = NULL, weight = NULL,
opacity = NULL, fill = NULL, fillColor = NULL, fillOpacity = NULL, dashArray = NULL,
smoothFactor = NULL, noClip = NULL, options = NULL){
options <- c(list(layerId = layerId),
options,
filterNULL(list(stroke = stroke, color = color, weight = weight, opacity = opacity,
fill = fill, fillColor = fillColor, fillOpacity = fillOpacity,
dashArray = dashArray, smoothFactor = smoothFactor, noClip = noClip)))
# Evaluate All Options
options <- evalFormula(options, data = data)
options <- do.call(data.frame, c(options, list(stringsAsFactors = FALSE)))
layerId <- options[[1]]
style <- options[-1] # drop layer column
leaflet::invokeMethod(map, data, "setStyle", "shape", layerId, style);
}
leafletjs <- tags$head(
tags$script(HTML(
'
window.LeafletWidget.methods.setStyle = function(category, layerId, style){
var map = this;
if (!layerId){
return;
} else if (!(typeof(layerId) === "object" && layerId.length)){ // in case a single layerid is given
layerId = [layerId];
}
//convert columnstore to row store
style = HTMLWidgets.dataframeToD3(style);
//console.log(style);
layerId.forEach(function(d,i){
var layer = map.layerManager.getLayer(category, d);
if (layer){ // or should this raise an error?
layer.setStyle(style[i]);
}
});
};
'
)))
#--- Defining UI
ui <- fluidPage(
leafletjs,
usei18n(lang),
pickerInput(inputId = 'selected_language', width = 125,
choices = c("gb", "de", "fr", "es"),
selected = lang$get_key_translation()),
leafletOutput("map")
)
#--- Defining Server Logic
server <- function(input, output, session){
output$map <- renderLeaflet({
leaflet(data = shape) %>%
#--- Initial Unfilled Polygon Map
addPolygons(layerId = ~CNTY_ID, stroke = TRUE, color = "white", weight = 1.25,
highlightOptions = highlightOptions(stroke = 5, weight = 10)) %>%
#--- Initial Layer Controls
addLayersControl(baseGroups = lang$t(names(layer_calls)))
})
#--- Filling Polygons Based On Base Layer-Variable After Translation
observe({
req(input$selected_language)
update_lang(session, input$selected_language)
leafletProxy("map", data = shape) %>%
#--- This Part Always Crashes Shiny!!!
setShapeStyle(layerId = ~CNTY_ID, fillOpacity = 1)#, fillColor = ~scale.color(get(layer_calls[lang$t(input$map_groups)])))
})
}
# Run the application
shinyApp(ui = ui, server = server)
My basic translation scheme would be provided by a JSON file which looks like this:
{
"languages": [
"gb",
"de",
"fr",
"es"
],
"translation": [
{
"gb": "First",
"de": "Erste",
"fr": "Premier",
"es": "Primera"
},
{
"gb": "Second",
"de": "Zweite",
"fr": "Deuxième",
"es": "Segundo"
}
]
}
In my One-Langue-App I can simply use , fillColor = ~scale.color(get(layer_calls[[input$map_groups]])) to trigger a recoloring after the base group has been changed. Unfortunately, I have no idea how to connect the selected base group to a call of the needed variable to trigger the recoloring. Any kind of help is greatly appreciated!

constructing json in R with jsonlite - too many brackets

Not a json expert, but I need what I think is referred to as "nested objects" and I am getting instead what I think is referred to as "nested arrays". In other words, some extra brackets. I'm trying to convert a dataframe into json data using jsonlite in R. Reproducible code and results below. Can anyone point me to how to get the data in the proper format (rows as nested objects)?
library(jsonlite)
testdat <- data.frame(locationColumn = c("US", "US"),
nameColumn = c("General Motors", "Walmart"),
zipColumn = c(19890, 72712) )
jsl <- jsonlite::toJSON(
list(
config = list(
item1 = list("country",
"city"),
item2 = "true",
item3 = "false",
item4 = 3
),
rows = split(testdat, 1:nrow(testdat))
),
auto_unbox = TRUE,
pretty = TRUE,
dataframe = "rows",
simplifyDataFrame = TRUE
)
jsl
Output:
{
"config": {
"item1": [
"country",
"city"
],
"item2": "true",
"item3": "false",
"item4": 3
},
"rows": {
"1": [
{
"locationColumn": "US",
"nameColumn": "General Motors",
"zipColumn": 19890
}
],
"2": [
{
"locationColumn": "US",
"nameColumn": "Walmart",
"zipColumn": 72712
}
]
}
}
What I need: (EDIT: I added some more complexity to the json. I need to keep the brackets in 'config', but not have brackets in 'rows'.
{
"config": {
"item1": [
"country",
"city"
],
"item2": "true",
"item3": "false",
"item4": 3
},
"rows": {
"1":
{
"locationColumn": "US",
"nameColumn": "General Motors",
"zipColumn": 19890
},
"2":
{
"locationColumn": "US",
"nameColumn": "Walmart",
"zipColumn": 72712
}
}
}
Here is a possible solution:
library(jsonlite)
testdat <- data.frame(locationColumn = c("US", "US"),
nameColumn = c("General Motors", "Walmart"),
zipColumn = c(19890, 72712) )
jsl <- jsonlite::toJSON(
list(
rows = split(testdat, 1:nrow(testdat))
),
auto_unbox = TRUE,
pretty = TRUE,
dataframe = "columns", #change from rows (moves brackets from row level to value level)
simplifyDataFrame = TRUE
)
#removed the backets if desired
#jsl<-gsub("\\[|\\]", "", jsl)
all.equal(testcase, fromJSON(jsl))
testcase<-fromJSON('{
"rows": {
"1":{
"locationColumn": "US",
"nameColumn": "General Motors",
"zipColumn": 19890
},
"2":{
"locationColumn": "US",
"nameColumn": "Walmart",
"zipColumn": 72712
}
}
}')
all.equal(testcase, fromJSON(jsl))
#[1] TRUE
EDIT Here is an approved version that manually edits the list of list in order to obtain the correct format.
#create a list of the data
top<-list(
config = list(
item1 = list("country",
"city"),
item2 = "true",
item3 = "false",
item4 = 3
),
rows = split(testdat, 1:nrow(testdat))
)
#edit the data frames store as part of rows
#lapply - lapply loops will parse each column in each row to create a new list
rows<-lapply(top$rows, function(x){
tempdf<-x
#collist<-lapply(names(tempdf), function(y){print(tempdf[ , y, drop=T])})
collist<-lapply(names(tempdf), function(y){tempdf[, y, drop=T]})
names(collist)<-names(tempdf)
collist
})
#update the list with the list of list
top$rows<-rows
#make the JSON
jsl <- jsonlite::toJSON(
top,
auto_unbox = TRUE,
pretty = TRUE,
dataframe = "columns",
simplifyDataFrame = TRUE
)

hover additional information with Shiny & ggplotly

I have been surfing around this site for answers to my problem with Shiny and Plotly (ggplotly) but none of these has been enough. I'm trying to customize hover boxtext of my ggplotly. I would to include more variables on that boxtext when you put your mouse over any point of my plot.
I have trying with this this solution
Any way to display data frame information besides x and y on hover with shiny/ggplot?
and this one: Shiny: Interactive ggplot with Vertical Line and Data Labels at Mouse Hover Point
Without any successful result
I'm working trying to create visualization for football data, I have this huge df which has the followings variables:
[1] "ID" "Nombre" "Apellido" "Rol"
[5] "Tecnica" "Club" "Competicion" "Nacionalidad"
[9] "PrimerToque" "Dribbling" "Versatilidad" "Pases"
[13] "Centros" "Remate" "TiroLibre" "Cabezazo"
[17] "TiroLejano" "SaqueLateral" "Marcaje" "Penales"
[21] "Tacle" "Corner" "Aceleracion" "Stamina"
[25] "Fuerza" "Agilidad" "Balance" "TendenciaLesion"
[29] "Salto" "FormaNatural" "Velocidad" "FechaNacimiento"
[33] "AnoNacimiento" "CA" "PA" "RepHome"
[37] "RepActual" "RepMundial" "Consistencia" "Altura"
[41] "Peso" "Posicion"
this is my ui file
library("shiny")
library("shinythemes")
library("shinyWidgets")
library("shinydashboard")
library("leaflet")
library("ggplot2")
library("dplyr")
library("ggrepel")
library("plotly")
ui <- shinyUI(fluidPage(
# Application title
titlePanel("Graph"),
sidebarLayout(
sidebarPanel(
selectizeInput("Atributo1", #xaxis
label = "AtributoX",
choices = c("Centros", "Pases", "PrimerToque", "Remate", "Tecnica","Dribbling","TiroLejano",
"TiroLibre", "SaqueLateral","Penales", "Corner" ,"Cabezazo", "Salto", "Aceleracion",
"Stamina", "Fuerza","Agilidad","Balance","TendenciaLesion","FormaNatural","Velocidad",
"Marcaje", "Tacle","Consistencia", "Versatilidad", "CA", "RepHome"), selected ="CA"),
selectizeInput("Atributo2", #yaxis
label = "AtributoY",
choices = c("Centros", "Pases", "PrimerToque", "Remate", "Tecnica","Dribbling","TiroLejano",
"TiroLibre", "SaqueLateral","Penales", "Corner" ,"Cabezazo", "Salto", "Aceleracion",
"Stamina", "Fuerza","Agilidad","Balance","TendenciaLesion","FormaNatural","Velocidad",
"Marcaje", "Tacle","Consistencia", "Versatilidad", "CA", "RepHome")),
sliderInput("numero", "Numero de Jugadores a Mostrar:",
value = 10, min = 1, max = 50, round = TRUE, dragRange = FALSE),
numericInput("Edad1", "Edad:", 42, value = 17),
numericInput("Edad2", "Edad:", 42),
sliderTextInput("Posicion","Posicion" ,
choices = c("GK","DL","DR","DC","DM","MC","ML","MR","AMC", "ST"),
selected = c("MC"), #incase you want all values by default
animate = FALSE, grid = FALSE,
hide_min_max = FALSE, from_fixed = FALSE,
to_fixed = FALSE, from_min = NULL, from_max = NULL, to_min = NULL,
to_max = NULL, force_edges = FALSE, width = NULL, pre = NULL,
post = NULL, dragRange = TRUE),
radioButtons("Color", label = "Color Por:",
choices = list("Club" = "Club", "Division" = "Competicion"),
selected = "Club")
),
mainPanel(
plotlyOutput("distPlot")
)
)
))
and my server file
server <- shinyServer(function(input, output) {
output$distPlot <- renderPlotly({ #Plot tipo Plotly
n <- input$numero
if (is.null(n)) {
n <- 1
}
dfjoin <- readRDS("dfjoin.rds")
a <- reactive({
dfjoin %>% filter(Posicion == input$Posicion) %>% filter(FechaNacimiento >= input$Edad1 & FechaNacimiento <= input$Edad2) %>% top_n(n, CA)
})
p <- ggplot(a(), aes_string(x = input$Atributo1, y = input$Atributo2,
label = "Apellido", colour = input$Color)) +
geom_text(position=position_jitter(h=1,w=1), check_overlap = TRUE) +
labs(colour= input$Color, title= paste("Grafico", input$Atributo1, "/", input$Atributo2, sep =" ")) +
theme(legend.position = "none")
p <- ggplotly(p)
print(p)
})
})
Currently Im getting only default hover information, which is Label, X axis, Y axis and colour. I would like to customize and include another variables as put First Name and Last Name. Which would be something like: paste(Nombre,Apellido, sep = " ")
I tried that line inside Tooltip:
$ggplotly(p, Tooltip = paste(Nombre,Apellido, sep = " "))
but didnt worked neither.
as a tip: in spanish:
Nombre = First Name
Apellido: Last Name
I've been doing that this way:
https://github.com/Bustami/DatoFutbol/blob/master/libertadores2019/shiny-app/server.R
Basically create a new column with all your text of interest (calling variables choosed by user) with HTML syntax and then use it with the "label" parameter inside ggplot and "tooltip" inside ggplotly.

plotly in R: adding labels to surface area charts through layout?

I'm working with surface area charts in plotly and I'm wondering how to change the labels as the process seems different from flat charts so I'm having trouble wrapping my head around how they layout should be arranged. I'm getting a warning message but I see that the title label has gone through, wondering how to get the X axis and Y axis to change. Below is my reproducible code using he built in data set freeny:
#stack question for surface plot
library(plotly)
library(zoo)
#set data
master = freeny
master$year = round(as.numeric(row.names(master)))
master$month = sample(1:6, 39, replace=TRUE)
master$month = paste0("0",master$month)
master$date = as.Date(with(master, paste0(year,"-" ,month,"-" ,"28")))
master$weekday = weekdays(master$date)
master$month_year = as.yearmon(master$date)
master
#build matrix
matrix_d = xtabs(income.level ~ month_year + weekday, master)
matrix_d
#plot
p = plot_ly(z = ~matrix_d) %>% add_surface()
p
#label
p = layout(p, # all of layout's properties: /r/reference/#layout
title = "income levels across month and weekdays", # layout's title: /r/reference/#layout-title
xaxis = list( # layout's xaxis is a named list. List of valid keys: /r/reference/#layout-xaxis
title = "weekday", # xaxis's title: /r/reference/#layout-xaxis-title
showgrid = F # xaxis's showgrid: /r/reference/#layout-xaxis-showgrid
),
yaxis = list( # layout's yaxis is a named list. List of valid keys: /r/reference/#layout-yaxis
title = "month_year" # yaxis's title: /r/reference/#layout-yaxis-title
),
zaxis = list(
title = "income_level"
))
p
Warning message:
'layout' objects don't have these attributes: 'zaxis'
Valid attributes include:
'font', 'title', 'titlefont', 'autosize', 'width', 'height', 'margin', 'paper_bgcolor', 'plot_bgcolor', 'separators', 'hidesources', 'smith', 'showlegend', 'dragmode', 'hovermode', 'xaxis', 'yaxis', 'scene', 'geo', 'legend', 'annotations', 'shapes', 'images', 'updatemenus', 'ternary', 'mapbox', 'radialaxis', 'angularaxis', 'direction', 'orientation', 'barmode', 'bargap', 'mapType'
EDIT FOLLOWUP:
Posted the answer below to the top question but as a followup how would I add values to the tick marks? I'm assuming there is a way to feed a list vector of ordinal values to the ticks such as c("0" = "sunday", "1" = "Monday" . . . ). Is this accurate?
Appreciate the help!!!
Found the answer from a different posting in case anyone ever needs it. I'm wondering though how to add the specific month and weekday to the tick marks?
p <- plot_ly(z = ~matrix_d) %>% add_surface() %>%
layout(title = 'income levels across month and weekdays',
scene = list(xaxis = list(title = 'weekday'),
yaxis = list(title = 'month'),
zaxis = list(title = 'income_level')))
p

How to read a geojson file containing feature collections to leaflet-shiny directly

My question is how to read a geojson file containing feature collections to leaflet-shiny. I have seen joe's github https://github.com/jcheng5/leaflet-shiny/blob/master/inst/examples/geojson/server.R but he did not use an external dataset but created the geojson manually. i am confused whether
Is that possible to read geojson file to leaflet-shiny directly?
If not, what does the structure of feature collections look like in shiny (in Joe's post it is multi-polygon) and how to create that in a faster and easier way?
You're probably looking to be able to manipulate the GeoJSON file directly in R-Shiny and R as opposed to reading a static file.
As previously mentioned, you can feed a string containing the GeoJSON to leaflet-shiny such as this GeoJSON FeatureCollection:
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"party": "Republican"},
"id": "North Dakota",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-104.05, 48.99],
[-97.22, 48.98],
[-96.58, 45.94],
[-104.03, 45.94],
[-104.05, 48.99]
]]
}
},
{
"type": "Feature",
"properties": {"party": "Democrat"},
"id": "Colorado",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-109.05, 41.00],
[-102.06, 40.99],
[-102.03, 36.99],
[-109.04, 36.99],
[-109.05, 41.00]
]]
}
}
]
}
Then you can use RJSONIO::fromJSON to read this object in the format provided in the example and manipulate it in R such as this (Note: it appears that you have to add styles after reading the GeoJSON file as opposed to reading a GeoJSON FeatureCollection file that already has styles):
geojson <- RJSONIO::fromJSON(fileLocation)
geojson[[2]][[1]]$properties$style <- list(color = "red",fillColor = "red")
geojson[[2]][[2]]$properties$style <- list(color = "blue",fillColor = "blue")
geojson$style <- list(weight = 5,stroke = "true",fill = "true",opacity = 1,fillOpacity = 0.4)
This will give you the same R object if you had just entered this:
geojson <- list(
type = "FeatureCollection",
features = list(
list(
type = "Feature",
geometry = list(type = "MultiPolygon",
coordinates = list(
list(
list(
c(-109.05, 41.00),
c(-102.06, 40.99),
c(-102.03, 36.99),
c(-109.04, 36.99),
c(-109.05, 41.00)
)
)
)
),
properties = list(
party = "Democrat",
style = list(
fillColor = "blue",
color = "blue"
)
),
id = "Colorado"
),
list(
type = "Feature",
geometry = list(type = "MultiPolygon",
coordinates = list(
list(
list(
c(-104.05, 48.99),
c(-97.22, 48.98),
c(-96.58, 45.94),
c(-104.03, 45.94),
c(-104.05, 48.99)
)
)
)
),
properties = list(
party = "Republican",
style = list(
fillColor = "red",
color = "red"
)
),
id = "North Dakota"
)
),
style = list(
weight = 5,
stroke = "true",
fill = "true",
fillOpacity = 0.4
opacity = 1
))
For question 1, refering to the API doc, you can provide instead directly a geojson string instead of a list like in the example.
The provided example also mentionned it with
You can also use a GeoJSON string value instead of a structured
GeoJSON object like this one
You can use this recipe to read your GeoJSON file
For question 2, as question 1 is Ok, no issue.

Resources