Act fast, special offers end soon! Up to $294 is savings when you get Premium today.
Get offer codes

Moving on Up: Upscaling your Analysis of Netflix Data with a Dashboard


Alright, we’re back. Here’s, a quick recap of what has happened.

In one of my past articles, I went over the importance of building out your portfolio with your own unguided projects and making it as painless as possible and figured it’s better to “walk the walk” instead of just talking about it. So, this meant creating three separate data projects of progressing complexity out of a single Netflix data set. The first of these projects was a simple cleaning and exploration project that laid out the foundation for each following project, including this one.

image


Based on this figure, that project constituted a “Tier-1 Foundational project”. Meaning that it’s fairly bare-bones in nature, albeit a very vital process for any data science project. While this project was completed using R, I realized that the majority on this platform are card-carrying members of Team Python. Since my skills with that language aren’t quite there yet, I used one of my advice and reached out to one of our community members to help out with showing that process. Thanks, @Rucha.

Obviously, the next step from there is to advance to the next level, a “Tier-2” project. But what constitutes one? Well, a tier-2 project is really anything that sits in a zone of being something of an upgrade from the “Tier-1” project but shouldn’t take longer than a week to complete (assuming you’re putting in more than 2 hours/day) outside of the initial cleaning process. Typically, this could take on the form of:

  1. A very detailed exploration of the data that may include some more specific comparative analyses

  2. Some kind of improvement to the data visualization

In this case, we’ll do option 1 by building out a simple interactive dashboard to show off the data.

Full disclosure: I’ve been dipping my toes into Python lately and I’ll admit it’s growing on me. Not totally loving it as much as R, but it’s getting there with a few things. However, one of the few things that R still has an edge over Python is in the area of dashboarding with dynamic features with the Shiny package compared to Dash.


THE OBJECTIVE

While we can go pretty in-depth with this dashboard, we’ll just stick with breaking down the data as it pertains to the cast. Specifically, let’s look at making a dynamic visualization to show the following:

  1. Differences between content with a credited and uncredited cast as it relates to the genre, content rating, and content type.

  2. Amongst those with a credited cast, the actors/actresses with the most credits as the lead and/or supporting role across genre and/or language (i.e., English-speaking or non-English speaking).


THE PROCESS

Whenever you are creating a dashboard for the first time, the first thing that you should do is create a quick sketch of how you would like it to look. Although this may change in some regard at the end of it, it does serve the purpose of providing a rough guide throughout the process. In my case, I would like for it to look like the following:


image

NOTE: Since a lot of the groundwork was done previously with the Tier-1 project, I’ll just move forward to the actual process here. If you are unsure about a particular aspect (i.e., how’d you get that) or a variable, you can refer to my Github page to familiarize yourself with the process.


The most obvious first step for us starting out is to create a blank skeleton.

library(shiny)
ui = fluidPage()  # where you code the front end side of things 
server = function(input, output) {} # Where you code the backend side of tings
shinyApp(ui = ui, server = server) # generates the Shiny Output 

image


The next step would be to include a title and maybe a quick little description or blurb.

