Update app.R
Browse files
app.R
CHANGED
@@ -8,7 +8,7 @@ library(rnaturalearth)
|
|
8 |
library(rnaturalearthdata)
|
9 |
library(countrycode)
|
10 |
library(ggplot2)
|
11 |
-
library(ggiraph)
|
12 |
|
13 |
# =============================
|
14 |
# UI
|
@@ -55,12 +55,11 @@ ui <- dashboardPage(
|
|
55 |
.sidebar-menu, .sidebar-menu li a, .sidebar-menu .fa {
|
56 |
font-family: 'OCR A Extended', monospace !important;
|
57 |
}
|
58 |
-
|
59 |
/* Header gradient background */
|
60 |
.main-header .navbar {
|
61 |
background: linear-gradient(to right, #3b6978, #204051) !important;
|
62 |
}
|
63 |
-
|
64 |
/* Logo area (left corner of the header) */
|
65 |
.main-header .logo {
|
66 |
background: #1b2a2f !important;
|
@@ -69,12 +68,10 @@ ui <- dashboardPage(
|
|
69 |
font-size: 18px;
|
70 |
font-weight: 600;
|
71 |
}
|
72 |
-
|
73 |
/* Sidebar background */
|
74 |
.main-sidebar {
|
75 |
background-color: #1b2a2f !important;
|
76 |
}
|
77 |
-
|
78 |
/* Active or hovered tab in the sidebar */
|
79 |
.sidebar-menu > li.active > a,
|
80 |
.sidebar-menu > li:hover > a {
|
@@ -82,19 +79,19 @@ ui <- dashboardPage(
|
|
82 |
border-left-color: #78cdd7 !important;
|
83 |
color: #ffffff !important;
|
84 |
}
|
85 |
-
|
86 |
/* Sidebar menu item icons */
|
87 |
.sidebar-menu .fa {
|
88 |
color: #78cdd7 !important;
|
89 |
}
|
90 |
-
|
91 |
/* Sidebar menu item text */
|
92 |
.sidebar-menu > li > a {
|
93 |
color: #b8c7ce !important;
|
94 |
font-size: 15px;
|
95 |
font-weight: 500;
|
96 |
}
|
97 |
-
|
98 |
/* Customize the boxes */
|
99 |
.box {
|
100 |
border-top: none !important;
|
@@ -106,12 +103,10 @@ ui <- dashboardPage(
|
|
106 |
color: #fff;
|
107 |
border-radius: 6px 6px 0 0;
|
108 |
}
|
109 |
-
|
110 |
/* Plot box spacing */
|
111 |
.box .box-body {
|
112 |
padding: 0 !important;
|
113 |
}
|
114 |
-
|
115 |
/* Footer text styling (plot captions, etc.) */
|
116 |
.small, small {
|
117 |
font-size: 75%;
|
@@ -127,7 +122,7 @@ ui <- dashboardPage(
|
|
127 |
width = 12,
|
128 |
title = strong("Global Leadership Project (GLP)"),
|
129 |
solidHeader = TRUE,
|
130 |
-
#
|
131 |
div(
|
132 |
style = "height: 80vh; padding: 10px;",
|
133 |
girafeOutput("cartogramPlot", width = "100%", height = "100%")
|
@@ -144,37 +139,45 @@ ui <- dashboardPage(
|
|
144 |
# =============================
|
145 |
server <- function(input, output, session) {
|
146 |
|
147 |
-
#
|
|
|
|
|
|
|
|
|
148 |
rankings_data <- reactive({
|
149 |
-
read_csv("CountryRepresentationRankings.csv") %>%
|
150 |
-
mutate(iso_a3 = countrycode(
|
|
|
|
|
|
|
|
|
|
|
151 |
})
|
152 |
|
153 |
-
#
|
154 |
world_sf <- reactive({
|
155 |
ne_countries(scale = "medium", returnclass = "sf") %>%
|
156 |
dplyr::select(name, iso_a3, pop_est, geometry) %>%
|
157 |
st_transform(crs = "ESRI:54009") # Mollweide projection
|
158 |
})
|
159 |
|
160 |
-
#
|
161 |
cartogram_sf <- reactive({
|
162 |
merged_sf <- world_sf() %>%
|
163 |
left_join(rankings_data(), by = "iso_a3")
|
164 |
-
# Filter out
|
165 |
merged_sf <- merged_sf[!is.na(merged_sf$Overall),]
|
166 |
-
|
167 |
})
|
168 |
|
169 |
-
#
|
170 |
output$cartogramPlot <- renderGirafe({
|
171 |
req(input$indexChoice)
|
172 |
|
173 |
plot_data <- cartogram_sf()
|
174 |
index_col <- input$indexChoice
|
175 |
|
176 |
-
# Build a tooltip string
|
177 |
-
# Modify this as desired to include more (or fewer) details.
|
178 |
plot_data$tooltip_text <- paste0(
|
179 |
"<b>Country:</b> ", plot_data$Country, "<br/>",
|
180 |
"<b>Overall:</b> ", ifelse(!is.na(plot_data$Overall), plot_data$Overall, "N/A"), "<br/>",
|
@@ -185,20 +188,21 @@ server <- function(input, output, session) {
|
|
185 |
"<b>Language:</b> ", ifelse(!is.na(plot_data$Language), plot_data$Language, "N/A")
|
186 |
)
|
187 |
|
188 |
-
#
|
189 |
p <- ggplot(plot_data) +
|
190 |
geom_sf_interactive(
|
191 |
-
|
192 |
-
fill = index_col,
|
193 |
-
tooltip =
|
194 |
-
data_id =
|
195 |
),
|
196 |
color = "grey20",
|
197 |
size = 0.1
|
198 |
) +
|
199 |
scale_fill_viridis_c(option = "D", na.value = "white") +
|
200 |
coord_sf(expand = FALSE) +
|
201 |
-
|
|
|
202 |
labs(
|
203 |
fill = paste(index_col, "Index"),
|
204 |
title = "Country Representation Rankings",
|
@@ -214,14 +218,17 @@ server <- function(input, output, session) {
|
|
214 |
legend.key.width = unit(2, "cm")
|
215 |
)
|
216 |
|
217 |
-
# Wrap the ggplot in a girafe object
|
218 |
girafe(
|
219 |
ggobj = p,
|
220 |
width_svg = 10,
|
221 |
height_svg = 6,
|
222 |
options = list(
|
223 |
-
|
224 |
-
|
|
|
|
|
|
|
225 |
)
|
226 |
)
|
227 |
})
|
@@ -230,4 +237,4 @@ server <- function(input, output, session) {
|
|
230 |
# =============================
|
231 |
# Launch the Shiny App
|
232 |
# =============================
|
233 |
-
shinyApp(ui = ui, server = server)
|
|
|
8 |
library(rnaturalearthdata)
|
9 |
library(countrycode)
|
10 |
library(ggplot2)
|
11 |
+
library(ggiraph) # For interactive hover tooltips
|
12 |
|
13 |
# =============================
|
14 |
# UI
|
|
|
55 |
.sidebar-menu, .sidebar-menu li a, .sidebar-menu .fa {
|
56 |
font-family: 'OCR A Extended', monospace !important;
|
57 |
}
|
58 |
+
|
59 |
/* Header gradient background */
|
60 |
.main-header .navbar {
|
61 |
background: linear-gradient(to right, #3b6978, #204051) !important;
|
62 |
}
|
|
|
63 |
/* Logo area (left corner of the header) */
|
64 |
.main-header .logo {
|
65 |
background: #1b2a2f !important;
|
|
|
68 |
font-size: 18px;
|
69 |
font-weight: 600;
|
70 |
}
|
|
|
71 |
/* Sidebar background */
|
72 |
.main-sidebar {
|
73 |
background-color: #1b2a2f !important;
|
74 |
}
|
|
|
75 |
/* Active or hovered tab in the sidebar */
|
76 |
.sidebar-menu > li.active > a,
|
77 |
.sidebar-menu > li:hover > a {
|
|
|
79 |
border-left-color: #78cdd7 !important;
|
80 |
color: #ffffff !important;
|
81 |
}
|
82 |
+
|
83 |
/* Sidebar menu item icons */
|
84 |
.sidebar-menu .fa {
|
85 |
color: #78cdd7 !important;
|
86 |
}
|
87 |
+
|
88 |
/* Sidebar menu item text */
|
89 |
.sidebar-menu > li > a {
|
90 |
color: #b8c7ce !important;
|
91 |
font-size: 15px;
|
92 |
font-weight: 500;
|
93 |
}
|
94 |
+
|
95 |
/* Customize the boxes */
|
96 |
.box {
|
97 |
border-top: none !important;
|
|
|
103 |
color: #fff;
|
104 |
border-radius: 6px 6px 0 0;
|
105 |
}
|
|
|
106 |
/* Plot box spacing */
|
107 |
.box .box-body {
|
108 |
padding: 0 !important;
|
109 |
}
|
|
|
110 |
/* Footer text styling (plot captions, etc.) */
|
111 |
.small, small {
|
112 |
font-size: 75%;
|
|
|
122 |
width = 12,
|
123 |
title = strong("Global Leadership Project (GLP)"),
|
124 |
solidHeader = TRUE,
|
125 |
+
# Use girafeOutput instead of plotOutput
|
126 |
div(
|
127 |
style = "height: 80vh; padding: 10px;",
|
128 |
girafeOutput("cartogramPlot", width = "100%", height = "100%")
|
|
|
139 |
# =============================
|
140 |
server <- function(input, output, session) {
|
141 |
|
142 |
+
# 1. Custom matches for countries not recognized by default in 'countrycode'
|
143 |
+
custom_iso_matches <- c("Kosovo" = "XKX",
|
144 |
+
"Somaliland" = "SOM") # or any valid code you prefer
|
145 |
+
|
146 |
+
# 2. Read CSV data and create ISO3 codes with custom matches
|
147 |
rankings_data <- reactive({
|
148 |
+
read_csv("CountryRepresentationRankings.csv", show_col_types = FALSE) %>%
|
149 |
+
mutate(iso_a3 = countrycode(
|
150 |
+
sourcevar = Country,
|
151 |
+
origin = "country.name",
|
152 |
+
destination = "iso3c",
|
153 |
+
custom_match = custom_iso_matches
|
154 |
+
))
|
155 |
})
|
156 |
|
157 |
+
# 3. Read/prepare world map shapefile
|
158 |
world_sf <- reactive({
|
159 |
ne_countries(scale = "medium", returnclass = "sf") %>%
|
160 |
dplyr::select(name, iso_a3, pop_est, geometry) %>%
|
161 |
st_transform(crs = "ESRI:54009") # Mollweide projection
|
162 |
})
|
163 |
|
164 |
+
# 4. Create the joined sf object (currently just a regular map)
|
165 |
cartogram_sf <- reactive({
|
166 |
merged_sf <- world_sf() %>%
|
167 |
left_join(rankings_data(), by = "iso_a3")
|
168 |
+
# Filter out rows with missing 'Overall', if you want to exclude them
|
169 |
merged_sf <- merged_sf[!is.na(merged_sf$Overall),]
|
170 |
+
merged_sf
|
171 |
})
|
172 |
|
173 |
+
# 5. Render the interactive map with ggiraph
|
174 |
output$cartogramPlot <- renderGirafe({
|
175 |
req(input$indexChoice)
|
176 |
|
177 |
plot_data <- cartogram_sf()
|
178 |
index_col <- input$indexChoice
|
179 |
|
180 |
+
# Build a tooltip string: customize to your preference
|
|
|
181 |
plot_data$tooltip_text <- paste0(
|
182 |
"<b>Country:</b> ", plot_data$Country, "<br/>",
|
183 |
"<b>Overall:</b> ", ifelse(!is.na(plot_data$Overall), plot_data$Overall, "N/A"), "<br/>",
|
|
|
188 |
"<b>Language:</b> ", ifelse(!is.na(plot_data$Language), plot_data$Language, "N/A")
|
189 |
)
|
190 |
|
191 |
+
# Use geom_sf_interactive with aes() + get() instead of aes_string()
|
192 |
p <- ggplot(plot_data) +
|
193 |
geom_sf_interactive(
|
194 |
+
aes(
|
195 |
+
fill = get(index_col),
|
196 |
+
tooltip = tooltip_text,
|
197 |
+
data_id = iso_a3
|
198 |
),
|
199 |
color = "grey20",
|
200 |
size = 0.1
|
201 |
) +
|
202 |
scale_fill_viridis_c(option = "D", na.value = "white") +
|
203 |
coord_sf(expand = FALSE) +
|
204 |
+
# Use a generic base_family to avoid font errors
|
205 |
+
theme_void(base_size = 14, base_family = "sans") +
|
206 |
labs(
|
207 |
fill = paste(index_col, "Index"),
|
208 |
title = "Country Representation Rankings",
|
|
|
218 |
legend.key.width = unit(2, "cm")
|
219 |
)
|
220 |
|
221 |
+
# Wrap the ggplot in a girafe object, including tooltip styling
|
222 |
girafe(
|
223 |
ggobj = p,
|
224 |
width_svg = 10,
|
225 |
height_svg = 6,
|
226 |
options = list(
|
227 |
+
opts_tooltip(
|
228 |
+
css = "background-color: white;
|
229 |
+
font-family: 'OCR A Extended', monospace;
|
230 |
+
color: black;"
|
231 |
+
)
|
232 |
)
|
233 |
)
|
234 |
})
|
|
|
237 |
# =============================
|
238 |
# Launch the Shiny App
|
239 |
# =============================
|
240 |
+
shinyApp(ui = ui, server = server)
|