Leaflet create separate layer groups - layer

I am creating a leaflet map with two different types of layers:
A layer for total rental households, and a layer for total borrowing households. This layer should be mutually exclusive: i.e., you should only be able to select one of these layers at a time (either show total rental households OR total borrowing households). This will effectively function as a base layer: you can only choose one.
A layer Sydney, and a layer for the Rest of NSW. This layer does not need to be mutually exclusive: i.e., can show both Sydney AND Rest of NSW at the same time. These will effectively function like overlays: you can choose as many as you like.
Currently, I have only figured out how to show these layers as four separate layers: Sydney Renters, Rest of NSW renters, Sydney Borrowers, Rest of NSW Borrowers. (see image)
I would like to have these as two separate layers, with a choice for Renters OR Borrowers, and a separate layer for Sydney AND/OR Rest of NSW.
Here is the code used to generate the map:
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron, group = "OSM (default)") %>%
addPolygons(data = sf_syd, fillColor = ~pal2(Renting), color="white", weight=1, fillOpacity=0.4, group="Sydney Renters",
highlight = highlightOptions(weight=2, color="black", fillOpacity = 0.7, bringToFront = TRUE)) %>%
addPolygons(data = sf_nsw, fillColor = ~pal2(Renting), color="white", weight=1, fillOpacity=0.4, group="Rest of NSW Renters",
highlight = highlightOptions(weight=2, color="black", fillOpacity = 0.7, bringToFront = TRUE)) %>%
addPolygons(data = sf_syd, fillColor = ~pal2(Borrowing), color="white", weight=1, fillOpacity=0.4, group="Sydney Borrowers",
highlight = highlightOptions(weight=2, color="black", fillOpacity = 0.7, bringToFront = TRUE)) %>%
addPolygons(data = sf_nsw, fillColor = ~pal2(Borrowing), color="white", weight=1, fillOpacity=0.4, group="Rest of NSW Borrowers",
highlight = highlightOptions(weight=2, color="black", fillOpacity = 0.7, bringToFront = TRUE)) %>%
addLayersControl(baseGroups = c("OSM (default)"),
overlayGroups = c("Sydney Renters",
"Rest of NSW Renters",
"Sydney Borrowers",
"Rest of NSW Borrowers"),
options = layersControlOptions(collapsed = FALSE)) %>%
addLegend(data= sf_syd, pal = pal2, values = ~perc_rental_stress, opacity = 0.7, position = "bottomright", title = "Households of </br> Household Type 'X'")

What you want is a user interface to filter the data before it goes into leaflet. This is not possible in Rleaflet without a UI layer like shiny.
You can theoretically create a matrix of combinations and create a layergroup for each possibility but this will not look good when mapping.
A proper shiny based solution looks like this,
library(shiny)
library(leaflet)
library(tmap)
data(World)
ui <- fluidPage(
leafletOutput("mymap"),
p(),
br(),
checkboxInput("asia", label = "Asia", TRUE),
checkboxInput("africa", label = "Africa", TRUE),
radioButtons("value",choiceValues = c("life_exp","footprint"), choiceNames =c("life_exp","footprint"), label = "test", selected = "life_exp")
)
server <- function(input, output, session) {
filtered_world <- reactive({
temp <- World %>% filter(1==2)
if(input$asia) { temp <- rbind(temp, World %>% filter(continent == 'Asia')) }
if(input$africa) { temp <- rbind(temp, World %>% filter(continent == 'Africa')) }
temp$value <- temp[[input$value]]
temp
})
output$mymap <- renderLeaflet({
data <- filtered_world()
pal <- colorNumeric(palette = "Blues",domain = data$value)
leaflet() %>%
addProviderTiles(providers$CartoDB.PositronNoLabels) %>%
addPolygons(data = data, fillColor = ~pal(value),
fillOpacity = 1, color = "black", weight = 1)
})
}
shinyApp(ui, server)

Related

plot gam results with original x values (not scaled and centred)