ui= fluidPage(

wellPanel(
	tags$h1("All about actors"), 
	tags$div(
           HTML("<body>
                <p style = 'font-size: 120%; text-align: justify'> 
                    Let's be honest, what makes or breaks watching something is all about the cast.  So why not look closer at this by checking out how certain cast-credited content differs from non-cast-credited content.  Also, since we want to have a deeper dive, let's look at what are the most credited actor/actress across genre, language and casting type.
                </p>
             </body>")
         ))
)

image


What is noticeable here is the use of the HTML() function. Since Shiny is essentially a web app, and everything that’s run on the web nowadays uses HTML + CSS, it’s no surprise we can use it here. In fact, if you have any experience with mark-up language, it’ll only augment your ability to utilize this package for the purpose of data visualization.

Moving on, the next part would be to incorporate the input widgets and outputs that compare Netflix content differentiating based on whether there is a credited cast or not. What we’ll need to do is allocate a segment of the page to both these components, which is accomplished using fluidRow() function. Additionally, we’ll also use the RadioButton() widget to serve as the means of switching between plot outputs, which is wrapped around a well panel.

ui= fluidPage(

wellPanel(
	tags$h1("All about actors"), 
	tags$div(
           HTML("<body>
                <p style = 'font-size: 120%; text-align: justify'> 
                    Let's be honest, what makes or breaks watching something is all about the cast.  
	       So why not look closer at this by checking out how certain cast-credited content differs from non-cast-credited content.  
	      Also, since we want to have a deeper dive, let's look at what are the most credited actor/actress across genre, language, and casting type.
                </p>
             </body>")
         )),

fluidRow(
        column(width = 3, 
	       wellPanel(radioButtons(inputId = "cast_charts", 
		  label = "What sort of chart involving cast type are you interested in observing?", 
		 choices = c("Just looking at cast counts" = "default", 
			        "Across content type" = "type", 
			        "Across content rating" = "content",
			        "English content vs. Non-English content" = "english",
			        "Across genres" = 'genre')))), 
        column(width = 8, plotOutput(outputId = "cast_charts"))
      ), 
      tags$br() 	
) # ending fluidPage

image


From here, the next step is to just add the corresponding component on the server-side. This is simply accomplished using a combination of the if/else statements in conjunction with ggplot() to make each individual plot dynamically react to the input widget.

server = function(input, output) {

output$cast_charts = renderPlot({
    
    if (input$cast_charts == "default") {
      
      netflix_cast_split %>% 
        mutate(
          any_cast = ifelse(cast == "Unknown/No Cast", "no", "yes")
        ) %>% 
        group_by(any_cast) %>% 
        summarise(count = n()) %>% 
        ggplot(aes(x = reorder(any_cast, count), y = count, fill = any_cast)) + 
        geom_bar(stat = 'identity', color = 'black') + 
        scale_fill_manual(values = c("yes" = 'firebrick2', 'no' = 'slateblue3')) + 
        theme_classic() + 
        theme(
          axis.line = element_line(color = 'black'),
          axis.text = element_text(color = 'black', size = 15), 
          axis.text.y = element_text(size = 15),
          axis.text.x = element_text(size = 15),
          plot.title = element_text(size = 20, hjust = 0.5),
          axis.title.x = element_text(size = 15),
          axis.title.y = element_text(size = 15), 
          strip.text.x =  element_text(size = 15, color = 'black')
        ) + 
        guides(fill = FALSE) + 
        labs(x = "Presence of a Credited Cast?", y = "Number of Netflix Content", title = "Breakdown of Netflix Content by Presence of Credited Cast") + 
        coord_flip()
    } else if (input$cast_charts == "english") {
      
      netflix_countryxcast_df %>% 
        mutate(
          any_cast = ifelse(cast == "Unknown/No Cast", "no", "yes")
        ) %>% 
        mutate(
          english_or_not = 
            ifelse(c(country_type == "main country" & country_name == "United States"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Canada"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "United Kingdom"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Australia"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "New Zealand"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Ireland"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Jamaica"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Barbados"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Belize"), "English Speaking", 
            ifelse(country_type == "main country", "Non-English Speaking", NA))))))))))
        ) %>%
        filter(country_type == "main country") %>% 
        filter(!is.na(english_or_not)) %>% 
        group_by(any_cast, english_or_not) %>% 
        summarise(count = n()) %>% 
        ggplot(aes(x = reorder(any_cast, count), y = count, fill = any_cast)) + 
        geom_bar(stat = 'identity', color = 'black') + 
        scale_fill_manual(values = c("yes" = 'firebrick2', 'no' = 'slateblue3')) + 
        theme_classic() + 
        labs(x = "Presence of a Credited Cast?", y = "Number of Netflix Content", title = "Breakdown of Netflix Content by Presence of Credited Cast and Language") + 
        theme(
          axis.line = element_line(color = 'black'),
          axis.text = element_text(color = 'black', size = 15), 
          axis.text.y = element_text(size = 15),
          axis.text.x = element_text(size = 15),
          plot.title = element_text(size = 20, hjust = 0.5),
          axis.title.x = element_text(size = 15),
          axis.title.y = element_text(size = 15), 
          strip.text.x =  element_text(size = 15, color = 'black')
        ) + 
        guides(fill = FALSE) + 
        coord_flip() + 
        facet_wrap(vars(english_or_not))
      
    } else if (input$cast_charts == "type") {
      
      netflix_cast_split %>% 
        mutate(
          any_cast = ifelse(cast == "Unknown/No Cast", "no", "yes")
        ) %>%
        group_by(any_cast, type) %>% 
        summarise(count = n()) %>% 
        ggplot(aes(x = reorder(any_cast, count), y = count, fill = any_cast)) + 
        geom_bar(stat = 'identity', color = 'black') + 
        scale_fill_manual(values = c("yes" = 'firebrick2', 'no' = 'slateblue3')) + 
        theme_classic() + 
        labs(x = "Presence of a Credited Cast?", y = "Number of Netflix Content", title = "Breakdown of Netflix Content by Presence of Credited Cast and Content Type") + 
        theme(
          axis.line = element_line(color = 'black'),
          axis.text = element_text(color = 'black', size = 15), 
          axis.text.y = element_text(size = 15),
          axis.text.x = element_text(size = 15),
          plot.title = element_text(size = 25, hjust = 0.5),
          axis.title.x = element_text(size = 15),
          axis.title.y = element_text(size = 15), 
          strip.text.x =  element_text(size = 15, color = 'black')
        ) + 
        guides(fill = FALSE) + 
        coord_flip() + 
        facet_wrap(vars(type))
      
    } else if (input$cast_charts == "genre") {
      
      netflix_genrexcast_df %>% 
        mutate(
          any_cast = ifelse(cast == "Unknown/No Cast", "no", "yes")
        ) %>%
        group_by(any_cast, genre) %>% 
        summarise(count = n()) %>% 
        ggplot(aes(x = reorder(any_cast, count), y = count, fill = any_cast)) + 
        geom_bar(stat = 'identity', color = 'black') + 
        scale_fill_manual(values = c("yes" = 'firebrick2', 'no' = 'slateblue3')) + 
        theme_classic() + 
        labs(x = "Presence of a Credited Cast?", y = "Number of Netflix Content", title = "Breakdown of Netflix Content by Presence of Credited Cast and Genre") + 
        theme(
          axis.line = element_line(color = 'black'),
          axis.text = element_text(color = 'black', size = 15), 
          axis.text.y = element_text(size = 15),
          axis.text.x = element_text(size = 15, angle = 90),
          plot.title = element_text(size = 25, hjust = 0.5),
          axis.title.x = element_text(size = 15),
          axis.title.y = element_text(size = 15), 
          strip.text.x =  element_text(size = 8, color = 'black')
        ) + 
        guides(fill = FALSE) + 
        coord_flip() + 
        facet_wrap(vars(genre))
      
    }  else if (input$cast_charts == "content") {
      
      netflix_cast_split %>% 
        mutate(
          any_cast = ifelse(cast == "Unknown/No Cast", "no", "yes")
        ) %>%
        group_by(any_cast, rating) %>% 
        summarise(count = n()) %>% 
        ggplot(aes(x = reorder(any_cast, count), y = count, fill = any_cast)) + 
        geom_bar(stat = 'identity', color = 'black') + 
        scale_fill_manual(values = c("yes" = 'firebrick2', 'no' = 'slateblue3')) + 
        theme_classic() + 
        labs(x = "Presence of a Credited Cast?", y = "Number of Netflix Content", title = "Breakdown of Netflix Content by Presence of Credited Cast and Content Rating") + 
        theme(
          axis.line = element_line(color = 'black'),
          axis.text = element_text(color = 'black', size = 15), 
          axis.text.y = element_text(size = 15),
          axis.text.x = element_text(size = 15),
          plot.title = element_text(size = 20, hjust = 0.5),
          axis.title.x = element_text(size = 15),
          axis.title.y = element_text(size = 15), 
          strip.text.x =  element_text(size = 15, color = 'black')
        ) + 
        guides(fill = FALSE) + 
        coord_flip() + 
        facet_wrap(vars(rating))
      
    }
    
  })
}

