Bob Ross Color

Author

Walter Hinkley

Autumn Glory

Autumn Glory

A fans interpretation of “The Joy of Painting” episode: Autumn glory

1

Did Bob Ross change the themes of his paintings throughout his 31 seasons

For this happy little adventure I chose the Bob Ross Paintings data set from https://www.twoinchbrush.com and https://github.com/frankiethull/BobRossColors. The data set involves a list of every painting that Bob Ross painted in his 31 seasons of The Joy of Painting television program. Types of data include column variables of Painting titles, Colors used, episode #, season #, video source, number of colors. When I was younger I often watched his show and enjoyed the calmness of his personality but also how simple his paintings appeared. Through this data set I want to determine if during his time on the show, did Bob Ross change his themes. Did he have a favorite theme? I would need to split the titles into separate words to get a feel for the themes of each painting. Then take the top 7 themes and plot them over his 31 seasons to see if there are patterns of favorites.

setwd("~/Desktop/Data Science 110")
#devtools::install_github("frankiethull/BobRossColors")
#install.packages("BobRossColors")
#install.packages("tm")
#install.packages("wordcloud")
#install.packages("wordcloud2")
#install.packages("stringr")
library(stringr)
library(tm)
Loading required package: NLP
library(wordcloud)
Loading required package: RColorBrewer
library(wordcloud2)
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ purrr     1.0.2
✔ forcats   1.0.0     ✔ readr     2.1.5
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ ggplot2::annotate() masks NLP::annotate()
✖ dplyr::filter()     masks stats::filter()
✖ dplyr::lag()        masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
library(ggpubr)
library(jpeg)
library(RColorBrewer)
library(BobRossColors)
library(tidytext)
library(dplyr)
library(highcharter)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
library(plotly)

Attaching package: 'plotly'

The following object is masked from 'package:ggplot2':

    last_plot

The following object is masked from 'package:stats':

    filter

The following object is masked from 'package:graphics':

    layout
library(scales)

Attaching package: 'scales'

The following object is masked from 'package:purrr':

    discard

The following object is masked from 'package:readr':

    col_factor
library(grid)
bob <- read_csv("bob_ross_paintings.csv")
New names:
Rows: 403 Columns: 29
── Column specification
──────────────────────────────────────────────────────── Delimiter: "," chr
(6): img_src, painting_title, youtube_src, colors, color_hex, tags dbl (23):
...1, painting_index, season, episode, num_colors, Black_Gesso, Br...
ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
Specify the column types or set `show_col_types = FALSE` to quiet this message.
• `` -> `...1`
head(bob)
# A tibble: 6 × 29
   ...1 painting_index img_src          painting_title season episode num_colors
  <dbl>          <dbl> <chr>            <chr>           <dbl>   <dbl>      <dbl>
1     1            282 https://www.two… A Walk in the…      1       1          8
2     2            283 https://www.two… Mt. McKinley        1       2          8
3     3            284 https://www.two… Ebony Sunset        1       3          9
4     4            285 https://www.two… Winter Mist         1       4          3
5     5            286 https://www.two… Quiet Stream        1       5          8
6     6            287 https://www.two… Winter Moon         1       6          4
# ℹ 22 more variables: youtube_src <chr>, colors <chr>, color_hex <chr>,
#   tags <chr>, Black_Gesso <dbl>, Bright_Red <dbl>, Burnt_Umber <dbl>,
#   Cadmium_Yellow <dbl>, Dark_Sienna <dbl>, Indian_Red <dbl>,
#   Indian_Yellow <dbl>, Liquid_Black <dbl>, Liquid_Clear <dbl>,
#   Midnight_Black <dbl>, Phthalo_Blue <dbl>, Phthalo_Green <dbl>,
#   Prussian_Blue <dbl>, Sap_Green <dbl>, Titanium_White <dbl>,
#   Van_Dyke_Brown <dbl>, Yellow_Ochre <dbl>, Alizarin_Crimson <dbl>

Create a Word Cloud of the Bob Ross Colors

Get the sums of color usage for each episode of “The Joy of Painting”

colSums(bob[,c(12:29)])
     Black_Gesso       Bright_Red      Burnt_Umber   Cadmium_Yellow 
             114              321               55              346 
     Dark_Sienna       Indian_Red    Indian_Yellow     Liquid_Black 
             290                0              293               19 
    Liquid_Clear   Midnight_Black     Phthalo_Blue    Phthalo_Green 
              51              317              323              116 
   Prussian_Blue        Sap_Green   Titanium_White   Van_Dyke_Brown 
             263              306              400              371 
    Yellow_Ochre Alizarin_Crimson 
             327              380 

