Spaces:
Sleeping
Sleeping
File size: 16,820 Bytes
59455e5 831d877 59455e5 3f20b9b 59455e5 fa53cd1 59455e5 fa53cd1 59455e5 fa53cd1 59455e5 fa53cd1 728ae3e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
required_packages <- c("leaflet","shiny","dplyr","RColorBrewer","scales","lattice","plotly","bslib","shinydashboard","remotes")
remotes::install_github("briatte/ggnet")
#remotes::install_github("rspatial/terra")
options(repos = c(CRAN = "https://cloud.r-project.org"))
for (pkg in required_packages) {
if (!requireNamespace(pkg, quietly = TRUE)) { install.packages(pkg) }
library(pkg, character.only = TRUE)
}
lapply(c("leaflet","shiny","dplyr","RColorBrewer","scales","lattice",
"plotly","ggnet","bslib","shinydashboard"), require, character.only = TRUE)
# install.packages("leafpop") # this is for the popups in leaflet
# for testing, set working directory to the app directory
#setwd("/Users/luciagomezteijeiro/Library/CloudStorage/OneDrive-UniversitédeGenève/BPL/Nisa_Lucia_Vini/philea/app")
# Load data
geo <- as.data.frame(readRDS("data/geo_QC_annotated_connectivity_rescaled.rds"))
geo <- geo[!is.na(geo$lat | !is.na(geo$lon)),] # remove foundations without addresses
p_members_data <- readRDS("data/p_members_data.rds")
p_purposes_data <- readRDS("data/p_purposes_data.rds")
p_geo_data <- readRDS("data/p_geo_data.rds")
# PREPARE POPUP FOR MAP AS FORMATED TEXT
geo$popup_content <- paste0(
"<b><span style='font-size:16px;'>", ifelse(is.na(geo$name_clean), "No name available", geo$name_clean), "</span></b><br>","<br>",
"<b>GPS Coordinates:</b> ", ifelse(is.na(geo$lat), "No latitude available", round(geo$lat,2)), ", ", ifelse(is.na(geo$lon), "No longitude available", round(geo$lon,2)), "<br>", # Example variable 1
"<b>ID:</b> ", ifelse(is.na(geo$ID), "Not available", geo$ID), "<br>","<br>",
"<b><span style='font-size:14px;'> Overall Connectivity Score:</b> ", ifelse(is.na(geo$overall_connectivity), "Not available", round(geo$overall_connectivity,2)), "<br>",
"<b>Board Connectivity Score: </b> ", ifelse(is.na(geo$strength_memb_scaled), "Not available", round(geo$strength_memb_scaled,2)), "<br>",
"<b>Purpose Connectivity Score: </b> ", ifelse(is.na(geo$strength_purp_scaled), "Not available", round(geo$strength_purp_scaled,2)), "<br>",
"<b>Geography Connectivity Score: </b> ", ifelse(is.na(geo$strength_geo_scaled), "Not available", round(geo$strength_geo_scaled,2)), "<br>","<br>",
"<b><span style='font-size:14px;'> Most connected foundations:</b> ","<br>",
"<b>Closer by board: </b> ", ifelse(is.na(geo$top_memb), "Not available", geo$top_memb), "<br>",
"<b>Closer by purpose: </b> ", ifelse(is.na(geo$top_purp), "Not available", geo$top_purp), "<br>",
"<b>Closer by geography: </b> ", ifelse(is.na(geo$top_geo), "Not available", geo$top_geo), "<br>"
# "<b>Funding:</b> $", format(funding, big.mark = ","), "<br>", # If you want to add financials
# "<b>Website:</b> <a href='", geo$website, "' target='_blank'>Visit</a>" # If you want a clickable URL
)
ui <- navbarPage("Spanish Philanthropic Landscape",id="nav",
# THEME
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
#theme = bs_theme(version = 4), # uncomment this to have a theme selector in the navbar, do the same in server side with bs_themer()
theme = bs_theme(version = 4, bootswatch = "lumen"),
tags$style(HTML(
# custom css to modify theme
"
.navbar-brand { font-size: 25px !important;}
body { font-size: 16px; }
h1 { font-size: 40px; }
h2, h3, h4, h5, h6 { font-size: 20px; }
.navbar, .navbar-nav, .navbar-default, .navbar-header { font-size: 20px !important; }
.container-fluid { font-size: 16px; }
"
)),
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# FIRST PAGE - INTERACTIVE MAP
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
tabPanel("Interactive Map",
fluidRow(column(12,
absolutePanel(top = 10, left = 20, right=20, width = "95%",
div(class="container-fluid",
selectizeInput("name_clean",
label=tagList(
tags$strong("Highlight one or several Foundations by Name")
),
choices = NULL, multiple = TRUE,
options = list(placeholder = "Search a foundation..."),width="100%") )
),
div(style = "margin-left: 20px; margin-right:20px; margin-top: 80px; font-size: 12px; color: #555; text-align: left;",
"Use the search bar to find and highlight foundations on the map.
All foundations are displayed by default in blue, while the selected ones will be highlighted in red.")
)),
fluidRow(column(12,
div(style = "padding-top: 25px;margin-left: 20px; margin-right:20px;", leafletOutput("map",height = "600px"))
)),
fluidRow(column(12,
div(style= "margin-left: 20px; margin-right:20px; margin-top:20px; font-size: 12px; color: #555; text-align: center;",
"Data compiled for ",
tags$em("PIO Winter Meeting 2025"),
" by Lucia Gomez Teijeiro (1), Nisa Thomas (2) and Jack O'Neill (3) (University of Geneva (1,2) / BFH (1) and Philea (3) respectively, 2025)",
tags$br(),
"Methodology derived from the Mapping Philanthropy research project. Open Source and available at",
tags$a(href="https://github.com/gomez-L/mapping_philanthropy","https://github.com/gomez-L/mapping_philanthropy",target="https://github.com/gomez-L/mapping_philanthropy")
)))
),
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# SECOND PAGE - NETWORK EXPLORER
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
tabPanel("Network Explorer",
fluidRow(column(12,
absolutePanel(top = 10, left = 20, right=20, width = "95%",
div(class="container-fluid",
selectizeInput("label_plotly",
label=tagList(
tags$strong("Highlight one or several Foundations by Name")
),
choices = NULL, multiple = TRUE,
options = list(placeholder = "Search a foundation..."),width="100%") )
),
div(style = "margin-left: 20px; margin-right:20px; margin-top: 80px; margin-bottom: 20px; font-size: 12px; color: #555; text-align: left;",
HTML(
"Use the search bar to find and highlight foundations in all networks at the same time.
All foundations are displayed by default in blue, while the selected ones will be highlighted in red.<br>
Here you will discover that foundation similarity is heterogeneous, as it depends on the dimension you explore 😊 !"))
)),
fluidRow(
column(4, # First Column - 1/3 is 4, as total width is 12 elements)
box(
status = "primary",width=12,style = "background-color: rgba(128, 128, 128, 0.1); border: 0.5px solid #000000;",
plotlyOutput("p_members", height = "60vh"),
p(HTML(paste("Network arranging foundations by the number of board members in common.<br>
Dot size indicates the number of board members each foundation has.<br>
Foundations in the periphery have less board members in common, those overlapping have connected boards")),
style="margin-left:10px; margin-right:10px; margin-top:10px; margin-bottom:10px; font-size:12px; text-align:center;")
)),
column(4, # Second column
box(
status = "primary",width=12,style = "background-color: rgba(128, 128, 128, 0.1); border: 0.5px solid #000000;",
plotlyOutput("p_purposes", height = "60vh"),
p(HTML(paste("Network arranging foundations by the similarity in their mission statements.<br>
Transformer-based instructed retrieval ensures that purpose similarity is captured.
Foundations in the periphery have more specific purposes, those in the center broader purposes.")),
style="margin-left:10px; margin-right:10px; margin-top:10px; margin-bottom:10px; font-size:12px; text-align:center;")
)),
column(4, # Third Column
box(
status = "primary",width=12,style = "background-color: rgba(128, 128, 128, 0.1); border: 0.5px solid #000000;",
plotlyOutput("p_geo", height = "60vh"),
p(HTML(paste("Network arranging foundations by their geographical proximity, in kilometers.<br>It resembles a map.<br><br><br>")),
style="margin-left:10px; margin-right:10px; margin-top:10px; margin-bottom:10px; font-size:12px; text-align:center;")
)),
),
fluidRow(column(12,
div(style= "margin-left: 20px; margin-right:20px; margin-top:20px; margin-bottom:50px; font-size: 12px; color: #555; text-align: center;",
"Data compiled for ",
tags$em("PIO Winter Meeting 2025"),
" by Lucia Gomez Teijeiro (1), Nisa Thomas (2) and Jack O'Neill (3) (University of Geneva (1,2) / BFH (1) and Philea (3) respectively, 2025)",
tags$br(),
"Methodology derived from the Mapping Philanthropy research project. Open Source and available at",
tags$a(href="https://github.com/gomez-L/mapping_philanthropy","https://github.com/gomez-L/mapping_philanthropy",target="https://github.com/gomez-L/mapping_philanthropy")
)))
),
)
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
server <- function(input, output, session) {
#bs_themer() # uncomment this to have a theme selector in the navbar, do the same in ui side with theme = bs_theme(version = 4),
# INTERACTIVE MAP
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# DEFINE SELECTIZEINPUT FOR MAP
# Load foundation names dynamically
observe({ updateSelectizeInput(session, "name_clean", choices = unique(geo$name_clean), server = TRUE) })
# OBSERVE MAP
# Render initial Leaflet Map with all points in blue
output$map <- renderLeaflet({ leaflet(geo) %>% addTiles() %>%
addCircleMarkers(lng =~lon,lat =~lat,label=~name_clean,color ="blue",layerId =~name_clean,radius=3,stroke=FALSE,fillOpacity=1,
popup =~popup_content)
})
# Observe selection and update marker colors
observeEvent(input$name_clean, {
leafletProxy("map") %>%
clearMarkers() %>%
addCircleMarkers(data = geo, lng = ~lon, lat = ~lat,
label = ~name_clean,color =~ifelse(name_clean %in% input$name_clean,"red","blue"),layerId = ~name_clean, # color changes with selection
radius=~ifelse(name_clean %in% input$name_clean,10,3), # size changes with selection
stroke=FALSE,fillOpacity=1,popup =~popup_content )
})
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# NETWORK EXPLORER
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
# DEFINE SELECTIZEINPUT FOR NETWORK EXPLORER
observe({ updateSelectizeInput(session, "label_plotly", choices = unique(c(geo$name_clean,p_members_data$label,p_purposes_data$label)), server = TRUE) })
output$p_members <- renderPlotly({
plot_ly(p_members_data, x = ~x, y = ~y) %>%
add_markers(color = I("blue"),alpha = 0.8,marker = list(size = ~n_members),text=~label,hoverinfo="text") %>%
filter(label %in% input$label_plotly) %>%
add_markers(color = I("red"),alpha = 0.8,marker = list(size=20),text=~label,hoverinfo="text") %>%
toWebGL() %>% layout(showlegend = FALSE,title=list(text="Shared Board Members",font=list(size=20),y=0.9,yanchor="top"),
xaxis = list(visible = FALSE,scaleanchor = "y"),yaxis = list(visible = FALSE),
margin = list(t = 100, r = 0, b = 0, l = 0),hoverlabel = list(bgcolor = "white") )
})
output$p_purposes <- renderPlotly({
plot_ly(p_purposes_data, x = ~x, y = ~y) %>%
add_markers(color = I("blue"), alpha = 0.5,text=~label,hoverinfo="text") %>%
filter(label %in% input$label_plotly) %>%
# WE COULD HAVE DETERMINED THE SIZE!! IT COULD HAVE BEEN THE PURPOSE HETEROGENEITY
add_markers(color = I("red"),alpha = 0.8,marker=list(size=20),text=~label,hoverinfo="text") %>%
toWebGL() %>% layout(showlegend = FALSE,title=list(text="Purpose Similarity",font=list(size=20),y=0.9,yanchor="top"),
xaxis = list(visible = FALSE,scaleanchor = "y"),yaxis = list(visible = FALSE),
margin = list(t = 100, r = 0, b = 0, l = 0),hoverlabel = list(bgcolor = "white") )
})
output$p_geo <- renderPlotly({
plot_ly(p_geo_data, x = ~(-y), y = ~x) %>%
add_markers(color = I("blue"), alpha = 0.5,text=~label,hoverinfo="text") %>%
filter(label %in% input$label_plotly) %>%
# WE COULD HAVE DETERMINED THE SIZE!! IT COULD HAVE BEEN THE CLOSENESS TO A CITY CENTER
add_markers(color = I("red"),alpha = 0.8,marker=list(size=20),text=~label,hoverinfo="text") %>%
toWebGL() %>% layout(showlegend = FALSE,title=list(text="Geographic Proximity",font=list(size=20),y=0.9,yanchor="top"),
xaxis = list(visible = FALSE,scaleanchor = "y"),yaxis = list(visible = FALSE),
margin = list(t = 100, r = 0, b = 0, l = 0),hoverlabel = list(bgcolor = "white") )
})
# --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- # --- #
}
shinyApp(ui, server)
|