image


What’s likely notable here is that when creating each of these individual plots, I’ve used different datasets that had been separated out based on certain variables. This is the reason why we had to create those several individualized data frames earlier on.

The following part would be to add the input widgets for determining who are the top credited actors/actresses (either headlining, supporting, or both) that’s based on genre, content rating, and/or language. As usual, we’ll start with the UI side of things by adding the necessary codes for the input widgets, which will be a combination of RadioButtons() and selectInput().

# On the UI Side
 
      fluidRow(
        column(width = 4, wellPanel(
          selectInput(inputId = "cast_comparisons", label = "Observe the top Actors/Actresses by what?", 
                      choices = c("Genre: TV Action & Adventure" = "TV Action & Adventure",
                                  "Genre: Movie Action & Adventure" = "Action & Adventure",
                                  "Genre: TV Drama" = "TV Dramas",
                                  "Genre: Movie Drama" = "Dramas",
                                  "Genre: TV Comedy" = "TV Comedies",
                                  "Genre: Movie Comedy" = "Comedies",
                                  "Genre: TV Horror" = "TV Horror",
                                  "Genre: Movie Horror" = "Horror Movies",
                                  "Genre: Stand-Up/Skits/Talk Shows" = "Stand-Up Comedy & Talk Shows",
                                  "Genre: Stand-Up Specials" = "Stand-Up Comedy",
                                  "Genre: Music & Musicals" = "Music & Musicals",
                                  "Genre: Sports" = "Sports Movies", 
                                  "Genre: LGBTQ" = "LGBTQ Movies",
                                  "Genre: Independent Movies" = "Independent Movies",
                                  "Genre: Classic & Cult TV" = "Classic & Cult TV",
                                  "Genre: Cult Movies" = "Cult Movies",
                                  "Genre: Classic Movies" = "Classic Movies",
                                  "Genre: Korean TV" = "Korean TV Shows",
                                  "Genre: British TV" = "British TV Shows",
                                  "Genre: Spanish TV" = "Spanish-Language TV Shows",
                                  "Genre: Children & Family Movies" = "Children & Family Movies",
                                  "Genre: Kids' TV" = "Kids' TV",
                                  "Genre: Teen TV" = "Teen TV Shows",
                                  "Genre: TV Thriller" = "TV Thrillers",
                                  "Genre: Movie Thriller" = "Thrillers",
                                  "Genre: Reality TV" = "Reality TV", 
                                  "Genre: International Movie" = "International Movies",
                                  "Genre: International TV" = "International TV Shows",
                                  "Genre: TV SciFi & Fantasy" = "TV Sci-Fi & Fantasy", 
                                  "Genre: Movie SciFi & Fantasy" = "Sci-Fi & Fantasy", 
                                  "Genre: Science & Nature TV" = "Science & Nature TV", 
                                  "Genre: TV Romance" = "Romantic TV Shows",
                                  "Genre: Movie Romance" = "Romantic Movies",
                                  "Genre: Anime Features" = "Anime Features",
                                  "Genre: Anime Series" = "Anime Series",
                                  "Genre: Crime TV" = "Crime TV Shows",
                                  "Genre: Mystery TV" = "TV Mysteries", 
                                  "Genre: Documentaries" = "Documentaries",
                                  "Genre: Docuseries" = "Docuseries",
                                  "Genre: Faith & Spirituality" = "Faith & Spirituality")),
          radioButtons(inputId = "cast_language", label = "Are you interested in English-Only Actors/Actresses?", 
                       choices = c("Yes, just English" = "English Speaking",
                                   "No, only Non-English" = "Non-English Speaking",
                                   "Both" = "both")), 
          radioButtons(inputId = "cast_type", label = "What cast billing are you interested in?", 
                       choices = c("Headliners Only" = "headliner",
                                   "Supporting Only" = "supporting cast",
                                   "Both" = "both")))), 
        column(width = 4, plotOutput(outputId = "top_cast")), 
        column(width = 4, uiOutput(outputId = "cast_image")))