I have a dataset that I am modeling with a gam. Because there are two continuous varaibles in the gam, I have centred and scaled these variables before adding them to the model. Therefore, when I use the built-in features in gratia to show the results, the x values are not the same as the original scale. I'd like to plot the results using the scale of the original data.
An example:
library(tidyverse)
library(mgcv)
library(gratia)
set.seed(42)
df <- data.frame(
doy = sample.int(90, 300, replace = TRUE),
year = sample(c(1980:2020), size = 300, replace = TRUE),
site = c(rep("A", 150), rep("B", 80), rep("C", 70)),
sex = sample(c("F", "M"), size = 300, replace = TRUE),
mass = rnorm(300, mean = 500, sd = 50)) %>%
mutate(doy.s = scale(doy, center = TRUE, scale = TRUE),
year.s = scale(year, center = TRUE, scale = TRUE),
across(c(sex, site), as.factor))
m1 <- gam(mass ~
s(year.s, site, bs = "fs", by = sex, k = 5) +
s(doy.s, site, bs = "fs", by = sex, k = 5) +
s(sex, bs = "re"),
data = df, method = "REML", family = gaussian)
draw(m1)
How do I re-plot the last two panels in this figure to show the relationship between year and mass with ggplot?
You can't do this with gratia::draw automatically (unless I'm mistaken).* But you can use gratia::smooth_estimates to get a dataframe which you can then do whatever you like with.
To answer your specific question: to re-plot the last two panels of the plot you provided, but with year unscaled, you can do the following
# Get a tibble of smooth estimates from the model
sm <- gratia::smooth_estimates(m1)
# Add a new column for the unscaled year
sm <- sm %>% mutate(year = mean(df$year) + (year.s * sd(df$year)))
# Plot the smooth s(year.s,site) for sex=F with year unscaled
pF <- sm %>% filter(smooth == "s(year.s,site):sexF" ) %>%
ggplot(aes(x = year, y = est, color=site)) +
geom_line() +
theme(legend.position = "none") +
labs(y = "Partial effect", title = "s(year.s,site)", subtitle = "By: sex; F")
# Plot the smooth s(year.s,site) for sex=M with year unscaled
pM <- sm %>% filter(smooth == "s(year.s,site):sexM" ) %>%
ggplot(aes(x = year, y = est, color=site)) +
geom_line() +
theme(legend.position = "none") +
labs(y = "Partial effect", title = "s(year.s,site)", subtitle = "By: sex; M")
library(patchwork) # use `patchwork` just for easy side-by-side plots
pF + pM
to get:
EDIT: If you also want to shift result on the y-axis as #GavinSimpson (who is the author and maintainer of gratia) mentioned, you can do this with add_constant, adding this code before plotting above:
sm <- sm %>%
add_constant(coef(m1)["(Intercept)"]) %>%
transform_fun(inv_link(m1))
[You should also in general untransform the smooth by the inverse of the model's link function. In your case this is just the identity, so it is not necessary, but in general it would be. That's what the second step above is doing.]
In your example, this results in:
*As mentioned in the custom-plotting vignette for gratia, the goal of draw not to be fully customizable, but just to be useful default. See there for recommendations about custom plots.

ggplot2_ combining line and barplot in one graph

Let's say I'm creating the grouped barplot by something like this:
data <- data.frame(time = factor(1:3), type = LETTERS[1:4], values = runif(24)*10)
ggplot(data, aes(x = type, y = values, fill = time)) +
stat_summary(fun=mean, geom='bar', width=0.55, size = 1, position=position_dodge(0.75))
Inside each type I want to connect all bar tops (meaning to connect 3 bars for A, 3 bars for B, and so on) with the line.
I'd like to get something like that as a result:
Is there a way to do that ?
Thank you!
I changed the code to another logic that I prefer, that is to prepare the data before using ggplot().
Code
library(dplyr)
library(ggplot2)
data <- data.frame(time = factor(1:3), type = LETTERS[1:4], values = runif(24)*10)
pdata <- data %>% group_by(type,time) %>% summarise(values = mean(values,na.rm = TRUE)) %>% ungroup()
pdata %>%
ggplot(aes(x = type, y = values)) +
geom_col(
mapping = aes(fill = time, group = time),
width = 0.55,
size = 1,
position = position_dodge(0.75)
)+
geom_line(
mapping = aes(group = type),
size = 1,
position = position_dodge2(.75)
)
Output

Center the plot title in ggsurvplot

