Spaces:
Running
Running
0.1.1 - payout summary
Browse files- Dockerfile +4 -3
- app/app.R +328 -19
Dockerfile
CHANGED
@@ -4,11 +4,12 @@ FROM rocker/r-ver
|
|
4 |
RUN R -q -e "install.packages(c('shiny', 'rmarkdown'))"
|
5 |
|
6 |
# additional shiny functionality
|
7 |
-
RUN R -q -e "install.packages(c('shinydashboard', 'shinydashboardPlus'
|
8 |
-
RUN R -q -e "install.packages(c('
|
9 |
|
10 |
# other R packages
|
11 |
-
RUN R -q -e "install.packages(c('
|
|
|
12 |
|
13 |
# copy the app to the image
|
14 |
WORKDIR /shinyapp
|
|
|
4 |
RUN R -q -e "install.packages(c('shiny', 'rmarkdown'))"
|
5 |
|
6 |
# additional shiny functionality
|
7 |
+
RUN R -q -e "install.packages(c('shinydashboard', 'shinydashboardPlus'))"
|
8 |
+
RUN R -q -e "install.packages(c('shinyWidgets,'shinycssloaders'))"
|
9 |
|
10 |
# other R packages
|
11 |
+
RUN R -q -e "install.packages(c('DT, 'plotly', 'scico', 'ggthemes'))"
|
12 |
+
RUN R -q -e "install.packages(c('data.table', 'dtplyr', 'Rnumerai'))"
|
13 |
|
14 |
# copy the app to the image
|
15 |
WORKDIR /shinyapp
|
app/app.R
CHANGED
@@ -3,19 +3,26 @@ library(shinydashboard)
|
|
3 |
library(shinydashboardPlus)
|
4 |
library(shinyWidgets)
|
5 |
library(shinycssloaders)
|
|
|
|
|
|
|
|
|
6 |
library(data.table)
|
|
|
7 |
library(Rnumerai)
|
8 |
-
library(DT)
|
9 |
|
10 |
|
11 |
# ==============================================================================
|
12 |
-
#
|
13 |
# ==============================================================================
|
14 |
|
15 |
# Download latest leaderboard from Numerai and get a list of all models
|
16 |
d_lb <- get_leaderboard()
|
17 |
ls_model <- sort(d_lb$username)
|
18 |
|
|
|
|
|
|
|
19 |
|
20 |
# ==============================================================================
|
21 |
# Helper Functions
|
@@ -94,23 +101,35 @@ ui <- shinydashboardPlus::dashboardPage(
|
|
94 |
userOutput("user")
|
95 |
),
|
96 |
|
|
|
|
|
|
|
|
|
|
|
97 |
sidebar = shinydashboardPlus::dashboardSidebar(
|
98 |
id = "sidebar",
|
99 |
sidebarMenu(
|
100 |
menuItem(text = "Start Here", tabName = "start", icon = icon("play")),
|
101 |
-
menuItem(text = "
|
102 |
-
menuItem(text = "
|
103 |
menuItem(text = "About", tabName = "about", icon = icon("question-circle"))
|
104 |
),
|
105 |
minified = TRUE,
|
106 |
collapsed = FALSE
|
107 |
),
|
108 |
|
|
|
|
|
|
|
|
|
|
|
109 |
body = dashboardBody(
|
110 |
|
111 |
tabItems(
|
112 |
|
113 |
# ========================================================================
|
|
|
|
|
114 |
|
115 |
tabItem(tabName = "start",
|
116 |
|
@@ -186,20 +205,99 @@ ui <- shinydashboardPlus::dashboardPage(
|
|
186 |
)
|
187 |
),
|
188 |
|
|
|
|
|
189 |
# ========================================================================
|
190 |
|
191 |
-
tabItem(tabName = "
|
192 |
fluidPage(
|
193 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
)
|
|
|
195 |
),
|
196 |
|
197 |
-
|
|
|
|
|
|
|
|
|
|
|
198 |
fluidPage(
|
199 |
markdown("![image](https://media.giphy.com/media/cftSzNoCTfSyAWctcl/giphy.gif)")
|
200 |
)
|
201 |
),
|
202 |
|
|
|
|
|
|
|
203 |
# ========================================================================
|
204 |
|
205 |
tabItem(tabName = "about",
|
@@ -207,7 +305,7 @@ ui <- shinydashboardPlus::dashboardPage(
|
|
207 |
markdown('#### Yet another Numerai community dashboard by <b><a href="https://linktr.ee/jofaichow" target="_blank">Jo-fai Chow</a></b>.'),
|
208 |
|
209 |
br(),
|
210 |
-
markdown("## **
|
211 |
markdown("#### This hobby project was inspired by Rajiv's <a href='https://huggingface.co/spaces/rajistics/shiny-kmeans' target='_blank'>shiny-kmeans</a> on 🤗 Spaces."),
|
212 |
|
213 |
br(),
|
@@ -215,6 +313,7 @@ ui <- shinydashboardPlus::dashboardPage(
|
|
215 |
markdown(
|
216 |
"
|
217 |
- #### **0.1.0** — First prototype with an interactive table output
|
|
|
218 |
"),
|
219 |
br(),
|
220 |
markdown("## **Session Info**"),
|
@@ -229,12 +328,11 @@ ui <- shinydashboardPlus::dashboardPage(
|
|
229 |
|
230 |
footer = shinydashboardPlus::dashboardFooter(
|
231 |
left = "Powered by ❤️, ☕, Shiny, and 🤗 Spaces",
|
232 |
-
right = paste0("Version 0.1.
|
233 |
|
234 |
)
|
235 |
|
236 |
|
237 |
-
|
238 |
# ==============================================================================
|
239 |
# Server
|
240 |
# ==============================================================================
|
@@ -253,23 +351,23 @@ server <- function(input, output) {
|
|
253 |
|
254 |
|
255 |
# ============================================================================
|
256 |
-
# Reactive
|
257 |
# ============================================================================
|
258 |
|
259 |
-
|
260 |
|
261 |
-
output$print_download <- renderPrint({
|
262 |
|
263 |
output$text_download <- renderText({
|
264 |
-
if (length(
|
265 |
})
|
266 |
|
267 |
output$text_preview <- renderText({
|
268 |
-
if (length(
|
269 |
})
|
270 |
|
271 |
output$text_next <- renderText({
|
272 |
-
if (length(
|
273 |
})
|
274 |
|
275 |
react_d_model <- eventReactive(
|
@@ -289,6 +387,10 @@ server <- function(input, output) {
|
|
289 |
}
|
290 |
)
|
291 |
|
|
|
|
|
|
|
|
|
292 |
output$dt_model <- DT::renderDT({
|
293 |
|
294 |
DT::datatable(
|
@@ -330,10 +432,217 @@ server <- function(input, output) {
|
|
330 |
formatStyle(columns = c("corr_pct", "tc_pct", "fncv3_pct"),
|
331 |
color = styleInterval(cuts = c(1, 5, 15, 85, 95, 99),
|
332 |
values = c("#692020", "#9A2F2F", "#D24141",
|
333 |
-
|
334 |
-
|
335 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
336 |
formatStyle(columns = c("payout"),
|
|
|
|
|
|
|
|
|
|
|
337 |
fontWeight = "bold",
|
338 |
color = styleInterval(cuts = c(-1e-15, 1e-15),
|
339 |
values = c("#D24141", "#D1D1D1", "#00A800")))
|
|
|
3 |
library(shinydashboardPlus)
|
4 |
library(shinyWidgets)
|
5 |
library(shinycssloaders)
|
6 |
+
library(DT)
|
7 |
+
library(plotly)
|
8 |
+
library(scico)
|
9 |
+
library(ggthemes)
|
10 |
library(data.table)
|
11 |
+
library(dtplyr)
|
12 |
library(Rnumerai)
|
|
|
13 |
|
14 |
|
15 |
# ==============================================================================
|
16 |
+
# Tournament Information
|
17 |
# ==============================================================================
|
18 |
|
19 |
# Download latest leaderboard from Numerai and get a list of all models
|
20 |
d_lb <- get_leaderboard()
|
21 |
ls_model <- sort(d_lb$username)
|
22 |
|
23 |
+
# Round info
|
24 |
+
d_comp <- get_competitions()
|
25 |
+
|
26 |
|
27 |
# ==============================================================================
|
28 |
# Helper Functions
|
|
|
101 |
userOutput("user")
|
102 |
),
|
103 |
|
104 |
+
|
105 |
+
# ============================================================================
|
106 |
+
# Sidebar
|
107 |
+
# ============================================================================
|
108 |
+
|
109 |
sidebar = shinydashboardPlus::dashboardSidebar(
|
110 |
id = "sidebar",
|
111 |
sidebarMenu(
|
112 |
menuItem(text = "Start Here", tabName = "start", icon = icon("play")),
|
113 |
+
menuItem(text = "Payout Summary", tabName = "payout", icon = icon("credit-card")),
|
114 |
+
menuItem(text = "Model Performance", tabName = "performance", icon = icon("line-chart")),
|
115 |
menuItem(text = "About", tabName = "about", icon = icon("question-circle"))
|
116 |
),
|
117 |
minified = TRUE,
|
118 |
collapsed = FALSE
|
119 |
),
|
120 |
|
121 |
+
|
122 |
+
# ============================================================================
|
123 |
+
# Main
|
124 |
+
# ============================================================================
|
125 |
+
|
126 |
body = dashboardBody(
|
127 |
|
128 |
tabItems(
|
129 |
|
130 |
# ========================================================================
|
131 |
+
# Start Here
|
132 |
+
# ========================================================================
|
133 |
|
134 |
tabItem(tabName = "start",
|
135 |
|
|
|
205 |
)
|
206 |
),
|
207 |
|
208 |
+
# ========================================================================
|
209 |
+
# Payout Summary
|
210 |
# ========================================================================
|
211 |
|
212 |
+
tabItem(tabName = "payout",
|
213 |
fluidPage(
|
214 |
+
|
215 |
+
markdown("# **Payout Summary**"),
|
216 |
+
markdown("### Remember to refresh the charts after making changes to model selection or settings below"),
|
217 |
+
br(),
|
218 |
+
|
219 |
+
fluidRow(
|
220 |
+
|
221 |
+
column(6,
|
222 |
+
|
223 |
+
markdown("## **Step 1 - Define the Range**"),
|
224 |
+
|
225 |
+
sliderInput(inputId = "range_round",
|
226 |
+
label = "Numerai Classic Tournament Rounds",
|
227 |
+
width = "100%",
|
228 |
+
min = min(d_comp$number),
|
229 |
+
max = max(d_comp$number),
|
230 |
+
# note: daily rounds from round 339
|
231 |
+
value = c(394, max(d_comp$number))
|
232 |
+
)
|
233 |
+
),
|
234 |
+
|
235 |
+
column(6,
|
236 |
+
|
237 |
+
markdown("## **Step 2 - Visualise**"),
|
238 |
+
br(),
|
239 |
+
actionBttn(inputId = "button_filter",
|
240 |
+
label = "Create / Refresh Charts",
|
241 |
+
color = "primary",
|
242 |
+
icon = icon("refresh"),
|
243 |
+
style = "gradient",
|
244 |
+
block = TRUE)
|
245 |
+
)
|
246 |
+
),
|
247 |
+
|
248 |
+
br(),
|
249 |
+
|
250 |
+
tabsetPanel(type = "tabs",
|
251 |
+
|
252 |
+
tabPanel("All Models",
|
253 |
+
|
254 |
+
br(),
|
255 |
+
|
256 |
+
h3(strong(textOutput(outputId = "text_payout"))),
|
257 |
+
|
258 |
+
fluidRow(
|
259 |
+
# class = "text-center",
|
260 |
+
valueBoxOutput("payout_confirmed", width = 3),
|
261 |
+
valueBoxOutput("payout_pending", width = 3),
|
262 |
+
valueBoxOutput("payout_total", width = 3),
|
263 |
+
valueBoxOutput("payout_average", width = 3)
|
264 |
+
),
|
265 |
+
|
266 |
+
br(),
|
267 |
+
|
268 |
+
shinycssloaders::withSpinner(plotlyOutput("plot_payout_stacked"))
|
269 |
+
|
270 |
+
),
|
271 |
+
|
272 |
+
tabPanel("Individual Models",
|
273 |
+
br(),
|
274 |
+
shinycssloaders::withSpinner(plotlyOutput("plot_payout_individual"))),
|
275 |
+
|
276 |
+
tabPanel("Summary Table",
|
277 |
+
br(), br(),
|
278 |
+
shinycssloaders::withSpinner(DTOutput("dt_payout_summary"))
|
279 |
+
)
|
280 |
+
|
281 |
+
)
|
282 |
+
|
283 |
)
|
284 |
+
|
285 |
),
|
286 |
|
287 |
+
|
288 |
+
# ========================================================================
|
289 |
+
# Model Performance
|
290 |
+
# ========================================================================
|
291 |
+
|
292 |
+
tabItem(tabName = "performance",
|
293 |
fluidPage(
|
294 |
markdown("![image](https://media.giphy.com/media/cftSzNoCTfSyAWctcl/giphy.gif)")
|
295 |
)
|
296 |
),
|
297 |
|
298 |
+
|
299 |
+
# ========================================================================
|
300 |
+
# About
|
301 |
# ========================================================================
|
302 |
|
303 |
tabItem(tabName = "about",
|
|
|
305 |
markdown('#### Yet another Numerai community dashboard by <b><a href="https://linktr.ee/jofaichow" target="_blank">Jo-fai Chow</a></b>.'),
|
306 |
|
307 |
br(),
|
308 |
+
markdown("## **Acknowledgements**"),
|
309 |
markdown("#### This hobby project was inspired by Rajiv's <a href='https://huggingface.co/spaces/rajistics/shiny-kmeans' target='_blank'>shiny-kmeans</a> on 🤗 Spaces."),
|
310 |
|
311 |
br(),
|
|
|
313 |
markdown(
|
314 |
"
|
315 |
- #### **0.1.0** — First prototype with an interactive table output
|
316 |
+
- #### **0.1.1** — Added a functional `Payout Summary`
|
317 |
"),
|
318 |
br(),
|
319 |
markdown("## **Session Info**"),
|
|
|
328 |
|
329 |
footer = shinydashboardPlus::dashboardFooter(
|
330 |
left = "Powered by ❤️, ☕, Shiny, and 🤗 Spaces",
|
331 |
+
right = paste0("Version 0.1.1"))
|
332 |
|
333 |
)
|
334 |
|
335 |
|
|
|
336 |
# ==============================================================================
|
337 |
# Server
|
338 |
# ==============================================================================
|
|
|
351 |
|
352 |
|
353 |
# ============================================================================
|
354 |
+
# Reactive: Data
|
355 |
# ============================================================================
|
356 |
|
357 |
+
react_ls_model <- eventReactive(input$button_download, {sort(input$model)})
|
358 |
|
359 |
+
output$print_download <- renderPrint({react_ls_model()})
|
360 |
|
361 |
output$text_download <- renderText({
|
362 |
+
if (length(react_ls_model()) >= 1) "Your Selection:" else " "
|
363 |
})
|
364 |
|
365 |
output$text_preview <- renderText({
|
366 |
+
if (length(react_ls_model()) >= 1) "Data Preview:" else " "
|
367 |
})
|
368 |
|
369 |
output$text_next <- renderText({
|
370 |
+
if (length(react_ls_model()) >= 1) "⬅ [NEW] Payout Summary 📈📊🔥" else " "
|
371 |
})
|
372 |
|
373 |
react_d_model <- eventReactive(
|
|
|
387 |
}
|
388 |
)
|
389 |
|
390 |
+
# ============================================================================
|
391 |
+
# Reactive: DataTable
|
392 |
+
# ============================================================================
|
393 |
+
|
394 |
output$dt_model <- DT::renderDT({
|
395 |
|
396 |
DT::datatable(
|
|
|
432 |
formatStyle(columns = c("corr_pct", "tc_pct", "fncv3_pct"),
|
433 |
color = styleInterval(cuts = c(1, 5, 15, 85, 95, 99),
|
434 |
values = c("#692020", "#9A2F2F", "#D24141",
|
435 |
+
"#D1D1D1", # light grey
|
436 |
+
"#00A800", "#007000", "#003700"))) |>
|
437 |
+
|
438 |
+
formatStyle(columns = c("payout"),
|
439 |
+
fontWeight = "bold",
|
440 |
+
color = styleInterval(cuts = c(-1e-15, 1e-15),
|
441 |
+
values = c("#D24141", "#D1D1D1", "#00A800")))
|
442 |
+
|
443 |
+
})
|
444 |
+
|
445 |
+
|
446 |
+
# ============================================================================
|
447 |
+
# Reactive: filtering data for all charts
|
448 |
+
# ============================================================================
|
449 |
+
|
450 |
+
react_d_filter <- eventReactive(
|
451 |
+
input$button_filter,
|
452 |
+
{
|
453 |
+
|
454 |
+
# Model data
|
455 |
+
d_filter <- react_d_model()
|
456 |
+
|
457 |
+
# Filtering
|
458 |
+
d_filter <- d_filter[pay_ftr > 0, ] # ignoring the new daily rounds for now
|
459 |
+
d_filter <- d_filter[round >= input$range_round[1], ]
|
460 |
+
d_filter <- d_filter[round <= input$range_round[2], ]
|
461 |
+
|
462 |
+
# Return
|
463 |
+
d_filter
|
464 |
+
|
465 |
+
})
|
466 |
+
|
467 |
+
|
468 |
+
# ============================================================================
|
469 |
+
# Reactive: Payout Value Boxes
|
470 |
+
# ============================================================================
|
471 |
+
|
472 |
+
output$text_payout <- renderText({
|
473 |
+
if (nrow(react_d_filter()) >= 1) "Payouts in NMR" else " "
|
474 |
+
})
|
475 |
+
|
476 |
+
output$payout_confirmed <- renderValueBox({
|
477 |
+
valueBox(value = round(sum(react_d_filter()[resolved == TRUE, ]$payout, na.rm = T), 2),
|
478 |
+
subtitle = "Confirmed",
|
479 |
+
icon = icon("check"),
|
480 |
+
color = "green")
|
481 |
+
})
|
482 |
+
|
483 |
+
output$payout_pending <- renderValueBox({
|
484 |
+
valueBox(value = round(sum(react_d_filter()[resolved == FALSE, ]$payout, na.rm = T), 2),
|
485 |
+
subtitle = "Pending",
|
486 |
+
icon = icon("clock"),
|
487 |
+
color = "yellow")
|
488 |
+
})
|
489 |
+
|
490 |
+
output$payout_total <- renderValueBox({
|
491 |
+
valueBox(value = round(sum(react_d_filter()$payout, na.rm = T), 2),
|
492 |
+
subtitle = "Confirmed + Pending",
|
493 |
+
icon = icon("plus"),
|
494 |
+
color = "aqua")
|
495 |
+
})
|
496 |
+
|
497 |
+
output$payout_average <- renderValueBox({
|
498 |
+
valueBox(value = round((sum(react_d_filter()$payout, na.rm = T) / length(unique(react_d_filter()$round))), 2),
|
499 |
+
subtitle = "Round Average",
|
500 |
+
icon = icon("credit-card"),
|
501 |
+
color = "light-blue")
|
502 |
+
})
|
503 |
+
|
504 |
+
|
505 |
+
# ============================================================================
|
506 |
+
# Reactive: Payout Charts
|
507 |
+
# ============================================================================
|
508 |
+
|
509 |
+
# Stacked Bar Chart
|
510 |
+
output$plot_payout_stacked <- renderPlotly({
|
511 |
+
|
512 |
+
p <- ggplot(react_d_filter(), aes(x = round, y = payout, fill = payout,
|
513 |
+
text = paste("Model:", model,
|
514 |
+
"\nRound:", round,
|
515 |
+
"\nResolved:", resolved,
|
516 |
+
"\nPayout:", round(payout,2), "NMR"))) +
|
517 |
+
geom_bar(position = "stack", stat = "identity") +
|
518 |
+
theme(
|
519 |
+
panel.border = element_rect(fill = 'transparent',
|
520 |
+
color = "grey", linewidth = 0.25),
|
521 |
+
panel.background = element_rect(fill = 'transparent'),
|
522 |
+
plot.background = element_rect(fill = 'transparent', color = NA),
|
523 |
+
panel.grid.major = element_blank(),
|
524 |
+
panel.grid.minor = element_blank(),
|
525 |
+
strip.background = element_rect(fill = 'transparent'),
|
526 |
+
strip.text = element_text(),
|
527 |
+
strip.clip = "on",
|
528 |
+
legend.background = element_rect(fill = 'transparent'),
|
529 |
+
legend.box.background = element_rect(fill = 'transparent')
|
530 |
+
) +
|
531 |
+
geom_hline(aes(yintercept = 0), linewidth = 0.25, color = "grey") +
|
532 |
+
scale_fill_scico(palette = "vikO", direction = -1, midpoint = 0) +
|
533 |
+
xlab("Tournament Round") +
|
534 |
+
ylab("Payout (NMR)")
|
535 |
+
|
536 |
+
# Generate plotly
|
537 |
+
ggplotly(p, tooltip = "text")
|
538 |
+
|
539 |
+
})
|
540 |
+
|
541 |
+
|
542 |
+
# Individual
|
543 |
+
output$plot_payout_individual <- renderPlotly({
|
544 |
+
|
545 |
+
# Get the number of unique models
|
546 |
+
n_model <- length(unique(react_d_filter()$model))
|
547 |
+
|
548 |
+
# Base plot
|
549 |
+
p <- ggplot(react_d_filter(), aes(x = round, y = payout, fill = payout,
|
550 |
+
text = paste("Round:", round,
|
551 |
+
"\nResolved:", resolved,
|
552 |
+
"\nPayout:", round(payout,2), "NMR"))) +
|
553 |
+
geom_bar(stat = "identity") +
|
554 |
+
theme(
|
555 |
+
panel.border = element_rect(fill = 'transparent',
|
556 |
+
color = "grey", linewidth = 0.25),
|
557 |
+
panel.background = element_rect(fill = 'transparent'),
|
558 |
+
plot.background = element_rect(fill = 'transparent', color = NA),
|
559 |
+
panel.grid.major = element_blank(),
|
560 |
+
panel.grid.minor = element_blank(),
|
561 |
+
strip.background = element_rect(fill = 'transparent'),
|
562 |
+
strip.text = element_text(),
|
563 |
+
strip.clip = "on",
|
564 |
+
legend.background = element_rect(fill = 'transparent'),
|
565 |
+
legend.box.background = element_rect(fill = 'transparent')
|
566 |
+
) +
|
567 |
+
geom_hline(aes(yintercept = 0), size = 0.25, color = "grey") +
|
568 |
+
scale_fill_scico(palette = "vikO", direction = -1, midpoint = 0) +
|
569 |
+
xlab("Tournament Round") +
|
570 |
+
ylab("Confirmed / Pending Payout (NMR)")
|
571 |
+
|
572 |
+
# Facet setting
|
573 |
+
if (n_model %% 5 == 0) {
|
574 |
+
p <- p + facet_wrap(. ~ model, ncol = 5)
|
575 |
+
} else {
|
576 |
+
p <- p + facet_wrap(. ~ model)
|
577 |
+
}
|
578 |
+
|
579 |
+
# Dynamic height adjustment
|
580 |
+
height <- 600 # default
|
581 |
+
if (n_model > 10) height = 800
|
582 |
+
if (n_model > 15) height = 1000
|
583 |
+
if (n_model > 20) height = 1200
|
584 |
+
if (n_model > 25) height = 1400
|
585 |
+
if (n_model > 30) height = 1600
|
586 |
+
if (n_model > 35) height = 1800
|
587 |
+
if (n_model > 40) height = 2000
|
588 |
+
if (n_model > 45) height = 2200
|
589 |
+
if (n_model > 50) height = 2400
|
590 |
+
|
591 |
+
# Generate plotly
|
592 |
+
ggplotly(p, height = height, tooltip = "text")
|
593 |
+
|
594 |
+
})
|
595 |
+
|
596 |
+
|
597 |
+
# ============================================================================
|
598 |
+
# Reactive: Payout Summary Table
|
599 |
+
# ============================================================================
|
600 |
+
|
601 |
+
output$dt_payout_summary <- DT::renderDT({
|
602 |
+
|
603 |
+
# Summarise payout
|
604 |
+
d_smry <-
|
605 |
+
react_d_filter() |> lazy_dt() |>
|
606 |
+
group_by(round, resolved) |>
|
607 |
+
summarise(stake = sum(stake, na.rm = T),
|
608 |
+
payout = sum(payout, na.rm = T)) |>
|
609 |
+
as.data.table()
|
610 |
+
d_smry$rate_of_return <- (d_smry$payout / d_smry$stake) * 100
|
611 |
+
|
612 |
+
# Generate a new DT
|
613 |
+
DT::datatable(
|
614 |
+
|
615 |
+
# Data
|
616 |
+
d_smry,
|
617 |
+
|
618 |
+
# Other Options
|
619 |
+
rownames = FALSE,
|
620 |
+
extensions = "Buttons",
|
621 |
+
options =
|
622 |
+
list(
|
623 |
+
dom = 'Bflrtip', # https://datatables.net/reference/option/dom
|
624 |
+
buttons = list('csv', 'excel', 'copy', 'print'), # https://rstudio.github.io/DT/003-tabletools-buttons.html
|
625 |
+
order = list(list(0, 'asc'), list(1, 'asc')),
|
626 |
+
pageLength = 20,
|
627 |
+
lengthMenu = c(5, 10, 20, 100, 500, 1000),
|
628 |
+
columnDefs = list(list(className = 'dt-center', targets = "_all")))
|
629 |
+
) |>
|
630 |
+
|
631 |
+
# Reformat individual columns
|
632 |
+
formatRound(columns = c("stake", "payout", "rate_of_return"), digits = 2) |>
|
633 |
+
|
634 |
+
formatStyle(columns = c("round"), fontWeight = "bold") |>
|
635 |
+
|
636 |
+
formatStyle(columns = c("stake"),
|
637 |
+
fontWeight = "bold",
|
638 |
+
color = styleInterval(cuts = -1e-15, values = c("#D24141", "#2196F3"))) |>
|
639 |
+
|
640 |
formatStyle(columns = c("payout"),
|
641 |
+
fontWeight = "bold",
|
642 |
+
color = styleInterval(cuts = c(-1e-15, 1e-15),
|
643 |
+
values = c("#D24141", "#D1D1D1", "#00A800"))) |>
|
644 |
+
|
645 |
+
formatStyle(columns = c("rate_of_return"),
|
646 |
fontWeight = "bold",
|
647 |
color = styleInterval(cuts = c(-1e-15, 1e-15),
|
648 |
values = c("#D24141", "#D1D1D1", "#00A800")))
|