image


As for the server-side of things, it’ll start with creating a reactive element that enables the switch between desired variables. This is possible with the switch() function that evaluates an expression based on its value and return from any existing list the corresponding element. In our case, it would return any element within the genre with the corresponding element from the dataset.

# on the server-side

cast_n_director_genre_2 = reactive({switch(input$cast_comparisons, as.character(input$cast_comparisons))})

From here, the if/else statements are used to indicate which sort of plot output would result based on the widget inputs. In our case, since the genre will serve as a means of filtering out a given data set, the language, and cast type input would serve in determining which of the many different separated data set to be used. Since each has three possible options, this means we have 8 possible options.

Below just shows how the code was written for one of the 8 different possible options since this can be a bit much. If you would like to see it in its entirety, you can check out the code here.

output$top_cast = renderPlot({
    
    if(input$cast_language == "both" & input$cast_type == "headliner")  {
      
      netflix_genrexcountryxcast_df %>% 
        filter(cast != "Unknown/No Cast") %>% 
        filter(cast_type == "headliner") %>% 
        filter(genre == as.character(cast_n_director_genre_2())) %>% 
        group_by(cast) %>% 
        summarise(count = n()) %>% 
        arrange(desc(count)) %>%
        filter(count > 1) %>% 
        top_n(5) %>% 
        ggplot(aes(x = reorder(cast, count), y = count, fill = cast)) + 
        geom_bar(stat = 'identity', color = 'black') + 
        guides(fill = F) +
        theme_classic() +
        theme(
          axis.text = element_text(color = 'black'),
          plot.caption = element_text(color = 'black', hjust = 0)
        ) + 
        coord_flip() +
        labs(x = "Top Headlining  Actors/Actresses", y = "Number of Netflix Content", caption = "* Only actors with at least 2 credited roles on Netflix")
      
    } else if (input$cast_language == "English Speaking" & input$cast_type == "headliner") {
      
      netflix_genrexcountryxcast_df %>% 
        filter(cast != "Unknown/No Cast") %>%
        filter(cast_type == "headliner") %>% 
        filter(genre == as.character(cast_n_director_genre_2())) %>%
        mutate(
          english_or_not = 
            ifelse(c(country_type == "main country" & country_name == "United States"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Canada"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "United Kingdom"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Australia"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "New Zealand"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Ireland"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Jamaica"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Barbados"), "English Speaking",
            ifelse(c(country_type == "main country" & country_name == "Belize"), "English Speaking", 
            ifelse(country_type == "main country", "Non-English Speaking", NA))))))))))
        ) %>% 
        filter(country_type == "main country") %>%
        filter(english_or_not == "English Speaking") %>% 
        group_by(cast) %>% 
        summarise(count = n()) %>% 
        arrange(desc(count)) %>%
        filter(count > 1) %>%
        top_n(5) %>% 
        ggplot(aes(x = reorder(cast, count), y = count, fill = cast)) + 
        geom_bar(stat = 'identity', color = 'black') + 
        guides(fill = F) +
        theme_classic() +
        theme(
          axis.text = element_text(color = 'black'),
          plot.caption = element_text(color = 'black', hjust = 0)
        ) + 
        coord_flip() +
        labs(x = "Top Headlining  Actors/Actresses", y = "Number of English-Speaking Netflix Content", caption = "* Only actors with at least 2 credited roles on Netflix")
      
	# Repeat the process for the 6 other possibilities

    }
    
  })