I'm struggling with getting my plot title to the center using ggsurvplot...
I've seen some posts mentioning something like xxxx$plot + theme(....)
but this solution does not seem to work for me.
Here's my code, maybe you can see what I'm missing:
surv_object_CA19.9 <- Surv(time = data_OS$OS_Days / 30, event = data_OS$Status.Death)
CA19.9_surv_fit <- survfit(surv_object_CA19.9 ~ CA19.9.initial_status, data = data_OS)
CA19.9_OS <- ggsurvplot(CA19.9_surv_fit, data = data_OS, pval = TRUE, xlab = "Time [Months]",
ylab = "Overall survival", risk.table = TRUE, legend.title = "",
risk.table.col. = "strata", risk.table.y.text = FALSE, surv.scale = "percent",
break.x.by = 6, xlim = c(0, 60), legend.labs = c("Pathological", "Normal"),
title = "Overall survival for patients with initially pathological or normal CA19-9 values",
CA19.9_OS$plot + theme(plot.title = element_text(hjust = 0.5)))
Thank you for any help! I'm still new to R and not particularly a friend of it yet, so any tips are highly appreciated!
One relatively easy solution is to define your own custom theme based off of the theme that is used in ggsurvplot(). Looking at the documentation for the function shows us that it is applying via ggtheme= the theme theme_survminer(). We can create a custom function that uses %+replace% to overwrite one of the theme elements of interest from theme_survminer():
custom_theme <- function() {
theme_survminer() %+replace%
theme(
plot.title=element_text(hjust=0.5)
)
}
Then, you can use that theme by association with the ggtheme= argument of ggsurvplot():
library(ggplot2)
library(survminer)
require("survival")
fit<- survfit(Surv(time, status) ~ sex, data = lung)
ggsurvplot(fit, data = lung, title='Awesome Plot Title', ggtheme=custom_theme())
#Add parameters to your theme as follows
centr = theme_grey() + theme(plot.title = element_text(hjust = 0.5, face = "bold"))
#Fit the model
fit<- survfit(Surv(time, status) ~ sex, data = lung)
#create survival plot
ggsurvplot(fit, data = lung, title="Your Title Here", ggtheme=centr)

Reactive or observe in dynamic filtering