Obtained library(BobRossColors) from https://github.com/frankiethull/BobRossColors

Show the Color hex of each of Bob Ross 18 Colors

print(unique_bob_ross_colors)
              color color_hex
             <char>    <char>
 1: AlizarinCrimson   #4E1500
 2:       BrightRed   #DB0000
 3:   CadmiumYellow   #FFEC00
 4:    PhthaloGreen   #102E3C
 5:    PrussianBlue   #021E44
 6:        SapGreen   #0A3410
 7:   TitaniumWhite   #FFFFFF
 8:    VanDykeBrown   #221B15
 9:      BlackGesso   #000000
10:      BurntUmber   #8A3324
11:    IndianYellow   #FFB800
12:     PhthaloBlue   #0C0040
13:     YellowOchre   #C79B00
14:     LiquidBlack   #000000
15:   MidnightBlack   #000000
16:     LiquidClear   #FFFFFF
17:      DarkSienna   #5F2E1F
18:       IndianRed   #CD5C5C

2

Show the colors matched to the hex codes

par(bg="transparent")
scales::show_col(unique_bob_ross_colors$color_hex)

Create a Data Frame for the Word Cloud to pull data from

colorlist = c("#000000", "#DB0000", "#8A3324", "#FFEC00", "#5F2E1F", "#FFB800", "#000000", "#FFFFFF", "#000000", "#0C0040", "#102E3C", "#021E44", "#0A3410", "#FFFFFF", "#221B15", "#C79B00", "#4E1500")

an additional color of indian red is in the Bob Ross color palette but was used 0 times according to the data set.

bob_cloud <- structure(list(word = c("Black Gesso", "Bright Red", "Burnt Umber", "Cadmium Yellow", "Dark Sienna", "Indian Yellow", "Liquid Black", "Liquid Clear", "Midnight Black", "Phthalo Blue", "Phthalo Green", "Prussian Blue", "Sap Green", "Titanium White", "Van Dyke Brown", "Yellow Ochre", "Alizarin Crimson"), count = c(114, 321, 55, 346, 290, 293, 19, 51, 317, 323, 116, 263, 306, 400, 371, 327, 380)),  row.names = c("1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17"), class = "data.frame")

3

Create Word Cloud

set.seed(1234)
par(bg="transparent")
wordcloud(words = bob_cloud$word, freq = bob_cloud$count, min.freq = 1,
          max.words = 500, random.order = TRUE, rot.per = .30,
          scale = c(2, 1),
          colors = colorlist,ordered.colors = TRUE)

Second path to a word cloud

par(bg="transparent")
set.seed(1357)
name = c("Black Gesso", "Bright Red", "Burnt Umber", "Cadmium Yellow", "Dark Sienna", "Indian Yellow", "Liquid Black", "Liquid Clear", "Midnight Black", "Phthalo Blue", "Phthalo Green", "Prussian Blue", "Sap Green", "Titanium White", "Van Dyke Brown", "Yellow Ochre", "Alizarin Crimson")
count = c(114, 321, 55, 346, 290, 293, 19, 51, 317, 323, 116, 263, 306, 400, 371, 327, 380)
colorlist = c("#000000", "#DB0000","#8A3324", "#FFEC00", "#5F2E1F", "#FFB800", "#000000", "#FFFFFF", "#000000", "#0C0040", "#102E3C", "#021E44", "#0A3410", "#FFFFFF", "#221B15", "#C79B00", "#4E1500")

wordcloud(name, count, colors=colorlist, ordered.colors=TRUE,
          scale = c(2, 1.3))

Track Bob Ross theme usage over all his 31 tv seasons

Create a table of all the Paintings Titles

tab <- table(bob$painting_title)
head(tab)

   A Cold Spring Day      A Copper Winter  A Mild Winter's Day 
                   1                    1                    1 
A Perfect Winter Day  A Pretty Autumn Day   A Spectacular View 
                   1                    1                    1 

Use grep to find a count for common title words

table(grep("\\winter\\>",bob$painting_title))

  4   6  11  15  30  43  56  79  89  94  98 105 109 124 129 139 156 183 187 214 
  1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1 
229 245 250 256 270 278 287 299 302 310 331 341 343 349 353 360 375 380 382 402 
  1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1 
paste("Winter - ", length(grep("Winter", bob$painting_title)), sep="")
[1] "Winter - 42"
table(grep("\\Mountain\\>",bob$painting_title))

  7  10  20  25  27  52  53  55  82  86  87  88  97  99 102 113 116 117 126 131 
  1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1 
145 146 153 154 155 156 161 164 166 172 174 199 207 221 224 236 248 266 272 289 
  1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1 
300 317 335 363 370 
  1   1   1   1   1 
