
library(dplyr)
library(scales)
library(ggplot2)


circular_grouped_barplot <- function(data, grp_col_name, label_col_name, value_col_name, text_hjust=NULL){
  # Oryginalny kod: https://www.r-graph-gallery.com/297-circular-barplot-with-groups/
  
  # Funkcja używana do przeskalowania wartości do skali (0, 100)
  # dla lepszego zrozumienia wykresu
  rescale100 <- function(x) rescale(x, to = c(0, 100))
  
  # Opóźnij wykonanie argumentów funkcji.
  # Zostaną one wykonane dzięki użyciu operatora podwójnego wykrzyknika (!!) syntax later on
  grp_var <- enquo(grp_col_name)
  label_var <- enquo(label_col_name)
  value_var <- enquo(value_col_name)
  
  # Odpowiednie przekształcenie danych w celu uzyskania wykresu
  data <- data %>% 
    mutate( 
      !!as_label(grp_var) := as.factor(!!grp_var),
      !!as_label(label_var) := as.factor(!!label_var),
      !!as_label(value_var) := rescale100(!!value_var) )
  
  # Ustaw liczbę 'pustych pasków' w celu dodania na końcu każdej grupy w danych
  empty_bars <- 3
  
  # Utwórz pustą ramkę danych w celu dodania do źródłowej ramki danych
  data_to_add <- data.frame( matrix(NA, empty_bars * nlevels(data[[as_label(grp_var)]]), ncol(data)) )
  colnames(data_to_add) <- colnames(data)
  data_to_add[[as_label(grp_var)]] <- rep(levels(data[[as_label(grp_var)]]), each = empty_bars)
  
  # Add the empty dataframe to the source one
  data <- rbind(data, data_to_add)
  # Zmiana kolejności danych według grup i wartości
  data <- data %>% arrange(!!grp_var, !!value_var)
  # Po uporządkowaniu dodaj identyfikator słupka 'id'
  data$id <- seq(1, nrow(data))
  
  # Uzyskaj całkowitą liczbę słupków
  number_of_bars <- nrow(data)
  
  # Odejmij 0,5 od id, ponieważ etykieta musi być na środku słupków,
  # a nie skrajnie po prawej (1) lub skrajnie po lewej (0)
  angles_of_bars <- 90 - 360 * (data$id - 0.5) / number_of_bars
  
  
  # Zdefiniujmy ramkę danych etykiet, zaczynając od data
  label_data <- data
  label_data$hjust <- ifelse( angles_of_bars < -90, 1, 0)
  label_data$angle <- ifelse( angles_of_bars < -90, angles_of_bars + 180, angles_of_bars)
  
  # Przygotowanie ramki danych dla linii bazowych grupy
  base_data <- data %>% 
    group_by(!!grp_var) %>% 
    summarize(start = min(id),
              end = max(id) - empty_bars) %>% 
    rowwise() %>% 
    mutate(title = floor(mean(c(start, end)))) %>% 
    inner_join( label_data %>% select(id, angle),
                by = c('title' = 'id')) %>% 
    mutate( angle = ifelse( (angle > 0 & angle <= 90) |
                              (angle > 180 & angle <= 270),
                            angle-90, angle+90 ) )
  
  
  # Jeśli istnieje więcej niż jedna grupa...
  if ( nrow(base_data) > 1 ) {
    
    # ...przygotowywanie ramki danych dla siatki
    grid_data <- base_data
    grid_data$end <- grid_data$end[ c( nrow(grid_data), 1:nrow(grid_data)-1)] + 1
    grid_data$start <- grid_data$start - 1
    grid_data <- grid_data[-1,]
    
    # Przygotowanie wykresu również poprzez dodanie siatki
    p <- data %>%
      ggplot(aes(x = id, y = !!value_var, fill = !!grp_var)) +
      
      # Dodaj wykres słupkowy
      geom_bar(stat='identity', alpha=0.5) +
      
      # Dodaj wskaźniki 100/75/50/25
      geom_segment(data=grid_data, aes(x = end, y = 100, xend = start, yend = 100),
                   colour = 'grey', alpha=1, size=0.3 , inherit.aes = FALSE ) +
      geom_segment(data=grid_data, aes(x = end, y = 80, xend = start, yend = 80),
                   colour = 'grey', alpha=1, size=0.3 , inherit.aes = FALSE ) +
      geom_segment(data=grid_data, aes(x = end, y = 60, xend = start, yend = 60),
                   colour = 'grey', alpha=1, size=0.3 , inherit.aes = FALSE ) +
      geom_segment(data=grid_data, aes(x = end, y = 40, xend = start, yend = 40),
                   colour = 'grey', alpha=1, size=0.3 , inherit.aes = FALSE ) +
      geom_segment(data=grid_data, aes(x = end, y = 20, xend = start, yend = 20),
                   colour = 'grey', alpha=1, size=0.3 , inherit.aes = FALSE ) +
      
      # Dodaj tekst wyświetlający wartość każdego wiersza 100/75/50/25
      annotate('text', x = rep(max(data$id), 5), y = c(20, 40, 60, 80, 100),
               label = c('20', '40', '60', '80', 100) , color='grey', size=3,
               angle=0, fontface='bold', hjust=1)
    
  } else {
    # ... jeśli istnieje tylko jedna grupa...
    
    # ... przygotuj wykres bez siatek
    p <- data %>%
      ggplot(aes(x = id, y = !!value_var, fill = !!grp_var)) +
      
      # Dodaj wykres słupkowy
      geom_bar(stat='identity', alpha=0.5) +
      
      # Dodaj tekst wyświetlający wartość każdego wiersza 100/75/50/25
      annotate('text', x = rep(max(data$id), 5), y = c(20, 40, 60, 80, 100),
               label = c('20', '40', '60', '80', 100) , color='grey', size=3,
               angle=0, fontface='bold', hjust=1)
    
  }
  
  # Teraz dodaj do wykresu wszystkie inne cechy
  
  # Liczba odrębnych grup
  num_group_elements <- length(unique(data[[as_label(grp_var)]]))
  
  # Definiowanie poziomego justowania tekstu, jeśli nie zostało przekazane jako parametr
  if (is.null(text_hjust)){
    text_horiz_justification <- rep.int(.5, num_group_elements)
  } else {
    text_horiz_justification <- text_hjust
  }
  
  p <- p +
    
    # Odstęp między osią x a dolną krawędzią figury będzie
    # niejawnie definiować wewnątrz wykresu szerokość pustego okręgu 
    ylim(-120,120) +
    theme_minimal() +
    theme(
      legend.position = 'none',
      axis.text = element_blank(),
      axis.title = element_blank(),
      panel.grid = element_blank(),
      plot.margin = unit(rep(-1,4), 'cm') 
    ) +
    
    # Wrap all in a circle!
    coord_polar()
    
  # Teraz dodajemy odpowiednio obrócone etykiety słupkowe, linie bazowe grup i
  # odpowiednio obrócone etykiety tekstowe grup
  p <- p +
    
    # Dodawanie etykiet
    geom_text(data = label_data,
              aes(x = id, y = !!value_var + 10, label = !!label_var, hjust = hjust),
              color = 'black', fontface = 'bold', alpha = 0.6, size = 3,
              angle = label_data$angle, inherit.aes = FALSE) +
    
    # Dodawanie linii bazowych grup
    geom_segment(data = base_data, aes(x = start, y = -5, xend = end, yend = -5),
                 colour = 'black', alpha=0.8, size=0.6 , inherit.aes = FALSE ) +
    
    # Dodawanie opisów grup
    geom_text(data = base_data, aes(x = title, y = -14, label=!!grp_var, angle = angle),
              hjust=text_horiz_justification, colour = 'black', alpha=0.8, size=4,
              fontface='bold', inherit.aes = FALSE)
  
  return(p)
}


# # Odkomentuj ten kod, jeśli nie używasz go w Power BI
# library(readr)
# csv_full_path <- 'C:\\<twoja-ścieżka>\\Chapter15\\Scores.csv'
# dataset <- read_csv(file = csv_full_path)

# # Możesz również przekazać poziome justowanie tekstu dla pogrupowanego okrągłego wykresu słupkowego jako parametr.
# # Długość wektorów musi pasować do długości speaker.characteristics
# circular_barplot_txthjust <- c(.5,.5,.5,.5)
dataset %>% 
  circular_grouped_barplot(grp_col_name = Characteristic, label_col_name = SpeakerName,
                           value_col_name = Votes)