I have a working app that uses multiple filters to plot some data and i want the filters to be dynamic and dependent on the filter above by only showing available options for the selection. For instance if the Location_Id == 1 then only 'Bike' User_Type is available in the 'User Type' filter. This all works when the app starts with the filters all constrained by the initial Location_ID starting value but as soon as i change the initial input (Location_Id) nothing is getting updated automatically and i have to do an Select All to see which data is available for the new selected Location Id. I have been reading all morning and it seems i need to perhaps include a reactive() somewhere in the server but its not clear how then i update the ui and if i need a render type function somewhere.
#Example for stack overflow
library(shiny)
library(datasets)
library(dplyr)
library(shinyWidgets)
library(lubridate)
#Create test data
set.seed(10)
Dates. <- sample(c(seq(as.Date("2017-01-01"),as.Date("2017-12-28"),1),seq(as.Date("2018-01-01"),as.Date("2019-12-28"),1)),1000)
Facility_Type. <- sample(c("Bikelane","No facility"),length(Dates.),replace = T)
Data.. <- data.frame(Date = Dates., Facility_Type = Facility_Type.)
Data..$User_Type_Desc<- sample(c("Bike","Pedestrian"),nrow(Data..),replace = T)
Data..$Counts <- sample(1:100,nrow(Data..),replace = T)
Data..$Location_Id <- sample(c("01","02","03","04"),nrow(Data..),replace = T)
Data..$Month <- months(Data..$Date)
Data..$Year <- year(Data..$Date)
Data..$User_Type_Desc <- as.character(Data..$User_Type_Desc)
Data..$Facility_Type <- as.character(Data..$Facility_Type)
#Force some changes on data to highlight problem
Data..$User_Type_Desc[Data..$Location_Id%in%"01"] <- "Bike"
Data..$User_Type_Desc[Data..$Location_Id%in%"04"] <- "Pedestrian"
ui <-
#shinyUI(fluidPage(
navbarPage(title = "Bend Bike/PedTraffic Counts",
#Graphics panel
tabPanel("Charting",
#headerPanel(title = "Bend Traffic Count Data Viewer"),
sidebarLayout(
sidebarPanel(
#Select Location Id
selectInput("Location_Id","Select a Location Id",choices = unique(Data..$Location_Id)),
#Select Year
pickerInput(inputId = "Year", label = "Select/deselect all + format selected", choices = NULL,
options = list(`actions-box` = TRUE, size = 10,`selected-text-format` = "count > 3"), multiple = TRUE),
#Select Month
pickerInput(inputId = "Month", label = "Select/deselect all + format selected", choices = NULL,
options = list(`actions-box` = TRUE, size = 10,`selected-text-format` = "count > 3"), multiple = TRUE),
#Location details
##################
#Select User Types
pickerInput(inputId = "User_Type", label = "Select/deselect all + format selected", choices = NULL,
options = list(`actions-box` = TRUE, size = 10,`selected-text-format` = "count > 3"), multiple = TRUE),
#Select Facility Types
pickerInput(inputId = "Facility_Type", label = "Select/deselect all + format selected", choices = NULL,
options = list(`actions-box` = TRUE, size = 10,`selected-text-format` = "count > 3"), multiple = TRUE)
#dateRangeInput("Date", "Input date range")
#selectInput("Date","Select a Product",choices = NULL)
#Panel end
),
mainPanel( plotOutput("location_plot"))
#Sidebar panel layout end
)
# Sidebar panel end
)
#PAge end
)
server <-
#print(str(product_list))
shinyServer(function(session,input,output) {
#Create selection menus
##########################
#Year selection with choices constrained by Location_Id
observe({
Years. <- unique(Data..$Year[Data..$Location_Id%in%input$Location_Id])
updatePickerInput(session,"Year","Select Year(s)",choices = Years.,selected = Years.[1])
})
#Month selection with Year choices
observe({
Months. <- unique(Data..$Month[Data..$Year%in%input$Year])
updatePickerInput(session,"Month","Select Month(s)",choices = Months., selected = Months.[1] )
})
#User Type
observe({
User_Type. <- unique(Data..$User_Type_Desc[Data..$Year%in%input$Year & Data..$Month%in%input$Month])
updatePickerInput(session,"User_Type","Select User Type(s)",choices = User_Type., selected = User_Type.[1])
})
#Facility Type
observe({
Facility_Type. <- unique(Data..$Facility_Type[Data..$Year%in%input$Year & Data..$Month%in%input$Month
& Data..$User_Type_Desc%in%input$User_Type])
updatePickerInput(session,"Facility_Type","Select Facility Type(s)",choices = Facility_Type., selected = Facility_Type.[1])
})
#Plot data
##########################
#Select final data and chart
output$location_plot <- renderPlot({
#Select data
dat <- Data..[Data..$Location_Id%in%input$Location_Id & Data..$Month%in%input$Month &
Data..$Year%in%input$Year & Data..$User_Type_Desc%in%input$User_Type,]
#Initialze chart
ggplot(data = dat, x=Date, y = Counts) +
geom_bar(aes(x = Date,y = Counts),color = "black", position = "dodge", stat = "identity")+
facet_wrap(Facility_Type~User_Type_Desc)
})
})
#Run App
shinyApp(ui,server)
I have developed a solution for the above problem that started this issue (making filters update with proper reactive-ness) but now that i have added a map the app tends to break after making selections in the first selector, in this example that would be the state.
I created a new example below that answers the above question but poses a new one: Why is my app crashing and does it have to do with improper way i handle the reactive-ness?
In order to get the app to crash you have to select a couple of different states and let it render. It seems to do it on California so it makes me wonder if its a matter of the amount of data the map is attempting to render. Unfortunately there is no error given RStudio just crashes. Not sure if this is the proper way to pose this question but if the reactive-ness is the problem with the RStudio crash i think its still relevant to this thread. Thx for any help!
library(shiny) # for shiny apps
library(ggplot2)
library(plotly)
library(dplyr)
library(shinyWidgets)
library(tigris)
library(mapview)
library(leaflet)
library(raster)
library(rgeos)
# Load(Create) data
State_01_Tracts_Sp <- tracts("01")
State_02_Tracts_Sp <- tracts("02")
State_04_Tracts_Sp <- tracts("04")
State_05_Tracts_Sp <- tracts("05")
State_06_Tracts_Sp <- tracts("06")
Tracts_Sp <- rbind(State_01_Tracts_Sp ,State_02_Tracts_Sp, State_04_Tracts_Sp,
State_05_Tracts_Sp , State_06_Tracts_Sp )
#Decode fips into descriptive state and county names
Tracts_Sp#data$State <-
fips_codes$state_name[match(Tracts_Sp#data$STATEFP,fips_codes$state_code)]
Tracts_Sp#data$County <-
fips_codes$county[match(Tracts_Sp#data$COUNTYFP,fips_codes$county_code)]
#Create a copy of the spatial data's data frame
Data.. <- Tracts_Sp#data
#Set up User Interface
ui <- fluidPage(
titlePanel("Census Viewer Test"),
tabsetPanel(
#Daily Counts Panel
##############
#Hourly Counts Panel
#######################
tabPanel("Tab 1",
#Call plot
fluidRow(column(width = 12,plotlyOutput("county_plot" ))),
#Location Details
fluidRow(
column(3,
h4("Select Details"),
uiOutput("State_selector"),
uiOutput("County_selector"),
uiOutput("Tract_selector")),
column(6,
#h4("Selected Location"),
leafletOutput("map_plot",height = 500))
#Close row
)
#Close panel
)
#Close setPanel
)
#PAge end
)
#Set up Server
#---------------------------
server <- shinyServer(function(session,input,output){
#Temporal Details
##################
#State
output$State_selector <- renderUI({
selectInput(inputId = "State",
label = "State", multiple = FALSE,
choices = c( unique(Data..$State)),
selected = unique(Data..$State)[1])
})
#County selection----
output$County_selector <- renderUI({
available0 <- as.character(unique(Data..$County[Data..$State %in% input$State ]
))
pickerInput(inputId = "County", label = "Select/deselect all + format selected",
choices = as.character(unique(available0)),
options = list(`actions-box` = TRUE, size = 10,`selected-text-format`
= "count > 3"), multiple = TRUE,selected = as.character(unique(available0)))
})
#Tract selection----
output$Tract_selector <- renderUI({
available1 <- as.character(unique(Data..$GEOID[Data..$State %in% input$State ] ))
pickerInput(inputId = "Tract", label = "Select/deselect all + format selected",
choices = as.character(unique(available1)),
options = list(`actions-box` = TRUE, size = 10,`selected-text-format`
= "count > 3"), multiple = TRUE,selected = as.character(unique(available1)))
})
#Graphics
#Select final data and chart-----
output$county_plot <- renderPlotly({
#Select data
dat <- Data..[Data..$State%in%input$State & Data..$County%in%input$County &
Data..$GEOID%in%input$Tract ,]
#Set up axis parameters depending on amount of data
angle = 90
#Initialze chart
ggplotly(ggplot(data = dat, x=GEOID, y = ALAND, fill = State) +
geom_bar(aes(x=GEOID, y = ALAND, fill = State),color = "black",
position = "dodge", stat = "identity")+
ggtitle(paste("Land Area of Select Counties
",unique(dat$State),sep="")) +
#Center plot
theme(plot.title = element_text(hjust = 0.5)) +
ylab("LAnd Area") +
xlab("") +
guides(color=guide_legend("State")) +
theme(axis.text.x = element_text(angle = angle, hjust =
1),plot.background = element_rect(fill = "darkseagreen"))) %>% layout(dragmode =
"select")
})
#Select final data and map-----
output$map_plot <- renderLeaflet({
#Select data
Map_Data_Sp <- Tracts_Sp[Tracts_Sp#data$State%in%input$State,]
class(Map_Data_Sp )
#Create map
Map <- mapview(Map_Data_Sp, map.types = "OpenStreetMap", legend = FALSE,
col.regions = "red",color = "black",cex = 10)
Map#map
#Close map
})
})
#Run App
shinyApp(ui,server)

Legend not showing. Error in strwidth(legend, units = "user", cex = cex, font = text.font) : plot.new has not been called yet

I have the code below that is a combination of two boxplots and dot plots in one. It is a representation of barring density in 4 different species. The grey depicts the males and the tan the females.
data<-read.csv("C:/Users/Jeremy/Documents/A_Trogon rufus/Black-and-White/BARDATA_boxplots_M.csv")
datF<-read.csv("C:/Users/Jeremy/Documents/A_Trogon rufus/FEMALES_BW&Morphom.csv")
cleandataM<-subset(data, data$Age=="Adult" & data$White!="NA", select=(OTU:Density))
cleandatF<-subset(datF, datF$Age=="Adult", select=(OTU:Density))
dataM<- as.data.frame(cleandataM)
dataF<- as.data.frame(cleandatF)
library(ggplot2)
ggplot(dataM, aes(factor(OTU), Density))+
geom_boxplot(data=dataF,aes(factor(OTU),Density), fill="AntiqueWhite")+
geom_boxplot(fill="lightgrey", alpha=0.5)+
geom_point(data=dataF,position = position_jitter(width = 0.1), colour="tan")+
geom_point(data=dataM, position = position_jitter(width = 0.1), color="DimGrey")+ scale_x_discrete(name="",limits=order)+
scale_y_continuous(name="Bar Density (bars/cm)")+
theme(panel.background = element_blank(),panel.grid.minor=element_blank(),
panel.grid.major=element_blank(),axis.line = element_line(colour = "black"),
axis.title.y = element_text(colour="black", size=14),
axis.text.y = element_text(colour="black", size=12),
axis.text.x = element_text(colour="black", size=14))
This works just fine.
However, when I try to add a legend as:
legend("topright", inset=.01, bty="n", cex=.75, title="Sex",
c("Male", "Female"), fill=c("lightgrey", "black")
It returns the following Error:
Error in strwidth(legend, units = "user", cex = cex, font = text.font) :
plot.new has not been called yet
Please, is there someone who could suggest how to correct this?