Whew, we’ve got a lot done with this dashboard and it looks pretty close to that rough draft that I’ve outlined earlier. The only thing left to do is input the appropriate image showcasing the top actor/actress as respective to the widget inputs.

Now, normally, this wouldn’t be a problem since the process behind it is really just a matter of using the appropriate tag function (this case tags$img()) and if/else statement that match to the given inputs as shown in a previous DQ article. However, if you’ve been following along, you’ll notice one problem: this data set doesn’t have such data. All it has is the listed cast member.

Oh no, we’ve reached a major dilemma in this project. What can we do here?


image


Alright, after a deep breath, let’s take a quick inventory of what we have and what we want:

WHAT WE HAVE WHAT WE WANT
A data set with a list of every credited cast member where the first listed cast = headliner and the rest are supporting, all of which are correctly listed with other variables (cast type). VS To showcase the top credited headlining/supporting cast across each genre type differentiated by language and/or cast type with a visual

Now there are a few possible solutions to this:


image


  1. Drop the picture aspect completely as it would be too much effort (the easiest option particularly if time is of the essence)

  2. Create another column that includes a link for each actor/actress. While it would result in a picture, this will be the most meathead/intensive process as there may be 100s, if not 1000s to search for where a picture may not even be available on the internet. Since I’m not getting paid for any of this, this is likely not worth the effort.

  3. Split the difference here and just figure out which are the top listed actors/actresses for each given input option. With 8 datasets used and about 39 possible genres, we will have at most 312 possible individual options.