paste("Mountain - ", length(grep("Mountain", bob$painting_title)), sep="")
[1] "Mountain - 51"

Clean Painting Titles column to find the top 7 words or themes

bob1 <- bob %>%
  dplyr::select(painting_title) %>%
  unnest_tokens(word, painting_title)
bob1 <- bob1 %>%
  anti_join(stop_words)
Joining with `by = join_by(word)`
bob1%>%
  count(word, sort = TRUE) %>%
  top_n(7)
Selecting by n
# A tibble: 7 × 2
  word         n
  <chr>    <int>
1 mountain    45
2 winter      37
3 oval        22
4 autumn      18
5 lake        16
6 cabin       15
7 sunset      13

4

Create visualization of his top themes

img1 <- readJPEG("bob.jpg")
bob1%>%
  count(word, sort = TRUE) %>%
  top_n(7)%>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(x = word, y = n, fill = word)) +
  background_image(img1)+
  geom_col(stat = "identity", width = .4, alpha = .7) +
  scale_fill_bob_ross()+
  xlab(NULL) +
  coord_flip() +
      labs(x = "Painting Title Words",
      y = "Count",
      title = "Common Painting Themes Used",
      caption = "Bob Ross, Inc. (BRI)")
Selecting by n
Warning in geom_col(stat = "identity", width = 0.4, alpha = 0.7): Ignoring
unknown parameters: `stat`

Detirmine if his Theme usage changed over time

Remove all stop words from the painting titles

stop_words <- stopwords("en")
# Function to remove stop words from a text string
remove_stopwords <- function(title) {
  # Split the title into words
  words <- strsplit(title, "\\s+")[[1]]
  
  # Remove stop words
  words <- words[!words %in% stop_words]
  
  # Rejoin the words into a single string
  return(paste(words, collapse = " "))
}

# Apply the function to the painting_title column
bob_ross_paintings$painting_title_clean <- sapply(bob$painting_title, remove_stopwords)

# View the updated data frame
head(bob_ross_paintings)
       X painting_index                                             img_src
   <int>          <int>                                              <char>
1:     1            282 https://www.twoinchbrush.com/images/painting282.png
2:     2            283 https://www.twoinchbrush.com/images/painting283.png
3:     3            284 https://www.twoinchbrush.com/images/painting284.png
4:     4            285 https://www.twoinchbrush.com/images/painting285.png
5:     5            286 https://www.twoinchbrush.com/images/painting286.png
6:     6            287 https://www.twoinchbrush.com/images/painting287.png
        painting_title season episode num_colors
                <char>  <int>   <int>      <int>
1: A Walk in the Woods      1       1          8
2:        Mt. McKinley      1       2          8
3:        Ebony Sunset      1       3          9
4:         Winter Mist      1       4          3
5:        Quiet Stream      1       5          8
6:         Winter Moon      1       6          4
                                 youtube_src
                                      <char>
1: https://www.youtube.com/embed/oh5p5f5_-7A
2: https://www.youtube.com/embed/RInDWhYceLU
3: https://www.youtube.com/embed/UOziR7PoVco
4: https://www.youtube.com/embed/0pwoixRikn4
5: https://www.youtube.com/embed/DFSIQNjKRfk
6: https://www.youtube.com/embed/loAzRUzx1wI
                                                                                                                                                         colors
                                                                                                                                                         <char>
1:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
2:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
3: ['Alizarin Crimson', 'Black Gesso', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
4:                                                                                                        ['Prussian Blue', 'Titanium White', 'Van Dyke Brown']
5:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
6:                                                                                         ['Black Gesso', 'Prussian Blue', 'Titanium White', 'Van Dyke Brown']
                                                                                             color_hex
                                                                                                <char>
1:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
2:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
3: ['#4E1500', '#000000', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
4:                                                                   ['#021E44', '#FFFFFF', '#221B15']
5:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
6:                                                        ['#000000', '#021E44', '#FFFFFF', '#221B15']
   Black_Gesso Bright_Red Burnt_Umber Cadmium_Yellow Dark_Sienna Indian_Red
         <int>      <int>       <int>          <int>       <int>      <int>
1:           0          1           0              1           0          0
2:           0          1           0              1           0          0
3:           1          1           0              1           0          0
4:           0          0           0              0           0          0
5:           0          1           0              1           0          0
6:           1          0           0              0           0          0
   Indian_Yellow Liquid_Black Liquid_Clear Midnight_Black Phthalo_Blue
           <int>        <int>        <int>          <int>        <int>
1:             0            0            0              0            0
2:             0            0            0              0            0
3:             0            0            0              0            0
4:             0            0            0              0            0
5:             0            0            0              0            0
6:             0            0            0              0            0
   Phthalo_Green Prussian_Blue Sap_Green Titanium_White Van_Dyke_Brown
           <int>         <int>     <int>          <int>          <int>
1:             1             1         1              1              1
2:             1             1         1              1              1
3:             1             1         1              1              1
4:             0             1         0              1              1
5:             1             1         1              1              1
6:             0             1         0              1              1
   Yellow_Ochre Alizarin_Crimson total painting_title_clean
          <int>            <int> <int>               <char>
1:            0                1     8         A Walk Woods
2:            0                1     8         Mt. McKinley
3:            0                1     9         Ebony Sunset
4:            0                0     3          Winter Mist
5:            0                1     8         Quiet Stream
6:            0                0     4          Winter Moon

Split the Painting Titles column in to seperate columns of title words/themes

# Split the words in the 'painting_title_clean' column into a list of words
painting_words_list <- strsplit(bob_ross_paintings$painting_title_clean, "\\s+")

# View the first few entries of the list
head(painting_words_list)
[[1]]
[1] "A"     "Walk"  "Woods"

[[2]]
[1] "Mt."      "McKinley"

[[3]]
[1] "Ebony"  "Sunset"

[[4]]
[1] "Winter" "Mist"  

[[5]]
[1] "Quiet"  "Stream"

[[6]]
[1] "Winter" "Moon"  
# Convert the list of words into a data frame
words_df <- do.call(rbind, lapply(painting_words_list, function(x) {
  # Pad each list to ensure they all have the same length by filling with NAs
  length(x) <- max(sapply(painting_words_list, length))
  return(x)
}))

# Convert to a data frame with proper column names
colnames(words_df) <- paste("Word", seq_along(words_df[1,]), sep="_")

# View the resulting data frame
head(words_df)
     Word_1   Word_2     Word_3  Word_4
[1,] "A"      "Walk"     "Woods" NA    
[2,] "Mt."    "McKinley" NA      NA    
[3,] "Ebony"  "Sunset"   NA      NA    
[4,] "Winter" "Mist"     NA      NA    
[5,] "Quiet"  "Stream"   NA      NA    
[6,] "Winter" "Moon"     NA      NA    

Create a data frame of the new split columns

# If words_df is a matrix, convert it to a data frame
words_df <- as.data.frame(words_df)

# Optionally, give the columns in words_df meaningful names, if they don't have them already
# Example: if your words_df represents the words as columns, you can name them like this:
colnames(words_df) <- paste0("word", 1:ncol(words_df))

# Check the first few rows to make sure it's correctly formatted
head(words_df)
   word1    word2 word3 word4
1      A     Walk Woods  <NA>
2    Mt. McKinley  <NA>  <NA>
3  Ebony   Sunset  <NA>  <NA>
4 Winter     Mist  <NA>  <NA>
5  Quiet   Stream  <NA>  <NA>
6 Winter     Moon  <NA>  <NA>

Merge the bob data set with the new themes data frame

# Check that both data frames have the same number of rows
if (nrow(bob_ross_paintings) == nrow(words_df)) {
  # Combine by columns (assuming they align row-wise)
  combined_data <- cbind(bob_ross_paintings, words_df)
  
  # View the first few rows of the combined data
  head(combined_data)
} else {
  # If the number of rows doesn't match, you'll need a different approach (e.g., merge by key)
  print("Number of rows in bob_ross_paintings and words_df do not match!")
}
       X painting_index                                             img_src
   <int>          <int>                                              <char>
1:     1            282 https://www.twoinchbrush.com/images/painting282.png
2:     2            283 https://www.twoinchbrush.com/images/painting283.png
3:     3            284 https://www.twoinchbrush.com/images/painting284.png
4:     4            285 https://www.twoinchbrush.com/images/painting285.png
5:     5            286 https://www.twoinchbrush.com/images/painting286.png
6:     6            287 https://www.twoinchbrush.com/images/painting287.png
        painting_title season episode num_colors
                <char>  <int>   <int>      <int>
1: A Walk in the Woods      1       1          8
2:        Mt. McKinley      1       2          8
3:        Ebony Sunset      1       3          9
4:         Winter Mist      1       4          3
5:        Quiet Stream      1       5          8
6:         Winter Moon      1       6          4
                                 youtube_src
                                      <char>
1: https://www.youtube.com/embed/oh5p5f5_-7A
2: https://www.youtube.com/embed/RInDWhYceLU
3: https://www.youtube.com/embed/UOziR7PoVco
4: https://www.youtube.com/embed/0pwoixRikn4
5: https://www.youtube.com/embed/DFSIQNjKRfk
6: https://www.youtube.com/embed/loAzRUzx1wI
                                                                                                                                                         colors
                                                                                                                                                         <char>
1:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
2:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
3: ['Alizarin Crimson', 'Black Gesso', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
4:                                                                                                        ['Prussian Blue', 'Titanium White', 'Van Dyke Brown']
5:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
6:                                                                                         ['Black Gesso', 'Prussian Blue', 'Titanium White', 'Van Dyke Brown']
                                                                                             color_hex
                                                                                                <char>
1:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
2:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
3: ['#4E1500', '#000000', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
4:                                                                   ['#021E44', '#FFFFFF', '#221B15']
5:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
6:                                                        ['#000000', '#021E44', '#FFFFFF', '#221B15']
   Black_Gesso Bright_Red Burnt_Umber Cadmium_Yellow Dark_Sienna Indian_Red
         <int>      <int>       <int>          <int>       <int>      <int>
1:           0          1           0              1           0          0
2:           0          1           0              1           0          0
3:           1          1           0              1           0          0
4:           0          0           0              0           0          0
5:           0          1           0              1           0          0
6:           1          0           0              0           0          0
   Indian_Yellow Liquid_Black Liquid_Clear Midnight_Black Phthalo_Blue
           <int>        <int>        <int>          <int>        <int>
1:             0            0            0              0            0
2:             0            0            0              0            0
3:             0            0            0              0            0
4:             0            0            0              0            0
5:             0            0            0              0            0
6:             0            0            0              0            0
   Phthalo_Green Prussian_Blue Sap_Green Titanium_White Van_Dyke_Brown
           <int>         <int>     <int>          <int>          <int>
1:             1             1         1              1              1
2:             1             1         1              1              1
3:             1             1         1              1              1
4:             0             1         0              1              1
5:             1             1         1              1              1
6:             0             1         0              1              1
   Yellow_Ochre Alizarin_Crimson total painting_title_clean  word1    word2
          <int>            <int> <int>               <char> <char>   <char>
1:            0                1     8         A Walk Woods      A     Walk
2:            0                1     8         Mt. McKinley    Mt. McKinley
3:            0                1     9         Ebony Sunset  Ebony   Sunset
4:            0                0     3          Winter Mist Winter     Mist
5:            0                1     8         Quiet Stream  Quiet   Stream
6:            0                0     4          Winter Moon Winter     Moon
    word3  word4
   <char> <char>
1:  Woods   <NA>
2:   <NA>   <NA>
3:   <NA>   <NA>
4:   <NA>   <NA>
5:   <NA>   <NA>
6:   <NA>   <NA>

clean new combined data frame to remove all rows that do not have the top 7 themes

# Define the words you're looking for
words_to_keep <- c("mountain", "winter", "oval", "autumn", "lake", "cabin", "sunset")

# Use filter() to keep rows where any of the word columns contain the specified words
combined_data_filtered <- combined_data %>%
  filter(
    # Check each word column (word1, word2, word3, word4) to see if it contains any of the target words
    grepl(paste(words_to_keep, collapse = "|"), word1, ignore.case = TRUE) |
    grepl(paste(words_to_keep, collapse = "|"), word2, ignore.case = TRUE) |
    grepl(paste(words_to_keep, collapse = "|"), word3, ignore.case = TRUE) |
    grepl(paste(words_to_keep, collapse = "|"), word4, ignore.case = TRUE)
  )

# View the filtered dataset
head(combined_data_filtered)
       X painting_index                                             img_src
   <int>          <int>                                              <char>
1:     3            284 https://www.twoinchbrush.com/images/painting284.png
2:     4            285 https://www.twoinchbrush.com/images/painting285.png
3:     6            287 https://www.twoinchbrush.com/images/painting287.png
4:     7            288 https://www.twoinchbrush.com/images/painting288.png
5:    10            291 https://www.twoinchbrush.com/images/painting291.png
6:    11            292 https://www.twoinchbrush.com/images/painting292.png
    painting_title season episode num_colors
            <char>  <int>   <int>      <int>
1:    Ebony Sunset      1       3          9
2:     Winter Mist      1       4          3
3:     Winter Moon      1       6          4
4: Autumn Mountain      1       7          8
5:   Mountain Lake      1      10          8
6:     Winter Glow      1      11          8
                                 youtube_src
                                      <char>
1: https://www.youtube.com/embed/UOziR7PoVco
2: https://www.youtube.com/embed/0pwoixRikn4
3: https://www.youtube.com/embed/loAzRUzx1wI
4: https://www.youtube.com/embed/sDdpc8uisD0
5: https://www.youtube.com/embed/wDnLlywAL5I
6: https://www.youtube.com/embed/Q03YvknOVe0
                                                                                                                                                         colors
                                                                                                                                                         <char>
1: ['Alizarin Crimson', 'Black Gesso', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
2:                                                                                                        ['Prussian Blue', 'Titanium White', 'Van Dyke Brown']
3:                                                                                         ['Black Gesso', 'Prussian Blue', 'Titanium White', 'Van Dyke Brown']
4:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
5:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
6:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
                                                                                             color_hex
                                                                                                <char>
1: ['#4E1500', '#000000', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
2:                                                                   ['#021E44', '#FFFFFF', '#221B15']
3:                                                        ['#000000', '#021E44', '#FFFFFF', '#221B15']
4:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
5:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
6:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
   Black_Gesso Bright_Red Burnt_Umber Cadmium_Yellow Dark_Sienna Indian_Red
         <int>      <int>       <int>          <int>       <int>      <int>
1:           1          1           0              1           0          0
2:           0          0           0              0           0          0
3:           1          0           0              0           0          0
4:           0          1           0              1           0          0
5:           0          1           0              1           0          0
6:           0          1           0              1           0          0
   Indian_Yellow Liquid_Black Liquid_Clear Midnight_Black Phthalo_Blue
           <int>        <int>        <int>          <int>        <int>
1:             0            0            0              0            0
2:             0            0            0              0            0
3:             0            0            0              0            0
4:             0            0            0              0            0
5:             0            0            0              0            0
6:             0            0            0              0            0
   Phthalo_Green Prussian_Blue Sap_Green Titanium_White Van_Dyke_Brown
           <int>         <int>     <int>          <int>          <int>
1:             1             1         1              1              1
2:             0             1         0              1              1
3:             0             1         0              1              1
4:             1             1         1              1              1
5:             1             1         1              1              1
6:             1             1         1              1              1
   Yellow_Ochre Alizarin_Crimson total painting_title_clean    word1    word2
          <int>            <int> <int>               <char>   <char>   <char>
1:            0                1     9         Ebony Sunset    Ebony   Sunset
2:            0                0     3          Winter Mist   Winter     Mist
3:            0                0     4          Winter Moon   Winter     Moon
4:            0                1     8      Autumn Mountain   Autumn Mountain
5:            0                1     8        Mountain Lake Mountain     Lake
6:            0                1     8          Winter Glow   Winter     Glow
    word3  word4
   <char> <char>
1:   <NA>   <NA>
2:   <NA>   <NA>
3:   <NA>   <NA>
4:   <NA>   <NA>
5:   <NA>   <NA>
6:   <NA>   <NA>
# Define the words to remove
words_to_remove <- c("half-oval", "lakeside", "mountains", "winter's", "wintertime")

# Filter the dataset to remove rows where any of the word columns contain any of the unwanted words
combined_data_filtered <- combined_data_filtered %>%
  filter(
    !grepl(paste(words_to_remove, collapse = "|"), word1, ignore.case = TRUE) &
    !grepl(paste(words_to_remove, collapse = "|"), word2, ignore.case = TRUE) &
    !grepl(paste(words_to_remove, collapse = "|"), word3, ignore.case = TRUE) &
    !grepl(paste(words_to_remove, collapse = "|"), word4, ignore.case = TRUE)
  )

# View the filtered dataset
head(combined_data_filtered)
       X painting_index                                             img_src
   <int>          <int>                                              <char>
1:     3            284 https://www.twoinchbrush.com/images/painting284.png
2:     4            285 https://www.twoinchbrush.com/images/painting285.png
3:     6            287 https://www.twoinchbrush.com/images/painting287.png
4:     7            288 https://www.twoinchbrush.com/images/painting288.png
5:    10            291 https://www.twoinchbrush.com/images/painting291.png
6:    11            292 https://www.twoinchbrush.com/images/painting292.png
    painting_title season episode num_colors
            <char>  <int>   <int>      <int>
1:    Ebony Sunset      1       3          9
2:     Winter Mist      1       4          3
3:     Winter Moon      1       6          4
4: Autumn Mountain      1       7          8
5:   Mountain Lake      1      10          8
6:     Winter Glow      1      11          8
                                 youtube_src
                                      <char>
1: https://www.youtube.com/embed/UOziR7PoVco
2: https://www.youtube.com/embed/0pwoixRikn4
3: https://www.youtube.com/embed/loAzRUzx1wI
4: https://www.youtube.com/embed/sDdpc8uisD0
5: https://www.youtube.com/embed/wDnLlywAL5I
6: https://www.youtube.com/embed/Q03YvknOVe0
                                                                                                                                                         colors
                                                                                                                                                         <char>
1: ['Alizarin Crimson', 'Black Gesso', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
2:                                                                                                        ['Prussian Blue', 'Titanium White', 'Van Dyke Brown']
3:                                                                                         ['Black Gesso', 'Prussian Blue', 'Titanium White', 'Van Dyke Brown']
4:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
5:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
6:                ['Alizarin Crimson', 'Bright Red', 'Cadmium Yellow', 'Phthalo Green\\r\\n', 'Prussian Blue', 'Sap Green', 'Titanium White', 'Van Dyke Brown']
                                                                                             color_hex
                                                                                                <char>
1: ['#4E1500', '#000000', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
2:                                                                   ['#021E44', '#FFFFFF', '#221B15']
3:                                                        ['#000000', '#021E44', '#FFFFFF', '#221B15']
4:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
5:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
6:            ['#4E1500', '#DB0000', '#FFEC00', '#102E3C', '#021E44', '#0A3410', '#FFFFFF', '#221B15']
   Black_Gesso Bright_Red Burnt_Umber Cadmium_Yellow Dark_Sienna Indian_Red
         <int>      <int>       <int>          <int>       <int>      <int>
1:           1          1           0              1           0          0
2:           0          0           0              0           0          0
3:           1          0           0              0           0          0
4:           0          1           0              1           0          0
5:           0          1           0              1           0          0
6:           0          1           0              1           0          0
   Indian_Yellow Liquid_Black Liquid_Clear Midnight_Black Phthalo_Blue
           <int>        <int>        <int>          <int>        <int>
1:             0            0            0              0            0
2:             0            0            0              0            0
3:             0            0            0              0            0
4:             0            0            0              0            0
5:             0            0            0              0            0
6:             0            0            0              0            0
   Phthalo_Green Prussian_Blue Sap_Green Titanium_White Van_Dyke_Brown
           <int>         <int>     <int>          <int>          <int>
1:             1             1         1              1              1
2:             0             1         0              1              1
3:             0             1         0              1              1
4:             1             1         1              1              1
5:             1             1         1              1              1
6:             1             1         1              1              1
   Yellow_Ochre Alizarin_Crimson total painting_title_clean    word1    word2
          <int>            <int> <int>               <char>   <char>   <char>
1:            0                1     9         Ebony Sunset    Ebony   Sunset
2:            0                0     3          Winter Mist   Winter     Mist
3:            0                0     4          Winter Moon   Winter     Moon
4:            0                1     8      Autumn Mountain   Autumn Mountain
5:            0                1     8        Mountain Lake Mountain     Lake
6:            0                1     8          Winter Glow   Winter     Glow
    word3  word4
   <char> <char>
1:   <NA>   <NA>
2:   <NA>   <NA>
3:   <NA>   <NA>
4:   <NA>   <NA>
5:   <NA>   <NA>
6:   <NA>   <NA>

Removed stop words and separate words from the painting_title column. Created new data frame with separated words and original bob data set. I left the #green info so that i could understand the code better. End of chatgpt.com resource for coding.

Remove the columns that are not needed for the GGplot

top_bob <- combined_data_filtered|>
  select(-img_src, -num_colors, -episode, -youtube_src, -colors, -color_hex, -Black_Gesso, -Bright_Red, -Burnt_Umber, -Cadmium_Yellow, -Dark_Sienna, -Indian_Red, -Indian_Yellow, -Liquid_Black, -Liquid_Clear, -Midnight_Black, -Phthalo_Blue, -Phthalo_Green, -Prussian_Blue, -Sap_Green, -Titanium_White, -Van_Dyke_Brown, -Yellow_Ochre, -Alizarin_Crimson, -total, -painting_title_clean)
head(top_bob)
       X painting_index  painting_title season    word1    word2  word3  word4
   <int>          <int>          <char>  <int>   <char>   <char> <char> <char>
1:     3            284    Ebony Sunset      1    Ebony   Sunset   <NA>   <NA>
2:     4            285     Winter Mist      1   Winter     Mist   <NA>   <NA>
3:     6            287     Winter Moon      1   Winter     Moon   <NA>   <NA>
4:     7            288 Autumn Mountain      1   Autumn Mountain   <NA>   <NA>
5:    10            291   Mountain Lake      1 Mountain     Lake   <NA>   <NA>
6:    11            292     Winter Glow      1   Winter     Glow   <NA>   <NA>

Switch data frame from wide to long

long_bob <- top_bob%>%
  pivot_longer(cols = 5:8,
               names_to = "word",
               values_to = "theme")%>%
  na.omit(long_bob1)%>%
  filter(grepl(paste(words_to_keep, collapse = "|"), theme, ignore.case = TRUE))

Create new data frame that has a theme count since theme is not numerical

long_bob_table <- long_bob|>
  group_by(season, theme)|>
  summarize(theme_count = n()) 
`summarise()` has grouped output by 'season'. You can override using the
`.groups` argument.
long_bob_table
# A tibble: 115 × 3
# Groups:   season [30]
   season theme    theme_count
    <int> <chr>          <int>
 1      1 Autumn             1
 2      1 Lake               1
 3      1 Mountain           2
 4      1 Sunset             1
 5      1 Winter             3
 6      2 Autumn             1
 7      2 Lake               1
 8      2 Mountain           2
 9      2 Winter             1
10      3 Lake               1
# ℹ 105 more rows

5

Create interactive plot of theme usage over the 31 seasons

bob2 <- ggplot(long_bob_table, aes(x = season, y = theme_count, color = theme))+
  geom_line(size = 1)+
  geom_point()+
  scale_color_bob_ross(painting = "ebony_sunset")+
  labs(x = "Seasons",
                 y = "Theme",
                 title = "Bob Ross Theme Usage Through His Seasons",
                 caption = "Twoinchbrush.com")+
    theme_dark()+
    theme(axis.text.x = element_text(angle = 45))
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
bob2 <- ggplotly(bob2)
bob2

Create regression line and correlation for Theme Mountain

word_to_keep <- c("Mountain")

long_bob_table_reg <- long_bob_table%>%
  filter(grepl(paste(word_to_keep, collapse = "|"), theme, ignore.case = TRUE))
head(long_bob_table_reg)
# A tibble: 6 × 3
# Groups:   season [6]
  season theme    theme_count
   <int> <chr>          <int>
1      1 Mountain           2
2      2 Mountain           2
3      3 Mountain           1
4      4 Mountain           1
5      5 Mountain           2
6      7 Mountain           4
reg1 <- ggplot(long_bob_table_reg, aes(x=season, y=theme_count))+
  geom_point()+
  geom_smooth(method='lm',formula=y~x, se = FALSE, linetype= "dotdash",
size = 0.6)+
  scale_color_bob_ross(painting = "ebony_sunset")+
  labs(x = "Seasons",
                 y = "Mountain Usage",
                 title = "Theme Mountain Regression Model",
                 caption = "Twoinchbrush.com")+
    theme_grey()
reg1

Correlation

cor(long_bob_table_reg$season, long_bob_table_reg$theme_count)
[1] -0.3663275

There is a slight negative correlation between seasons and the usage of the theme Mountain.

6

Linear Regression Model

fit1 <- lm(season ~ theme_count, data = long_bob_table_reg)
summary(fit1)

Call:
lm(formula = season ~ theme_count, data = long_bob_table_reg)

Residuals:
    Min      1Q  Median      3Q     Max 
-13.644  -5.644   1.356   6.911  12.356 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   19.200      2.928   6.557 1.09e-06 ***
theme_count   -2.556      1.354  -1.888   0.0717 .  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 8.121 on 23 degrees of freedom
Multiple R-squared:  0.1342,    Adjusted R-squared:  0.09655 
F-statistic: 3.565 on 1 and 23 DF,  p-value: 0.07169

The model equation is Theme_Count(Mountain) = -2.56(season) + 19.20 The P value right of theme count says that it is not very significant The Rsquared number of .096 says that only 9.6% of the variability can be eplained by this model.

Summary of Bob

Although there was a slight decline in the most common theme of Mountain, I don’t think there is a correlation of theme usage from season to season. Theme usage seams to have a randomness. When Bob Ross started painting he was in Alaska and his beginning of painting mountains my be why it was his most common theme on his TV show. You can see in the interactive plot of theme usage that non of the top themes were used in the last few seasons.

Interesting facts about Bob Ross

  • Bob ross was in the Air Force for 20 years
  • He was stationed in Fairbanks Alaska and there he took a painting class and that started his love of painting
  • Ross’s signature perm was a way for him to save money from haircuts but he later came to hate his style. He kept it because it was such a big part of his persona
  • Bob had a big love of animals and had a squirrel name peapod
  • Bob would film each of his 13 episode seasons in 2 days (had 31 seasons)
  • Bob Ross did his tv show for free and also donated most of the paintings to PBS
  • Bob passed away at 52 due to lymphoma

Sources

  • https://www.twoinchbrush.com data created from this page
  • https://github.com/frankiethull/BobRossColors created the csv file and Bob Ross Color Palette
  • https://www.reddit.com/r/HappyTrees/comments/l3m8ci/my_first_attempt_at_a_bob_ross_autumn_glory_it/ provided the iamge of the painting reproduction Autumn Glory
  • Bob Ross, Inc. (BRI) source for the image in the bar graph with Bob Ross Photo
  • ChatGpt.com used to help create and learn code for cleaning in designated section