Pokémon Dashboard
Live App Here!
My favorite video game/hobby is Pokémon. Creating a dashboard to search and display all of the available Pokémon was a great way to start learning how to program shiny dashboards in R. I am particularly proud of learning how to create, add and delete lines from, and reference a newly created table with the app itself. The data was taken from Kaggle, and the pictures come from serebii.
Shiny App Code
library(shiny)
library(tidyverse)
# Load Data
load("pkmn_shinyEnvironment.RData")
# Define UI for application that draws a histogram
pkm_ui_adv2 <- fluidPage(
navbarPage ("Advanced Pokemon Finder",
#theme = "spacelab",
tabPanel("Pokemon Finder",
column(3, wellPanel(
h3("Select Attributes"),
actionButton("update", "Update View", width = "100%", class = "btn-primary"),
selectInput("Pkmn_Type_1",
h4("Pokemon Type 1"),
choices = c("All",
unique(pokemon2.1$`Type 1`)),
selected = "",
multiple=TRUE,
selectize=TRUE),
selectInput("Pkmn_Type_2",
h4("Pokemon Type 2"),
choices = c("All",
unique(pokemon2.1$`Type 2`)),
selected = "",
multiple=TRUE,
selectize=TRUE),
sliderInput("Gen",
h4("Generation"),
min = 1,
max = 8,
value = c(1,8)),
ticks = FALSE,
sliderInput("base_total",
h4("Base Stat Total"),
min = 0,
max = 1125,
value = c(0, 1125),
step = 100),
checkboxGroupInput("Legend",
h4("Legendary"),
choices = c(unique(pokemon2.1$`Legendary?`)),
selected = unique(pokemon2.1$`Legendary?`))
),
wellPanel(
h3("Additional Filters"),
selectInput("tbl_ops",
h4("Additional Columns"),
choices = c("All", "Catch Rate", "Base Friendship",
"Base XP", "Egg Type 1", "Egg Type 2", "Percent Male"),
selected = "",
multiple=TRUE,
selectize=TRUE),
sliderInput("atk",
h4("Attack"),
min = 0,
max = 250,
value = c(0, 250)),
sliderInput("def",
h4("Defense"),
min = 0,
max = 250,
value = c(0, 250)),
sliderInput("sp_atk",
h4("Special Attack"),
min = 0,
max = 250,
value = c(0, 250)),
sliderInput("sp_def",
h4("Special Defense"),
min = 0,
max = 250,
value = c(0, 250)),
sliderInput("spd",
h4("Speed"),
min = 0,
max = 250,
value = c(0, 250))
)),
fluidRow(
column(8,
# h4("Type 1:"),
# textOutput("selected_type_1"),
#
# h4("Type 2:"),
# textOutput("selected_type_2"),
#
# h4("Testing"),
# textOutput("testing"),
DT::dataTableOutput("found_pkmn", width = "110%"), #table width with scrollable table (in datatable options),
actionButton("add_pkmn", "Add Pokemon to List", class = "btn-primary", width = "50%"),
h6("Open the Second Tab Before Adding Pokemon"),
uiOutput("pkmn_img1"),
h6("Images from Serebii.net"),
))),
tabPanel("My Team",
fluidRow(
column(3,
actionButton("del_pkmn", "Remove Pokemon", class = "btn-primary", width = "100%"))
),
br(),
fluidRow(
column(10,
DT::dataTableOutput("pkmn_list", width = "100%"),
downloadButton("dwn_list", "Download List (.csv)", class = "btn-primary", width = "60%")),
h4("Strong Against: "), textOutput("strong_against"),
br(),
h4("Weak Against: "), textOutput("weak_against"),
uiOutput("pkmn_img2")
)
)
)
)
pkm_server_adv2 <- function(input,output){
# output$selected_type_1 <- renderText({paste(input$Pkmn_Type_1)})
#
# output$selected_type_2 <- renderText({paste(input$Pkmn_Type_2)})
#
# output$testing <- renderText({paste(pokemon2.2[(update_pkmn()$`index`[input$found_pkmn_rows_selected]+1),])})
## output$testing <- renderText({paste("All" %in% input$Pkmn_Type_1)})
#output$testing <- renderText(paste(pokemon_list_r$x))
# output$testing <- renderText(paste(((((input$Pkmn_Type_1)) %in% ((input$Pkmn_Type_2))) == TRUE)))
output$found_pkmn <- DT::renderDataTable(DT::datatable(
update_pkmn(), options = list(lengthMenu = c(10, 25, 50), pageLength = 10, autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(visible=FALSE, targets=c(0,1)))), selection = "single"
))
# First Tab
update_pkmn <- eventReactive(input$update,{
pokemon2.1_s <- pokemon2.1
# Main Bar
if ((is.null(isolate(input$Pkmn_Type_1)) == TRUE) & (is.null(isolate(input$Pkmn_Type_2)) == TRUE))
{}
else if ((is.null(isolate(input$Pkmn_Type_1)) == TRUE) & ((is.null(isolate(input$Pkmn_Type_2)) == FALSE) || ("All" %in% input$Pkmn_Type_2 == FALSE)))
{pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Type 2` %in% input$Pkmn_Type_2,]}
## Null Handle Type 2 First
else if ((isolate(input$Pkmn_Type_1)) %in% (isolate(input$Pkmn_Type_2)) &
("All" %in% input$Pkmn_Type_1 == FALSE) & (is.null(isolate(input$Pkmn_Type_1)) == FALSE))
{pokemon2.1_s <- rbind(pokemon2.1[pokemon2.1$`Type 1` %in% input$Pkmn_Type_1,],
pokemon2.1[pokemon2.1$`Type 2` %in% input$Pkmn_Type_2,])}
else {
if ((is.null(isolate(input$Pkmn_Type_1)) == TRUE) || ("All" %in% input$Pkmn_Type_1 == TRUE))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Type 1` %in% input$Pkmn_Type_1,]}
if ((is.null(isolate(input$Pkmn_Type_2)) == TRUE) || ("All" %in% input$Pkmn_Type_2 == TRUE))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Type 2` %in% input$Pkmn_Type_2,]}
}
if ((is.null(isolate(input$Gen)) == TRUE) || (input$Gen[1] == 1 && input$Gen[2] == 8))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$Gen >= input$Gen[1],]
pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$Gen <= input$Gen[2],]}
if (is.null(isolate(input$Legend)) == TRUE)
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Legendary?` %in% input$Legend,]}
if ((is.null(isolate(input$base_total)) == TRUE) || (input$base_total[1] == 0 & input$base_total[2] == 1125))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Base Stat Total` >= input$base_total[1],]
pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Base Stat Total` <= input$base_total[2],]}
# Secondary Bar
if ((is.null(isolate(input$atk)) == TRUE) || (input$atk[1] == 0 & input$atk[2] == 250))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Attack` >= input$atk[1],]
pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Attack` <= input$atk[2],]}
if ((is.null(isolate(input$def)) == TRUE) || (input$def[1] == 0 & input$def[2] == 250))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Defense` >= input$def[1],]
pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Defense` <= input$def[2],]}
if ((is.null(isolate(input$sp_atk)) == TRUE) || (input$sp_atk[1] == 0 & input$sp_atk[2] == 250))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Special Attack` >= input$sp_atk[1],]
pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Special Attack` <= input$sp_atk[2],]}
if ((is.null(isolate(input$sp_def)) == TRUE) || (input$sp_def[1] == 0 & input$sp_def[2] == 250))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Special Defense` >= input$sp_def[1],]
pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Special Defense` <= input$sp_def[2],]}
if ((is.null(isolate(input$spd)) == TRUE) || (input$spd[1] == 0 & input$spd[2] == 250))
{}
else {pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Speed` >= input$spd[1],]
pokemon2.1_s <- pokemon2.1_s[pokemon2.1_s$`Speed` <= input$spd[2],]}
# Table Options
if ((is.null(isolate(input$tbl_ops)) == TRUE))
{pokemon2.1_s <- subset(pokemon2.1_s, select = -c(`Catch Rate`, `Base Friendship`,
`Base XP`, `Egg Group 1`, `Egg Group 2`, `Percent Male`))}
else if (isolate(input$tbl_ops) %in% "All" == TRUE)
{}
else {pokemon2.1_s <- subset(pokemon2.1_s, select = -(c(`Catch Rate`, `Base Friendship`,
`Base XP`, `Egg Group 1`, `Egg Group 2`, `Percent Male`)[!(c("Catch Rate", "Base Friendship", "Base XP", "Egg Group 1", "Egg Group 2", "Percent Male") %in% input$tbl_ops)]))}
#pokemon2.1_s <- slice_min(pokemon2.1_s, n = 50, order_by = pokemon2.1_s$`Dex Number`, with_ties = F) #Not needed as the datatable does a good job collapsing
pokemon2.1_s})
# Image Generation
output$pkmn_img1 <- renderUI(
if (is.null(input$found_pkmn_rows_selected) == TRUE)
{}
else
{tags$img(src = paste("https://www.serebii.net/pokemon/art/",{str_pad(update_pkmn()$`Dex Number`[input$found_pkmn_rows_selected], 3, pad = "0")},".png", sep = ""))})
# Second Tab
pokemon_list_r <- reactiveValues(x = pokemon_list)
proxy <- DT::dataTableProxy("pkmn_list")
observe(DT::replaceData(proxy, pokemon_list_r$x))
# Download List Table
# output$testing <- renderText({paste(dplyr::bind_rows(pokemon_list_r$x))})
output$dwn_list <- downloadHandler(
filename = function() {
paste("my pokemon", ".csv", sep = "")},
content = function(file) {
write.csv({dplyr::bind_rows(pokemon_list_r$x)}, file, row.names = TRUE)}
)
# Adding to New Table
observeEvent(input$add_pkmn, {
if (is.null(input$found_pkmn_rows_selected) == TRUE)
{}
else
{pokemon_list_r$x <- pokemon_list_r$x %>%
bind_rows(
{pokemon2.2[(update_pkmn()$index[input$found_pkmn_rows_selected]+1),]})}
}
)
observeEvent(input$del_pkmn, {
if (is.null(input$pkmn_list_rows_selected) == TRUE)
{}
else
{pokemon_list_r$x <- pokemon_list_r$x[-c(input$pkmn_list_rows_selected),]}
}
)
# Table Output
output$pkmn_list <- DT::renderDataTable(pokemon_list, options = list(autoWidth = TRUE, scrollX = TRUE, columnDefs = list(list(visible=FALSE, targets=c(0,1, 4:5, 8:9, 14, 25:51)))),
selection = "single"
)
# Image Generation
output$pkmn_img2 <- renderUI(
if (is.null(input$pkmn_list_rows_selected) == TRUE)
{}
else
{tags$img(src = paste("https://www.serebii.net/pokemon/art/",{str_pad(pokemon_list_r$x[input$pkmn_list_rows_selected,2], 3, pad = "0")},".png", sep = ""))})
# Type Advantages
# output$testing <- renderText({paste((0.5 %in% pokemon_list_r$x[,50] == TRUE) || (0.25 %in% pokemon_list_r$x[,50] == TRUE) || (0 %in% pokemon_list_r$x[,50] == TRUE))})
output$strong_against <- renderText({
types(1)
})
output$weak_against <- renderText({
types(0)
})
types <- function(type_p){
type_dis <- c()
type_adv <- c()
if ((1 %in% pokemon_list_r$x[,51] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,51] == TRUE) || (0.25 %in% pokemon_list_r$x[,51] == TRUE) || (0 %in% pokemon_list_r$x[,51] == TRUE)) {type_adv <- c(type_adv, "Fairy") }
else {type_dis <- c(type_dis, "Fairy") }
if ((1 %in% pokemon_list_r$x[,50] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,50] == TRUE) || (0.25 %in% pokemon_list_r$x[,50] == TRUE) || (0 %in% pokemon_list_r$x[,50] == TRUE)) {type_adv <- c(type_adv, "Steel") }
else {type_dis <- c(type_dis, "Steel") }
if ((1 %in% pokemon_list_r$x[,49] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,49] == TRUE) || (0.25 %in% pokemon_list_r$x[,49] == TRUE) || (0 %in% pokemon_list_r$x[,49] == TRUE)) {type_adv <- c(type_adv, "Dark") }
else {type_dis <- c(type_dis, "Dark") }
if ((1 %in% pokemon_list_r$x[,48] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,48] == TRUE) || (0.25 %in% pokemon_list_r$x[,48] == TRUE) || (0 %in% pokemon_list_r$x[,48] == TRUE)) {type_adv <- c(type_adv, "Dragon") }
else {type_dis <- c(type_dis, "Dragon") }
if ((1 %in% pokemon_list_r$x[,47] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,47] == TRUE) || (0.25 %in% pokemon_list_r$x[,47] == TRUE) || (0 %in% pokemon_list_r$x[,47] == TRUE)) {type_adv <- c(type_adv, "Ghost") }
else {type_dis <- c(type_dis, "Ghost") }
if ((1 %in% pokemon_list_r$x[,46] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,46] == TRUE) || (0.25 %in% pokemon_list_r$x[,46] == TRUE) || (0 %in% pokemon_list_r$x[,46] == TRUE)) {type_adv <- c(type_adv, "Rock") }
else {type_dis <- c(type_dis, "Rock") }
if ((1 %in% pokemon_list_r$x[,45] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,45] == TRUE) || (0.25 %in% pokemon_list_r$x[,45] == TRUE) || (0 %in% pokemon_list_r$x[,45] == TRUE)) {type_adv <- c(type_adv, "Bug") }
else {type_dis <- c(type_dis, "Bug") }
if ((1 %in% pokemon_list_r$x[,44] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,44] == TRUE) || (0.25 %in% pokemon_list_r$x[,44] == TRUE) || (0 %in% pokemon_list_r$x[,44] == TRUE)) {type_adv <- c(type_adv, "Psychic") }
else {type_dis <- c(type_dis, "Psychic") }
if ((1 %in% pokemon_list_r$x[,43] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,43] == TRUE) || (0.25 %in% pokemon_list_r$x[,43] == TRUE) || (0 %in% pokemon_list_r$x[,43] == TRUE)) {type_adv <- c(type_adv, "Flying") }
else {type_dis <- c(type_dis, "Flying") }
if ((1 %in% pokemon_list_r$x[,42] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,42] == TRUE) || (0.25 %in% pokemon_list_r$x[,42] == TRUE) || (0 %in% pokemon_list_r$x[,42] == TRUE)) {type_adv <- c(type_adv, "Ground") }
else {type_dis <- c(type_dis, "Ground") }
if ((1 %in% pokemon_list_r$x[,41] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,41] == TRUE) || (0.25 %in% pokemon_list_r$x[,41] == TRUE) || (0 %in% pokemon_list_r$x[,41] == TRUE)) {type_adv <- c(type_adv, "Poison") }
else {type_dis <- c(type_dis, "Poison") }
if ((1 %in% pokemon_list_r$x[,40] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,40] == TRUE) || (0.25 %in% pokemon_list_r$x[,40] == TRUE) || (0 %in% pokemon_list_r$x[,40] == TRUE)) {type_adv <- c(type_adv, "Fighting") }
else {type_dis <- c(type_dis, "Fighting") }
if ((1 %in% pokemon_list_r$x[,39] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,39] == TRUE) || (0.25 %in% pokemon_list_r$x[,39] == TRUE) || (0 %in% pokemon_list_r$x[,39] == TRUE)) {type_adv <- c(type_adv, "Ice") }
else {type_dis <- c(type_dis, "Ice") }
if ((1 %in% pokemon_list_r$x[,38] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,38] == TRUE) || (0.25 %in% pokemon_list_r$x[,38] == TRUE) || (0 %in% pokemon_list_r$x[,38] == TRUE)) {type_adv <- c(type_adv, "Grass") }
else {type_dis <- c(type_dis, "Grass") }
if ((1 %in% pokemon_list_r$x[,37] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,37] == TRUE) || (0.25 %in% pokemon_list_r$x[,37] == TRUE) || (0 %in% pokemon_list_r$x[,37] == TRUE)) {type_adv <- c(type_adv, "Electric") }
else {type_dis <- c(type_dis, "Electric") }
if ((1 %in% pokemon_list_r$x[,36] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,36] == TRUE) || (0.25 %in% pokemon_list_r$x[,36] == TRUE) || (0 %in% pokemon_list_r$x[,36] == TRUE)) {type_adv <- c(type_adv, "Water") }
else {type_dis <- c(type_dis, "Water") }
if ((1 %in% pokemon_list_r$x[,35] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,35] == TRUE) || (0.25 %in% pokemon_list_r$x[,35] == TRUE) || (0 %in% pokemon_list_r$x[,35] == TRUE)) {type_adv <- c(type_adv, "Fire") }
else {type_dis <- c(type_dis, "Fire") }
if ((1 %in% pokemon_list_r$x[,34] == TRUE)) {}
else if ((0.5 %in% pokemon_list_r$x[,34] == TRUE) || (0.25 %in% pokemon_list_r$x[,34] == TRUE) || (0 %in% pokemon_list_r$x[,34] == TRUE)) {type_adv <- c(type_adv, "Normal") }
else {type_dis <- c(type_dis, "Normal") }
if (type_p == 1) {paste(type_adv, collapse=", ")}
else {paste(type_dis, collapse=", ")}
}
}
shinyApp(ui = pkm_ui_adv2, server = pkm_server_adv2)