library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.0     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ 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(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

Paste your string of values into the parentheses for each color

red <- c(0,251,0,232,0,214,0,82,0,222,0,104,0,202,0,184,1,208,2,223,3,202,4,145,5,205,6,156,7,250,8,204,9,232,10,170,11,227)

green <- c(0,206,0,166,0,204,0,70,0,199,0,64,0,176,0,139,1,167,2,130,3,159,4,103,5,173,6,106,7,169,8,135,9,175,10,110,11,175)

blue <- c(0,148,0,146,0,200,0,72,0,180,0,55,0,164,0,122,1,151,2,79,3,133,4,90,5,146,6,85,7,135,8,101,9,164,10,87,11,156)

# create R, G, B variables to use later based on values pasted above, removing indices

R <- red[c(FALSE, TRUE)]
G <- green[c(FALSE, TRUE)]
B <- blue[c(FALSE, TRUE)]

# Create a data frame of the RGB values
df <- tibble(R,G,B)

# make a version of the data frame with hex_codes
df_hex <- df %>% mutate(hex_code = rgb(R/255,G/255,B/255)) 

#create a 3-D scatterplot of the data
plot_ly(df_hex, x = ~R, y = ~G, z= ~B, marker = list(color = ~hex_code)) %>% 
  add_markers() %>% 
layout(scene = list(xaxis = list(title = 'Red', nticks = 4, range = list(0,255)),
yaxis = list(title = 'Green', nticks = 4, range = list(0,255)),
zaxis = list(title = 'Blue', nticks = 4, range = list(0,255))))
# cluster data with kmeans
df$cluster <- factor(kmeans(df,2)$cluster)

# view a small sample of data to see how it worked
sample_n(df, 10)
## # A tibble: 10 × 4
##        R     G     B cluster
##    <dbl> <dbl> <dbl> <fct>  
##  1   156   106    85 2      
##  2   145   103    90 2      
##  3   202   176   164 1      
##  4    82    70    72 2      
##  5   184   139   122 2      
##  6   205   173   146 1      
##  7   250   169   135 1      
##  8   232   175   164 1      
##  9   202   159   133 1      
## 10   204   135   101 2
# create 3-D scatterplot color-coded by cluster
plot_ly(df, x=~R, y=~G, z=~B, color=~cluster) %>%
     add_markers(size=1.5)
## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels

## Warning in RColorBrewer::brewer.pal(N, "Set2"): minimal value for n is 3, returning requested palette with 3 different levels
# create new data frame grouped by cluster with average colors for each skin tone cluster
df_clust <- df %>% group_by(cluster) %>% mutate(hex_avg = rgb(mean(R)/255, mean(G)/255, mean(B)/255)) %>% group_by(cluster, hex_avg) %>% summarize()
## `summarise()` has grouped output by 'cluster'. You can override using the
## `.groups` argument.
# create color palate
hex_pal <- df_clust$hex_avg

# create a bar graph of the clusters
df %>% group_by(cluster) %>%
  ggplot(aes(cluster, fill=cluster)) +
  geom_bar() + scale_fill_manual(values=hex_pal) +
  labs(title = "Frequency of Skin Tones", x = "Skin Tone Cluster", y = "Frequency")+theme_minimal()