As tempting it is to go with option 1, we’ll go with option 3 since there are a few things that it has going for it to be a more viable route aside from my desire to have a pictorial element in the dashboard. For one, compared to the pain that would come out of option 2, having about a few hundred searches is a much better route to take compared to a few thousand searches, plus I had the time. Also, while it’s true there are a possible 312 unique results, the majority of the outcomes will likely be the same actor/actress for multiple genres. Lastly, by individually going through each outcome, you can get actually go into a deep dive into the data to see if the actual outcomes make sense or not given your base level of knowledge about the TV & Film industry to suss out unusual findings.

So, after playing around with the various different inputs, you’ll recognize that there is a fair number of ties as well as recurring actors/actresses that are listed as the top-credited headliner/supporting member based on a number of Netflix credits. In this case, there are 79 unique answers. While it’s a lot, but way more manageable even when compared to some of the steps used during the data wrangling process.


NOTE: I’m not going to be showing the entire process here as it is quite long. However, I will run down the individual components used to make this run on the server-side with the use of some placeholder variables. For the entire process, see here.


Output$cast_image = renderUI({

# Step 1: put the link for each of the unique actors/actresses that were found to have the highest credits for a given input into a variable

url_tie = “some_url_for_tie_image”
url_for_actor_2 = “actor_2_url”
url_for_actor_3 = “actor_3_url”
url_for_actor_4 = “actor_4_url”
url_for_actor_5 = “actor_5_url”
url_for_actor_22 = “actor_22_url”
url_for_actor_33 = “actor_33_url”
url_for_actor_44 = “actor_44_url”
url_for_actor_55 = “actor_55_url”
url_for_actor_12 = “actor_12_url”
url_for_actor_13 = “actor_13_url”
url_for_actor_14 = “actor_14_url”
url_for_actor_1 = “actor_1_url”


# Step 2: using a series of if/else functions, you will make a variable that provides one of the url_variables above as a potential output THAT DOESN’T RESULT IN A TWO-PERSON TIE (will show what to do with these later). 

# There will be eight of these variables, each corresponding to one of the eight possible combinations b/t language input and cast type input 

english_headliner_img = 
       ifelse(c(input$cast_language == "English Speaking" & input$cast_type == "headliner" & (input$cast_comparisons == "Action & Adventure" | input$cast_comparisons == "Thrillers" | input$cast_comparisons == "Sci-Fi & Fantasy")), url_for_actor_1,
       ifelse(c(input$cast_language == "English Speaking" & input$cast_type == "headliner" & (input$cast_comparisons == "International Movies" | input$cast_comparisons == "Documentaries" | 
input$cast_compaisons == "Docuseries")), url_for_actor_22,
      ifelse(c(input$cast_language == "English Speaking" & input$cast_type == "headliner" & input$cast_comparisons == "TV Mysteries"), url_for_actor_33, url_tie)))

# repeat for English & supporting, English & both, non-English & supporting, non-English & headliner, non-English & both, both & headliner, both & supporting and overall 

# Step 3: using a series of if and else if statements that are used to address any sort of two-way tie where I will result in a “tag” specific output.  This would be followed with the findings that specifically resulted in a tie involving at least 3 actors/actresses and lastly followed-up with the unique singular outputs as done in step 2

if (input$cast_language == "both" & input$cast_type == "both" & input$cast_comparisons == "TV Action & Adventure") {
      
      tags$div(
        HTML("<div class = 'row'>
                  <img src = 'actor_4_url' width='250' height='400'>
                  
                  <img src = ‘actor_33_url' width='250' height='400'>
    	     </div>")
        )
      
    } else if (input$cast_language == "both" & input$cast_type == "both" & input$cast_comparisons == "TV Comedies") {
      
      tags$div(
        HTML("<div class = 'row'>
                  <img src = actor_22_url' width='250' height='400'>
                  
                  <img src = 'actor_33_url’ width='250' height='400'>
    	     </div>"))
      
    } else if (input$cast_language == "both" & input$cast_type == "both" & input$cast_comparisons == "Stand-Up Comedy") {
      
      tags$div(
        HTML("<div class = 'row'>
                  <img src = 'actor_11_url' width='250' height='400'>
                  
                  <img src = 'actor_44_url' width='250' height='400'>
    	     </div>"))
      
    } else if (input$cast_language == "both" & input$cast_type == "both" & (input$cast_comparisons == "TV Horror" | 
                                                                            input$cast_comparisons == "Music & Musicals" | 
                                                                            input$cast_comparisons == "LGBTQ Movies" | 
                                                                            input$cast_comparisons == "Classic & Cult TV" | 
                                                                            input$cast_comparisons == "Cult Movies" | 
                                                                            input$cast_comparisons == "Korean TV Shows" | 
                                                                            input$cast_comparisons == "Spanish-Language TV Shows" | 
                                                                            input$cast_comparisons == "Teen TV Show" | 
                                                                            input$cast_comparisons == "TV Thrillers" | 
                                                                            input$cast_comparisons == "Reality TV" | 
                                                                            input$cast_comparisons == "TV Sci-Fi & Fantasy" | 
                                                                            input$cast_comparisons == "Sci-Fi & Fantasy" | 
                                                                            input$cast_comparisons == "Crime TV Shows" | 
                                                                            input$cast_comparisons == "TV Mysteries" | 
                                                                            input$cast_comparisons == "Faith & Spirituality")) {
      
      tags$img(src = url_tie , width = '800', height = '400')
} else if (input$cast_language == "English Speaking" & input$cast_type == "headliner") {
      
      tags$img(src = english_headliner_img, width = "275", height = '400')

})

The end product would look something like this:


And boom! We have ourselves a nice little Tier-2 project.

While relatively simplistic in terms of the type of functions used, it is undoubtedly an upgrade from the more static form of data reporting with the use of reactive elements. Additionally, we were also able to overcome one major roadblock in a rather slick way in order to achieve our desired outcome. Obviously, we can go a step further with improving upon the visual of this dashboard in terms of font styling and size, but you’ll need some additional knowledge in the area of HTML and CSS to do so, which really is in the area of a UI/UX designer or a front-end developer but not necessarily a data analyst or scientist. Although might be worth it to stand out with your portfolio.

Having shown a Tier-1 and Tier-2 down, the next project will be that almighty Tier-3 project. A fitting grand finale of sorts. What exactly that I’ll be doing for it will be a surprise, so be on the lookout in the coming weeks as we cap off this little series along with some of the other articles from some of the other community members helping me out with showing off these projects on the Python side.

If you’re interested in check out some of my other projects, you can head over to my GitHub to check some of them out. Alternatively, if you’re got some idea on a collaborative project or just want to connect, hit me up on my LinkedIn.

Thanks for the read.

1 Like