cjerzak commited on
Commit
638f9f7
·
verified ·
1 Parent(s): 6daf1d7

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +318 -20
app.R CHANGED
@@ -4,37 +4,333 @@ library(shinydashboard)
4
  library(dplyr)
5
  library(readr)
6
  library(sf)
7
- library(cartogram)
8
  library(ggplot2)
9
  library(rnaturalearth)
10
  library(rnaturalearthdata)
11
  library(countrycode)
12
 
13
  # =============================
14
- # UI
15
  # =============================
16
  ui <- dashboardPage(
17
- dashboardHeader(title = "Country Representation Rankings"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  dashboardSidebar(
19
  sidebarMenu(
20
  menuItem("Cartogram", tabName = "cartogramTab", icon = icon("globe"))
21
  ),
22
- selectInput(
23
- inputId = "indexChoice",
24
- label = "Select Representation Index:",
25
- choices = c("Overall", "RepresentationGap", "Ethnicity",
26
- "Gender", "Religion", "Language"),
27
- selected = "Overall"
 
 
 
28
  )
29
  ),
 
30
  dashboardBody(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  tabItems(
32
  tabItem(
33
  tabName = "cartogramTab",
34
  fluidRow(
35
  box(
36
  width = 12,
37
- div(style = "height: 80vh;", plotOutput("cartogramPlot", height = "100%"))
 
 
 
 
38
  )
39
  )
40
  )
@@ -43,7 +339,7 @@ ui <- dashboardPage(
43
  )
44
 
45
  # =============================
46
- # SERVER
47
  # =============================
48
  server <- function(input, output, session) {
49
 
@@ -56,7 +352,7 @@ server <- function(input, output, session) {
56
  # ---- Read/prepare world map shapefile ----
57
  world_sf <- reactive({
58
  ne_countries(scale = "medium", returnclass = "sf") %>%
59
- select(name, iso_a3, pop_est, geometry) %>%
60
  st_transform(crs = "ESRI:54009") # Mollweide projection
61
  })
62
 
@@ -64,8 +360,9 @@ server <- function(input, output, session) {
64
  cartogram_sf <- reactive({
65
  merged_sf <- world_sf() %>%
66
  left_join(rankings_data(), by = "iso_a3")
 
67
  merged_sf <- merged_sf[!is.na(merged_sf$Overall),]
68
- return(merged_sf) # Regular map; cartogram functions are commented out
69
  })
70
 
71
  # ---- Plot output ----
@@ -79,7 +376,8 @@ server <- function(input, output, session) {
79
  geom_sf(aes_string(fill = index_col), color = "grey20", size = 0.1) +
80
  scale_fill_viridis_c(option = "D", na.value = "white") +
81
  coord_sf(expand = FALSE) +
82
- theme_void(base_size = 14) +
 
83
  labs(
84
  fill = paste(index_col, "Index"),
85
  title = "Country Representation Rankings",
@@ -87,12 +385,12 @@ server <- function(input, output, session) {
87
  caption = "Source: Global Leadership Project (GLP) & Natural Earth"
88
  ) +
89
  theme(
90
- plot.title = element_text(face = "bold", hjust = 0.5),
91
- plot.subtitle = element_text(hjust = 0.5),
92
- plot.caption = element_text(hjust = 1),
93
- plot.margin = unit(c(0, 0, 0, 0), "cm"),
94
  legend.position = "bottom",
95
- legend.direction = "horizontal"
 
96
  )
97
  })
98
  }
@@ -100,4 +398,4 @@ server <- function(input, output, session) {
100
  # =============================
101
  # Launch the Shiny App
102
  # =============================
103
- shinyApp(ui = ui, server = server)
 
4
  library(dplyr)
5
  library(readr)
6
  library(sf)
7
+ library(cartogram) # optional if you decide to do cartograms later
8
  library(ggplot2)
9
  library(rnaturalearth)
10
  library(rnaturalearthdata)
11
  library(countrycode)
12
 
13
  # =============================
14
+ # UI
15
  # =============================
16
  ui <- dashboardPage(
17
+
18
+ # Use black skin for the dashboard
19
+ skin = "black",
20
+
21
+ dashboardHeader(
22
+ title = span(
23
+ style = "font-weight: 600; font-size: 18px;",
24
+ "Country Representation"
25
+ )
26
+ ),
27
+
28
+ dashboardSidebar(
29
+ sidebarMenu(
30
+ menuItem("Map Type", tabName = "cartogramTab", icon = icon("globe"))
31
+ ),
32
+ div(
33
+ style = "margin: 15px;",
34
+ selectInput(
35
+ inputId = "indexChoice",
36
+ label = "Select Representation Index:",
37
+ choices = c("Overall", "RepresentationGap", "Ethnicity",
38
+ "Gender", "Religion", "Language"),
39
+ selected = "Overall"
40
+ )
41
+ )
42
+ ),
43
+
44
+ dashboardBody(
45
+ # Bring in the OCR A Extended font from Google Fonts
46
+ tags$head(
47
+ tags$link(
48
+ href = "https://fonts.googleapis.com/css2?family=OCR+A+Extended&display=swap",
49
+ rel = "stylesheet"
50
+ ),
51
+ tags$style(HTML("
52
+ /* Force OCR A Extended font across the entire UI and all HTML elements */
53
+ html, body, h1, h2, h3, h4, h5, h6, p, div, span, label, input, button, select,
54
+ .box, .content-wrapper, .main-sidebar, .main-header .navbar, .main-header .logo,
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;
67
+ color: #ffffff !important;
68
+ border-bottom: none;
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 {
81
+ background-color: #344e5c !important;
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;
101
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
102
+ border-radius: 6px;
103
+ }
104
+ .box.box-solid > .box-header {
105
+ background-color: #204051;
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%;
118
+ }
119
+ "))
120
+ ),
121
+
122
+ tabItems(
123
+ tabItem(
124
+ tabName = "cartogramTab",
125
+ fluidRow(
126
+ box(
127
+ width = 12,
128
+ title = strong("Global Leadership Project (GLP)"),
129
+ solidHeader = TRUE,
130
+ div(style = "height: 80vh; padding: 10px;",
131
+ plotOutput("cartogramPlot", height = "100%")
132
+ )
133
+ )
134
+ )
135
+ )
136
+ )
137
+ )
138
+ )
139
+
140
+ # =============================
141
+ # SERVER
142
+ # =============================
143
+ server <- function(input, output, session) {
144
+
145
+ # ---- Read CSV data and create ISO3 codes ----
146
+ rankings_data <- reactive({
147
+ read_csv("CountryRepresentationRankings.csv") %>%
148
+ mutate(iso_a3 = countrycode(Country, origin = "country.name", destination = "iso3c"))
149
+ })
150
+
151
+ # ---- Read/prepare world map shapefile ----
152
+ world_sf <- reactive({
153
+ ne_countries(scale = "medium", returnclass = "sf") %>%
154
+ dplyr::select(name, iso_a3, pop_est, geometry) %>%
155
+ st_transform(crs = "ESRI:54009") # Mollweide projection
156
+ })
157
+
158
+ # ---- Create cartogram (currently a regular map) ----
159
+ cartogram_sf <- reactive({
160
+ merged_sf <- world_sf() %>%
161
+ left_join(rankings_data(), by = "iso_a3")
162
+ # Filter out NA values in 'Overall' to avoid missing countries
163
+ merged_sf <- merged_sf[!is.na(merged_sf$Overall),]
164
+ return(merged_sf)
165
+ })
166
+
167
+ # ---- Plot output ----
168
+ output$cartogramPlot <- renderPlot({
169
+ req(input$indexChoice)
170
+
171
+ index_col <- input$indexChoice
172
+ plot_data <- cartogram_sf()
173
+
174
+ ggplot(plot_data) +
175
+ geom_sf(aes_string(fill = index_col), color = "grey20", size = 0.1) +
176
+ scale_fill_viridis_c(option = "D", na.value = "white") +
177
+ coord_sf(expand = FALSE) +
178
+ # Force OCR A Extended font in the plot
179
+ #theme_void(base_size = 14, base_family = "OCR A Extended") +
180
+ theme_void(base_size = 14, base_family = "Courier New") +
181
+ labs(
182
+ fill = paste(index_col, "Index"),
183
+ title = "Country Representation Rankings",
184
+ subtitle = "Map Colored by Selected Representation Index",
185
+ caption = "Source: Global Leadership Project (GLP) & Natural Earth"
186
+ ) +
187
+ theme(
188
+ plot.title = element_text(face = "bold", hjust = 0.5, size = 20),
189
+ plot.subtitle = element_text(hjust = 0.5, size = 14),
190
+ plot.caption = element_text(hjust = 1, size = 10),
191
+ legend.position = "bottom",
192
+ legend.direction = "horizontal",
193
+ legend.key.width = unit(2, "cm")
194
+ )
195
+ })
196
+ }
197
+
198
+ # =============================
199
+ # Launch the Shiny App
200
+ # =============================
201
+ shinyApp(ui = ui, server = server)
202
+ options(error = NULL)
203
+ library(shiny)
204
+ library(shinydashboard)
205
+ library(dplyr)
206
+ library(readr)
207
+ library(sf)
208
+ library(cartogram) # optional if you decide to do cartograms later
209
+ library(ggplot2)
210
+ library(rnaturalearth)
211
+ library(rnaturalearthdata)
212
+ library(countrycode)
213
+
214
+ # =============================
215
+ # UI
216
+ # =============================
217
+ ui <- dashboardPage(
218
+
219
+ # Use black skin for the dashboard
220
+ skin = "black",
221
+
222
+ dashboardHeader(
223
+ title = span(
224
+ style = "font-weight: 600; font-size: 18px;",
225
+ "Country Representation"
226
+ )
227
+ ),
228
+
229
  dashboardSidebar(
230
  sidebarMenu(
231
  menuItem("Cartogram", tabName = "cartogramTab", icon = icon("globe"))
232
  ),
233
+ div(
234
+ style = "margin: 15px;",
235
+ selectInput(
236
+ inputId = "indexChoice",
237
+ label = "Select Representation Index:",
238
+ choices = c("Overall", "RepresentationGap", "Ethnicity",
239
+ "Gender", "Religion", "Language"),
240
+ selected = "Overall"
241
+ )
242
  )
243
  ),
244
+
245
  dashboardBody(
246
+ # Bring in the OCR A Extended font from Google Fonts
247
+ tags$head(
248
+ tags$link(
249
+ href = "https://fonts.googleapis.com/css2?family=OCR+A+Extended&display=swap",
250
+ rel = "stylesheet"
251
+ ),
252
+ tags$style(HTML("
253
+ /* Force OCR A Extended font across the entire UI and all HTML elements */
254
+ html, body, h1, h2, h3, h4, h5, h6, p, div, span, label, input, button, select,
255
+ .box, .content-wrapper, .main-sidebar, .main-header .navbar, .main-header .logo,
256
+ .sidebar-menu, .sidebar-menu li a, .sidebar-menu .fa {
257
+ font-family: 'OCR A Extended', monospace !important;
258
+ }
259
+
260
+ /* Header gradient background */
261
+ .main-header .navbar {
262
+ background: linear-gradient(to right, #3b6978, #204051) !important;
263
+ }
264
+
265
+ /* Logo area (left corner of the header) */
266
+ .main-header .logo {
267
+ background: #1b2a2f !important;
268
+ color: #ffffff !important;
269
+ border-bottom: none;
270
+ font-size: 18px;
271
+ font-weight: 600;
272
+ }
273
+
274
+ /* Sidebar background */
275
+ .main-sidebar {
276
+ background-color: #1b2a2f !important;
277
+ }
278
+
279
+ /* Active or hovered tab in the sidebar */
280
+ .sidebar-menu > li.active > a,
281
+ .sidebar-menu > li:hover > a {
282
+ background-color: #344e5c !important;
283
+ border-left-color: #78cdd7 !important;
284
+ color: #ffffff !important;
285
+ }
286
+
287
+ /* Sidebar menu item icons */
288
+ .sidebar-menu .fa {
289
+ color: #78cdd7 !important;
290
+ }
291
+
292
+ /* Sidebar menu item text */
293
+ .sidebar-menu > li > a {
294
+ color: #b8c7ce !important;
295
+ font-size: 15px;
296
+ font-weight: 500;
297
+ }
298
+
299
+ /* Customize the boxes */
300
+ .box {
301
+ border-top: none !important;
302
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
303
+ border-radius: 6px;
304
+ }
305
+ .box.box-solid > .box-header {
306
+ background-color: #204051;
307
+ color: #fff;
308
+ border-radius: 6px 6px 0 0;
309
+ }
310
+
311
+ /* Plot box spacing */
312
+ .box .box-body {
313
+ padding: 0 !important;
314
+ }
315
+
316
+ /* Footer text styling (plot captions, etc.) */
317
+ .small, small {
318
+ font-size: 75%;
319
+ }
320
+ "))
321
+ ),
322
+
323
  tabItems(
324
  tabItem(
325
  tabName = "cartogramTab",
326
  fluidRow(
327
  box(
328
  width = 12,
329
+ title = strong("Cartogram / Map"),
330
+ solidHeader = TRUE,
331
+ div(style = "height: 80vh; padding: 10px;",
332
+ plotOutput("cartogramPlot", height = "100%")
333
+ )
334
  )
335
  )
336
  )
 
339
  )
340
 
341
  # =============================
342
+ # SERVER
343
  # =============================
344
  server <- function(input, output, session) {
345
 
 
352
  # ---- Read/prepare world map shapefile ----
353
  world_sf <- reactive({
354
  ne_countries(scale = "medium", returnclass = "sf") %>%
355
+ dplyr::select(name, iso_a3, pop_est, geometry) %>%
356
  st_transform(crs = "ESRI:54009") # Mollweide projection
357
  })
358
 
 
360
  cartogram_sf <- reactive({
361
  merged_sf <- world_sf() %>%
362
  left_join(rankings_data(), by = "iso_a3")
363
+ # Filter out NA values in 'Overall' to avoid missing countries
364
  merged_sf <- merged_sf[!is.na(merged_sf$Overall),]
365
+ return(merged_sf)
366
  })
367
 
368
  # ---- Plot output ----
 
376
  geom_sf(aes_string(fill = index_col), color = "grey20", size = 0.1) +
377
  scale_fill_viridis_c(option = "D", na.value = "white") +
378
  coord_sf(expand = FALSE) +
379
+ # Force OCR A Extended font in the plot
380
+ theme_void(base_size = 14, base_family = "OCR A Extended") +
381
  labs(
382
  fill = paste(index_col, "Index"),
383
  title = "Country Representation Rankings",
 
385
  caption = "Source: Global Leadership Project (GLP) & Natural Earth"
386
  ) +
387
  theme(
388
+ plot.title = element_text(face = "bold", hjust = 0.5, size = 20),
389
+ plot.subtitle = element_text(hjust = 0.5, size = 14),
390
+ plot.caption = element_text(hjust = 1, size = 10),
 
391
  legend.position = "bottom",
392
+ legend.direction = "horizontal",
393
+ legend.key.width = unit(2, "cm")
394
  )
395
  })
396
  }
 
398
  # =============================
399
  # Launch the Shiny App
400
  # =============================
401
+ shinyApp(ui = ui, server = server)